home *** CD-ROM | disk | FTP | other *** search
/ World of Graphics / WOGRAPH.BIN / 729.SOURCE.ZIP / 3DS2POV.C next >
C/C++ Source or Header  |  1993-05-06  |  57KB  |  2,411 lines

  1. /*
  2.       3DS2POV.C  Copyright (c) 1993 Steve Anger and Jeff Bowermaster
  3.  
  4.       Reads a 3D Studio .3DS file and writes a POV-Ray, Vivid, or
  5.       Polyray scene file.
  6.  
  7.       Version 1.7                 Written May/93
  8.  
  9.       Compiled with MSDOS GNU C++ 2.2.2
  10. */
  11.  
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <math.h>
  15. #include <values.h>
  16. #include <string.h>
  17. #include <ctype.h>
  18. #include "vect.h"
  19. #include "rayopt.h"
  20.  
  21. #ifdef __TURBOC__
  22. #include <alloc.h>
  23. extern unsigned _stklen = 16384;
  24. #endif
  25.  
  26. #define M3DMAGIC         (0x4D4D)
  27. #define COLOR_F          (0x0010)
  28. #define COLOR_24         (0x0011)
  29. #define INT_PERCENTAGE   (0x0030)
  30. #define FLOAT_PERCENTAGE (0x0031)
  31. #define MDATA            (0x3D3D)
  32. #define AMBIENT_LIGHT    (0x2100)
  33. #define SOLID_BGND       (0x1200)
  34. #define USE_SOLID_BGND   (0x1201)
  35. #define FOG              (0x2200)
  36. #define FOG_BGND         (0x2210)
  37. #define USE_FOG          (0x2201)
  38. #define DEFAULT_VIEW     (0x3000)
  39. #define VIEW_CAMERA      (0x3080)
  40. #define MAT_ENTRY        (0xAFFF)
  41. #define NAMED_OBJECT     (0x4000)
  42. #define N_TRI_OBJECT     (0x4100)
  43. #define N_DIRECT_LIGHT   (0x4600)
  44. #define N_CAMERA         (0x4700)
  45. #define OBJ_HIDDEN       (0x4010)
  46. #define OBJ_DOESNT_CAST  (0x4012)
  47. #define POINT_ARRAY      (0x4110)
  48. #define FACE_ARRAY       (0x4120)
  49. #define MSH_MAT_GROUP    (0x4130)
  50. #define SMOOTH_GROUP     (0x4150)
  51. #define MESH_MATRIX      (0x4160)
  52. #define DL_OFF           (0x4620)
  53. #define DL_SPOTLIGHT     (0x4610)
  54. #define DL_SHADOWED      (0x4630)
  55. #define MAT_NAME         (0xA000)
  56. #define MAT_AMBIENT      (0xA010)
  57. #define MAT_DIFFUSE      (0xA020)
  58. #define MAT_SPECULAR     (0xA030)
  59. #define MAT_SHININESS    (0xA040)
  60. #define MAT_TRANSPARENCY (0xA050)
  61.  
  62. #ifndef TRUE
  63. #define TRUE  1
  64. #define FALSE 0
  65. #endif
  66.  
  67. #define MAX_LIB  10
  68. #define ASPECT   1.333
  69.  
  70. /* Output formats */
  71. #define POV10    0
  72. #define POV20    1
  73. #define VIVID    2
  74. #define POLYRAY  3
  75. #define RAW      99
  76.  
  77. #define DEG(x) ((180.0/M_PI)*(x))
  78. #define RAD(x) ((M_PI/180.0)*(x))
  79.  
  80. /* A generic list type */
  81. #define LIST_INSERT(root, node) list_insert ((List **)&root, (List *)node)
  82. #define LIST_FIND(root, name)   list_find   ((List **)&root, name)
  83. #define LIST_DELETE(root, node) list_delete ((List **)&root, (List *)node)
  84. #define LIST_KILL(root)         list_kill   ((List **)&root)
  85.  
  86. #define LIST_FIELDS  \
  87.     char name[80];   \
  88.     void *next;
  89.  
  90.  
  91. typedef unsigned char  byte;
  92. typedef unsigned short word;
  93. typedef unsigned long  dword;
  94.  
  95. typedef struct {
  96.     LIST_FIELDS
  97. } List;
  98.  
  99.  
  100. typedef struct {
  101.     int a, b, c;
  102. } Face;
  103.  
  104.  
  105. typedef struct {
  106.     float red, green, blue;
  107. } Color;
  108.  
  109.  
  110. /* Transformation command */
  111. typedef struct {
  112.     LIST_FIELDS
  113.  
  114.     Matrix matrix;
  115. } Transform;
  116.  
  117.  
  118. /* Morph command */
  119. typedef struct {
  120.     LIST_FIELDS
  121.  
  122.     int    count;          /* Number of objects in morph */
  123.     char   names[4][80];   /* Name of n'th object in average */
  124.     float  weight[4];      /* Weight applied to n'th object */
  125.  
  126.     Matrix matrix;
  127. } Morph;
  128.  
  129.  
  130. /* Omni light command */
  131. typedef struct {
  132.     LIST_FIELDS
  133.  
  134.     Vector pos;            /* Light position */
  135.     Color  col;            /* Light color */
  136. } OmniLight;
  137.  
  138.  
  139. /* Spotlight command */
  140. typedef struct {
  141.     LIST_FIELDS
  142.  
  143.     Vector pos;            /* Spotlight position */
  144.     Vector target;         /* Spotlight target location */
  145.     Color  col;            /* Spotlight color */
  146.     float  hotspot;        /* Hotspot angle (degrees) */
  147.     float  falloff;        /* Falloff angle (degrees) */
  148.     int    shadow_flag;    /* Shadow flag (not used) */
  149. } Spotlight;
  150.  
  151.  
  152. /* Camera command */
  153. typedef struct {
  154.     LIST_FIELDS
  155.  
  156.     Vector pos;            /* Camera location */
  157.     Vector target;         /* Camera target */
  158.     float  bank;           /* Banking angle (degrees) */
  159.     float  lens;           /* Camera lens size (mm) */
  160. } Camera;
  161.  
  162.  
  163. /* Material list */
  164. typedef struct {
  165.     LIST_FIELDS
  166.  
  167.     int  external;         /* Externally defined material? */
  168. } Material;
  169.  
  170.  
  171. /* Object summary */
  172. typedef struct {
  173.     LIST_FIELDS
  174.  
  175.     Vector center;         /* Min value of object extents */
  176.     Vector lengths;        /* Max value of object extents */
  177. } Summary;
  178.  
  179.  
  180. /* Material property */
  181. typedef struct {
  182.     LIST_FIELDS
  183.  
  184.     Color ambient;
  185.     Color diffuse;
  186.     Color specular;
  187.     float shininess;
  188.     float transparency;
  189. } MatProp;
  190.  
  191.  
  192. /* A mesh object */
  193. typedef struct {
  194.     LIST_FIELDS
  195.  
  196.     int  vertices;         /* Number of vertices */
  197.     Vector *vertex;        /* List of object vertices */
  198.  
  199.     int  faces;            /* Number of faces */
  200.     Face *face;            /* List of object faces */
  201.     Material **mtl;        /* Materials for each face */
  202.  
  203.     Matrix matrix;         /* Local mesh matrix */
  204.     Matrix invmatrix;
  205.     Vector center;         /* Center of object */
  206.     Vector lengths;        /* Dimensions of object */
  207.  
  208.     int hidden;            /* Hidden flag */
  209.     int shadow;            /* Shadow flag */
  210. } Mesh;
  211.  
  212.  
  213. typedef struct {
  214.     dword start;
  215.     dword end;
  216.     dword length;
  217.     word  tag;
  218. } Chunk;
  219.  
  220.  
  221. typedef struct {
  222.     byte red;
  223.     byte green;
  224.     byte blue;
  225. } Color_24;
  226.  
  227.  
  228. OmniLight *omni_list  = NULL;
  229. Spotlight *spot_list  = NULL;
  230. Camera    *cam_list   = NULL;
  231. Mesh      *mesh_list  = NULL;
  232. Transform *trans_list = NULL;
  233. Morph     *morph_list = NULL;
  234. Material  *mtl_list   = NULL;
  235. List      *excl_list  = NULL;
  236. Summary   *summary    = NULL;
  237.  
  238. FILE   *in;
  239. FILE   *out;
  240. char   inname[80];
  241. char   outname[80];
  242. char   vuename[80];
  243. char   obj_name[80] = "";
  244. Color  fog_color  = {0.0, 0.0, 0.0};
  245. Color  col        = {0.0, 0.0, 0.0};
  246. Vector pos        = {0.0, 0.0, 0.0};
  247. Vector target     = {0.0, 0.0, 0.0};
  248. float  fog_distance = 0.0;
  249. float  hotspot = -1;
  250. float  falloff = -1;
  251. Mesh   *mesh = NULL;
  252. int    frame = -1;
  253. char   libname[MAX_LIB][80];
  254. float  smooth = 60.0;
  255. int    bound = 0;
  256. int    verbose = 0;
  257. int    format = POV10;
  258. int    cameras = 0;
  259. int    libs = 0;
  260. float  vue_version = 1.0;
  261. Matrix *ani_matrix = NULL;
  262.  
  263.  
  264. void process_args (int argc, char *argv[]);
  265. void parse_option (char *option);
  266. void list_insert (List **root, List *new_node);
  267. void *list_find (List **root, char *name);
  268. void list_delete (List **root, List *node);
  269. void list_kill (List **root);
  270. Material *update_materials (char *new_material, int ext);
  271. void read_library (char *fname);
  272. void write_intro (FILE *f);
  273. void write_summary (FILE *f);
  274. void write_bgsolid (FILE *f, Color col);
  275. void write_light (FILE *f, char *name, Vector pos, Color col);
  276. void write_spot (FILE *f, char *name, Vector pos, Vector target, Color col,
  277.      float hotspot, float falloff);
  278. void write_fog (FILE *f, Color col, float dist);
  279. void write_camera (FILE *f, char *name, Vector pos, Vector target, float lens,
  280.      float bank);
  281. void write_texture (FILE *f, char *mat);
  282. void write_mesh (FILE *f, Mesh *mesh);
  283. Transform *parse_transform (char *string);
  284. Morph *parse_morph (char *string);
  285. OmniLight *parse_omnilight (char *string);
  286. Spotlight *parse_spotlight (char *string);
  287. Camera *parse_camera (char *string);
  288. void read_frame (char *filename, int frame_no);
  289. void find_frame (FILE *f, int frame_no);
  290. void save_animation (void);
  291. Mesh *create_mesh (char *name, int vertices, int faces);
  292. Mesh *copy_mesh (Mesh *mesh);
  293. void free_mesh_data (Mesh *mesh);
  294. void update_limits (Mesh *mesh);
  295. char *before (char *str, char *target);
  296. char *after (char *str, char *target);
  297. char *between (char *str, char *target1, char *target2);
  298. char *parse_string (char *str);
  299. char upcase (char c);
  300. void parse_file (void);
  301. void parse_3ds (Chunk *mainchunk);
  302. void parse_mdata (Chunk *mainchunk);
  303. void parse_fog (Chunk *mainchunk);
  304. void parse_fog_bgnd (void);
  305. void parse_mat_entry (void);
  306. void parse_named_object (Chunk *mainchunk);
  307. void parse_n_tri_object (Chunk *mainchunk);
  308. void parse_point_array (void);
  309. void parse_face_array (Chunk *mainchunk);
  310. void parse_msh_mat_group (void);
  311. void parse_smooth_group (void);
  312. void parse_mesh_matrix (void);
  313. void parse_n_direct_light (Chunk *mainchunk);
  314. void parse_dl_spotlight (void);
  315. void parse_n_camera (void);
  316. void parse_color (Color *color);
  317. void parse_color_f (Color *color);
  318. void parse_color_24 (Color_24 *color);
  319. float parse_percentage (void);
  320. short parse_int_percentage (void);
  321. float parse_float_percentage (void);
  322. void start_chunk (Chunk *chunk);
  323. void end_chunk (Chunk *chunk);
  324. byte read_byte (void);
  325. word read_word (void);
  326. dword read_dword (void);
  327. float read_float (void);
  328. void read_point (Vector v);
  329. char *read_string (void);
  330. float findfov (float lens);
  331.  
  332.  
  333. int main (int argc, char *argv[])
  334. {
  335.     Material *m;
  336.     int i;
  337.  
  338.     process_args (argc, argv);
  339.  
  340.     if (format != RAW) {
  341.     opt_set_format (format);
  342.     opt_set_dec (4);
  343.     opt_set_bound (bound);
  344.     opt_set_smooth (smooth);
  345.     opt_set_quiet (!verbose);
  346.     opt_set_fname (outname, "");
  347.     }
  348.  
  349.     if ((in = fopen (inname, "rb")) == NULL) {
  350.     printf ("Cannot open input file %s!\n", inname);
  351.     exit (1);
  352.     }
  353.  
  354.     if ((out = fopen (outname, "w")) == NULL) {
  355.     printf ("Cannot open output file %s!\n", outname);
  356.     exit (1);
  357.     }
  358.  
  359.     /* Load the names of pre-defined materials */
  360.     for (i = 0; i < MAX_LIB; i++) {
  361.     if (strlen(libname[i]) > 0)
  362.         read_library (libname[i]);
  363.     }
  364.  
  365.     /* Load the instructions for the current frame */
  366.     if (strlen(vuename) > 0)
  367.     read_frame (vuename, frame);
  368.  
  369.     printf("Output to: %s\n", outname);
  370.  
  371.     if (frame >= 0)
  372.     printf ("Generating frame #%d\n", frame);
  373.  
  374.     printf("\nPlease wait; Processing...\n");
  375.  
  376.     write_intro(out);
  377.  
  378.     parse_file();
  379.  
  380.     fclose(in);
  381.  
  382.     for (m = mtl_list; m != NULL; m = m->next) {
  383.     if (!m->external)
  384.         write_texture (out, m->name);
  385.     }
  386.  
  387.     fclose (out);
  388.  
  389.     if (frame >= 0)
  390.     save_animation();
  391.  
  392.     if (format != RAW) {
  393.         out = fopen (outname, "a");
  394.         write_summary (out);
  395.         fclose (out);
  396.  
  397.     opt_finish();
  398.     }
  399.  
  400.     LIST_KILL (omni_list);
  401.     LIST_KILL (spot_list);
  402.     LIST_KILL (cam_list);
  403.     LIST_KILL (mesh_list);
  404.     LIST_KILL (trans_list);
  405.     LIST_KILL (morph_list);
  406.     LIST_KILL (mtl_list);
  407.     LIST_KILL (excl_list);
  408.     LIST_KILL (summary);
  409.  
  410.     return 0;
  411. }
  412.  
  413.  
  414. /* Handle the command line args */
  415. void process_args (int argc, char *argv[])
  416. {
  417.     int i;
  418.     char *env_opt, *option;
  419.  
  420.     printf("\n\nAutoDesk 3D Studio to Raytracer file Translator. May/93\n");
  421.     printf("Version 1.7 Copyright (c) 1993 Steve Anger and Jeff Bowermaster\n");
  422. #ifdef __GNUC__
  423.     printf ("32 bit version. DOS extender Copyright (c) 1991 DJ Delorie\n");
  424. #endif
  425.     printf ("\n");
  426.  
  427.     if (argc < 2) {
  428.     printf ("Usage: 3ds2pov inputfile[.3ds] [outputfile] [options]\n\n");
  429.     printf ("Options: -snnn        - Smooth triangles with angles < nnn\n");
  430.     printf ("         -l<filename> - Specifies 3DS texture library\n");
  431.     printf ("         -a<filename> - Use animation information in specified file\n");
  432.     printf ("         -fnnn        - Generate frame nnn of animation\n");
  433.     printf ("         -x<object>   - Exclude this object from conversion\n");
  434.     printf ("         -u           - Do not add nested bounds to output (unbounded)\n");
  435.     printf ("         -v           - Verbose status messages\n");
  436.     printf ("         -op          - Output to POV-Ray 1.0 format (default)\n");
  437.     printf ("         -op2         - Output to POV-Ray 2.0 format\n");
  438.     printf ("         -ov          - Output to Vivid 2.0 format\n");
  439.     printf ("         -ol          - Output to poLyray format\n");
  440.     printf ("         -or          - Output to RAW triangle format\n\n");
  441.     printf ("ex. 3ds2pov birdshow -s70 -v -l3ds.inc\n\n");
  442.     exit(1);
  443.     }
  444.  
  445.     strcpy (inname, "");
  446.     strcpy (outname, "");
  447.     strcpy (vuename, "");
  448.  
  449.     for (i = 0; i < MAX_LIB; i++)
  450.     strcpy (libname[i], "");
  451.  
  452.     frame = -1;
  453.     smooth = 60.0;
  454.     bound = 0;
  455.     verbose = 0;
  456.     format = POV10;
  457.     libs = 0;
  458.  
  459.     /* Parse the enviroment string options */
  460.     env_opt = getenv ("3DS2POV");
  461.  
  462.     if (env_opt != NULL) {
  463.     option = parse_string (env_opt);
  464.  
  465.     while (strlen(option) > 0) {
  466.         parse_option (option);
  467.         option = parse_string (NULL);
  468.     }
  469.     }
  470.  
  471.     /* Parse the command line options */
  472.     for (i = 1; i < argc; i++)
  473.     parse_option (argv[i]);
  474.  
  475.     if (strlen(inname) == 0)
  476.     abortmsg ("No input file specified", 1);
  477.  
  478.     if (strlen(outname) == 0) {
  479.     strcpy (outname, inname);
  480.  
  481.     switch (format) {
  482.         case POV10:
  483.         case POV20:   add_ext (outname, "pov", 1); break;
  484.         case VIVID:   add_ext (outname, "v",   1); break;
  485.         case POLYRAY: add_ext (outname, "pi",  1); break;
  486.         case RAW:     add_ext (outname, "raw", 1); break;
  487.     }
  488.     }
  489.     else {
  490.     switch (format) {
  491.         case POV10:
  492.         case POV20:   add_ext (outname, "pov", 0); break;
  493.         case VIVID:   add_ext (outname, "v",   0); break;
  494.         case POLYRAY: add_ext (outname, "pi",  0); break;
  495.         case RAW:     add_ext (outname, "raw", 0); break;
  496.     }
  497.     }
  498.  
  499.     if ((strlen(vuename) > 0) ^ (frame >= 0))
  500.     abortmsg ("The -a and -f parameters must be used together", 1);
  501. }
  502.  
  503.  
  504. void parse_option (char *option)
  505. {
  506.     List *excl;
  507.     char name[80];
  508.  
  509.     if (option[0] == '-' || option[0] == '+' || option[0] == '/') {
  510.     switch (upcase(option[1])) {
  511.         case 'A': strcpy (vuename, &option[2]);
  512.               break;
  513.  
  514.         case 'F': if (option[2] != '\0')
  515.               frame = atoi (&option[2]);
  516.               break;
  517.  
  518.         case 'L': if (libs == MAX_LIB)
  519.               abortmsg ("Too many libraries specified", 1);
  520.  
  521.               strcpy (libname[libs++], &option[2]);
  522.               break;
  523.  
  524.         case 'O': switch (upcase(option[2])) {
  525.               case 'P': if (option[3] == '2')
  526.                     format = POV20;
  527.                     else
  528.                     format = POV10;
  529.                     break;
  530.  
  531.               case 'V': format = VIVID;
  532.                     break;
  533.  
  534.               case 'L': format = POLYRAY;
  535.                     break;
  536.  
  537.               case 'R': format = RAW;
  538.                     break;
  539.  
  540.               default:  printf ("Invalid output format %s specified\n", option);
  541.                     exit(1);
  542.               }
  543.               break;
  544.  
  545.         case 'S': if (option[2] != '\0')
  546.               smooth = atof (&option[2]);
  547.               break;
  548.  
  549.         case 'U': bound = 2;
  550.               break;
  551.  
  552.         case 'V': verbose = 1;
  553.               break;
  554.  
  555.         case 'X': strcpy (name, parse_string (&option[2]));
  556.               cleanup_name (name);
  557.  
  558.               excl = malloc (sizeof (*excl));
  559.               strcpy (excl->name, name);
  560.  
  561.               LIST_INSERT (excl_list, excl);
  562.               break;
  563.  
  564.         default : printf ("\nInvalid option %s specified\n", option);
  565.               exit (1);
  566.     }
  567.     }
  568.     else if (strlen (inname) == 0) {
  569.     strcpy (inname, option);
  570.     add_ext (inname, "3ds", 0);
  571.     }
  572.     else if (strlen (outname) == 0)
  573.     strcpy (outname, option);
  574.     else
  575.     abortmsg ("Too many file names specified.\n", 1);
  576. }
  577.  
  578.  
  579. /* Insert a new node into the list */
  580. void list_insert (List **root, List *new_node)
  581. {
  582.     new_node->next = *root;
  583.  
  584.     *root = new_node;
  585. }
  586.  
  587.  
  588. /* Find the node with the specified name */
  589. void *list_find (List **root, char *name)
  590. {
  591.     List *p;
  592.  
  593.     for (p = *root; p != NULL; p = p->next) {
  594.     if (strcmp (p->name, name) == 0)
  595.         break;
  596.     }
  597.  
  598.     return (void *)p;
  599. }
  600.  
  601.  
  602. /* Delete the indicated node from the list */
  603. void list_delete (List **root, List *node)
  604. {
  605.     List *prev;
  606.  
  607.     prev = *root;
  608.     while (prev != NULL && prev->next != node)
  609.     prev = prev->next;
  610.  
  611.     if (prev == NULL)
  612.     *root = node->next;
  613.     else
  614.     prev->next = node->next;
  615.  
  616.     free (node);
  617. }
  618.  
  619.  
  620. /* Delete the entire list */
  621. void list_kill (List **root)
  622. {
  623.     List *temp;
  624.  
  625.     while (*root != NULL) {
  626.     temp = *root;
  627.     *root = (*root)->next;
  628.     free (temp);
  629.     }
  630. }
  631.  
  632.  
  633. /* Add a new material to the material list */
  634. Material *update_materials (char *new_material, int ext)
  635. {
  636.     Material *p;
  637.  
  638.     p = LIST_FIND (mtl_list, new_material);
  639.  
  640.     if (p == NULL) {
  641.     p = malloc (sizeof (*p));
  642.  
  643.     if (p == NULL)
  644.         abortmsg ("Out of memory adding material", 1);
  645.  
  646.     strcpy (p->name, new_material);
  647.     p->external = ext;
  648.  
  649.     LIST_INSERT (mtl_list, p);
  650.     }
  651.  
  652.     return p;
  653. }
  654.  
  655.  
  656. /* Load in any predefined materials */
  657. void read_library (char *fname)
  658. {
  659.     FILE *lib;
  660.     char string[256], name[80];
  661.  
  662.     if ((lib = fopen (fname, "r")) == NULL) {
  663.     printf ("Cannot open texture library file %s!\n", fname);
  664.     exit(1);
  665.     }
  666.  
  667.     switch (format) {
  668.     case POV10:
  669.     case POV20:
  670.         while (fgets (string, 256, lib) != NULL) {
  671.         if (strstr (string, "#declare")) {
  672.             strcpy (name, between (string, "#declare", "="));
  673.             cleanup_name (name);
  674.             (void)update_materials (name, TRUE);
  675.         }
  676.         }
  677.         break;
  678.  
  679.     case VIVID:
  680.         while (fgets (string, 256, lib) != NULL) {
  681.         if (strstr (string, "#define")) {
  682.             (void)parse_string (string);
  683.             strcpy (name, parse_string (NULL));
  684.             cleanup_name (name);
  685.             (void)update_materials (name, TRUE);
  686.         }
  687.         }
  688.         break;
  689.  
  690.     case POLYRAY:
  691.         while (fgets (string, 256, lib) != NULL) {
  692.         if (strstr (string, "define")) {
  693.             (void)parse_string (string);
  694.             strcpy (name, parse_string (NULL));
  695.             cleanup_name (name);
  696.             (void)update_materials (name, TRUE);
  697.         }
  698.         }
  699.         break;
  700.     }
  701.  
  702.     fclose (lib);
  703. }
  704.  
  705.  
  706. void write_intro (FILE *f)
  707. {
  708.     int i;
  709.  
  710.     switch (format) {
  711.     case POV10:
  712.     case POV20:
  713.         fprintf (f, "#include \"colors.inc\"\n");
  714.         fprintf (f, "#include \"shapes.inc\"\n");
  715.         fprintf (f, "#include \"textures.inc\"\n");
  716.  
  717.         for (i = 0; i < MAX_LIB; i++) {
  718.         if (strlen(libname[i]) > 0)
  719.             fprintf (f, "#include \"%s\"\n", libname[i]);
  720.         }
  721.  
  722.         fprintf (f, "\n");
  723.         break;
  724.  
  725.     case VIVID:
  726.         fprintf (f, "#include color.vc\n");
  727.  
  728.         for (i = 0; i < MAX_LIB; i++) {
  729.         if (strlen(libname[i]) > 0)
  730.             fprintf (f, "#include %s\n", libname[i]);
  731.         }
  732.  
  733.         fprintf (f, "\n");
  734.         break;
  735.  
  736.     case POLYRAY:
  737.         fprintf (f, "include \"colors.inc\"\n");
  738.  
  739.         for (i = 0; i < MAX_LIB; i++) {
  740.         if (strlen(libname[i]) > 0)
  741.             fprintf (f, "include \"%s\"\n", libname[i]);
  742.         }
  743.  
  744.         fprintf (f, "\n");
  745.         break;
  746.     }
  747. }
  748.  
  749.  
  750. /* Write the object summary */
  751. void write_summary (FILE *f)
  752. {
  753.     Summary *s;
  754.  
  755.     if (summary == NULL)
  756.         return;
  757.  
  758.     fprintf (f, "//   Object    CenterX    CenterY    CenterZ    LengthX    LengthY    LengthZ\n");
  759.     fprintf (f, "// ---------- ---------- ---------- ---------- ---------- ---------- ----------\n");
  760.  
  761.     for (s = summary; s != NULL; s = s->next) {
  762.         fprintf (f, "// %-10s%11.2f%11.2f%11.2f%11.2f%11.2f%11.2f\n",
  763.          s->name, s->center[X], s->center[Y], s->center[Z],
  764.          s->lengths[X], s->lengths[Y], s->lengths[Z]);
  765.     }
  766.  
  767.     fprintf (f, "\n");
  768. }
  769.  
  770.  
  771. /* Write background solid color */
  772. void write_bgsolid (FILE *f, Color col)
  773. {
  774.     switch (format) {
  775.     case POV10:
  776.         fprintf (f, "/* Background color */\n");
  777.         fprintf (f, "object {\n");
  778.         fprintf (f, "   sphere { <0.0 0.0 0.0> 1e6 }\n");
  779.         fprintf (f, "   texture {\n");
  780.         fprintf (f, "      ambient 1.0\n");
  781.         fprintf (f, "      diffuse 0.0\n");
  782.         fprintf (f, "      color red %4.2f green %4.2f blue %4.2f\n",
  783.                  col.red, col.green, col.blue);
  784.         fprintf (f, "   }\n");
  785.         fprintf (f, "}\n\n");
  786.         break;
  787.  
  788.     case POV20:
  789.         fprintf (f, "background { color red %4.2f green %4.2f blue %4.2f }\n\n",
  790.                col.red, col.green, col.blue);
  791.         break;
  792.  
  793.     case POLYRAY:
  794.         fprintf (f, "background <%4.2f, %4.2f, %4.2f>\n\n",
  795.                col.red, col.green, col.blue);
  796.         break;
  797.     }
  798. }
  799.  
  800.  
  801. void write_light (FILE *f, char *name, Vector pos, Color col)
  802. {
  803.     switch (format) {
  804.     case POV10:
  805.         fprintf (f, "/* Light: %s */\n", name);
  806.         fprintf (f, "object {\n");
  807.         fprintf (f, "    light_source { <%.4f %.4f %.4f> color red %4.2f green %4.2f blue %4.2f }\n",
  808.              pos[X], pos[Y], pos[Z], col.red, col.green, col.blue);
  809.         fprintf (f, "}\n\n");
  810.         break;
  811.  
  812.     case POV20:
  813.         fprintf (f, "/* Light: %s */\n", name);
  814.         fprintf (f, "light_source {\n");
  815.         fprintf (f, "    <%.4f, %.4f, %.4f> color rgb <%4.2f, %4.2f, %4.2f>\n",
  816.              pos[X], pos[Y], pos[Z], col.red, col.green, col.blue);
  817.         fprintf (f, "}\n\n");
  818.         break;
  819.  
  820.     case VIVID:
  821.         fprintf (f, "/* Light: %s */\n", name);
  822.         fprintf (f, "light {\n");
  823.         fprintf (f, "    type point\n");
  824.         fprintf (f, "    position %.4f %.4f %.4f\n",
  825.                    pos[X], pos[Y], pos[Z]);
  826.         fprintf (f, "    color %4.2f %4.2f %4.2f\n",
  827.                    col.red, col.green, col.blue);
  828.         fprintf (f, "}\n\n");
  829.         break;
  830.  
  831.     case POLYRAY:
  832.         fprintf (f, "// Light: %s\n", name);
  833.         fprintf (f, "light <%4.2f, %4.2f, %4.2f>, <%.4f, %.4f, %.4f>\n\n",
  834.               col.red, col.green, col.blue, pos[X], pos[Y], pos[Z]);
  835.         break;
  836.     }
  837. }
  838.  
  839.  
  840. void write_spot (FILE *f, char *name, Vector pos, Vector target, Color col,
  841.               float hotspot, float falloff)
  842. {
  843.     switch (format) {
  844.     case POV10:
  845.         fprintf (f, "/* Spotlight: %s */\n", name);
  846.         fprintf (f, "object {\n");
  847.         fprintf (f, "    light_source {\n");
  848.         fprintf (f, "        <%.4f %.4f %.4f> color red %4.2f green %4.2f blue %4.2f\n",
  849.                    pos[X], pos[Y], pos[Z],
  850.                    col.red, col.green, col.blue);
  851.         fprintf (f, "        spotlight\n");
  852.         fprintf (f, "        point_at <%.4f %.4f %.4f>\n",
  853.                    target[X], target[Y], target[Z]);
  854.         fprintf (f, "        tightness 0\n");
  855.         fprintf (f, "        radius %.2f\n", 0.5*hotspot);
  856.         fprintf (f, "        falloff %.2f\n", 0.5*falloff);
  857.         fprintf (f, "    }\n");
  858.         fprintf (f, "}\n\n");
  859.         break;
  860.  
  861.     case POV20:
  862.         fprintf (f, "/* Spotlight: %s */\n", name);
  863.         fprintf (f, "light_source {\n");
  864.         fprintf (f, "    <%.4f, %.4f, %.4f> color rgb <%4.2f, %4.2f, %4.2f>\n",
  865.                    pos[X], pos[Y], pos[Z],
  866.                    col.red, col.green, col.blue);
  867.         fprintf (f, "    spotlight\n");
  868.         fprintf (f, "    point_at <%.4f, %.4f, %.4f>\n",
  869.                    target[X], target[Y], target[Z]);
  870.         fprintf (f, "    tightness 0\n");
  871.         fprintf (f, "    radius %.2f\n", 0.5*hotspot);
  872.         fprintf (f, "    falloff %.2f\n", 0.5*falloff);
  873.         fprintf (f, "}\n\n");
  874.         break;
  875.  
  876.     case VIVID:
  877.         fprintf (f, "/* Spotlight: %s */\n", name);
  878.         fprintf (f, "light {\n");
  879.         fprintf (f, "    type spot\n");
  880.         fprintf (f, "    position %.4f %.4f %.4f\n",
  881.                    pos[X], pos[Y], pos[Z]);
  882.         fprintf (f, "    at %.4f %.4f %.4f\n",
  883.                    target[X], target[Y], target[Z]);
  884.         fprintf (f, "    color %4.2f %4.2f %4.2f\n",
  885.                    col.red, col.green, col.blue);
  886.         fprintf (f, "    min_angle %.2f\n", hotspot);
  887.         fprintf (f, "    max_angle %.2f\n", falloff);
  888.         fprintf (f, "}\n\n");
  889.         break;
  890.  
  891.     case POLYRAY:
  892.         fprintf (f, "// Spotlight: %s\n", name);
  893.         fprintf (f, "spot_light <%4.2f, %4.2f, %4.2f>, <%.4f, %.4f, %.4f>,\n",
  894.               col.red, col.green, col.blue, pos[X], pos[Y], pos[Z]);
  895.         fprintf (f, "           <%.4f, %.4f, %.4f>, 0.0, %.2f, %.2f\n\n",
  896.               target[X], target[Y], target[Z], hotspot/2.0, falloff/2.0);
  897.         break;
  898.     }
  899. }
  900.  
  901.  
  902. void write_fog (FILE *f, Color col, float dist)
  903. {
  904.     if (dist <= 0.0)
  905.     return;
  906.  
  907.     switch (format) {
  908.     case POV10:
  909.         fprintf (f, "fog {\n");
  910.         fprintf (f, "    color red %4.2f green %4.2f blue %4.2f %.4f\n",
  911.               col.red, col.green, col.blue, dist/2.0);
  912.         fprintf (f, "}\n\n");
  913.         break;
  914.  
  915.     case POV20:
  916.         fprintf (f, "fog {\n");
  917.         fprintf (f, "    color red %4.2f green %4.2f blue %4.2f distance %.4f\n",
  918.               col.red, col.green, col.blue, dist/2.0);
  919.         fprintf (f, "}\n\n");
  920.         break;
  921.     }
  922. }
  923.  
  924.  
  925. void write_camera (FILE *f, char *name, Vector pos, Vector target,
  926.                 float lens, float bank)
  927. {
  928.     float fov;
  929.  
  930.     cameras++;
  931.  
  932.     fov = findfov (lens);
  933.  
  934.     switch (format) {
  935.     case POV10:
  936.         /* Comment out multiple cameras */
  937.         if (cameras > 1)
  938.         fprintf (f, "/*\n");
  939.  
  940.         fprintf (f, "/* Camera: %s */\n", name);
  941.         fprintf (f, "camera {\n");
  942.         fprintf (f, "   location <%.4f %.4f %.4f>\n",
  943.                   pos[X], pos[Y], pos[Z]);
  944.         fprintf (f, "   direction <0 %.3f 0>\n", 0.60/tan(0.5*RAD(fov)) );
  945.         fprintf (f, "   up <0 0 1>\n");
  946.         fprintf (f, "   sky  <0 0 1>\n");
  947.         fprintf (f, "   right <%.3f 0 0>\n", ASPECT);
  948.         fprintf (f, "   look_at <%.4f %.4f %.4f>\n",
  949.                   target[X], target[Y], target[Z]);
  950.         if (bank != 0.0)
  951.         fprintf (f, "   /* Bank angle = %.2f */\n", bank);
  952.  
  953.         fprintf (f, "}\n");
  954.  
  955.         if (cameras > 1)
  956.         fprintf (f, "*/\n");
  957.  
  958.         fprintf (f, "\n");
  959.         break;
  960.  
  961.     case POV20:
  962.         /* Comment out multiple cameras */
  963.         if (cameras > 1)
  964.         fprintf (f, "/*\n");
  965.  
  966.         fprintf (f, "/* Camera: %s */\n", name);
  967.         fprintf (f, "camera {\n");
  968.         fprintf (f, "   location <%.4f, %.4f, %.4f>\n",
  969.                   pos[X], pos[Y], pos[Z]);
  970.         fprintf (f, "   direction <0, %.3f, 0>\n", 0.60/tan(0.5*RAD(fov)) );
  971.         fprintf (f, "   up <0, 0, 1>\n");
  972.         fprintf (f, "   sky  <0, 0, 1>\n");
  973.         fprintf (f, "   right <%.3f, 0, 0>\n", ASPECT);
  974.         fprintf (f, "   look_at <%.4f, %.4f, %.4f>\n",
  975.                   target[X], target[Y], target[Z]);
  976.         if (bank != 0.0)
  977.         fprintf (f, "   /* Bank angle = %.2f */\n", bank);
  978.  
  979.         fprintf (f, "}\n");
  980.  
  981.         if (cameras > 1)
  982.         fprintf (f, "*/\n");
  983.  
  984.         fprintf (f, "\n");
  985.         break;
  986.  
  987.     case VIVID:
  988.         fprintf (f, "/* Camera: %s */\n", name);
  989.  
  990.         if (cameras > 1)
  991.         fprintf (f, "/*\n");
  992.  
  993.         fprintf (f, "studio {\n");
  994.         fprintf (f, "    from %.4f %.4f %.4f\n",
  995.                    pos[X], pos[Y], pos[Z]);
  996.         fprintf (f, "    at %.4f %.4f %.4f\n",
  997.                    target[X], target[Y], target[Z]);
  998.         fprintf (f, "    up 0 0 1\n");
  999.         fprintf (f, "    angle %.2f\n", 1.1*fov);
  1000.         fprintf (f, "    aspect %.3f\n", ASPECT);
  1001.         fprintf (f, "    resolution 320 200\n");
  1002.         fprintf (f, "    antialias none\n");
  1003.         fprintf (f, "}\n");
  1004.  
  1005.         if (cameras > 1)
  1006.         fprintf (f, "*/\n");
  1007.  
  1008.         fprintf (f, "\n");
  1009.         break;
  1010.  
  1011.     case POLYRAY:
  1012.         if (cameras == 1) {
  1013.         fprintf (f, "// Camera: %s\n", name);
  1014.         fprintf (f, "viewpoint {\n");
  1015.         fprintf (f, "    from <%.4f, %.4f, %.4f>\n",
  1016.                    pos[X], pos[Y], pos[Z]);
  1017.         fprintf (f, "    at <%.4f, %.4f, %.4f>\n",
  1018.                    target[X], target[Y], target[Z]);
  1019.         fprintf (f, "    up <0, 0, 1>\n");
  1020.         fprintf (f, "    angle %.2f\n", 0.85*fov);
  1021.         fprintf (f, "    aspect %.3f\n", -(ASPECT));
  1022.         fprintf (f, "    resolution 320, 200\n");
  1023.         fprintf (f, "}\n");
  1024.         }
  1025.  
  1026.         fprintf (f, "\n");
  1027.         break;
  1028.     }
  1029. }
  1030.  
  1031.  
  1032. void write_texture (FILE *f, char *mat)
  1033. {
  1034.     switch (format) {
  1035.     case POV10:
  1036.         fprintf (f, "#declare %s = texture {\n", mat);
  1037.         fprintf (f, "    ambient 0.1\n");
  1038.         fprintf (f, "    diffuse 0.7\n");
  1039.         fprintf (f, "    phong 1.0\n");
  1040.         fprintf (f, "    phong_size 70.0\n");
  1041.         fprintf (f, "    color White\n");
  1042.         fprintf (f, "}\n\n");
  1043.         break;
  1044.  
  1045.     case POV20:
  1046.         fprintf (f, "#declare %s = texture {\n", mat);
  1047.         fprintf (f, "    finish { Shiny }\n");
  1048.         fprintf (f, "    pigment { White }\n");
  1049.         fprintf (f, "}\n\n");
  1050.         break;
  1051.  
  1052.     case VIVID:
  1053.         fprintf (f, "#define %s \\ \n", mat);
  1054.         fprintf (f, "    surface {           \\ \n");
  1055.         fprintf (f, "        diffuse white   \\ \n");
  1056.         fprintf (f, "        shine 70 white  \\ \n");
  1057.         fprintf (f, "    }\n\n");
  1058.         break;
  1059.  
  1060.     case POLYRAY:
  1061.         fprintf (f, "define %s\n", mat);
  1062.         fprintf (f, "texture {\n");
  1063.         fprintf (f, "    surface {\n");
  1064.         fprintf (f, "        ambient white, 0.1\n");
  1065.         fprintf (f, "        diffuse white, 0.7\n");
  1066.         fprintf (f, "        specular white, 1.0\n");
  1067.         fprintf (f, "        microfacet Reitz 10\n");
  1068.         fprintf (f, "    }\n");
  1069.         fprintf (f, "}\n\n");
  1070.         break;
  1071.     }
  1072. }
  1073.  
  1074.  
  1075. /* Write a mesh file */
  1076. void write_mesh (FILE *f, Mesh *mesh)
  1077. {
  1078.     int i;
  1079.     Vector va, vb, vc;
  1080.     Summary *new_summary;
  1081.  
  1082.     if (mesh->hidden)
  1083.     return;
  1084.  
  1085.     if (LIST_FIND (excl_list, mesh->name))
  1086.     return;
  1087.  
  1088.     new_summary = malloc (sizeof(*new_summary));
  1089.     if (new_summary == NULL)
  1090.     abortmsg ("Out of memory adding summary", 1);
  1091.  
  1092.     strcpy (new_summary->name, mesh->name);
  1093.     vect_copy (new_summary->center,  mesh->center);
  1094.     vect_copy (new_summary->lengths, mesh->lengths);
  1095.  
  1096.     LIST_INSERT (summary, new_summary);
  1097.  
  1098.     switch (format) {
  1099.     case POV10:
  1100.     case POV20:
  1101.     case VIVID:
  1102.     case POLYRAY:
  1103.         opt_set_vert (mesh->vertices);
  1104.  
  1105.         for (i = 0; i < mesh->faces; i++) {
  1106.         vect_copy (va, mesh->vertex[mesh->face[i].a]);
  1107.         vect_copy (vb, mesh->vertex[mesh->face[i].b]);
  1108.         vect_copy (vc, mesh->vertex[mesh->face[i].c]);
  1109.  
  1110.         if (frame >= 0 && vue_version > 2.0) {
  1111.             vect_transform (va, va, mesh->invmatrix);
  1112.             vect_transform (vb, vb, mesh->invmatrix);
  1113.             vect_transform (vc, vc, mesh->invmatrix);
  1114.         }
  1115.  
  1116.         #ifdef USEOLDTRANS
  1117.         if (ani_matrix != NULL) {
  1118.             vect_transform (va, va, *ani_matrix);
  1119.             vect_transform (vb, vb, *ani_matrix);
  1120.             vect_transform (vc, vc, *ani_matrix);
  1121.         }
  1122.         #endif
  1123.  
  1124.         opt_set_texture (mesh->mtl[i]->name);
  1125.  
  1126.         opt_add_tri (va[X], va[Y], va[Z], vc[X], vc[Y], vc[Z],
  1127.                  vb[X], vb[Y], vb[Z]);
  1128.         }
  1129.  
  1130.         fclose (f);
  1131.  
  1132.         #ifndef USEOLDTRANS
  1133.         if (ani_matrix != NULL)
  1134.         opt_set_transform (*ani_matrix);
  1135.         #endif
  1136.  
  1137.         opt_write_file (mesh->name);
  1138.  
  1139.         f = fopen (outname, "a");
  1140.         break;
  1141.  
  1142.     case RAW:
  1143.         fprintf (f, "%s\n", mesh->name);
  1144.  
  1145.         for (i = 0; i < mesh->faces; i++) {
  1146.         vect_copy (va, mesh->vertex[mesh->face[i].a]);
  1147.         vect_copy (vb, mesh->vertex[mesh->face[i].b]);
  1148.         vect_copy (vc, mesh->vertex[mesh->face[i].c]);
  1149.  
  1150.         if (frame >= 0 || vue_version > 2.0) {
  1151.             vect_transform (va, va, mesh->invmatrix);
  1152.             vect_transform (vb, vb, mesh->invmatrix);
  1153.             vect_transform (vc, vc, mesh->invmatrix);
  1154.         }
  1155.  
  1156.         if (ani_matrix != NULL) {
  1157.             vect_transform (va, va, *ani_matrix);
  1158.             vect_transform (vb, vb, *ani_matrix);
  1159.             vect_transform (vc, vc, *ani_matrix);
  1160.         }
  1161.  
  1162.         fprintf (f, "%f %f %f   %f %f %f   %f %f %f\n",
  1163.                 va[X], va[Y], va[Z], vb[X], vb[Y], vb[Z],
  1164.                 vc[X], vc[Y], vc[Z]);
  1165.         }
  1166.  
  1167.         break;
  1168.     }
  1169. }
  1170.  
  1171.  
  1172. /* Parses an object transformation and returns a pointer to the
  1173.    newly allocated transformation */
  1174. Transform *parse_transform (char *string)
  1175. {
  1176.     Transform *t;
  1177.     char      *token;
  1178.     int       token_no;
  1179.  
  1180.     t = (Transform *)malloc (sizeof(*t));
  1181.     if (t == NULL)
  1182.     abortmsg ("Out of memory allocating transform", 1);
  1183.  
  1184.     mat_identity (t->matrix);
  1185.  
  1186.     token = parse_string (string);
  1187.     token_no = 0;
  1188.  
  1189.     while (strlen(token) > 0) {
  1190.      switch (token_no) {
  1191.          case  0: break;
  1192.          case  1: strcpy (t->name, token); break;
  1193.          case  2: t->matrix[0][0] = atof(token); break;
  1194.          case  3: t->matrix[0][1] = atof(token); break;
  1195.          case  4: t->matrix[0][2] = atof(token); break;
  1196.          case  5: t->matrix[1][0] = atof(token); break;
  1197.          case  6: t->matrix[1][1] = atof(token); break;
  1198.          case  7: t->matrix[1][2] = atof(token); break;
  1199.          case  8: t->matrix[2][0] = atof(token); break;
  1200.          case  9: t->matrix[2][1] = atof(token); break;
  1201.          case 10: t->matrix[2][2] = atof(token); break;
  1202.          case 11: t->matrix[3][0] = atof(token); break;
  1203.          case 12: t->matrix[3][1] = atof(token); break;
  1204.          case 13: t->matrix[3][2] = atof(token); break;
  1205.  
  1206.          default: abortmsg ("Error parsing transform", 1);
  1207.      }
  1208.  
  1209.      token = parse_string (NULL);
  1210.      token_no++;
  1211.     }
  1212.  
  1213.     t->matrix[0][3] = 0.0;
  1214.     t->matrix[1][3] = 0.0;
  1215.     t->matrix[2][3] = 0.0;
  1216.     t->matrix[3][3] = 1.0;
  1217.  
  1218.     cleanup_name (t->name);
  1219.  
  1220.     return t;
  1221. }
  1222.  
  1223.  
  1224. /* Parses a morph command and returns a pointer to the
  1225.    newly allocated morph */
  1226. Morph *parse_morph (char *string)
  1227. {
  1228.     Morph  *m;
  1229.     char   *token;
  1230.     int    i, token_no;
  1231.  
  1232.     m = (Morph *)malloc (sizeof(*m));
  1233.     if (m == NULL)
  1234.     abortmsg ("Out of memory allocating morph", 1);
  1235.  
  1236.     mat_identity (m->matrix);
  1237.  
  1238.     token = parse_string (string);
  1239.  
  1240.     token = parse_string (NULL);
  1241.     strcpy (m->name, token);
  1242.  
  1243.     token = parse_string (NULL);
  1244.     m->count = atoi (token);
  1245.  
  1246.     if (strlen (m->name) == 0 || m->count < 1 || m->count > 4)
  1247.     abortmsg ("Error parsing morph command", 1);
  1248.  
  1249.     cleanup_name (m->name);
  1250.  
  1251.     for (i = 0; i < m->count; i++) {
  1252.     token = parse_string (NULL);
  1253.     strcpy (m->names[i], token);
  1254.  
  1255.     token = parse_string (NULL);
  1256.     m->weight[i] = atof (token);
  1257.  
  1258.     if (strlen (m->names[i]) == 0)
  1259.         abortmsg ("Error parsing morph command", 1);
  1260.  
  1261.     cleanup_name (m->names[i]);
  1262.     }
  1263.  
  1264.     token = parse_string (NULL);
  1265.     token_no = 0;
  1266.  
  1267.     while (strlen(token) > 0) {
  1268.      switch (token_no) {
  1269.          case  0: m->matrix[0][0] = atof(token); break;
  1270.          case  1: m->matrix[0][1] = atof(token); break;
  1271.          case  2: m->matrix[0][2] = atof(token); break;
  1272.          case  3: m->matrix[1][0] = atof(token); break;
  1273.          case  4: m->matrix[1][1] = atof(token); break;
  1274.          case  5: m->matrix[1][2] = atof(token); break;
  1275.          case  6: m->matrix[2][0] = atof(token); break;
  1276.          case  7: m->matrix[2][1] = atof(token); break;
  1277.          case  8: m->matrix[2][2] = atof(token); break;
  1278.          case  9: m->matrix[3][0] = atof(token); break;
  1279.          case 10: m->matrix[3][1] = atof(token); break;
  1280.          case 11: m->matrix[3][2] = atof(token); break;
  1281.  
  1282.          default: abortmsg ("Error parsing morph command", 1);
  1283.      }
  1284.  
  1285.      token = parse_string (NULL);
  1286.      token_no++;
  1287.     }
  1288.  
  1289.     m->matrix[0][3] = 0.0;
  1290.     m->matrix[1][3] = 0.0;
  1291.     m->matrix[2][3] = 0.0;
  1292.     m->matrix[3][3] = 1.0;
  1293.  
  1294.     return m;
  1295. }
  1296.  
  1297.  
  1298. /* Parses an omni light and returns a pointer to the
  1299.    newly allocated light */
  1300. OmniLight *parse_omnilight (char *string)
  1301. {
  1302.     OmniLight *o;
  1303.     char      *token;
  1304.     int       token_no;
  1305.  
  1306.     o = (OmniLight *)malloc (sizeof(*o));
  1307.     if (o == NULL)
  1308.     abortmsg ("Out of memory allocating omnilight", 1);
  1309.  
  1310.     token = parse_string (string);
  1311.     token_no = 0;
  1312.  
  1313.     while (strlen(token) > 0) {
  1314.      switch (token_no) {
  1315.          case 0: break;
  1316.          case 1: strcpy (o->name, token); break;
  1317.          case 2: o->pos[X] = atof (token); break;
  1318.          case 3: o->pos[Y] = atof (token); break;
  1319.          case 4: o->pos[Z] = atof (token); break;
  1320.          case 5: o->col.red   = atof (token); break;
  1321.          case 6: o->col.green = atof (token); break;
  1322.          case 7: o->col.blue  = atof (token); break;
  1323.  
  1324.          default: abortmsg ("Error parsing omnilight", 1);
  1325.      }
  1326.  
  1327.      token = parse_string (NULL);
  1328.      token_no++;
  1329.     }
  1330.  
  1331.     cleanup_name (o->name);
  1332.  
  1333.     return o;
  1334. }
  1335.  
  1336.  
  1337. /* Parses a spotlight and returns a pointer to the
  1338.    newly allocated spotlight */
  1339. Spotlight *parse_spotlight (char *string)
  1340. {
  1341.     Spotlight *s;
  1342.     char      *token;
  1343.     int       token_no;
  1344.  
  1345.     s = (Spotlight *)malloc (sizeof(*s));
  1346.     if (s == NULL)
  1347.     abortmsg ("Out of memory allocating spotlight", 1);
  1348.  
  1349.     token = parse_string (string);
  1350.     token_no = 0;
  1351.  
  1352.     while (strlen(token) > 0) {
  1353.      switch (token_no) {
  1354.          case  0: break;
  1355.          case  1: strcpy (s->name, token); break;
  1356.          case  2: s->pos[X] = atof (token); break;
  1357.          case  3: s->pos[Y] = atof (token); break;
  1358.          case  4: s->pos[Z] = atof (token); break;
  1359.          case  5: s->target[X] = atof (token); break;
  1360.          case  6: s->target[Y] = atof (token); break;
  1361.          case  7: s->target[Z] = atof (token); break;
  1362.          case  8: s->col.red   = atof (token); break;
  1363.          case  9: s->col.green = atof (token); break;
  1364.          case 10: s->col.blue  = atof (token); break;
  1365.          case 11: s->hotspot   = atof (token); break;
  1366.          case 12: s->falloff   = atof (token); break;
  1367.          case 13: break;
  1368.  
  1369.          default: abortmsg ("Error parsing spotlight", 1);
  1370.      }
  1371.  
  1372.      token = parse_string (NULL);
  1373.      token_no++;
  1374.     }
  1375.  
  1376.     cleanup_name (s->name);
  1377.  
  1378.     return s;
  1379. }
  1380.  
  1381.  
  1382. /* Parses a camera command and returns a pointer to the
  1383.    newly allocated camera */
  1384. Camera *parse_camera (char *string)
  1385. {
  1386.     Camera *c;
  1387.     char   *token;
  1388.     int    token_no;
  1389.  
  1390.     c = (Camera *)malloc (sizeof(*c));
  1391.     if (c == NULL)
  1392.     abortmsg ("Out of memory allocating camera", 1);
  1393.  
  1394.     token = parse_string (string);
  1395.     token_no = 0;
  1396.  
  1397.     while (strlen(token) > 0) {
  1398.      switch (token_no) {
  1399.          case 0: break;
  1400.          case 1: c->pos[X] = atof (token); break;
  1401.          case 2: c->pos[Y] = atof (token); break;
  1402.          case 3: c->pos[Z] = atof (token); break;
  1403.          case 4: c->target[X] = atof (token); break;
  1404.          case 5: c->target[Y] = atof (token); break;
  1405.          case 6: c->target[Z] = atof (token); break;
  1406.          case 7: c->bank = atof (token); break;
  1407.          case 8: c->lens = atof (token); break;
  1408.  
  1409.          default: abortmsg ("Error parsing camera", 1);
  1410.      }
  1411.  
  1412.      token = parse_string (NULL);
  1413.      token_no++;
  1414.     }
  1415.  
  1416.     return c;
  1417. }
  1418.  
  1419.  
  1420. /* Load the transforms, camera movements, etc for the specified frame */
  1421. void read_frame (char *filename, int frame_no)
  1422. {
  1423.     FILE  *f;
  1424.     char  fname[80];
  1425.     char  string[256];
  1426.     char  *token;
  1427.     Transform *t, *t0;
  1428.     Transform *trans0_list = NULL;
  1429.     Morph     *m, *m0;
  1430.     Morph     *morph0_list = NULL;
  1431.  
  1432.     /* Open the .vue file */
  1433.     strcpy (fname, filename);   /* Make a copy we can mess with */
  1434.     add_ext (fname, "vue", 0);
  1435.  
  1436.     f = fopen (fname, "r");
  1437.     if (f == NULL) {
  1438.     printf ("Error opening file '%s'\n", fname);
  1439.     exit(1);
  1440.     }
  1441.  
  1442.     /* Load the specified frame */
  1443.     find_frame (f, frame_no);
  1444.  
  1445.     while (fgets (string, 256, f) != NULL) {
  1446.     token = parse_string (string);
  1447.  
  1448.     if (strcmp (token, "frame") == 0)
  1449.         break;
  1450.     else if (strcmp (token, "transform") == 0) {
  1451.         t = parse_transform (string);
  1452.         t0 = LIST_FIND (trans0_list, t->name);
  1453.  
  1454.         if (t0 != NULL)
  1455.         mat_mult (t->matrix, t->matrix, t0->matrix);
  1456.  
  1457.         LIST_INSERT (trans_list, t);
  1458.     }
  1459.     else if (strcmp (token, "morph") == 0) {
  1460.         m = parse_morph (string);
  1461.  
  1462.         m0 = LIST_FIND (morph0_list, m->name);
  1463.  
  1464.         if (m0 != NULL)
  1465.         mat_mult (m->matrix, m->matrix, m0->matrix);
  1466.  
  1467.         LIST_INSERT (morph_list, m);
  1468.     }
  1469.     else if (strcmp (token, "light") == 0) {
  1470.         LIST_INSERT (omni_list, parse_omnilight (string));
  1471.     }
  1472.     else if (strcmp (token, "spotlight") == 0) {
  1473.         LIST_INSERT (spot_list, parse_spotlight (string));
  1474.     }
  1475.     else if (strcmp (token, "camera") == 0) {
  1476.         if (cam_list != NULL)
  1477.         abortmsg ("ERROR - Multiple cameras in .vue file", 1);
  1478.  
  1479.         LIST_INSERT (cam_list, parse_camera (string));
  1480.     }
  1481.     else if (strcmp (token, "top") == 0)
  1482.         abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
  1483.     else if (strcmp (token, "bottom") == 0)
  1484.         abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
  1485.     else if (strcmp (token, "left") == 0)
  1486.         abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
  1487.     else if (strcmp (token, "right") == 0)
  1488.         abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
  1489.     else if (strcmp (token, "front") == 0)
  1490.         abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
  1491.     else if (strcmp (token, "back") == 0)
  1492.         abortmsg ("ERROR - Orthogonal viewports are not supported", 1);
  1493.     else if (strcmp (token, "user") == 0)
  1494.         abortmsg ("ERROR - User viewports are not supported", 1);
  1495.     }
  1496.  
  1497.     LIST_KILL (trans0_list);
  1498.     LIST_KILL (morph0_list);
  1499.  
  1500.     fclose(f);
  1501. }
  1502.  
  1503.  
  1504. void find_frame (FILE *f, int frame_no)
  1505. {
  1506.     char  string[256];
  1507.     char  *token;
  1508.     int   frame = 0;
  1509.  
  1510.     /* Search the .vue file for the required frame */
  1511.     while (1) {
  1512.     /* Read the next line in the file */
  1513.     if (fgets (string, 256, f) == NULL) {
  1514.         printf ("Unable to locate frame #%d in .vue file\n", frame_no);
  1515.         exit(1);
  1516.     }
  1517.  
  1518.     token = parse_string (string);
  1519.  
  1520.     if (strcmp (token, "frame") == 0) {
  1521.         token = parse_string (NULL);
  1522.  
  1523.         if (strlen(token) == 0) {
  1524.         printf ("Unable to locate frame #%d in .vue file\n", frame_no);
  1525.         exit(1);
  1526.         }
  1527.  
  1528.         frame = atoi (token);
  1529.  
  1530.         if (frame == frame_no)
  1531.         break;
  1532.     }
  1533.     else if (strcmp (token, "VERSION") == 0) {
  1534.         token = parse_string (NULL);
  1535.  
  1536.         vue_version = atoi(token) / 100.0;
  1537.     }
  1538.     }
  1539. }
  1540.  
  1541.  
  1542. void save_animation()
  1543. {
  1544.     Mesh      *mesh, *master;
  1545.     Transform *t;
  1546.     Morph     *m;
  1547.     Vector    temp;
  1548.     int       i, j;
  1549.  
  1550.     printf ("\n");
  1551.  
  1552.     for (t = trans_list; t != NULL; t = t->next) {
  1553.      printf ("Transforming object: %s\n", t->name);
  1554.  
  1555.      ani_matrix = &(t->matrix);
  1556.  
  1557.      mesh = LIST_FIND (mesh_list, t->name);
  1558.  
  1559.      if (mesh == NULL) {
  1560.          printf ("Unable to locate mesh object %s\n", t->name);
  1561.          exit(1);
  1562.      }
  1563.  
  1564.      write_mesh (out, mesh);
  1565.     }
  1566.  
  1567.     for (m = morph_list; m != NULL; m = m->next) {
  1568.     printf ("Morphing object: %s\n", m->name);
  1569.  
  1570.     ani_matrix = &(m->matrix);
  1571.  
  1572.     mesh = LIST_FIND (mesh_list, m->name);
  1573.     if (mesh == NULL) {
  1574.         printf ("Unable to locate mesh object %s\n", m->name);
  1575.         exit(1);
  1576.     }
  1577.  
  1578.     /* Make a copy to mess with */
  1579.     master = copy_mesh (mesh);
  1580.     master->hidden = FALSE;
  1581.  
  1582.     strcpy (master->name, m->name);
  1583.  
  1584.     for (i = 0; i < master->vertices; i++)
  1585.         vect_init (master->vertex[i], 0.0, 0.0, 0.0);
  1586.  
  1587.     for (i = 0; i < m->count; i++) {
  1588.         mesh = LIST_FIND (mesh_list, m->names[i]);
  1589.         if (mesh == NULL) {
  1590.         printf ("Unable to locate mesh object %s\n", m->names[0]);
  1591.         exit(1);
  1592.         }
  1593.  
  1594.         if (mesh->vertices != master->vertices)
  1595.         abortmsg ("Morphed objects do not contain the same number of vertices", 1);
  1596.  
  1597.         if (mesh->faces != master->faces)
  1598.         abortmsg ("Morphed objects do not contain the same number of faces", 1);
  1599.  
  1600.         for (j = 0; j < master->vertices; j++) {
  1601.         vect_transform (temp, mesh->vertex[j], mesh->invmatrix);
  1602.         vect_scale (temp, temp, m->weight[i]);
  1603.         vect_add (master->vertex[j], master->vertex[j], temp);
  1604.         }
  1605.     }
  1606.  
  1607.     for (i = 0; i < master->vertices; i++)
  1608.         vect_transform (master->vertex[i], master->vertex[i], master->matrix);
  1609.  
  1610.     write_mesh (out, master);
  1611.  
  1612.     free_mesh_data (master);
  1613.     free (master);
  1614.     }
  1615.  
  1616.     for (mesh = mesh_list; mesh != NULL; mesh = mesh->next)
  1617.     free_mesh_data (mesh);
  1618. }
  1619.  
  1620.  
  1621. /* Create a new mesh */
  1622. Mesh *create_mesh (char *name, int vertices, int faces)
  1623. {
  1624.     Mesh *new_mesh;
  1625.  
  1626.     new_mesh = malloc (sizeof(*new_mesh));
  1627.     if (new_mesh == NULL)
  1628.     abortmsg ("Out of memory allocating mesh", 1);
  1629.  
  1630.     strcpy (new_mesh->name, name);
  1631.  
  1632.     new_mesh->vertices = vertices;
  1633.  
  1634.     if (vertices <= 0)
  1635.     new_mesh->vertex = NULL;
  1636.     else {
  1637.     new_mesh->vertex = malloc (vertices * sizeof(*new_mesh->vertex));
  1638.     if (new_mesh->vertex == NULL)
  1639.         abortmsg ("Out of memory allocating mesh", 1);
  1640.     }
  1641.  
  1642.     new_mesh->faces = faces;
  1643.  
  1644.     if (faces <= 0) {
  1645.     new_mesh->face = NULL;
  1646.     new_mesh->mtl = NULL;
  1647.     }
  1648.     else {
  1649.     new_mesh->face = malloc (faces * sizeof(*new_mesh->face));
  1650.     if (new_mesh->face == NULL)
  1651.         abortmsg ("Out of memory allocating mesh", 1);
  1652.  
  1653.     new_mesh->mtl = malloc (faces * sizeof(*new_mesh->mtl));
  1654.     if (new_mesh->mtl == NULL)
  1655.         abortmsg ("Out of memory allocating mesh", 1);
  1656.     }
  1657.  
  1658.     vect_init (new_mesh->center,  0.0, 0.0, 0.0);
  1659.     vect_init (new_mesh->lengths, 0.0, 0.0, 0.0);
  1660.  
  1661.     mat_identity (new_mesh->matrix);
  1662.     mat_identity (new_mesh->invmatrix);
  1663.  
  1664.     new_mesh->hidden = FALSE;
  1665.     new_mesh->shadow = TRUE;
  1666.  
  1667.     return new_mesh;
  1668. }
  1669.  
  1670.  
  1671. /* Creates a duplicate copy of a mesh */
  1672. Mesh *copy_mesh (Mesh *mesh)
  1673. {
  1674.     Mesh *new_mesh;
  1675.     int  i;
  1676.  
  1677.     new_mesh = create_mesh (mesh->name, mesh->vertices, mesh->faces);
  1678.  
  1679.     if (new_mesh == NULL)
  1680.     abortmsg ("Out of memory allocating mesh", 1);
  1681.  
  1682.     for (i = 0; i < mesh->vertices; i++)
  1683.     vect_copy (new_mesh->vertex[i], mesh->vertex[i]);
  1684.  
  1685.     for (i = 0; i < mesh->faces; i++) {
  1686.     new_mesh->face[i] = mesh->face[i];
  1687.     new_mesh->mtl[i]  = mesh->mtl[i];
  1688.     }
  1689.  
  1690.     mat_copy (new_mesh->matrix, mesh->matrix);
  1691.     mat_copy (new_mesh->invmatrix, mesh->invmatrix);
  1692.  
  1693.     vect_copy (new_mesh->center,  mesh->center);
  1694.     vect_copy (new_mesh->lengths, mesh->lengths);
  1695.  
  1696.     new_mesh->hidden = mesh->hidden;
  1697.     new_mesh->shadow = mesh->shadow;
  1698.  
  1699.     return new_mesh;
  1700. }
  1701.  
  1702.  
  1703. /* Free all data associated with mesh object */
  1704. void free_mesh_data (Mesh *mesh)
  1705. {
  1706.     if (mesh->vertex != NULL)
  1707.     free (mesh->vertex);
  1708.  
  1709.     if (mesh->face != NULL)
  1710.     free (mesh->face);
  1711.  
  1712.     if (mesh->mtl != NULL)
  1713.     free (mesh->mtl);
  1714. }
  1715.  
  1716.  
  1717. /* Updates the center (pivot) point of the mesh */
  1718. void update_limits (Mesh *mesh)
  1719. {
  1720.     Vector vmin = {+MAXFLOAT, +MAXFLOAT, +MAXFLOAT};
  1721.     Vector vmax = {-MAXFLOAT, -MAXFLOAT, -MAXFLOAT};
  1722.     int    i;
  1723.  
  1724.     for (i = 0; i < mesh->vertices; i++) {
  1725.     vect_min (vmin, vmin, mesh->vertex[i]);
  1726.     vect_max (vmax, vmax, mesh->vertex[i]);
  1727.     }
  1728.  
  1729.     vect_add  (mesh->center, vmin, vmax);
  1730.     vect_scale (mesh->center, mesh->center, 0.5);
  1731.  
  1732.     vect_sub (mesh->lengths, vmax, vmin);
  1733. }
  1734.  
  1735.  
  1736. /* Return the sub-string of 'str' that is before 'target' */
  1737. char *before (char *str, char *target)
  1738. {
  1739.     static char result[256];
  1740.     char   *search;
  1741.  
  1742.     strncpy (result, str, 256);
  1743.     result[255] = '\0';
  1744.  
  1745.     search = strstr (result, target);
  1746.  
  1747.     if (search != NULL)
  1748.     *search = '\0';
  1749.  
  1750.     return result;
  1751. }
  1752.  
  1753.  
  1754. /* Return the sub-string of 'str' that is after 'target' */
  1755. char *after (char *str, char *target)
  1756. {
  1757.     static char result[256];
  1758.     char   *search;
  1759.  
  1760.     search = strstr (str, target);
  1761.  
  1762.     if (search == NULL)
  1763.     strncpy (result, "", 256);
  1764.     else
  1765.     strncpy (result, search + strlen(target), 256);
  1766.  
  1767.     result[255] = '\0';
  1768.  
  1769.     return result;
  1770. }
  1771.  
  1772.  
  1773. /* Return the sub-string of 'str' that is between 'target1' and 'target2' */
  1774. char *between (char *str, char *target1, char *target2)
  1775. {
  1776.     static char result[256];
  1777.  
  1778.     strcpy (result, after (str, target1));
  1779.     strcpy (result, before (result, target2));
  1780.  
  1781.     return result;
  1782. }
  1783.  
  1784.  
  1785. /* Works like the C strtok() function except that it can handle */
  1786. /* tokens enclosed in double quotes */
  1787. char *parse_string (char *str)
  1788. {
  1789.     static char result[256];
  1790.     static char *p;
  1791.     char QUOTE = '\"';
  1792.     int  index;
  1793.  
  1794.     strcpy (result, "");
  1795.     index = 0;
  1796.  
  1797.     if (str != NULL)
  1798.     p = str;
  1799.  
  1800.     /* Find the start of the next token */
  1801.     while (isspace (*p))
  1802.     p++;
  1803.  
  1804.     if (*p == QUOTE) {
  1805.     p++;
  1806.  
  1807.     while (*p != '\0' && *p != QUOTE)
  1808.         result[index++] = *p++;
  1809.  
  1810.     if (*p == QUOTE)
  1811.         p++;
  1812.     }
  1813.     else {
  1814.     while (*p != '\0' && !isspace(*p))
  1815.         result[index++] = *p++;
  1816.     }
  1817.  
  1818.     result[index] = '\0';
  1819.  
  1820.     return result;
  1821. }
  1822.  
  1823.  
  1824. /* Convert character 'c' to upper case */
  1825. char upcase (char c)
  1826. {
  1827.     if (c >= 'a' && c <= 'z')
  1828.     c = c - 'a' + 'A';
  1829.  
  1830.     return c;
  1831. }
  1832.  
  1833.  
  1834. void parse_file()
  1835. {
  1836.     Chunk chunk;
  1837.  
  1838.     start_chunk(&chunk);
  1839.  
  1840.     if (chunk.tag == M3DMAGIC)
  1841.     parse_3ds (&chunk);
  1842.     else
  1843.     abortmsg ("Error: Input file is not .3DS format", 1);
  1844.  
  1845.     end_chunk (&chunk);
  1846. }
  1847.  
  1848.  
  1849. void parse_3ds (Chunk *mainchunk)
  1850. {
  1851.     Chunk chunk;
  1852.  
  1853.     do  {
  1854.     start_chunk (&chunk);
  1855.  
  1856.     if (chunk.end <= mainchunk->end) {
  1857.         switch (chunk.tag) {
  1858.         case MDATA: parse_mdata (&chunk);
  1859.                 break;
  1860.         }
  1861.     }
  1862.  
  1863.     end_chunk (&chunk);
  1864.     } while (chunk.end <= mainchunk->end);
  1865. }
  1866.  
  1867.  
  1868. void parse_mdata (Chunk *mainchunk)
  1869. {
  1870.     Chunk chunk;
  1871.     Color bgnd_color;
  1872.  
  1873.     do  {
  1874.     start_chunk (&chunk);
  1875.  
  1876.     if (chunk.end <= mainchunk->end) {
  1877.         switch (chunk.tag) {
  1878.         case SOLID_BGND:     parse_color (&bgnd_color);
  1879.                      break;
  1880.         case USE_SOLID_BGND: write_bgsolid (out, bgnd_color);
  1881.                      break;
  1882.         case FOG:            parse_fog (&chunk);
  1883.                      break;
  1884.         case FOG_BGND:       parse_fog_bgnd();
  1885.                      break;
  1886.         case USE_FOG:        write_fog (out, fog_color, fog_distance);
  1887.                      break;
  1888.         case MAT_ENTRY:      parse_mat_entry();
  1889.                      break;
  1890.         case NAMED_OBJECT:   parse_named_object (&chunk);
  1891.                      break;
  1892.         }
  1893.     }
  1894.  
  1895.     end_chunk (&chunk);
  1896.     } while (chunk.end <= mainchunk->end);
  1897. }
  1898.  
  1899.  
  1900. void parse_fog (Chunk *mainchunk)
  1901. {
  1902.     Chunk chunk;
  1903.  
  1904.     (void)read_float();
  1905.     (void)read_float();
  1906.     fog_distance = read_float();
  1907.     (void)read_float();
  1908.  
  1909.     parse_color (&fog_color);
  1910.  
  1911.     do  {
  1912.     start_chunk (&chunk);
  1913.  
  1914.     if (chunk.end <= mainchunk->end) {
  1915.         switch (chunk.tag) {
  1916.         case FOG_BGND: parse_fog_bgnd();
  1917.                    break;
  1918.         }
  1919.     }
  1920.  
  1921.     end_chunk (&chunk);
  1922.     } while (chunk.end <= mainchunk->end);
  1923. }
  1924.  
  1925.  
  1926. void parse_fog_bgnd()
  1927. {
  1928.  
  1929. }
  1930.  
  1931.  
  1932. void parse_mat_entry()
  1933. {
  1934.  
  1935. }
  1936.  
  1937.  
  1938. void parse_named_object (Chunk *mainchunk)
  1939. {
  1940.     Chunk chunk;
  1941.  
  1942.     strcpy (obj_name, read_string());
  1943.     cleanup_name (obj_name);
  1944.  
  1945.     printf ("Working on: %s\n", obj_name);
  1946.  
  1947.     mesh = NULL;
  1948.  
  1949.     do  {
  1950.     start_chunk (&chunk);
  1951.  
  1952.     if (chunk.end <= mainchunk->end) {
  1953.         switch (chunk.tag) {
  1954.         case N_TRI_OBJECT:    parse_n_tri_object (&chunk);
  1955.                       break;
  1956.         case N_DIRECT_LIGHT:  parse_n_direct_light (&chunk);
  1957.                       break;
  1958.         case N_CAMERA:        parse_n_camera();
  1959.                       break;
  1960.         case OBJ_HIDDEN:      if (mesh != NULL) mesh->hidden = TRUE;
  1961.                       break;
  1962.         case OBJ_DOESNT_CAST: if (mesh != NULL) mesh->shadow = FALSE;
  1963.                       break;
  1964.         }
  1965.     }
  1966.  
  1967.     end_chunk (&chunk);
  1968.     } while (chunk.end <= mainchunk->end);
  1969.  
  1970.     if (mesh != NULL) {
  1971.     update_limits (mesh);
  1972.  
  1973.     if (frame >= 0) {
  1974.         LIST_INSERT (mesh_list, mesh);
  1975.     }
  1976.     else {
  1977.         write_mesh (out, mesh);
  1978.  
  1979.         free_mesh_data (mesh);
  1980.         free (mesh);
  1981.     }
  1982.     }
  1983. }
  1984.  
  1985.  
  1986. void parse_n_tri_object (Chunk *mainchunk)
  1987. {
  1988.     Chunk chunk;
  1989.  
  1990.     mesh = create_mesh (obj_name, 0, 0);
  1991.  
  1992.     do  {
  1993.     start_chunk (&chunk);
  1994.  
  1995.     if (chunk.end <= mainchunk->end) {
  1996.         switch (chunk.tag) {
  1997.         case POINT_ARRAY:  parse_point_array();
  1998.                    break;
  1999.         case FACE_ARRAY:   parse_face_array (&chunk);
  2000.                    break;
  2001.         case MESH_MATRIX:  parse_mesh_matrix();
  2002.                    break;
  2003.         }
  2004.     }
  2005.  
  2006.     end_chunk (&chunk);
  2007.     } while (chunk.end <= mainchunk->end);
  2008. }
  2009.  
  2010.  
  2011. void parse_point_array()
  2012. {
  2013.     int i;
  2014.  
  2015.     mesh->vertices = read_word();
  2016.     mesh->vertex = malloc (mesh->vertices * sizeof(*(mesh->vertex)));
  2017.     if (mesh->vertex == NULL)
  2018.     abortmsg ("Out of memory allocating mesh", 1);
  2019.  
  2020.     for (i = 0; i < mesh->vertices; i++)
  2021.     read_point (mesh->vertex[i]);
  2022. }
  2023.  
  2024.  
  2025. void parse_face_array (Chunk *mainchunk)
  2026. {
  2027.     Chunk chunk;
  2028.     Material *default_mtl;
  2029.     int i;
  2030.  
  2031.     mesh->faces = read_word();
  2032.     mesh->face = malloc (mesh->faces * sizeof(*(mesh->face)));
  2033.     if (mesh->face == NULL)
  2034.     abortmsg ("Out of memory allocating mesh", 1);
  2035.  
  2036.     mesh->mtl = malloc (mesh->faces * sizeof(*(mesh->mtl)));
  2037.     if (mesh->mtl == NULL)
  2038.     abortmsg ("Out of memory allocating mesh", 1);
  2039.  
  2040.     default_mtl = update_materials ("Default", 0);
  2041.  
  2042.     for (i = 0; i < mesh->faces; i++) {
  2043.     mesh->face[i].a = read_word();
  2044.     mesh->face[i].b = read_word();
  2045.     mesh->face[i].c = read_word();
  2046.     (void)read_word();
  2047.  
  2048.     mesh->mtl[i] = default_mtl;
  2049.     }
  2050.  
  2051.     do  {
  2052.     start_chunk (&chunk);
  2053.  
  2054.     if (chunk.end <= mainchunk->end) {
  2055.         switch (chunk.tag) {
  2056.         case MSH_MAT_GROUP: parse_msh_mat_group();
  2057.                     break;
  2058.         case SMOOTH_GROUP:  parse_smooth_group();
  2059.                     break;
  2060.         }
  2061.     }
  2062.  
  2063.     end_chunk (&chunk);
  2064.     } while (chunk.end <= mainchunk->end);
  2065. }
  2066.  
  2067.  
  2068. void parse_msh_mat_group()
  2069. {
  2070.     Material *new_mtl;
  2071.     char mtlname[80];
  2072.     int  mtlcnt;
  2073.     int  i, face;
  2074.  
  2075.     strcpy (mtlname, read_string());
  2076.     cleanup_name (mtlname);
  2077.  
  2078.     new_mtl = update_materials (mtlname, 0);
  2079.  
  2080.     mtlcnt = read_word();
  2081.  
  2082.     for (i = 0; i < mtlcnt; i++) {
  2083.     face = read_word();
  2084.     mesh->mtl[face] = new_mtl;
  2085.     }
  2086. }
  2087.  
  2088.  
  2089. void parse_smooth_group()
  2090. {
  2091.  
  2092. }
  2093.  
  2094.  
  2095. void parse_mesh_matrix()
  2096. {
  2097.     int i, j;
  2098.  
  2099.     if (mesh != NULL) {
  2100.     for (i = 0; i < 4; i++) {
  2101.         for (j = 0; j < 3; j++)
  2102.         mesh->matrix[i][j] = read_float();
  2103.     }
  2104.  
  2105.     mat_inv (mesh->invmatrix, mesh->matrix);
  2106.     }
  2107. }
  2108.  
  2109.  
  2110. void parse_n_direct_light (Chunk *mainchunk)
  2111. {
  2112.     Chunk chunk;
  2113.     Spotlight *s;
  2114.     OmniLight *o;
  2115.     int light_off = FALSE;
  2116.     int spot_flag = FALSE;
  2117.  
  2118.     read_point (pos);
  2119.     parse_color (&col);
  2120.  
  2121.     do  {
  2122.     start_chunk (&chunk);
  2123.  
  2124.     if (chunk.end <= mainchunk->end) {
  2125.         switch (chunk.tag) {
  2126.         case DL_OFF:       light_off = TRUE;
  2127.                    break;
  2128.         case DL_SPOTLIGHT: parse_dl_spotlight();
  2129.                    spot_flag = TRUE;
  2130.                    break;
  2131.         }
  2132.     }
  2133.  
  2134.     end_chunk (&chunk);
  2135.     } while (chunk.end <= mainchunk->end);
  2136.  
  2137.     if (light_off)
  2138.     return;
  2139.  
  2140.     if (!spot_flag) {
  2141.     if (frame >= 0) {
  2142.         o = LIST_FIND (omni_list, obj_name);
  2143.  
  2144.         if (o != NULL) {
  2145.         pos[X] = o->pos[X];
  2146.         pos[Y] = o->pos[Y];
  2147.         pos[Z] = o->pos[Z];
  2148.         col    = o->col;
  2149.         }
  2150.     }
  2151.  
  2152.     write_light (out, obj_name, pos, col);
  2153.     }
  2154.     else {
  2155.     if (frame >= 0) {
  2156.         s = LIST_FIND (spot_list, obj_name);
  2157.  
  2158.         if (s != NULL) {
  2159.         pos[X]    = s->pos[X];
  2160.         pos[Y]    = s->pos[Y];
  2161.         pos[Z]    = s->pos[Z];
  2162.         target[X] = s->target[X];
  2163.         target[Y] = s->target[Y];
  2164.         target[Z] = s->target[Z];
  2165.         col       = s->col;
  2166.         hotspot   = s->hotspot;
  2167.         falloff   = s->falloff;
  2168.         }
  2169.     }
  2170.  
  2171.     if (falloff <= 0.0)
  2172.         falloff = 180.0;
  2173.  
  2174.     if (hotspot <= 0.0)
  2175.         hotspot = 0.7*falloff;
  2176.  
  2177.     write_spot (out, obj_name, pos, target, col, hotspot, falloff);
  2178.     }
  2179. }
  2180.  
  2181.  
  2182. void parse_dl_spotlight()
  2183. {
  2184.     read_point (target);
  2185.  
  2186.     hotspot = read_float();
  2187.     falloff = read_float();
  2188. }
  2189.  
  2190.  
  2191. void parse_n_camera()
  2192. {
  2193.     float  bank;
  2194.     float  lens;
  2195.  
  2196.     read_point (pos);
  2197.     read_point (target);
  2198.     bank = read_float();
  2199.     lens = read_float();
  2200.  
  2201.     if (frame >= 0 && cam_list != NULL) {
  2202.     pos[X]    = cam_list->pos[X];
  2203.     pos[Y]    = cam_list->pos[Y];
  2204.     pos[Z]    = cam_list->pos[Z];
  2205.     target[X] = cam_list->target[X];
  2206.     target[Y] = cam_list->target[Y];
  2207.     target[Z] = cam_list->target[Z];
  2208.     lens      = cam_list->lens;
  2209.     bank      = cam_list->bank;
  2210.     }
  2211.  
  2212.     write_camera (out, obj_name, pos, target, lens, bank);
  2213. }
  2214.  
  2215.  
  2216. void parse_color (Color *color)
  2217. {
  2218.     Chunk chunk;
  2219.     Color_24 color_24;
  2220.  
  2221.     start_chunk (&chunk);
  2222.  
  2223.     switch (chunk.tag) {
  2224.     case COLOR_F:  parse_color_f (color);
  2225.                break;
  2226.  
  2227.     case COLOR_24: parse_color_24 (&color_24);
  2228.                color->red   = color_24.red/255.0;
  2229.                color->green = color_24.green/255.0;
  2230.                color->blue  = color_24.blue/255.0;
  2231.                break;
  2232.  
  2233.     default:       abortmsg ("Error parsing color", 1);
  2234.     }
  2235.  
  2236.     end_chunk (&chunk);
  2237. }
  2238.  
  2239.  
  2240. void parse_color_f (Color *color)
  2241. {
  2242.     color->red   = read_float();
  2243.     color->green = read_float();
  2244.     color->blue  = read_float();
  2245. }
  2246.  
  2247.  
  2248. void parse_color_24 (Color_24 *color)
  2249. {
  2250.     color->red   = read_byte();
  2251.     color->green = read_byte();
  2252.     color->blue  = read_byte();
  2253. }
  2254.  
  2255.  
  2256. float parse_percentage()
  2257. {
  2258.     Chunk chunk;
  2259.     float percent = 0.0;
  2260.  
  2261.     start_chunk (&chunk);
  2262.  
  2263.     switch (chunk.tag) {
  2264.     case INT_PERCENTAGE:   percent = parse_int_percentage()/100.0;
  2265.                    break;
  2266.  
  2267.     case FLOAT_PERCENTAGE: percent = parse_float_percentage();
  2268.                    break;
  2269.  
  2270.     default:               abortmsg ("Error parsing percent", 1);
  2271.     }
  2272.  
  2273.     end_chunk (&chunk);
  2274.  
  2275.     return percent;
  2276. }
  2277.  
  2278.  
  2279. short parse_int_percentage()
  2280. {
  2281.     word percent = read_word();
  2282.  
  2283.     return percent;
  2284. }
  2285.  
  2286.  
  2287. float parse_float_percentage()
  2288. {
  2289.     float percent = read_float();
  2290.  
  2291.     return percent;
  2292. }
  2293.  
  2294.  
  2295. void start_chunk (Chunk *chunk)
  2296. {
  2297.     chunk->start  = ftell(in);
  2298.     chunk->tag    = read_word();
  2299.     chunk->length = read_dword();
  2300.     chunk->end    = chunk->start + chunk->length;
  2301. }
  2302.  
  2303.  
  2304. void end_chunk (Chunk *chunk)
  2305. {
  2306.     fseek (in, chunk->end, 0);
  2307. }
  2308.  
  2309.  
  2310. byte read_byte()
  2311. {
  2312.     byte data;
  2313.  
  2314.     data = fgetc (in);
  2315.  
  2316.     return data;
  2317. }
  2318.  
  2319.  
  2320. word read_word()
  2321. {
  2322.     word data;
  2323.  
  2324.     fread (&data, 2, 1, in);
  2325.  
  2326.     return data;
  2327. }
  2328.  
  2329.  
  2330. dword read_dword()
  2331. {
  2332.     dword data;
  2333.  
  2334.     fread (&data, 4, 1, in);
  2335.  
  2336.     return data;
  2337. }
  2338.  
  2339.  
  2340. float read_float()
  2341. {
  2342.     float data;
  2343.  
  2344.     fread (&data, 4, 1, in);
  2345.  
  2346.     return data;
  2347. }
  2348.  
  2349.  
  2350. void read_point (Vector v)
  2351. {
  2352.     v[X] = read_float();
  2353.     v[Y] = read_float();
  2354.     v[Z] = read_float();
  2355. }
  2356.  
  2357.  
  2358. char *read_string()
  2359. {
  2360.     static char string[80];
  2361.     int i;
  2362.  
  2363.     for (i = 0; i < 80; i++) {
  2364.     string[i] = read_byte();
  2365.  
  2366.     if (string[i] == '\0')
  2367.         break;
  2368.     }
  2369.  
  2370.     return string;
  2371. }
  2372.  
  2373.  
  2374. float findfov (float lens)
  2375. {
  2376.     static float lens_table[13] =
  2377.          { 15.0, 17.0, 24.0, 35.0, 50.0, 85.0, 100.0, 135.0, 200.0,
  2378.            500.0, 625.0, 800.0, 1000.0 };
  2379.     static float fov_table[13] =
  2380.          { 115.0, 102.0, 84.0, 63.0, 46.0, 28.0, 24.0, 18.0,
  2381.            12.0, 5.0, 4.0, 3.125, 2.5 };
  2382.  
  2383.     float fov, f1, f2, l1, l2;
  2384.     int   i;
  2385.  
  2386.     if (lens < 15.0)
  2387.     lens = 15.0;
  2388.     else if (lens > 1000.0)
  2389.     lens = 1000.0;
  2390.  
  2391.     for (i = 0; i < 13; i++)
  2392.     if (lens < lens_table[i])
  2393.         break;
  2394.  
  2395.     if (i == 13)
  2396.     i = 12;
  2397.     else if (i == 0)
  2398.     i = 1;
  2399.  
  2400.     f1 = fov_table[i-1];
  2401.     f2 = fov_table[i];
  2402.     l1 = lens_table[i-1];
  2403.     l2 = lens_table[i];
  2404.  
  2405.     fov = f1 + (lens - l1) * (f2 - f1) / (l2 - l1);
  2406.  
  2407.     return fov;
  2408. }
  2409.  
  2410.  
  2411.