Back to index

radiance  4R0+20100331
3ds2mgf.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: 3ds2mgf.c,v 1.10 2008/11/10 19:08:18 greg Exp $";
00003 #endif
00004 /*
00005       3DS2POV.C  by Steve Anger and Jeff Bowermaster
00006                      MGF output added by Greg Ward
00007 
00008       Reads a 3D Studio .3DS file and writes a POV-Ray, Vivid,
00009       Polyray, MGF or raw scene file.
00010 
00011       Version 2.0 Written Feb/96
00012 
00013       Compiled with MSDOS GNU C++ 2.4.1 or generic ANSI-C compiler
00014 */
00015 
00016 #include <stdio.h>
00017 #include <stdlib.h>
00018 #include <math.h>
00019 #include <string.h>
00020 #include <ctype.h>
00021 #include "vect.h"
00022 #include "rayopt.h"
00023 
00024 #ifdef __TURBOC__
00025 #include <alloc.h>
00026 extern unsigned _stklen = 16384;
00027 #endif
00028 
00029 
00030 #define FALSE 0
00031 #define TRUE  1
00032 
00033 /* Internal bounding modes */
00034 #define OFF  0
00035 #define ON   1
00036 #define AUTO 2
00037 
00038 #define MAX_LIB  10
00039 #define ASPECT   1.333
00040 
00041 /* Output formats */
00042 #define POV10    0
00043 #define POV20    1
00044 #define VIVID    2
00045 #define POLYRAY  3
00046 #define MGF      4
00047 #define RAW      99
00048 
00049 #define DEG(x) ((double)(180.0/M_PI)*(x))
00050 #define RAD(x) ((double)(M_PI/180.0)*(x))
00051 
00052 #ifndef M_PI
00053 #define M_PI (3.14159265358979323846)
00054 #endif
00055 
00056 #ifndef MAXFLOAT
00057 #define MAXFLOAT (1e37)
00058 #endif
00059                             /* RGB chromaticity definitions for MGF */
00060 #define CIE_x_r             0.640
00061 #define CIE_y_r             0.330
00062 #define CIE_x_g             0.290
00063 #define CIE_y_g             0.600
00064 #define CIE_x_b             0.150
00065 #define CIE_y_b             0.060
00066                             /* computed luminances from above */
00067 #define CIE_Y_r             0.265
00068 #define CIE_Y_g             0.670
00069 #define CIE_Y_b             0.065
00070 
00071 /* A generic list type */
00072 #define LIST_INSERT(root, node) list_insert ((List **)&root, (List *)node)
00073 #define LIST_FIND(root, name)   list_find   ((List **)&root, name)
00074 #define LIST_DELETE(root, node) list_delete ((List **)&root, (List *)node)
00075 #define LIST_KILL(root)         list_kill   ((List **)&root)
00076 
00077 #define LIST_FIELDS  \
00078     char name[80];   \
00079     void *next;
00080 
00081 
00082 typedef unsigned char  byte;
00083 typedef unsigned short word;
00084 typedef unsigned long  dword;
00085 
00086 typedef struct {
00087     LIST_FIELDS
00088 } List;
00089 
00090 
00091 typedef struct {
00092     int a, b, c;
00093 } Face;
00094 
00095 
00096 typedef struct {
00097     float red, green, blue;
00098 } Colour;
00099 
00100 
00101 /* Transformation command */
00102 typedef struct {
00103     LIST_FIELDS
00104 
00105     Matrix matrix;
00106 } Transform;
00107 
00108 
00109 /* Morph command */
00110 typedef struct {
00111     LIST_FIELDS
00112 
00113     int    count;          /* Number of objects in morph */
00114     char   names[4][80];   /* Name of n'th object in average */
00115     float  weight[4];      /* Weight applied to n'th object */
00116 
00117     Matrix matrix;
00118 } Morph;
00119 
00120 
00121 /* Omni light command */
00122 typedef struct {
00123     LIST_FIELDS
00124 
00125     Vector pos;            /* Light position */
00126     Colour col;            /* Light colour */
00127 } OmniLight;
00128 
00129 
00130 /* Spotlight command */
00131 typedef struct {
00132     LIST_FIELDS
00133 
00134     Vector pos;            /* Spotlight position */
00135     Vector target;         /* Spotlight target location */
00136     Colour col;            /* Spotlight colour */
00137     float  hotspot;        /* Hotspot angle (degrees) */
00138     float  falloff;        /* Falloff angle (degrees) */
00139     int    shadow_flag;    /* Shadow flag (not used) */
00140 } Spotlight;
00141 
00142 
00143 /* Camera command */
00144 typedef struct {
00145     LIST_FIELDS
00146 
00147     Vector pos;            /* Camera location */
00148     Vector target;         /* Camera target */
00149     float  bank;           /* Banking angle (degrees) */
00150     float  lens;           /* Camera lens size (mm) */
00151 } Camera;
00152 
00153 
00154 /* Material list */
00155 typedef struct {
00156     LIST_FIELDS
00157 
00158     int  external;         /* Externally defined material? */
00159 } Material;
00160 
00161 
00162 /* Object summary */
00163 typedef struct {
00164     LIST_FIELDS
00165 
00166     Vector center;         /* Min value of object extents */
00167     Vector lengths;        /* Max value of object extents */
00168 } Summary;
00169 
00170 
00171 /* Material property */
00172 typedef struct {
00173     LIST_FIELDS
00174 
00175     Colour ambient;
00176     Colour diffuse;
00177     Colour specular;
00178     float  shininess;
00179     float  transparency;
00180     float  reflection;
00181     int    self_illum;
00182     int    two_side;
00183     char   tex_map[40];
00184     float  tex_strength;
00185     char   bump_map[40];
00186     float  bump_strength;
00187 } MatProp;
00188 
00189 
00190 /* Default material property */
00191 MatProp DefaultMaterial = { "Default", NULL, {1.0, 1.0, 1.0}, {1.0, 1.0, 1.0},
00192                           {1.0, 1.0, 1.0}, 70.0, 0.0, 0.0, FALSE, FALSE };
00193 
00194 /* A mesh object */
00195 typedef struct {
00196     LIST_FIELDS
00197 
00198     int  vertices;         /* Number of vertices */
00199     Vector *vertex;        /* List of object vertices */
00200 
00201     int  faces;            /* Number of faces */
00202     Face *face;            /* List of object faces */
00203     Material **mtl;        /* Materials for each face */
00204 
00205     Matrix matrix;         /* Local mesh matrix */
00206     Matrix invmatrix;
00207     Vector center;         /* Center of object */
00208     Vector lengths;        /* Dimensions of object */
00209 
00210     int hidden;            /* Hidden flag */
00211     int shadow;            /* Shadow flag */
00212 } Mesh;
00213 
00214 
00215 typedef struct {
00216     dword start;
00217     dword end;
00218     dword length;
00219     word  tag;
00220 } Chunk;
00221 
00222 
00223 typedef struct {
00224     byte red;
00225     byte green;
00226     byte blue;
00227 } Colour_24;
00228 
00229 
00230 Colour Black = {0.0, 0.0, 0.0};
00231 
00232 OmniLight *omni_list  = NULL;
00233 Spotlight *spot_list  = NULL;
00234 Camera    *cam_list   = NULL;
00235 Mesh      *mesh_list  = NULL;
00236 Transform *trans_list = NULL;
00237 Morph     *morph_list = NULL;
00238 Material  *mtl_list   = NULL;
00239 List      *excl_list  = NULL;
00240 List      *box_list   = NULL;
00241 MatProp   *mprop_list = NULL;
00242 Summary   *summary    = NULL;
00243 
00244 
00245 FILE   *in;
00246 FILE   *out;
00247 char   inname[80];
00248 char   outname[80];
00249 char   vuename[80];
00250 char   obj_name[80] = "";
00251 Colour fog_colour = {0.0, 0.0, 0.0};
00252 Colour col        = {0.0, 0.0, 0.0};
00253 Colour global_amb = {0.1, 0.1, 0.1};
00254 Vector pos        = {0.0, 0.0, 0.0};
00255 Vector target     = {0.0, 0.0, 0.0};
00256 float  fog_distance = 0.0;
00257 float  hotspot = -1;
00258 float  falloff = -1;
00259 Mesh   *mesh = NULL;
00260 int    frame = -1;
00261 char   libname[MAX_LIB][80];
00262 float  smooth = 60.0;
00263 int    bound = 0;
00264 int    verbose = 0;
00265 int    format = POV20;
00266 int    internal_bounding = AUTO;
00267 int    box_all = FALSE;
00268 int    cameras = 0;
00269 int    libs = 0;
00270 float  vue_version = 1.0;
00271 Matrix *ani_matrix = NULL;
00272 int    no_opt = FALSE;
00273 FILE   *meshf = NULL;
00274 
00275 
00276 void process_args (int argc, char *argv[]);
00277 void parse_option (char *option);
00278 void list_insert (List **root, List *new_node);
00279 void *list_find (List **root, char *name);
00280 void list_delete (List **root, List *node);
00281 void list_kill (List **root);
00282 Material *update_materials (char *new_material, int ext);
00283 MatProp *create_mprop (void);
00284 void read_library (char *fname);
00285 void write_intro (FILE *f);
00286 void write_summary (FILE *f);
00287 void write_bgsolid (FILE *f, Colour col);
00288 void write_light (FILE *f, char *name, Vector pos, Colour col);
00289 void write_spot (FILE *f, char *name, Vector pos, Vector target, Colour col,
00290         float hotspot, float falloff);
00291 void write_fog (FILE *f, Colour col, float dist);
00292 void write_camera (FILE *f, char *name, Vector pos, Vector target, float lens,
00293         float bank);
00294 void write_material (FILE *f, char *mat);
00295 void write_pov10_material (FILE *f, MatProp *m);
00296 void write_pov20_material (FILE *f, MatProp *m);
00297 void write_vivid_material (FILE *f, MatProp *m);
00298 void write_polyray_material (FILE *f, MatProp *m);
00299 void write_mgf_material (FILE *f, MatProp *m);
00300 void write_mesh (FILE *f, Mesh *mesh);
00301 Transform *parse_transform (char *string);
00302 Morph *parse_morph (char *string);
00303 OmniLight *parse_omnilight (char *string);
00304 Spotlight *parse_spotlight (char *string);
00305 Camera *parse_camera (char *string);
00306 void read_frame (char *filename, int frame_no);
00307 void find_frame (FILE *f, int frame_no);
00308 void save_animation (void);
00309 Mesh *create_mesh (char *name, int vertices, int faces);
00310 Mesh *copy_mesh (Mesh *mesh);
00311 void free_mesh_data (Mesh *mesh);
00312 void update_limits (Mesh *mesh);
00313 char *before (char *str, char *target);
00314 char *after (char *str, char *target);
00315 char *between (char *str, char *target1, char *target2);
00316 char *parse_string (char *str);
00317 char upcase (char c);
00318 float colour_intens (Colour *colour);
00319 void parse_file (void);
00320 void parse_3ds (Chunk *mainchunk);
00321 void parse_mdata (Chunk *mainchunk);
00322 void parse_fog (Chunk *mainchunk);
00323 void parse_fog_bgnd (void);
00324 void parse_mat_entry (Chunk *mainchunk);
00325 char *parse_mapname (Chunk *mainchunk);
00326 void parse_named_object (Chunk *mainchunk);
00327 void parse_n_tri_object (Chunk *mainchunk);
00328 void parse_point_array (void);
00329 void parse_face_array (Chunk *mainchunk);
00330 void parse_msh_mat_group (void);
00331 void parse_smooth_group (void);
00332 void parse_mesh_matrix (void);
00333 void parse_n_direct_light (Chunk *mainchunk);
00334 void parse_dl_spotlight (void);
00335 void parse_n_camera (void);
00336 void parse_colour (Colour *colour);
00337 void parse_colour_f (Colour *colour);
00338 void parse_colour_24 (Colour_24 *colour);
00339 float parse_percentage (void);
00340 short parse_int_percentage (void);
00341 float parse_float_percentage (void);
00342 void start_chunk (Chunk *chunk);
00343 void end_chunk (Chunk *chunk);
00344 byte read_byte (void);
00345 word read_word (void);
00346 dword read_dword (void);
00347 float read_float (void);
00348 void read_point (Vector v);
00349 char *read_string (void);
00350 float findfov (float lens);
00351 int read_mgfmatname (char *s, int n, FILE *f);
00352 
00353 char *progname;
00354 
00355 
00356 int main (int argc, char *argv[])
00357 {
00358     char meshfname[128];
00359     Material *m;
00360     int i;
00361 
00362     process_args (argc, argv);
00363 
00364     if (!no_opt) {
00365        opt_set_format (format);
00366        opt_set_dec (4);
00367        opt_set_bound (bound);
00368        opt_set_smooth (smooth);
00369        opt_set_quiet (!verbose);
00370        opt_set_fname (outname, "");
00371     } else if (format == MGF) {
00372        strcpy(meshfname, outname);
00373        add_ext(meshfname, "inc", 1);
00374        if (!strcmp(meshfname, outname)) {
00375            printf ("Output and mesh file names are identical!\n");
00376            exit (1);
00377        }
00378        if ((meshf = fopen (meshfname, "w")) == NULL) {
00379            printf ("Cannot open mesh output file %s!\n", meshfname);
00380            exit (1);
00381        }
00382     }
00383 
00384     if ((in = fopen (inname, "rb")) == NULL) {
00385        printf ("Cannot open input file %s!\n", inname);
00386        exit (1);
00387     }
00388 
00389     if ((out = fopen (outname, "w")) == NULL) {
00390        printf ("Cannot open output file %s!\n", outname);
00391        exit (1);
00392     }
00393 
00394     /* Load the names of pre-defined materials */
00395     for (i = 0; i < MAX_LIB; i++) {
00396        if (strlen(libname[i]) > 0)
00397            read_library (libname[i]);
00398     }
00399 
00400     /* Load the instructions for the current frame */
00401     if (strlen(vuename) > 0)
00402        read_frame (vuename, frame);
00403 
00404     printf("Output to: %s\n", outname);
00405 
00406     if (frame >= 0)
00407        printf ("Generating frame #%d\n", frame);
00408 
00409     printf("\nPlease wait; Processing...\n");
00410 
00411     write_intro(out);
00412 
00413     parse_file();
00414 
00415     fclose(in);
00416 
00417     for (m = mtl_list; m != NULL; m = m->next) {
00418        if (!m->external)
00419            write_material (out, m->name);
00420     }
00421 
00422     if (frame >= 0)
00423        save_animation();
00424 
00425     if (!no_opt) {
00426         write_summary (out);
00427         fflush (out);
00428 
00429        opt_finish();
00430     } else if (meshf != NULL) {
00431        fclose(meshf);
00432        fprintf (out, "i %s\n", meshfname);
00433     }
00434 
00435     fclose (out);
00436 
00437     LIST_KILL (omni_list);
00438     LIST_KILL (spot_list);
00439     LIST_KILL (cam_list);
00440     LIST_KILL (mesh_list);
00441     LIST_KILL (trans_list);
00442     LIST_KILL (morph_list);
00443     LIST_KILL (mtl_list);
00444     LIST_KILL (excl_list);
00445     LIST_KILL (box_list);
00446     LIST_KILL (mprop_list);
00447     LIST_KILL (summary);
00448 
00449     return 0;
00450 }
00451 
00452 
00453 /* Handle the command line args */
00454 void process_args (int argc, char *argv[])
00455 {
00456     int i;
00457     char *env_opt, *option;
00458 
00459     printf("\n\nAutodesk 3D Studio to Raytracer file Translator. Feb/96\n");
00460     printf("Version 2.0 by Steve Anger and Jeff Bowermaster 1996\n");
00461     printf ("\n");
00462 
00463     if (argc < 2) {
00464        printf ("Usage: %s inputfile[.3ds] [outputfile] [options]\n\n", argv[0]);
00465        printf ("Options: -snnn        - Smooth triangles with angles < nnn\n");
00466        printf ("         -l<filename> - Specifies native material library\n");
00467        printf ("         -a<filename> - Use animation information in specified file\n");
00468        printf ("         -fnnn        - Generate frame nnn of animation\n");
00469        printf ("         -x<object>   - Exclude this object from conversion\n");
00470        printf ("         -b<object>   - Convert this object as a box\n");
00471        printf ("         +i, -i       - Turn internal bounding on or off\n");
00472        printf ("         +v, -v       - Turn verbose status messages on or off\n");
00473        printf ("         -op          - Output to POV-Ray 2.0 format\n");
00474        printf ("         -op1         - Output to POV-Ray 1.0 format\n");
00475        printf ("         -ov          - Output to Vivid format\n");
00476        printf ("         -ol          - Output to poLyray format\n");
00477        printf ("         -om          - Output to MGF\n");
00478        printf ("         -or          - Output to RAW triangle format\n\n");
00479        printf ("ex. %s birdshow +v -lmaterials.inc\n\n", argv[0]);
00480        exit(1);
00481     }
00482                                    /* figure default format from name */
00483     progname = strrchr(argv[0], '/');
00484     if (progname == NULL) progname = argv[0];
00485     else progname++;
00486     if (!strcmp(progname, "3ds2pov"))
00487        format = POV20;
00488     else if (!strcmp(progname, "3ds2viv"))
00489        format = VIVID;
00490     else if (!strcmp(progname, "3ds2pi"))
00491        format = POLYRAY;
00492     else if (!strcmp(progname, "3ds2mgf"))
00493        format = MGF;
00494     else if (!strcmp(progname, "3ds2raw"))
00495        format = RAW;
00496     else
00497        format = POV20;             /* default if program name strange */
00498 
00499     strcpy (inname, "");
00500     strcpy (outname, "");
00501     strcpy (vuename, "");
00502 
00503     for (i = 0; i < MAX_LIB; i++)
00504        strcpy (libname[i], "");
00505 
00506     frame = -1;
00507     smooth = 70.0;
00508     bound = 0;
00509     verbose = 0;
00510     internal_bounding = AUTO;
00511     box_all = FALSE;
00512     libs = 0;
00513 
00514     /* Parse the enviroment string options */
00515     env_opt = getenv ("3DS2POV");
00516 
00517     if (env_opt != NULL) {
00518        option = parse_string (env_opt);
00519 
00520        while (strlen(option) > 0) {
00521            parse_option (option);
00522            option = parse_string (NULL);
00523        }
00524     }
00525 
00526     /* Parse the command line options */
00527     for (i = 1; i < argc; i++)
00528        parse_option (argv[i]);
00529 
00530     if (strlen(inname) == 0)
00531        abortmsg ("No input file specified", 1);
00532 
00533     if (strlen(outname) == 0)
00534        strcpy (outname, inname);
00535 
00536     switch (format) {
00537        case POV10:
00538        case POV20:   add_ext (outname, "pov", 1); break;
00539        case VIVID:   add_ext (outname, "v",   1); break;
00540        case POLYRAY: add_ext (outname, "pi",  1); break;
00541        case MGF:     add_ext (outname, "mgf", 1); break;
00542        case RAW:     add_ext (outname, "raw", 1); break;
00543     }
00544 
00545     switch (internal_bounding) {
00546        case OFF:  bound = 2; break;
00547        case ON:   bound = 0; break;
00548        case AUTO: bound = (format == POV10) ? 0 : 2; break;
00549     }
00550 
00551     if ((strlen(vuename) > 0) != (frame >= 0))
00552        abortmsg ("The -a and -f parameters must be used together", 1);
00553 
00554     if (format == RAW || (format == MGF && smooth < 0.1))
00555        no_opt = TRUE;
00556 }
00557 
00558 
00559 void parse_option (char *option)
00560 {
00561     List *excl, *box;
00562     char name[80];
00563 
00564     if (option[0] == '-' || option[0] == '+') {
00565        switch (upcase(option[1])) {
00566            case 'A': strcpy (vuename, &option[2]);
00567                     break;
00568 
00569            case 'B': strcpy (name, parse_string (&option[2]));
00570                     if (strlen(name) == 0)
00571                        box_all = TRUE;
00572                     else {
00573                        cleanup_name (name);
00574 
00575                        box = malloc (sizeof (*box));
00576                        strcpy (box->name, name);
00577 
00578                        LIST_INSERT (box_list, box);
00579                     }
00580                     break;
00581 
00582            case 'F': if (option[2] != '\0')
00583                        frame = atoi (&option[2]);
00584                     break;
00585 
00586            case 'I': if (option[0] == '-')
00587                        internal_bounding = OFF;
00588                     else
00589                        internal_bounding = ON;
00590                     break;
00591 
00592            case 'L': if (libs == MAX_LIB)
00593                        abortmsg ("Too many libraries specified", 1);
00594 
00595                     strcpy (libname[libs++], &option[2]);
00596                     break;
00597 
00598            case 'O': switch (upcase(option[2])) {
00599                        case 'P': if (option[3] == '1')
00600                                    format = POV10;
00601                                 else
00602                                    format = POV20;
00603                                 break;
00604 
00605                        case 'V': format = VIVID;
00606                                 break;
00607 
00608                        case 'L': format = POLYRAY;
00609                                 break;
00610 
00611                        case 'R': format = RAW;
00612                                 break;
00613 
00614                        case 'M': format = MGF;
00615                                 break;
00616 
00617                        default:  printf ("Invalid output format %s specified\n", option);
00618                                 exit(1);
00619                     }
00620                     break;
00621 
00622            case 'S': if (option[2] != '\0')
00623                        smooth = atof (&option[2]);
00624                     break;
00625 
00626            case 'U': printf ("Warning: -u parameter no long has any effect\n");
00627                     printf ("         use +i or -i instead.\n");
00628                     break;
00629 
00630            case 'V': if (option[0] == '-')
00631                        verbose = 0;
00632                     else
00633                        verbose = 1;
00634                     break;
00635 
00636            case 'X': strcpy (name, parse_string (&option[2]));
00637                     cleanup_name (name);
00638 
00639                     excl = malloc (sizeof (*excl));
00640                     strcpy (excl->name, name);
00641 
00642                     LIST_INSERT (excl_list, excl);
00643                     break;
00644 
00645            default : printf ("\nInvalid option %s specified\n", option);
00646                     exit (1);
00647        }
00648     }
00649     else if (strlen (inname) == 0) {
00650        strcpy (inname, option);
00651        add_ext (inname, "3ds", 0);
00652     }
00653     else if (strlen (outname) == 0)
00654        strcpy (outname, option);
00655     else
00656        abortmsg ("Too many file names specified.\n", 1);
00657 }
00658 
00659 
00660 /* Insert a new node into the list */
00661 void list_insert (List **root, List *new_node)
00662 {
00663     new_node->next = *root;
00664 
00665     *root = new_node;
00666 }
00667 
00668 
00669 /* Find the node with the specified name */
00670 void *list_find (List **root, char *name)
00671 {
00672     List *p;
00673 
00674     for (p = *root; p != NULL; p = p->next) {
00675        if (strcmp (p->name, name) == 0)
00676            break;
00677     }
00678 
00679     return (void *)p;
00680 }
00681 
00682 
00683 /* Delete the indicated node from the list */
00684 void list_delete (List **root, List *node)
00685 {
00686     List *prev;
00687 
00688     prev = *root;
00689     while (prev != NULL && prev->next != node)
00690        prev = prev->next;
00691 
00692     if (prev == NULL)
00693        *root = node->next;
00694     else
00695        prev->next = node->next;
00696 
00697     free (node);
00698 }
00699 
00700 
00701 /* Delete the entire list */
00702 void list_kill (List **root)
00703 {
00704     List *temp;
00705 
00706     while (*root != NULL) {
00707        temp = *root;
00708        *root = (*root)->next;
00709        free (temp);
00710     }
00711 }
00712 
00713 
00714 /* Add a new material to the material list */
00715 Material *update_materials (char *new_material, int ext)
00716 {
00717     Material *p;
00718 
00719     p = LIST_FIND (mtl_list, new_material);
00720 
00721     if (p == NULL) {
00722        p = malloc (sizeof (*p));
00723 
00724        if (p == NULL)
00725            abortmsg ("Out of memory adding material", 1);
00726 
00727        strcpy (p->name, new_material);
00728        p->external = ext;
00729 
00730        LIST_INSERT (mtl_list, p);
00731     }
00732 
00733     return p;
00734 }
00735 
00736 
00737 MatProp *create_mprop()
00738 {
00739     MatProp *new_mprop;
00740 
00741     new_mprop = malloc (sizeof(*new_mprop));
00742     if (new_mprop == NULL)
00743        abortmsg ("Out of memory adding material", 1);
00744 
00745     strcpy (new_mprop->name, "");
00746     new_mprop->ambient = Black;
00747     new_mprop->diffuse = Black;
00748     new_mprop->specular = Black;
00749     new_mprop->shininess = 0.0;
00750     new_mprop->transparency = 0.0;
00751     new_mprop->reflection = 0.0;
00752     new_mprop->self_illum = FALSE;
00753     new_mprop->two_side = FALSE;
00754 
00755     strcpy (new_mprop->tex_map, "");
00756     new_mprop->tex_strength = 0.0;
00757 
00758     strcpy (new_mprop->bump_map, "");
00759     new_mprop->bump_strength = 0.0;
00760 
00761     return new_mprop;
00762 }
00763 
00764 
00765 /* Load in any predefined materials */
00766 void read_library (char *fname)
00767 {
00768     FILE *lib;
00769     char string[256], name[80];
00770 
00771     if ((lib = fopen (fname, "r")) == NULL) {
00772        printf ("Cannot open texture library file %s!\n", fname);
00773        exit(1);
00774     }
00775 
00776     switch (format) {
00777        case POV10:
00778        case POV20:
00779            while (fgets (string, 256, lib) != NULL) {
00780               if (strstr (string, "#declare")) {
00781                   strcpy (name, between (string, "#declare", "="));
00782                   cleanup_name (name);
00783                   (void)update_materials (name, TRUE);
00784               }
00785            }
00786            break;
00787 
00788        case VIVID:
00789            while (fgets (string, 256, lib) != NULL) {
00790               if (strstr (string, "#define")) {
00791                   (void)parse_string (string);
00792                   strcpy (name, parse_string (NULL));
00793                   cleanup_name (name);
00794                   (void)update_materials (name, TRUE);
00795               }
00796            }
00797            break;
00798 
00799        case POLYRAY:
00800            while (fgets (string, 256, lib) != NULL) {
00801               if (strstr (string, "define")) {
00802                   (void)parse_string (string);
00803                   strcpy (name, parse_string (NULL));
00804                   cleanup_name (name);
00805                   (void)update_materials (name, TRUE);
00806               }
00807            }
00808            break;
00809 
00810        case MGF:
00811            while (read_mgfmatname(name, 80, lib))
00812               (void)update_materials (name, TRUE);
00813            break;
00814     }
00815 
00816     fclose (lib);
00817 }
00818 
00819 
00820 /* parse the next MGF material name from f, return FALSE if EOF */
00821 int read_mgfmatname (char *s, int n, FILE *f)
00822 {      
00823     char inpline[128];
00824     register char *cp, *cp2;
00825     register int i;
00826                                    /* find material */
00827     while (fgets(inpline, sizeof(inpline), f) != NULL) {
00828        for (cp = inpline; isspace(*cp); cp++)
00829            ;
00830        if (*cp++ != 'm' || !isspace(*cp++))
00831            continue;
00832        while (isspace(*cp))
00833            cp++;
00834        if (!*cp)
00835            continue;
00836        for (i=n, cp2=s; *cp && !isspace(*cp); cp++)     /* get name */
00837            if (--i > 0)
00838               *cp2++ = *cp;
00839        *cp2 = '\0';
00840        while (isspace(*cp))
00841            cp++;
00842        if (*cp++ != '=' || !isspace(*cp))        /* not defined? */
00843            continue;
00844        return TRUE;
00845     }
00846     return FALSE;
00847 }
00848 
00849 
00850 void write_intro (FILE *f)
00851 {
00852     int i;
00853 
00854     switch (format) {
00855        case POV10:
00856        case POV20:
00857            fprintf (f, "#include \"colors.inc\"\n");
00858            fprintf (f, "#include \"shapes.inc\"\n");
00859            fprintf (f, "#include \"textures.inc\"\n");
00860 
00861            for (i = 0; i < MAX_LIB; i++) {
00862               if (strlen(libname[i]) > 0)
00863                   fprintf (f, "#include \"%s\"\n", libname[i]);
00864            }
00865 
00866            fprintf (f, "\n");
00867            break;
00868 
00869        case VIVID:
00870            fprintf (f, "#include color.vc\n");
00871 
00872            for (i = 0; i < MAX_LIB; i++) {
00873               if (strlen(libname[i]) > 0)
00874                   fprintf (f, "#include %s\n", libname[i]);
00875            }
00876 
00877            fprintf (f, "\n");
00878            break;
00879 
00880        case POLYRAY:
00881            fprintf (f, "include \"colors.inc\"\n");
00882 
00883            for (i = 0; i < MAX_LIB; i++) {
00884               if (strlen(libname[i]) > 0)
00885                   fprintf (f, "include \"%s\"\n", libname[i]);
00886            }
00887 
00888            fprintf (f, "\n");
00889            break;
00890 
00891        case MGF:
00892            fprintf (f, "c R =\n\tcxy %.3f %.3f\n", CIE_x_r, CIE_y_r);
00893            fprintf (f, "c G =\n\tcxy %.3f %.3f\n", CIE_x_g, CIE_y_g);
00894            fprintf (f, "c B =\n\tcxy %.3f %.3f\n", CIE_x_b, CIE_y_b);
00895 
00896            for (i = 0; i < MAX_LIB; i++) {
00897               if (strlen(libname[i]) > 0)
00898                   fprintf (f, "i %s\n", libname[i]);
00899            }
00900 
00901            fprintf (f, "\n");
00902            break;
00903     }
00904 }
00905 
00906 
00907 /* Write the object summary */
00908 void write_summary (FILE *f)
00909 {
00910     char *comstr;
00911     Summary *s;
00912 
00913     if (summary == NULL)
00914         return;
00915 
00916     switch (format) {
00917        case POV10:
00918        case POV20:
00919        case VIVID:
00920        case POLYRAY:
00921            comstr = "//";
00922            break;
00923        case MGF:
00924            comstr = "# ";
00925            break;
00926        default:
00927               printf ("Illegal format in write_summary() '%c'\n", format);
00928               exit(1);
00929     }
00930     fprintf (f, "%s   Object    CenterX    CenterY    CenterZ    LengthX    LengthY    LengthZ\n", comstr);
00931     fprintf (f, "%s ---------- ---------- ---------- ---------- ---------- ---------- ----------\n", comstr);
00932 
00933     for (s = summary; s != NULL; s = s->next) {
00934         fprintf (f, "%s %-10s%11.2f%11.2f%11.2f%11.2f%11.2f%11.2f\n",
00935                comstr, s->name, s->center[X], s->center[Y], s->center[Z],
00936                s->lengths[X], s->lengths[Y], s->lengths[Z]);
00937     }
00938 
00939     fprintf (f, "\n");
00940 }
00941 
00942 
00943 /* Write background solid colour */
00944 void write_bgsolid (FILE *f, Colour col)
00945 {
00946     switch (format) {
00947        case POV10:
00948            fprintf (f, "/* Background colour */\n");
00949            fprintf (f, "object {\n");
00950            fprintf (f, "   sphere { <0.0 0.0 0.0> 1e6 }\n");
00951            fprintf (f, "   texture {\n");
00952            fprintf (f, "      ambient 1.0\n");
00953            fprintf (f, "      diffuse 0.0\n");
00954            fprintf (f, "      color red %4.2f green %4.2f blue %4.2f\n",
00955                              col.red, col.green, col.blue);
00956            fprintf (f, "   }\n");
00957            fprintf (f, "}\n\n");
00958            break;
00959 
00960        case POV20:
00961            fprintf (f, "background { color red %4.2f green %4.2f blue %4.2f }\n\n",
00962                         col.red, col.green, col.blue);
00963            break;
00964 
00965        case POLYRAY:
00966            fprintf (f, "background <%4.2f, %4.2f, %4.2f>\n\n",
00967                         col.red, col.green, col.blue);
00968            break;
00969     }
00970 }
00971 
00972 
00973 void write_light (FILE *f, char *name, Vector pos, Colour col)
00974 {
00975     switch (format) {
00976        case POV10:
00977            fprintf (f, "/* Light: %s */\n", name);
00978            fprintf (f, "object {\n");
00979            fprintf (f, "    light_source { <%.4f %.4f %.4f> color red %4.2f green %4.2f blue %4.2f }\n",
00980                      pos[X], pos[Y], pos[Z], col.red, col.green, col.blue);
00981            fprintf (f, "}\n\n");
00982            break;
00983 
00984        case POV20:
00985            fprintf (f, "/* Light: %s */\n", name);
00986            fprintf (f, "light_source {\n");
00987            fprintf (f, "    <%.4f, %.4f, %.4f> color rgb <%4.2f, %4.2f, %4.2f>\n",
00988                    pos[X], pos[Y], pos[Z], col.red, col.green, col.blue);
00989            fprintf (f, "}\n\n");
00990            break;
00991 
00992        case VIVID:
00993            fprintf (f, "/* Light: %s */\n", name);
00994            fprintf (f, "light {\n");
00995            fprintf (f, "    type point\n");
00996            fprintf (f, "    position %.4f %.4f %.4f\n",
00997                           pos[X], pos[Y], pos[Z]);
00998            fprintf (f, "    color %4.2f %4.2f %4.2f\n",
00999                           col.red, col.green, col.blue);
01000            fprintf (f, "}\n\n");
01001            break;
01002 
01003        case POLYRAY:
01004            fprintf (f, "// Light: %s\n", name);
01005            fprintf (f, "light <%4.2f, %4.2f, %4.2f>, <%.4f, %.4f, %.4f>\n\n",
01006                       col.red, col.green, col.blue, pos[X], pos[Y], pos[Z]);
01007            break;
01008 
01009        case MGF:
01010            fprintf (f, "\n# Light\n");
01011            if (name[0]) fprintf (f, "o %s\n", name);
01012            fprintf (f, "m\n\tsides 1\n\tc\n\t\t\tcmix %.3f R %.3f G %.3f B\n\ted %e\n",
01013                   CIE_Y_r*col.red, CIE_Y_g*col.green, CIE_Y_b*col.blue,
01014            100000.0*(CIE_Y_r*col.red + CIE_Y_g*col.green + CIE_Y_b*col.blue));
01015            fprintf (f, "v c =\n\tp %.4f %.4f %.4f\nsph c .01\n",
01016                   pos[X], pos[Y], pos[Z]);
01017            if (name[0]) fprintf (f, "o\n");
01018            fprintf (f, "\n");
01019            break;
01020     }
01021 }
01022 
01023 
01024 void write_spot (FILE *f, char *name, Vector pos, Vector target, Colour col,
01025                        float hotspot, float falloff)
01026 {
01027     switch (format) {
01028        case POV10:
01029            fprintf (f, "/* Spotlight: %s */\n", name);
01030            fprintf (f, "object {\n");
01031            fprintf (f, "    light_source {\n");
01032            fprintf (f, "        <%.4f %.4f %.4f> color red %4.2f green %4.2f blue %4.2f\n",
01033                                pos[X], pos[Y], pos[Z],
01034                                col.red, col.green, col.blue);
01035            fprintf (f, "        spotlight\n");
01036            fprintf (f, "        point_at <%.4f %.4f %.4f>\n",
01037                                target[X], target[Y], target[Z]);
01038            fprintf (f, "        tightness 0\n");
01039            fprintf (f, "        radius %.2f\n", 0.5*hotspot);
01040            fprintf (f, "        falloff %.2f\n", 0.5*falloff);
01041            fprintf (f, "    }\n");
01042            fprintf (f, "}\n\n");
01043            break;
01044 
01045        case POV20:
01046            fprintf (f, "/* Spotlight: %s */\n", name);
01047            fprintf (f, "light_source {\n");
01048            fprintf (f, "    <%.4f, %.4f, %.4f> color rgb <%4.2f, %4.2f, %4.2f>\n",
01049                           pos[X], pos[Y], pos[Z],
01050                           col.red, col.green, col.blue);
01051            fprintf (f, "    spotlight\n");
01052            fprintf (f, "    point_at <%.4f, %.4f, %.4f>\n",
01053                           target[X], target[Y], target[Z]);
01054            fprintf (f, "    tightness 0\n");
01055            fprintf (f, "    radius %.2f\n", 0.5*hotspot);
01056            fprintf (f, "    falloff %.2f\n", 0.5*falloff);
01057            fprintf (f, "}\n\n");
01058            break;
01059 
01060        case VIVID:
01061            fprintf (f, "/* Spotlight: %s */\n", name);
01062            fprintf (f, "light {\n");
01063            fprintf (f, "    type spot\n");
01064            fprintf (f, "    position %.4f %.4f %.4f\n",
01065                           pos[X], pos[Y], pos[Z]);
01066            fprintf (f, "    at %.4f %.4f %.4f\n",
01067                           target[X], target[Y], target[Z]);
01068            fprintf (f, "    color %4.2f %4.2f %4.2f\n",
01069                           col.red, col.green, col.blue);
01070            fprintf (f, "    min_angle %.2f\n", hotspot);
01071            fprintf (f, "    max_angle %.2f\n", falloff);
01072            fprintf (f, "}\n\n");
01073            break;
01074 
01075        case POLYRAY:
01076            fprintf (f, "// Spotlight: %s\n", name);
01077            fprintf (f, "spot_light <%4.2f, %4.2f, %4.2f>, <%.4f, %.4f, %.4f>,\n",
01078                        col.red, col.green, col.blue, pos[X], pos[Y], pos[Z]);
01079            fprintf (f, "           <%.4f, %.4f, %.4f>, 0.0, %.2f, %.2f\n\n",
01080                        target[X], target[Y], target[Z], hotspot/2.0, falloff/2.0);
01081            break;
01082 
01083        case MGF:
01084            fprintf (f, "\n# Spotlight\n");
01085            if (name[0]) fprintf (f, "o %s\n", name);
01086            fprintf (f, "# hotspot: %.2f\n# falloff: %.2f\n", hotspot, falloff);
01087            fprintf (f, "m\n\tsides 1\n\tc\n\t\t\tcmix %.3f R %.3f G %.3f B\n\ted %e\n",
01088                   CIE_Y_r*col.red, CIE_Y_g*col.green, CIE_Y_b*col.blue,
01089            100000.0*(CIE_Y_r*col.red + CIE_Y_g*col.green + CIE_Y_b*col.blue));
01090            fprintf (f, "v c =\n\tp %.4f %.4f %.4f\n\tn %.4f %.4f %.4f\n",
01091                   pos[X], pos[Y], pos[Z],
01092                   target[X]-pos[X], target[Y]-pos[Y], target[Z]-pos[Z]);
01093            fprintf (f, "ring c 0 .01\n");
01094            if (name[0]) fprintf (f, "o\n");
01095            fprintf (f, "\n");
01096            break;
01097     }
01098 }
01099 
01100 
01101 void write_fog (FILE *f, Colour col, float dist)
01102 {
01103     if (dist <= 0.0)
01104        return;
01105 
01106     switch (format) {
01107        case POV10:
01108            fprintf (f, "fog {\n");
01109            fprintf (f, "    color red %4.2f green %4.2f blue %4.2f %.4f\n",
01110                        col.red, col.green, col.blue, dist/2.0);
01111            fprintf (f, "}\n\n");
01112            break;
01113 
01114        case POV20:
01115            fprintf (f, "fog {\n");
01116            fprintf (f, "    color red %4.2f green %4.2f blue %4.2f distance %.4f\n",
01117                        col.red, col.green, col.blue, dist/2.0);
01118            fprintf (f, "}\n\n");
01119            break;
01120     }
01121 }
01122 
01123 
01124 void write_camera (FILE *f, char *name, Vector pos, Vector target,
01125                          float lens, float bank)
01126 {
01127     float fov;
01128 
01129     cameras++;
01130 
01131     fov = findfov (lens);
01132 
01133     switch (format) {
01134        case POV10:
01135            /* Comment out multiple cameras */
01136            if (cameras > 1)
01137               fprintf (f, "/*\n");
01138 
01139            fprintf (f, "/* Camera: %s */\n", name);
01140            fprintf (f, "camera {\n");
01141            fprintf (f, "   location <%.4f %.4f %.4f>\n",
01142                            pos[X], pos[Y], pos[Z]);
01143            fprintf (f, "   direction <0 %.3f 0>\n", 0.60/tan(0.5*RAD(fov)) );
01144            fprintf (f, "   up <0 0 1>\n");
01145            fprintf (f, "   sky  <0 0 1>\n");
01146            fprintf (f, "   right <%.3f 0 0>\n", ASPECT);
01147            fprintf (f, "   look_at <%.4f %.4f %.4f>\n",
01148                            target[X], target[Y], target[Z]);
01149            if (bank != 0.0)
01150               fprintf (f, "   /* Bank angle = %.2f */\n", bank);
01151 
01152            fprintf (f, "}\n");
01153 
01154            if (cameras > 1)
01155               fprintf (f, "*/\n");
01156 
01157            fprintf (f, "\n");
01158            break;
01159 
01160        case POV20:
01161            /* Comment out multiple cameras */
01162            if (cameras > 1)
01163               fprintf (f, "/*\n");
01164 
01165            fprintf (f, "/* Camera: %s */\n", name);
01166            fprintf (f, "camera {\n");
01167            fprintf (f, "   location <%.4f, %.4f, %.4f>\n",
01168                            pos[X], pos[Y], pos[Z]);
01169            fprintf (f, "   direction <0, %.3f, 0>\n", 0.60/tan(0.5*RAD(fov)) );
01170            fprintf (f, "   up <0, 0, 1>\n");
01171            fprintf (f, "   sky  <0, 0, 1>\n");
01172            fprintf (f, "   right <%.3f, 0, 0>\n", ASPECT);
01173            fprintf (f, "   look_at <%.4f, %.4f, %.4f>\n",
01174                            target[X], target[Y], target[Z]);
01175            if (bank != 0.0)
01176               fprintf (f, "   /* Bank angle = %.2f */\n", bank);
01177 
01178            fprintf (f, "}\n");
01179 
01180            if (cameras > 1)
01181               fprintf (f, "*/\n");
01182 
01183            fprintf (f, "\n");
01184            break;
01185 
01186        case VIVID:
01187            fprintf (f, "/* Camera: %s */\n", name);
01188 
01189            if (cameras > 1)
01190               fprintf (f, "/*\n");
01191 
01192            fprintf (f, "studio {\n");
01193            fprintf (f, "    from %.4f %.4f %.4f\n",
01194                             pos[X], pos[Y], pos[Z]);
01195            fprintf (f, "    at %.4f %.4f %.4f\n",
01196                             target[X], target[Y], target[Z]);
01197            fprintf (f, "    up 0 0 1\n");
01198            fprintf (f, "    angle %.2f\n", 1.1*fov);
01199            fprintf (f, "    aspect %.3f\n", ASPECT);
01200            fprintf (f, "    resolution 320 200\n");
01201            fprintf (f, "    antialias none\n");
01202            fprintf (f, "}\n");
01203 
01204            if (cameras > 1)
01205               fprintf (f, "*/\n");
01206 
01207            fprintf (f, "\n");
01208            break;
01209 
01210        case POLYRAY:
01211            if (cameras == 1) {
01212               fprintf (f, "// Camera: %s\n", name);
01213               fprintf (f, "viewpoint {\n");
01214               fprintf (f, "    from <%.4f, %.4f, %.4f>\n",
01215                                pos[X], pos[Y], pos[Z]);
01216               fprintf (f, "    at <%.4f, %.4f, %.4f>\n",
01217                                target[X], target[Y], target[Z]);
01218               fprintf (f, "    up <0, 0, 1>\n");
01219               fprintf (f, "    angle %.2f\n", 0.85*fov);
01220               fprintf (f, "    aspect %.3f\n", -(ASPECT));
01221               fprintf (f, "    resolution 320, 200\n");
01222               fprintf (f, "}\n");
01223            }
01224 
01225            fprintf (f, "\n");
01226            break;
01227 
01228        case MGF:
01229            fprintf (f, "# Camera %s\n", name);
01230            fprintf (f, "# from: %.4f %.4f %.4f\n", pos[X], pos[Y], pos[Z]);
01231            fprintf (f, "# to: %.4f %.4f %.4f\n", target[X], target[Y], target[Z]);
01232            fprintf (f, "# lens length: %.2f\n", lens);
01233            fprintf (f, "# bank: %.2f\n", bank);
01234            break;
01235     }
01236 }
01237 
01238 
01239 void write_material (FILE *f, char *mat)
01240 {
01241     MatProp *mprop = LIST_FIND (mprop_list, mat);
01242 
01243     if (mprop == NULL) {
01244        mprop = &DefaultMaterial;
01245        (void)strcpy(mprop->name, mat);
01246     }
01247 
01248     switch (format) {
01249        case POV10:
01250            write_pov10_material (f, mprop);
01251            break;
01252 
01253        case POV20:
01254            write_pov20_material (f, mprop);
01255            break;
01256 
01257        case VIVID:
01258            write_vivid_material (f, mprop);
01259            break;
01260 
01261        case POLYRAY:
01262            write_polyray_material (f, mprop);
01263            break;
01264 
01265        case MGF:
01266            write_mgf_material (f, mprop);
01267            break;
01268     }
01269 }
01270 
01271 
01272 void write_pov10_material (FILE *f, MatProp *m)
01273 {
01274     float amb = 0.1, dif = 0.9, spec = 1.0;
01275     float dist_white, dist_diff, phong, phong_size;
01276     float red, green, blue;
01277 
01278     /* amb = get_ambient (m); */
01279 
01280     if (m->self_illum) {
01281        amb = 0.9;
01282        dif = 0.1;
01283     }
01284 
01285     dist_white = fabs(1.0 - m->specular.red) +
01286                fabs(1.0 - m->specular.green) +
01287                fabs(1.0 - m->specular.blue);
01288 
01289     dist_diff  = fabs(m->diffuse.red   - m->specular.red) +
01290                fabs(m->diffuse.green - m->specular.green) +
01291                fabs(m->diffuse.blue  - m->specular.blue);
01292 
01293 
01294     phong_size = 0.7*m->shininess;
01295     if (phong_size < 1.0) phong_size = 1.0;
01296 
01297     if (phong_size > 30.0)
01298        phong = 1.0;
01299     else
01300        phong = phong_size/30.0;
01301 
01302     fprintf (f, "#declare %s = texture {\n", m->name);
01303     fprintf (f, "    ambient %.2f\n", amb);
01304     fprintf (f, "    diffuse %.2f\n", dif);
01305     fprintf (f, "    phong %.2f\n", phong);
01306     fprintf (f, "    phong_size %.1f\n", phong_size);
01307 
01308     if (dist_diff < dist_white)
01309        fprintf (f, "    metallic\n");
01310 
01311     if (m->reflection > 0.0) {
01312        spec = (m->specular.red + m->specular.green + m->specular.blue)/3.0;
01313        fprintf (f, "    reflection %.3f\n", spec * m->reflection);
01314     }
01315 
01316     if (m->transparency > 0.0) {
01317        red   = m->diffuse.red;
01318        green = m->diffuse.green;
01319        blue  = m->diffuse.blue;
01320 
01321        /* Saturate the colour towards white as the transparency increases */
01322        red   = ((1.0 - m->transparency) * red)   + m->transparency;
01323        green = ((1.0 - m->transparency) * green) + m->transparency;
01324        blue  = ((1.0 - m->transparency) * blue)  + m->transparency;
01325 
01326        fprintf (f, "    color red %.3f green %.3f blue %.3f alpha %.3f\n",
01327                       red, green, blue, m->transparency);
01328        fprintf (f, "    ior 1.1\n");
01329        fprintf (f, "    refraction 1.0\n");
01330     }
01331     else
01332        fprintf (f, "    color red %.3f green %.3f blue %.3f\n",
01333                       m->diffuse.red, m->diffuse.green, m->diffuse.blue);
01334 
01335     if (strlen (m->tex_map) > 0) {
01336        fprintf (f, "    /* Image map: %s, Strength: %.2f */\n",
01337                       m->tex_map, m->tex_strength);
01338     }
01339 
01340     if (strlen (m->bump_map) > 0) {
01341        fprintf (f, "    /* Bump map: %s, Strength: %.2f */\n",
01342                       m->bump_map, m->bump_strength);
01343     }
01344 
01345     fprintf (f, "}\n\n");
01346 }
01347 
01348 
01349 void write_pov20_material (FILE *f, MatProp *m)
01350 {
01351     float amb = 0.1, dif = 0.9, spec = 1.0;
01352     float dist_white, dist_diff, phong, phong_size;
01353     float red, green, blue;
01354 
01355     /* amb = get_ambient (m); */
01356 
01357     if (m->self_illum) {
01358        amb = 0.9;
01359        dif = 0.1;
01360     }
01361 
01362     dist_white = fabs(1.0 - m->specular.red) +
01363                fabs(1.0 - m->specular.green) +
01364                fabs(1.0 - m->specular.blue);
01365 
01366     dist_diff  = fabs(m->diffuse.red   - m->specular.red) +
01367                fabs(m->diffuse.green - m->specular.green) +
01368                fabs(m->diffuse.blue  - m->specular.blue);
01369 
01370     phong_size = 0.7*m->shininess;
01371     if (phong_size < 1.0) phong_size = 1.0;
01372 
01373     if (phong_size > 30.0)
01374        phong = 1.0;
01375     else
01376        phong = phong_size/30.0;
01377 
01378     fprintf (f, "#declare %s = texture {\n", m->name);
01379     fprintf (f, "    finish {\n");
01380     fprintf (f, "        ambient %.2f\n", amb);
01381     fprintf (f, "        diffuse %.2f\n", dif);
01382     fprintf (f, "        phong %.2f\n", phong);
01383     fprintf (f, "        phong_size %.1f\n", phong_size);
01384 
01385     if (dist_diff < dist_white)
01386        fprintf (f, "        metallic\n");
01387 
01388     if (m->reflection > 0.0) {
01389        spec = (m->specular.red + m->specular.green + m->specular.blue)/3.0;
01390        fprintf (f, "        reflection %.3f\n", spec * m->reflection);
01391     }
01392 
01393     if (m->transparency > 0.0) {
01394        fprintf (f, "        ior 1.1\n");
01395        fprintf (f, "        refraction 1.0\n");
01396     }
01397 
01398     fprintf (f, "    }\n");
01399 
01400     if (m->transparency > 0.0) {
01401        red   = m->diffuse.red;
01402        green = m->diffuse.green;
01403        blue  = m->diffuse.blue;
01404 
01405        /* Saturate the colour towards white as the transparency increases */
01406        red   = ((1.0 - m->transparency) * red)   + m->transparency;
01407        green = ((1.0 - m->transparency) * green) + m->transparency;
01408        blue  = ((1.0 - m->transparency) * blue)  + m->transparency;
01409 
01410        fprintf (f, "    pigment { rgbf <%.3f, %.3f, %.3f, %.3f> }\n",
01411                   red, green, blue, m->transparency);
01412     }
01413     else
01414        fprintf (f, "    pigment { rgb <%.3f, %.3f, %.3f> }\n",
01415                   m->diffuse.red, m->diffuse.green, m->diffuse.blue);
01416 
01417     if (strlen (m->tex_map) > 0) {
01418        fprintf (f, "    /* Image map: %s, Strength: %.2f */\n",
01419                       m->tex_map, m->tex_strength);
01420     }
01421 
01422     if (strlen (m->bump_map) > 0) {
01423        fprintf (f, "    /* Bump map: %s, Strength: %.2f */\n",
01424                       m->bump_map, m->bump_strength);
01425     }
01426 
01427     fprintf (f, "}\n\n");
01428 }
01429 
01430 
01431 void write_vivid_material (FILE *f, MatProp *m)
01432 {
01433     float amb = 0.1, dif = 0.9;
01434 
01435     /* amb = get_ambient (m); */
01436 
01437     if (m->self_illum) {
01438        amb = 0.9;
01439        dif = 0.1;
01440     }
01441 
01442     if (m->transparency > 0.0) {
01443        dif = dif - m->transparency;
01444        if (dif < 0.0) dif = 0.0;
01445     }
01446 
01447     fprintf (f, "#define %s \\ \n", m->name);
01448     fprintf (f, "    surface {           \\ \n");
01449     fprintf (f, "        ambient %.3f %.3f %.3f \\ \n",
01450                       amb*m->ambient.red, amb*m->ambient.green, amb*m->ambient.blue);
01451 
01452     fprintf (f, "        diffuse %.3f %.3f %.3f \\ \n",
01453                       dif*m->diffuse.red, dif*m->diffuse.green, dif*m->diffuse.blue);
01454 
01455     fprintf (f, "        shine %.1f  %.3f %.3f %.3f \\ \n",
01456                       0.7*m->shininess, m->specular.red, m->specular.green, m->specular.blue);
01457 
01458     if (m->transparency > 0.0) {
01459        fprintf (f, "        transparent %.3f*white \\ \n", 1.0 - (1.0 - m->transparency)/14.0);
01460        fprintf (f, "        ior 1.1 \\ \n");
01461     }
01462 
01463     if (m->reflection > 0.0)
01464        fprintf (f, "        specular %.3f*white \\ \n", m->reflection);
01465 
01466     if (strlen (m->tex_map) > 0) {
01467        fprintf (f, "        /* Image map: %s, Strength: %.2f */ \\ \n",
01468                           m->tex_map, m->tex_strength);
01469     }
01470 
01471     if (strlen (m->bump_map) > 0) {
01472        fprintf (f, "        /* Bump map: %s, Strength: %.2f */ \\ \n",
01473                           m->bump_map, m->bump_strength);
01474     }
01475 
01476     fprintf (f, "    }\n\n");
01477 }
01478 
01479 
01480 void write_polyray_material (FILE *f, MatProp *m)
01481 {
01482     float amb = 0.1, dif = 0.9, spec;
01483 
01484     /* amb = get_ambient (m); */
01485 
01486     if (m->self_illum) {
01487        amb = 0.9;
01488        dif = 0.1;
01489     }
01490 
01491     if (m->transparency > 0.0) {
01492        dif = dif - m->transparency;
01493        if (dif < 0.0) dif = 0.0;
01494     }
01495 
01496     if (m->shininess == 0.0)
01497        m->shininess = 0.1;
01498 
01499     if (m->shininess > 40.0)
01500        spec = 1.0;
01501     else
01502        spec = m->shininess/40.0;
01503 
01504     fprintf (f, "define %s\n", m->name);
01505     fprintf (f, "texture {\n");
01506     fprintf (f, "    surface {\n");
01507     fprintf (f, "        ambient <%.3f, %.3f, %.3f>, %.1f\n",
01508                       m->ambient.red, m->ambient.green, m->ambient.blue, amb);
01509 
01510     fprintf (f, "        diffuse <%.3f, %.3f, %.3f>, %.1f\n",
01511                       m->diffuse.red, m->diffuse.green, m->diffuse.blue, dif);
01512 
01513     fprintf (f, "        specular <%.3f, %.3f, %.3f>, %.2f\n",
01514                       m->specular.red, m->specular.green, m->specular.blue, spec);
01515 
01516     fprintf (f, "        microfacet Reitz %.1f\n", 400.0/m->shininess);
01517 
01518     if (m->transparency > 0.0)
01519        fprintf (f, "        transmission %.3f, 1.1\n", m->transparency);
01520 
01521     if (m->reflection > 0.0)
01522        fprintf (f, "        reflection %.3f\n", m->reflection);
01523 
01524     if (strlen (m->tex_map) > 0) {
01525        fprintf (f, "        // Image map: %s, Strength: %.2f\n",
01526                           m->tex_map, m->tex_strength);
01527     }
01528 
01529     if (strlen (m->bump_map) > 0) {
01530        fprintf (f, "        // Bump map: %s, Strength: %.2f\n",
01531                           m->bump_map, m->bump_strength);
01532     }
01533 
01534     fprintf (f, "    }\n");
01535     fprintf (f, "}\n\n");
01536 }
01537 
01538 
01539 void write_mgf_material (FILE *f, MatProp *m)
01540 {
01541     float  dmag, smag, rdmag, rsmag, tdmag, tsmag, total;
01542 
01543     fprintf (f, "m %s =\n", m->name);
01544     fprintf (f, "\tsides %d\n", m->two_side ? 2 : 1);
01545     dmag = CIE_Y_r*m->diffuse.red + CIE_Y_g*m->diffuse.green
01546               + CIE_Y_b*m->diffuse.blue;
01547     smag = CIE_Y_r*m->specular.red + CIE_Y_g*m->specular.green
01548               + CIE_Y_b*m->specular.blue;
01549     rdmag = dmag;
01550     rsmag = smag * m->reflection;
01551     tdmag = 0.0;
01552     tsmag = m->transparency;
01553     total = rdmag + rsmag + tdmag + tsmag;
01554     if (total > 0.99) {
01555        total = 0.9/total;
01556        dmag *= total;
01557        smag *= total;
01558        rdmag *= total;
01559        rsmag *= total;
01560        tdmag *= total;
01561        tsmag *= total;
01562        total = 0.9;
01563     }
01564     if (dmag > 0.005) {
01565        fprintf (f, "\tc\n\t\tcmix %.3f R %.3f G %.3f B\n",
01566               CIE_Y_r*m->diffuse.red,
01567               CIE_Y_g*m->diffuse.green,
01568               CIE_Y_b*m->diffuse.blue);
01569        if (rdmag > 0.005)
01570            fprintf (f, "\trd %.4f\n", rdmag);
01571        if (tdmag > 0.005)
01572            fprintf (f, "\ttd %.4f\n", tdmag);
01573        if (m->self_illum)
01574            fprintf (f, "\ted %.4f\n", dmag);
01575     }
01576     if (m->shininess > 1.1 && rsmag > 0.005) {
01577        fprintf (f, "\tc\n\t\tcmix %.3f R %.3f G %.3f B\n",
01578               CIE_Y_r*m->specular.red,
01579               CIE_Y_g*m->specular.green,
01580               CIE_Y_b*m->specular.blue);
01581        fprintf (f, "\trs %.4f %.4f\n", rsmag, 0.6/sqrt(m->shininess));
01582     }
01583     if (tsmag > 0.005)
01584        fprintf (f, "\tc\n\tts %.4f 0\n", tsmag);
01585 
01586     if (strlen (m->tex_map) > 0) {
01587        fprintf (f, "# image map: %s, strength: %.2f\n",
01588                       m->tex_map, m->tex_strength);
01589     }
01590 
01591     if (strlen (m->bump_map) > 0) {
01592        fprintf (f, "# bump map: %s, strength: %.2f\n",
01593                       m->bump_map, m->bump_strength);
01594     }
01595 
01596     fprintf (f, "\n");
01597 }
01598 
01599 
01600 /* Write a mesh file */
01601 void write_mesh (FILE *f, Mesh *mesh)
01602 {
01603     int i;
01604     char curmat[80];
01605     Vector va, vb, vc;
01606     Summary *new_summary;
01607     Matrix obj_matrix;
01608 
01609     if (mesh->hidden || LIST_FIND (excl_list, mesh->name))
01610        return;
01611 
01612     /* Add this object's stats to the summary */
01613     new_summary = malloc (sizeof(*new_summary));
01614     if (new_summary == NULL)
01615        abortmsg ("Out of memory adding summary", 1);
01616 
01617     strcpy (new_summary->name, mesh->name);
01618     vect_copy (new_summary->center,  mesh->center);
01619     vect_copy (new_summary->lengths, mesh->lengths);
01620 
01621     LIST_INSERT (summary, new_summary);
01622 
01623     /* Compute the object transformation matrix for animations */
01624     if (ani_matrix != NULL) {
01625        mat_copy (obj_matrix, *ani_matrix);
01626        if (vue_version > 2.0)
01627            mat_mult (obj_matrix, mesh->invmatrix, obj_matrix);
01628     }
01629 
01630     switch (format) {
01631        case MGF:
01632            if (no_opt) {
01633               if (mesh->name[0]) fprintf (meshf, "o %s\n", mesh->name);
01634               for (i = 0; i < mesh->vertices; i++) {
01635                   vect_copy(va, mesh->vertex[i]);
01636                   if (ani_matrix != NULL)
01637                      vect_transform (va, va, obj_matrix);
01638                   fprintf (meshf, "v v%d =\n\tp %.5f %.5f %.5f\n",
01639                             i, va[X], va[Y], va[Z]);
01640               }
01641               curmat[0] = '\0';
01642               for (i = 0; i < mesh->faces; i++) {
01643                   if (strcmp(mesh->mtl[i]->name, curmat)) {
01644                      strcpy(curmat, mesh->mtl[i]->name);
01645                      fprintf (meshf, "m %s\n", curmat);
01646                   }
01647                   fprintf (meshf, "f v%d v%d v%d\n", mesh->face[i].a,
01648                             mesh->face[i].b, mesh->face[i].c);
01649               }
01650               if (mesh->name[0]) fprintf (meshf, "o\n");
01651               break;
01652            }
01653            /*FALL THROUGH*/
01654        case POV10:
01655        case POV20:
01656        case VIVID:
01657        case POLYRAY:
01658            opt_set_vert (mesh->vertices);
01659 
01660            for (i = 0; i < mesh->faces; i++) {
01661               vect_copy (va, mesh->vertex[mesh->face[i].a]);
01662               vect_copy (vb, mesh->vertex[mesh->face[i].b]);
01663               vect_copy (vc, mesh->vertex[mesh->face[i].c]);
01664 
01665               opt_set_texture (mesh->mtl[i]->name);
01666 
01667               opt_add_tri (va[X], va[Y], va[Z], vc[X], vc[Y], vc[Z],
01668                           vb[X], vb[Y], vb[Z]);
01669            }
01670 
01671            fflush (f);
01672 
01673            if (ani_matrix != NULL)
01674               opt_set_transform (obj_matrix);
01675 
01676            if (box_all || LIST_FIND (box_list, mesh->name))
01677               opt_write_box (mesh->name);
01678            else
01679               opt_write_file (mesh->name);
01680 
01681            break;
01682 
01683        case RAW:
01684            fprintf (f, "%s\n", mesh->name);
01685 
01686            for (i = 0; i < mesh->faces; i++) {
01687               vect_copy (va, mesh->vertex[mesh->face[i].a]);
01688               vect_copy (vb, mesh->vertex[mesh->face[i].b]);
01689               vect_copy (vc, mesh->vertex[mesh->face[i].c]);
01690 
01691               if (ani_matrix != NULL) {
01692                   vect_transform (va, va, obj_matrix);
01693                   vect_transform (vb, vb, obj_matrix);
01694                   vect_transform (vc, vc, obj_matrix);
01695               }
01696 
01697               fprintf (f, "%f %f %f   %f %f %f   %f %f %f\n",
01698                          va[X], va[Y], va[Z], vb[X], vb[Y], vb[Z],
01699                          vc[X], vc[Y], vc[Z]);
01700            }
01701 
01702            break;
01703     }
01704 }
01705 
01706 
01707 /* Parses an object transformation and returns a pointer to the
01708    newly allocated transformation */
01709 Transform *parse_transform (char *string)
01710 {
01711     Transform *t;
01712     char      *token;
01713     int       token_no;
01714 
01715     t = (Transform *)malloc (sizeof(*t));
01716     if (t == NULL)
01717        abortmsg ("Out of memory allocating transform", 1);
01718 
01719     mat_identity (t->matrix);
01720 
01721     token = parse_string (string);
01722     token_no = 0;
01723 
01724     while (strlen(token) > 0) {
01725         switch (token_no) {
01726             case  0: break;
01727             case  1: strcpy (t->name, token); break;
01728             case  2: t->matrix[0][0] = atof(token); break;
01729             case  3: t->matrix[0][1] = atof(token); break;
01730             case  4: t->matrix[0][2] = atof(token); break;
01731             case  5: t->matrix[1][0] = atof(token); break;
01732             case  6: t->matrix[1][1] = atof(token); break;
01733             case  7: t->matrix[1][2] = atof(token); break;
01734             case  8: t->matrix[2][0] = atof(token); break;
01735             case  9: t->matrix[2][1] = atof(token); break;
01736             case 10: t->matrix[2][2] = atof(token); break;
01737             case 11: t->matrix[3][0] = atof(token); break;
01738             case 12: t->matrix[3][1] = atof(token); break;
01739             case 13: t->matrix[3][2] = atof(token); break;
01740 
01741             default: abortmsg ("Error parsing transform", 1);
01742         }
01743 
01744         token = parse_string (NULL);
01745         token_no++;
01746     }
01747 
01748     t->matrix[0][3] = 0.0;
01749     t->matrix[1][3] = 0.0;
01750     t->matrix[2][3] = 0.0;
01751     t->matrix[3][3] = 1.0;
01752 
01753     cleanup_name (t->name);
01754 
01755     return t;
01756 }
01757 
01758 
01759 /* Parses a morph command and returns a pointer to the
01760    newly allocated morph */
01761 Morph *parse_morph (char *string)
01762 {
01763     Morph  *m;
01764     char   *token;
01765     int    i, token_no;
01766 
01767     m = (Morph *)malloc (sizeof(*m));
01768     if (m == NULL)
01769        abortmsg ("Out of memory allocating morph", 1);
01770 
01771     mat_identity (m->matrix);
01772 
01773     token = parse_string (string);
01774 
01775     token = parse_string (NULL);
01776     strcpy (m->name, token);
01777 
01778     token = parse_string (NULL);
01779     m->count = atoi (token);
01780 
01781     if (strlen (m->name) == 0 || m->count < 1 || m->count > 4)
01782        abortmsg ("Error parsing morph command", 1);
01783 
01784     cleanup_name (m->name);
01785 
01786     for (i = 0; i < m->count; i++) {
01787        token = parse_string (NULL);
01788        strcpy (m->names[i], token);
01789 
01790        token = parse_string (NULL);
01791        m->weight[i] = atof (token);
01792 
01793        if (strlen (m->names[i]) == 0)
01794            abortmsg ("Error parsing morph command", 1);
01795 
01796        cleanup_name (m->names[i]);
01797     }
01798 
01799     token = parse_string (NULL);
01800     token_no = 0;
01801 
01802     while (strlen(token) > 0) {
01803         switch (token_no) {
01804             case  0: m->matrix[0][0] = atof(token); break;
01805             case  1: m->matrix[0][1] = atof(token); break;
01806             case  2: m->matrix[0][2] = atof(token); break;
01807             case  3: m->matrix[1][0] = atof(token); break;
01808             case  4: m->matrix[1][1] = atof(token); break;
01809             case  5: m->matrix[1][2] = atof(token); break;
01810             case  6: m->matrix[2][0] = atof(token); break;
01811             case  7: m->matrix[2][1] = atof(token); break;
01812             case  8: m->matrix[2][2] = atof(token); break;
01813             case  9: m->matrix[3][0] = atof(token); break;
01814             case 10: m->matrix[3][1] = atof(token); break;
01815             case 11: m->matrix[3][2] = atof(token); break;
01816 
01817             default: abortmsg ("Error parsing morph command", 1);
01818         }
01819 
01820         token = parse_string (NULL);
01821         token_no++;
01822     }
01823 
01824     m->matrix[0][3] = 0.0;
01825     m->matrix[1][3] = 0.0;
01826     m->matrix[2][3] = 0.0;
01827     m->matrix[3][3] = 1.0;
01828 
01829     return m;
01830 }
01831 
01832 
01833 /* Parses an omni light and returns a pointer to the
01834    newly allocated light */
01835 OmniLight *parse_omnilight (char *string)
01836 {
01837     OmniLight *o;
01838     char      *token;
01839     int       token_no;
01840 
01841     o = (OmniLight *)malloc (sizeof(*o));
01842     if (o == NULL)
01843        abortmsg ("Out of memory allocating omnilight", 1);
01844 
01845     token = parse_string (string);
01846     token_no = 0;
01847 
01848     while (strlen(token) > 0) {
01849         switch (token_no) {
01850             case 0: break;
01851             case 1: strcpy (o->name, token); break;
01852             case 2: o->pos[X] = atof (token); break;
01853             case 3: o->pos[Y] = atof (token); break;
01854             case 4: o->pos[Z] = atof (token); break;
01855             case 5: o->col.red   = atof (token); break;
01856             case 6: o->col.green = atof (token); break;
01857             case 7: o->col.blue  = atof (token); break;
01858 
01859             default: abortmsg ("Error parsing omnilight", 1);
01860         }
01861 
01862         token = parse_string (NULL);
01863         token_no++;
01864     }
01865 
01866     cleanup_name (o->name);
01867 
01868     return o;
01869 }
01870 
01871 
01872 /* Parses a spotlight and returns a pointer to the
01873    newly allocated spotlight */
01874 Spotlight *parse_spotlight (char *string)
01875 {
01876     Spotlight *s;
01877     char      *token;
01878     int       token_no;
01879 
01880     s = (Spotlight *)malloc (sizeof(*s));
01881     if (s == NULL)
01882        abortmsg ("Out of memory allocating spotlight", 1);
01883 
01884     token = parse_string (string);
01885     token_no = 0;
01886 
01887     while (strlen(token) > 0) {
01888         switch (token_no) {
01889             case  0: break;
01890             case  1: strcpy (s->name, token); break;
01891             case  2: s->pos[X] = atof (token); break;
01892             case  3: s->pos[Y] = atof (token); break;
01893             case  4: s->pos[Z] = atof (token); break;
01894             case  5: s->target[X] = atof (token); break;
01895             case  6: s->target[Y] = atof (token); break;
01896             case  7: s->target[Z] = atof (token); break;
01897             case  8: s->col.red   = atof (token); break;
01898             case  9: s->col.green = atof (token); break;
01899             case 10: s->col.blue  = atof (token); break;
01900             case 11: s->hotspot   = atof (token); break;
01901             case 12: s->falloff   = atof (token); break;
01902             case 13: break;
01903 
01904             default: abortmsg ("Error parsing spotlight", 1);
01905         }
01906 
01907         token = parse_string (NULL);
01908         token_no++;
01909     }
01910 
01911     cleanup_name (s->name);
01912 
01913     return s;
01914 }
01915 
01916 
01917 /* Parses a camera command and returns a pointer to the
01918    newly allocated camera */
01919 Camera *parse_camera (char *string)
01920 {
01921     Camera *c;
01922     char   *token;
01923     int    token_no;
01924 
01925     c = (Camera *)malloc (sizeof(*c));
01926     if (c == NULL)
01927        abortmsg ("Out of memory allocating camera", 1);
01928 
01929     token = parse_string (string);
01930     token_no = 0;
01931 
01932     while (strlen(token) > 0) {
01933         switch (token_no) {
01934             case 0: break;
01935             case 1: c->pos[X] = atof (token); break;
01936             case 2: c->pos[Y] = atof (token); break;
01937             case 3: c->pos[Z] = atof (token); break;
01938             case 4: c->target[X] = atof (token); break;
01939             case 5: c->target[Y] = atof (token); break;
01940             case 6: c->target[Z] = atof (token); break;
01941             case 7: c->bank = atof (token); break;
01942             case 8: c->lens = atof (token); break;
01943 
01944             default: abortmsg ("Error parsing camera", 1);
01945         }
01946 
01947         token = parse_string (NULL);
01948         token_no++;
01949     }
01950 
01951     return c;
01952 }
01953 
01954 
01955 /* Load the transforms, camera movements, etc for the specified frame */
01956 void read_frame (char *filename, int frame_no)
01957 {
01958     FILE  *f;
01959     char  fname[80];
01960     char  string[256];
01961     char  *token;
01962 
01963     /* Open the .vue file */
01964     strcpy (fname, filename);   /* Make a copy we can mess with */
01965     add_ext (fname, "vue", 0);
01966 
01967     f = fopen (fname, "r");
01968     if (f == NULL) {
01969        printf ("Error opening file '%s'\n", fname);
01970        exit(1);
01971     }
01972 
01973     /* Load the specified frame */
01974     find_frame (f, frame_no);
01975 
01976     while (fgets (string, 256, f) != NULL) {
01977        token = parse_string (string);
01978 
01979        if (strcmp (token, "frame") == 0)
01980            break;
01981        else if (strcmp (token, "transform") == 0) {
01982            LIST_INSERT (trans_list, parse_transform (string));
01983        }
01984        else if (strcmp (token, "morph") == 0) {
01985            LIST_INSERT (morph_list, parse_morph (string));
01986        }
01987        else if (strcmp (token, "light") == 0) {
01988            LIST_INSERT (omni_list, parse_omnilight (string));
01989        }
01990        else if (strcmp (token, "spotlight") == 0) {
01991            LIST_INSERT (spot_list, parse_spotlight (string));
01992        }
01993        else if (strcmp (token, "camera") == 0) {
01994            if (cam_list != NULL)
01995               abortmsg ("ERROR - Multiple cameras in .vue file", 1);
01996 
01997            LIST_INSERT (cam_list, parse_camera (string));
01998        }
01999        else if (strcmp (token, "top") == 0)
02000            abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
02001        else if (strcmp (token, "bottom") == 0)
02002            abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
02003        else if (strcmp (token, "left") == 0)
02004            abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
02005        else if (strcmp (token, "right") == 0)
02006            abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
02007        else if (strcmp (token, "front") == 0)
02008            abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
02009        else if (strcmp (token, "back") == 0)
02010            abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
02011        else if (strcmp (token, "user") == 0)
02012            abortmsg ("ERROR - User viewports are not supported", 1);
02013     }
02014 
02015     fclose(f);
02016 }
02017 
02018 
02019 void find_frame (FILE *f, int frame_no)
02020 {
02021     char  string[256];
02022     char  *token;
02023     int   frame = 0;
02024 
02025     /* Search the .vue file for the required frame */
02026     while (1) {
02027        /* Read the next line in the file */
02028        if (fgets (string, 256, f) == NULL) {
02029            printf ("Unable to locate frame #%d in .vue file\n", frame_no);
02030            exit(1);
02031        }
02032 
02033        token = parse_string (string);
02034 
02035        if (strcmp (token, "frame") == 0) {
02036            token = parse_string (NULL);
02037 
02038            if (strlen(token) == 0) {
02039               printf ("Unable to locate frame #%d in .vue file\n", frame_no);
02040               exit(1);
02041            }
02042 
02043            frame = atoi (token);
02044 
02045            if (frame == frame_no)
02046               break;
02047        }
02048        else if (strcmp (token, "VERSION") == 0) {
02049            token = parse_string (NULL);
02050 
02051            vue_version = atoi(token) / 100.0;
02052        }
02053     }
02054 }
02055 
02056 
02057 void save_animation()
02058 {
02059     Mesh      *mesh, *master;
02060     Transform *t;
02061     Morph     *m;
02062     Vector    temp;
02063     int       i, j;
02064 
02065     printf ("\n");
02066 
02067     for (t = trans_list; t != NULL; t = t->next) {
02068         printf ("Transforming object: %s\n", t->name);
02069 
02070         ani_matrix = &(t->matrix);
02071 
02072         mesh = LIST_FIND (mesh_list, t->name);
02073 
02074         if (mesh == NULL) {
02075             printf ("Unable to locate mesh object %s\n", t->name);
02076             exit(1);
02077         }
02078 
02079         write_mesh (out, mesh);
02080     }
02081 
02082     for (m = morph_list; m != NULL; m = m->next) {
02083        printf ("Morphing object: %s\n", m->name);
02084 
02085        ani_matrix = &(m->matrix);
02086 
02087        mesh = LIST_FIND (mesh_list, m->name);
02088        if (mesh == NULL) {
02089            printf ("Unable to locate mesh object %s\n", m->name);
02090            exit(1);
02091        }
02092 
02093        /* Make a copy to mess with */
02094        master = copy_mesh (mesh);
02095        master->hidden = FALSE;
02096 
02097        strcpy (master->name, m->name);
02098 
02099        for (i = 0; i < master->vertices; i++)
02100            vect_init (master->vertex[i], 0.0, 0.0, 0.0);
02101 
02102        for (i = 0; i < m->count; i++) {
02103            mesh = LIST_FIND (mesh_list, m->names[i]);
02104            if (mesh == NULL) {
02105               printf ("Unable to locate mesh object %s\n", m->names[0]);
02106               exit(1);
02107            }
02108 
02109            if (mesh->vertices != master->vertices)
02110               abortmsg ("Morphed objects do not contain the same number of vertices", 1);
02111 
02112            if (mesh->faces != master->faces)
02113               abortmsg ("Morphed objects do not contain the same number of faces", 1);
02114 
02115            for (j = 0; j < master->vertices; j++) {
02116               vect_transform (temp, mesh->vertex[j], mesh->invmatrix);
02117               vect_scale (temp, temp, m->weight[i]);
02118               vect_add (master->vertex[j], master->vertex[j], temp);
02119            }
02120        }
02121 
02122        for (i = 0; i < master->vertices; i++)
02123            vect_transform (master->vertex[i], master->vertex[i], master->matrix);
02124 
02125        write_mesh (out, master);
02126 
02127        free_mesh_data (master);
02128        free (master);
02129     }
02130 
02131     for (mesh = mesh_list; mesh != NULL; mesh = mesh->next)
02132        free_mesh_data (mesh);
02133 }
02134 
02135 
02136 /* Create a new mesh */
02137 Mesh *create_mesh (char *name, int vertices, int faces)
02138 {
02139     Mesh *new_mesh;
02140 
02141     new_mesh = malloc (sizeof(*new_mesh));
02142     if (new_mesh == NULL)
02143        abortmsg ("Out of memory allocating mesh", 1);
02144 
02145     strcpy (new_mesh->name, name);
02146 
02147     new_mesh->vertices = vertices;
02148 
02149     if (vertices <= 0)
02150        new_mesh->vertex = NULL;
02151     else {
02152        new_mesh->vertex = malloc (vertices * sizeof(*new_mesh->vertex));
02153        if (new_mesh->vertex == NULL)
02154            abortmsg ("Out of memory allocating mesh", 1);
02155     }
02156 
02157     new_mesh->faces = faces;
02158 
02159     if (faces <= 0) {
02160        new_mesh->face = NULL;
02161        new_mesh->mtl = NULL;
02162     }
02163     else {
02164        new_mesh->face = malloc (faces * sizeof(*new_mesh->face));
02165        if (new_mesh->face == NULL)
02166            abortmsg ("Out of memory allocating mesh", 1);
02167 
02168        new_mesh->mtl = malloc (faces * sizeof(*new_mesh->mtl));
02169        if (new_mesh->mtl == NULL)
02170            abortmsg ("Out of memory allocating mesh", 1);
02171     }
02172 
02173     vect_init (new_mesh->center,  0.0, 0.0, 0.0);
02174     vect_init (new_mesh->lengths, 0.0, 0.0, 0.0);
02175 
02176     mat_identity (new_mesh->matrix);
02177     mat_identity (new_mesh->invmatrix);
02178 
02179     new_mesh->hidden = FALSE;
02180     new_mesh->shadow = TRUE;
02181 
02182     return new_mesh;
02183 }
02184 
02185 
02186 /* Creates a duplicate copy of a mesh */
02187 Mesh *copy_mesh (Mesh *mesh)
02188 {
02189     Mesh *new_mesh;
02190     int  i;
02191 
02192     new_mesh = create_mesh (mesh->name, mesh->vertices, mesh->faces);
02193 
02194     if (new_mesh == NULL)
02195        abortmsg ("Out of memory allocating mesh", 1);
02196 
02197     for (i = 0; i < mesh->vertices; i++)
02198        vect_copy (new_mesh->vertex[i], mesh->vertex[i]);
02199 
02200     for (i = 0; i < mesh->faces; i++) {
02201        new_mesh->face[i] = mesh->face[i];
02202        new_mesh->mtl[i]  = mesh->mtl[i];
02203     }
02204 
02205     mat_copy (new_mesh->matrix, mesh->matrix);
02206     mat_copy (new_mesh->invmatrix, mesh->invmatrix);
02207 
02208     vect_copy (new_mesh->center,  mesh->center);
02209     vect_copy (new_mesh->lengths, mesh->lengths);
02210 
02211     new_mesh->hidden = mesh->hidden;
02212     new_mesh->shadow = mesh->shadow;
02213 
02214     return new_mesh;
02215 }
02216 
02217 
02218 /* Free all data associated with mesh object */
02219 void free_mesh_data (Mesh *mesh)
02220 {
02221     if (mesh->vertex != NULL)
02222        free (mesh->vertex);
02223 
02224     if (mesh->face != NULL)
02225        free (mesh->face);
02226 
02227     if (mesh->mtl != NULL)
02228        free (mesh->mtl);
02229 }
02230 
02231 
02232 /* Updates the center (pivot) point of the mesh */
02233 void update_limits (Mesh *mesh)
02234 {
02235     Vector vmin = {+MAXFLOAT, +MAXFLOAT, +MAXFLOAT};
02236     Vector vmax = {-MAXFLOAT, -MAXFLOAT, -MAXFLOAT};
02237     int    i;
02238 
02239     for (i = 0; i < mesh->vertices; i++) {
02240        vect_min (vmin, vmin, mesh->vertex[i]);
02241        vect_max (vmax, vmax, mesh->vertex[i]);
02242     }
02243 
02244     vect_add  (mesh->center, vmin, vmax);
02245     vect_scale (mesh->center, mesh->center, 0.5);
02246 
02247     vect_sub (mesh->lengths, vmax, vmin);
02248 }
02249 
02250 
02251 /* Return the sub-string of 'str' that is before 'target' */
02252 char *before (char *str, char *target)
02253 {
02254     static char result[256];
02255     char   *search;
02256 
02257     strncpy (result, str, 256);
02258     result[255] = '\0';
02259 
02260     search = strstr (result, target);
02261 
02262     if (search != NULL)
02263        *search = '\0';
02264 
02265     return result;
02266 }
02267 
02268 
02269 /* Return the sub-string of 'str' that is after 'target' */
02270 char *after (char *str, char *target)
02271 {
02272     static char result[256];
02273     char   *search;
02274 
02275     search = strstr (str, target);
02276 
02277     if (search == NULL)
02278        strncpy (result, "", 256);
02279     else
02280        strncpy (result, search + strlen(target), 256);
02281 
02282     result[255] = '\0';
02283 
02284     return result;
02285 }
02286 
02287 
02288 /* Return the sub-string of 'str' that is between 'target1' and 'target2' */
02289 char *between (char *str, char *target1, char *target2)
02290 {
02291     static char result[256];
02292 
02293     strcpy (result, after (str, target1));
02294     strcpy (result, before (result, target2));
02295 
02296     return result;
02297 }
02298 
02299 
02300 /* Works like the C strtok() function except that it can handle */
02301 /* tokens enclosed in double quotes */
02302 char *parse_string (char *str)
02303 {
02304     static char result[256];
02305     static char *p;
02306     char QUOTE = '\"';
02307     int  index;
02308 
02309     strcpy (result, "");
02310     index = 0;
02311 
02312     if (str != NULL)
02313        p = str;
02314 
02315     /* Find the start of the next token */
02316     while (isspace (*p))
02317        p++;
02318 
02319     if (*p == QUOTE) {
02320        p++;
02321 
02322        while (*p != '\0' && *p != QUOTE)
02323            result[index++] = *p++;
02324 
02325        if (*p == QUOTE)
02326            p++;
02327     }
02328     else {
02329        while (*p != '\0' && !isspace(*p))
02330            result[index++] = *p++;
02331     }
02332 
02333     result[index] = '\0';
02334 
02335     return result;
02336 }
02337 
02338 
02339 /* Convert character 'c' to upper case */
02340 char upcase (char c)
02341 {
02342     if (c >= 'a' && c <= 'z')
02343        c = c - 'a' + 'A';
02344 
02345     return c;
02346 }
02347 
02348 
02349 float colour_intens (Colour *colour)
02350 {
02351     return sqrt (colour->red   * colour->red +
02352                colour->green * colour->green +
02353                colour->blue  * colour->blue);
02354 }
02355 
02356 
02357 void parse_file()
02358 {
02359     Chunk chunk;
02360 
02361     start_chunk(&chunk);
02362 
02363     if (chunk.tag == 0x4D4D)
02364        parse_3ds (&chunk);
02365     else
02366        abortmsg ("Error: Input file is not .3DS format", 1);
02367 
02368     end_chunk (&chunk);
02369 }
02370 
02371 
02372 void parse_3ds (Chunk *mainchunk)
02373 {
02374     Chunk chunk;
02375 
02376     do  {
02377        start_chunk (&chunk);
02378        if (feof(in)) {
02379               fprintf(stderr, "%s: unexpected EOF\n", progname);
02380               break;
02381        }
02382        if (chunk.end <= mainchunk->end) {
02383            switch (chunk.tag) {
02384               case 0x3D3D: parse_mdata (&chunk);
02385                           break;
02386            }
02387        }
02388 
02389        end_chunk (&chunk);
02390     } while (chunk.end <= mainchunk->end);
02391 }
02392 
02393 
02394 void parse_mdata (Chunk *mainchunk)
02395 {
02396     Chunk chunk;
02397     Colour bgnd_colour;
02398 
02399     do  {
02400        start_chunk (&chunk);
02401 
02402        if (chunk.end <= mainchunk->end) {
02403            switch (chunk.tag) {
02404               case 0x2100: parse_colour (&global_amb);
02405                           break;
02406               case 0x1200: parse_colour (&bgnd_colour);
02407                           break;
02408               case 0x1201: write_bgsolid (out, bgnd_colour);
02409                           break;
02410               case 0x2200: parse_fog (&chunk);
02411                           break;
02412               case 0x2210: parse_fog_bgnd();
02413                           break;
02414               case 0x2201: write_fog (out, fog_colour, fog_distance);
02415                           break;
02416               case 0xAFFF: parse_mat_entry (&chunk);
02417                           break;
02418               case 0x4000: parse_named_object (&chunk);
02419                           break;
02420            }
02421        }
02422 
02423        end_chunk (&chunk);
02424     } while (chunk.end <= mainchunk->end);
02425 }
02426 
02427 
02428 void parse_fog (Chunk *mainchunk)
02429 {
02430     Chunk chunk;
02431 
02432     (void)read_float();
02433     (void)read_float();
02434     fog_distance = read_float();
02435     (void)read_float();
02436 
02437     parse_colour (&fog_colour);
02438 
02439     do  {
02440        start_chunk (&chunk);
02441 
02442        if (chunk.end <= mainchunk->end) {
02443            switch (chunk.tag) {
02444               case 0x2210: parse_fog_bgnd();
02445                           break;
02446            }
02447        }
02448 
02449        end_chunk (&chunk);
02450     } while (chunk.end <= mainchunk->end);
02451 }
02452 
02453 
02454 void parse_fog_bgnd()
02455 {
02456 
02457 }
02458 
02459 
02460 void parse_mat_entry (Chunk *mainchunk)
02461 {
02462     Chunk chunk;
02463     MatProp *mprop;
02464 
02465     mprop = create_mprop();
02466 
02467     do  {
02468        start_chunk (&chunk);
02469 
02470        if (chunk.end <= mainchunk->end) {
02471            switch (chunk.tag) {
02472               case 0xA000: strcpy (mprop->name, read_string());
02473                           cleanup_name (mprop->name);
02474                           break;
02475 
02476               case 0xA010: parse_colour (&mprop->ambient);
02477                           break;
02478 
02479               case 0xA020: parse_colour (&mprop->diffuse);
02480                           break;
02481 
02482               case 0xA030: parse_colour (&mprop->specular);
02483                           break;
02484 
02485               case 0xA040: mprop->shininess = 100.0*parse_percentage();
02486                           break;
02487 
02488               case 0xA050: mprop->transparency = parse_percentage();
02489                           break;
02490 
02491               case 0xA080: mprop->self_illum = TRUE;
02492                           break;
02493 
02494               case 0xA081: mprop->two_side = TRUE;
02495                           break;
02496 
02497               case 0xA220: mprop->reflection = parse_percentage();
02498                           (void)parse_mapname (&chunk);
02499                           break;
02500 
02501               case 0xA310: if (mprop->reflection == 0.0)
02502                              mprop->reflection = 1.0;
02503                           break;
02504 
02505               case 0xA200: mprop->tex_strength = parse_percentage();
02506                           strcpy (mprop->tex_map, parse_mapname (&chunk));
02507                           break;
02508 
02509               case 0xA230: mprop->bump_strength = parse_percentage();
02510                           strcpy (mprop->bump_map, parse_mapname (&chunk));
02511                           break;
02512            }
02513        }
02514 
02515        end_chunk (&chunk);
02516     } while (chunk.end <= mainchunk->end);
02517 
02518     LIST_INSERT (mprop_list, mprop);
02519 }
02520 
02521 
02522 char *parse_mapname (Chunk *mainchunk)
02523 {
02524     static char name[80] = "";
02525     Chunk chunk;
02526 
02527     do  {
02528        start_chunk (&chunk);
02529 
02530        if (chunk.end <= mainchunk->end) {
02531            switch (chunk.tag) {
02532               case 0xA300: strcpy (name, read_string());
02533                           break;
02534            }
02535        }
02536 
02537        end_chunk (&chunk);
02538     } while (chunk.end <= mainchunk->end);
02539 
02540     return name;
02541 }
02542 
02543 
02544 void parse_named_object (Chunk *mainchunk)
02545 {
02546     Chunk chunk;
02547 
02548     strcpy (obj_name, read_string());
02549     cleanup_name (obj_name);
02550 
02551     printf ("Working on: %s\n", obj_name);
02552 
02553     mesh = NULL;
02554 
02555     do  {
02556        start_chunk (&chunk);
02557 
02558        if (chunk.end <= mainchunk->end) {
02559            switch (chunk.tag) {
02560               case 0x4100: parse_n_tri_object (&chunk);
02561                           break;
02562               case 0x4600: parse_n_direct_light (&chunk);
02563                           break;
02564               case 0x4700: parse_n_camera();
02565                           break;
02566               case 0x4010: if (mesh != NULL) mesh->hidden = TRUE;
02567                           break;
02568               case 0x4012: if (mesh != NULL) mesh->shadow = FALSE;
02569                           break;
02570            }
02571        }
02572 
02573        end_chunk (&chunk);
02574     } while (chunk.end <= mainchunk->end);
02575 
02576     if (mesh != NULL) {
02577        update_limits (mesh);
02578 
02579        if (frame >= 0)
02580            LIST_INSERT (mesh_list, mesh);
02581        else {
02582            write_mesh (out, mesh);
02583 
02584            free_mesh_data (mesh);
02585            free (mesh);
02586        }
02587     }
02588 }
02589 
02590 
02591 void parse_n_tri_object (Chunk *mainchunk)
02592 {
02593     Chunk chunk;
02594 
02595     mesh = create_mesh (obj_name, 0, 0);
02596 
02597     do  {
02598        start_chunk (&chunk);
02599 
02600        if (chunk.end <= mainchunk->end) {
02601            switch (chunk.tag) {
02602               case 0x4110: parse_point_array();
02603                           break;
02604               case 0x4120: parse_face_array (&chunk);
02605                           break;
02606               case 0x4160: parse_mesh_matrix();
02607                           break;
02608            }
02609        }
02610 
02611        end_chunk (&chunk);
02612     } while (chunk.end <= mainchunk->end);
02613 }
02614 
02615 
02616 void parse_point_array()
02617 {
02618     int i;
02619 
02620     mesh->vertices = read_word();
02621     mesh->vertex = malloc (mesh->vertices * sizeof(*(mesh->vertex)));
02622     if (mesh->vertex == NULL)
02623        abortmsg ("Out of memory allocating mesh", 1);
02624 
02625     for (i = 0; i < mesh->vertices; i++)
02626        read_point (mesh->vertex[i]);
02627 }
02628 
02629 
02630 void parse_face_array (Chunk *mainchunk)
02631 {
02632     Chunk chunk;
02633     int i;
02634 
02635     mesh->faces = read_word();
02636     mesh->face = malloc (mesh->faces * sizeof(*(mesh->face)));
02637     if (mesh->face == NULL)
02638        abortmsg ("Out of memory allocating mesh", 1);
02639 
02640     mesh->mtl = malloc (mesh->faces * sizeof(*(mesh->mtl)));
02641     if (mesh->mtl == NULL)
02642        abortmsg ("Out of memory allocating mesh", 1);
02643 
02644     for (i = 0; i < mesh->faces; i++) {
02645        mesh->face[i].a = read_word();
02646        mesh->face[i].b = read_word();
02647        mesh->face[i].c = read_word();
02648        (void)read_word();
02649 
02650        mesh->mtl[i] = NULL;
02651     }
02652 
02653     do  {
02654        start_chunk (&chunk);
02655 
02656        if (chunk.end <= mainchunk->end) {
02657            switch (chunk.tag) {
02658               case 0x4130: parse_msh_mat_group();
02659                           break;
02660               case 0x4150: parse_smooth_group();
02661                           break;
02662            }
02663        }
02664 
02665        end_chunk (&chunk);
02666     } while (chunk.end <= mainchunk->end);
02667 
02668     for (i = 0; i < mesh->faces; i++) {
02669        if (mesh->mtl[i] == NULL)
02670            mesh->mtl[i] = update_materials ("Default", 0);
02671     }
02672 }
02673 
02674 
02675 void parse_msh_mat_group()
02676 {
02677     Material *new_mtl;
02678     char mtlname[80];
02679     int  mtlcnt;
02680     int  i, face;
02681 
02682     strcpy (mtlname, read_string());
02683     cleanup_name (mtlname);
02684 
02685     new_mtl = update_materials (mtlname, 0);
02686 
02687     mtlcnt = read_word();
02688 
02689     for (i = 0; i < mtlcnt; i++) {
02690        face = read_word();
02691        mesh->mtl[face] = new_mtl;
02692     }
02693 }
02694 
02695 
02696 void parse_smooth_group()
02697 {
02698 
02699 }
02700 
02701 
02702 void parse_mesh_matrix()
02703 {
02704     int i, j;
02705 
02706     if (mesh != NULL) {
02707        for (i = 0; i < 4; i++) {
02708            for (j = 0; j < 3; j++)
02709               mesh->matrix[i][j] = read_float();
02710        }
02711 
02712        mat_inv (mesh->invmatrix, mesh->matrix);
02713     }
02714 }
02715 
02716 
02717 void parse_n_direct_light (Chunk *mainchunk)
02718 {
02719     Chunk chunk;
02720     Spotlight *s;
02721     OmniLight *o;
02722     int light_off = FALSE;
02723     int spot_flag = FALSE;
02724 
02725     read_point (pos);
02726     parse_colour (&col);
02727 
02728     do  {
02729        start_chunk (&chunk);
02730 
02731        if (chunk.end <= mainchunk->end) {
02732            switch (chunk.tag) {
02733               case 0x4620: light_off = TRUE;
02734                           break;
02735               case 0x4610: parse_dl_spotlight();
02736                           spot_flag = TRUE;
02737                           break;
02738            }
02739        }
02740 
02741        end_chunk (&chunk);
02742     } while (chunk.end <= mainchunk->end);
02743 
02744     if (light_off)
02745        return;
02746 
02747     if (!spot_flag) {
02748        if (frame >= 0) {
02749            o = LIST_FIND (omni_list, obj_name);
02750 
02751            if (o != NULL) {
02752               pos[X] = o->pos[X];
02753               pos[Y] = o->pos[Y];
02754               pos[Z] = o->pos[Z];
02755               col    = o->col;
02756            }
02757        }
02758 
02759        write_light (out, obj_name, pos, col);
02760     }
02761     else {
02762        if (frame >= 0) {
02763            s = LIST_FIND (spot_list, obj_name);
02764 
02765            if (s != NULL) {
02766               pos[X]    = s->pos[X];
02767               pos[Y]    = s->pos[Y];
02768               pos[Z]    = s->pos[Z];
02769               target[X] = s->target[X];
02770               target[Y] = s->target[Y];
02771               target[Z] = s->target[Z];
02772               col       = s->col;
02773               hotspot   = s->hotspot;
02774               falloff   = s->falloff;
02775            }
02776        }
02777 
02778        if (falloff <= 0.0)
02779            falloff = 180.0;
02780 
02781        if (hotspot <= 0.0)
02782            hotspot = 0.7*falloff;
02783 
02784        write_spot (out, obj_name, pos, target, col, hotspot, falloff);
02785     }
02786 }
02787 
02788 
02789 void parse_dl_spotlight()
02790 {
02791     read_point (target);
02792 
02793     hotspot = read_float();
02794     falloff = read_float();
02795 }
02796 
02797 
02798 void parse_n_camera()
02799 {
02800     float  bank;
02801     float  lens;
02802 
02803     read_point (pos);
02804     read_point (target);
02805     bank = read_float();
02806     lens = read_float();
02807 
02808     if (frame >= 0 && cam_list != NULL) {
02809        pos[X]    = cam_list->pos[X];
02810        pos[Y]    = cam_list->pos[Y];
02811        pos[Z]    = cam_list->pos[Z];
02812        target[X] = cam_list->target[X];
02813        target[Y] = cam_list->target[Y];
02814        target[Z] = cam_list->target[Z];
02815        lens      = cam_list->lens;
02816        bank      = cam_list->bank;
02817     }
02818 
02819     write_camera (out, obj_name, pos, target, lens, bank);
02820 }
02821 
02822 
02823 void parse_colour (Colour *colour)
02824 {
02825     Chunk chunk;
02826     Colour_24 colour_24;
02827 
02828     start_chunk (&chunk);
02829 
02830     switch (chunk.tag) {
02831        case 0x0010: parse_colour_f (colour);
02832                    break;
02833 
02834        case 0x0011: parse_colour_24 (&colour_24);
02835                    colour->red   = colour_24.red/255.0;
02836                    colour->green = colour_24.green/255.0;
02837                    colour->blue  = colour_24.blue/255.0;
02838                    break;
02839 
02840        default:     abortmsg ("Error parsing colour", 1);
02841     }
02842 
02843     end_chunk (&chunk);
02844 }
02845 
02846 
02847 void parse_colour_f (Colour *colour)
02848 {
02849     colour->red   = read_float();
02850     colour->green = read_float();
02851     colour->blue  = read_float();
02852 }
02853 
02854 
02855 void parse_colour_24 (Colour_24 *colour)
02856 {
02857     colour->red   = read_byte();
02858     colour->green = read_byte();
02859     colour->blue  = read_byte();
02860 }
02861 
02862 
02863 float parse_percentage()
02864 {
02865     Chunk chunk;
02866     float percent = 0.0;
02867 
02868     start_chunk (&chunk);
02869 
02870     switch (chunk.tag) {
02871        case 0x0030: percent = parse_int_percentage()/100.0;
02872                    break;
02873 
02874        case 0x0031: percent = parse_float_percentage();
02875                    break;
02876 
02877        default:     printf ("WARNING: Error parsing percentage");
02878     }
02879 
02880     end_chunk (&chunk);
02881 
02882     return percent;
02883 }
02884 
02885 
02886 short parse_int_percentage()
02887 {
02888     word percent = read_word();
02889 
02890     return percent;
02891 }
02892 
02893 
02894 float parse_float_percentage()
02895 {
02896     float percent = read_float();
02897 
02898     return percent;
02899 }
02900 
02901 
02902 void start_chunk (Chunk *chunk)
02903 {
02904     chunk->start  = ftell(in);
02905     chunk->tag    = read_word();
02906     chunk->length = read_dword();
02907     if (chunk->length < sizeof(word)+sizeof(dword))
02908        chunk->length = sizeof(word) + sizeof(dword);
02909     chunk->end    = chunk->start + chunk->length;
02910 }
02911 
02912 
02913 void end_chunk (Chunk *chunk)
02914 {
02915     fseek (in, chunk->end, 0);
02916 }
02917 
02918 
02919 byte read_byte()
02920 {
02921     byte data;
02922 
02923     data = fgetc (in);
02924 
02925     return data;
02926 }
02927 
02928 
02929 word read_word()
02930 {
02931     word data;
02932 
02933     data = fgetc (in);
02934     data |= fgetc (in) << 8;
02935 
02936     return data;
02937 }
02938 
02939 
02940 dword read_dword()
02941 {
02942     dword data;
02943 
02944     data = read_word();
02945     data |= read_word() << 16;
02946 
02947     return data;
02948 }
02949 
02950 
02951 float read_float()
02952 {
02953     union { dword i; char c[8]; } u;
02954     dword data;
02955 
02956     data = read_dword();
02957 
02958     if (sizeof(dword) == sizeof(float))
02959        return *(float *)&data;
02960 
02961     u.i = 1;
02962     if (u.c[0] == 0)
02963        return *(float *)&data;     /* assume big-endian */
02964 
02965     if (sizeof(dword) != 2*sizeof(float)) {
02966        fputs("Unsupported word length\n", stderr);
02967        exit(1);
02968     }
02969     u.i = data;
02970     return *(float *)&u.c[4];
02971 }
02972 
02973 
02974 void read_point (Vector v)
02975 {
02976     v[X] = read_float();
02977     v[Y] = read_float();
02978     v[Z] = read_float();
02979 }
02980 
02981 
02982 char *read_string()
02983 {
02984     static char string[80];
02985     int i;
02986 
02987     for (i = 0; i < 80; i++) {
02988        string[i] = read_byte();
02989 
02990        if (string[i] == '\0')
02991            break;
02992     }
02993 
02994     return string;
02995 }
02996 
02997 
02998 float findfov (float lens)
02999 {
03000     static float lens_table[13] =
03001                { 15.0, 17.0, 24.0, 35.0, 50.0, 85.0, 100.0, 135.0, 200.0,
03002                  500.0, 625.0, 800.0, 1000.0 };
03003     static float fov_table[13] =
03004                { 115.0, 102.0, 84.0, 63.0, 46.0, 28.0, 24.0, 18.0,
03005                  12.0, 5.0, 4.0, 3.125, 2.5 };
03006 
03007     float fov, f1, f2, l1, l2;
03008     int   i;
03009 
03010     if (lens < 15.0)
03011        lens = 15.0;
03012     else if (lens > 1000.0)
03013        lens = 1000.0;
03014 
03015     for (i = 0; i < 13; i++)
03016        if (lens < lens_table[i])
03017            break;
03018 
03019     if (i == 13)
03020        i = 12;
03021     else if (i == 0)
03022        i = 1;
03023 
03024     f1 = fov_table[i-1];
03025     f2 = fov_table[i];
03026     l1 = lens_table[i-1];
03027     l2 = lens_table[i];
03028 
03029     fov = f1 + (lens - l1) * (f2 - f1) / (l2 - l1);
03030 
03031     return fov;
03032 }
03033 
03034