home *** CD-ROM | disk | FTP | other *** search
/ Current Shareware 1994 January / SHAR194.ISO / graphuti / rawpov18.zip / SOURCE.ZIP / RAYOPT.C < prev    next >
C/C++ Source or Header  |  1993-10-02  |  60KB  |  2,302 lines

  1. /*-------------------------------------------------------------------------
  2.  
  3.          Triangle Bounder/Smoother for POV-Ray
  4.             Copyright (c) 1993 Steve Anger
  5.  
  6.     A number of C routines that can be used to generate POV-Ray ray tracer
  7.  files from triangle data.  Supports generation of smooth triangles and an
  8.  optimal set of bounding shapes for much faster traces.  Output files are
  9.  compatible with POV-Ray v1.0.  This program may be freely modified and
  10.  distributed.
  11.                        Compuserve: 70714,3113
  12.                         YCCMR BBS: (708)358-5611
  13.  
  14. --------------------------------------------------------------------------*/
  15.  
  16. #ifdef __TURBOC__
  17. #include <alloc.h>
  18. #endif
  19.  
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <ctype.h>
  24. #include <math.h>
  25. #include "vect.h"
  26. #include "rayopt.h"
  27.  
  28. #if defined(applec) || defined(THINK_C)
  29. #include "RAW2POV.mac.h"
  30. #else
  31. #define COOPERATE
  32. #endif
  33.  
  34. #define HASHSIZE  1000          /* Size of hash table for vertex lookup */
  35. #define DEGEN_TOL (1e-8)        /* float comparison tolerance for checking */
  36.                 /* for degenerate triangles */
  37. #define MAX_TEX   500           /* Maximum allowable number of texture */
  38.                 /* declarations */
  39.  
  40. #define POV10   0
  41. #define POV20   1
  42. #define VIVID   2
  43. #define POLYRAY 3
  44.  
  45. #ifndef MAXFLOAT
  46. #define MAXFLOAT (1e37)
  47. #endif
  48.  
  49. typedef struct {
  50.     float red;
  51.     float green;
  52.     float blue;
  53. } Palette;
  54.  
  55. typedef char *Texture;
  56.  
  57. typedef struct {
  58.     unsigned vert[3];
  59.     unsigned text_index;
  60.     char     text_type;
  61.     char     flag;
  62. } Triangle;
  63.  
  64.  
  65. /* Linked list of triangles */
  66. typedef struct TList {
  67.     Triangle     *tri;
  68.     struct TList *next;
  69. } TriList;
  70.  
  71.  
  72. /* Double linked list of triangles */
  73. typedef struct TList2 {
  74.     Triangle      *tri;
  75.     struct TList2 *prev;
  76.     struct TList2 *next;
  77. } TriList2;
  78.  
  79.  
  80. /* List of triangle vertices */
  81. typedef struct VList {
  82.     unsigned     vert;
  83.     struct VList *next;
  84. } VertList;
  85.  
  86.  
  87. /* List of triangle groups */
  88. typedef struct GTree {
  89.     TriList2     *index[3];    /* Triangles indexed by x, y, and z coord */
  90.     Vector       vmin;         /* min/max extents of triangle vertices */
  91.     Vector       vmax;         /*    "       "     "     "        "     */
  92.     float        area;         /* Total surface area of bounding region */
  93.     unsigned     obj_cnt;      /* Total number of triangles in group */
  94.     int          child_cnt;    /* Number of children */
  95.     int          split_cnt;    /* Number of times this node has been split */
  96.     struct GTree *parent;      /* Parent of this node */
  97.     struct GTree *next;        /* Next node at this level */
  98.     struct GTree *child;       /* First child of this ndoe */
  99. } GroupTree;
  100.  
  101. static Palette   *ptable;      /* Palette table */
  102. static unsigned  pmax;         /* Maximum size of table */
  103. static unsigned  psize;        /* Current size */
  104.  
  105. static Texture   *ttable;      /* Named texture table */
  106. static unsigned  tmax;         /* Maximum size of table */
  107. static unsigned  tsize;        /* Current size */
  108.  
  109. static Vector    *vtable;      /* Vertice table */
  110. static unsigned  vmax;         /* Maximum size of table */
  111. static unsigned  vsize;        /* Current size */
  112.  
  113. static Vector    gmin = {+MAXFLOAT, +MAXFLOAT, +MAXFLOAT};
  114. static Vector    gmax = {-MAXFLOAT, -MAXFLOAT, -MAXFLOAT};
  115.  
  116. static Matrix    trans_matrix;
  117. static int       use_transform = 0;
  118.  
  119. static VertList  **vert_hash;    /* Hash table for looking up vertices */
  120. static TriList   **tri_index;    /* Index for smooth triangle generation */
  121.  
  122. static GroupTree *groot;         /* Tree representing the object hierarchy */
  123.  
  124. static int       initialized  = 0;
  125. static int       quiet_mode   = 0;
  126. static int       bound_mode   = 0;
  127. static float     smooth_angle = 0.0;
  128. static unsigned  vert_init    = 0;
  129. static int       dec_point    = 4;
  130. static int       out_format   = POV10;
  131.  
  132. static char      out_file[64] = "rayopt.pov";
  133. static char      inc_file[64] = "rayopt.inc";
  134.  
  135. static unsigned  tot_bounds   = 0;
  136. static unsigned  object_cnt   = 0;
  137.  
  138. static Vector    last_vmin = {0.0, 0.0, 0.0};
  139. static Vector    last_vmax = {0.0, 0.0, 0.0};
  140. static unsigned  last_vert_cnt = 0;
  141. static unsigned  last_tri_cnt = 0;
  142. static float     last_index = 0.0;
  143. static unsigned  last_bounds = 0;
  144.  
  145. static Palette   last_pal;
  146. static char      last_texture[64] = "";
  147. static unsigned  texture_index;
  148. static char      texture_type;
  149. static char      object_name[64] = "";
  150.  
  151. static float     orig_tpr;    /* Number of Tests Per Ray before optimization */
  152. static float     final_tpr;   /*    "   "    "    "   "  after optimization */
  153. static float     bound_cost;  /* Cost of testing a bound relative to testing */
  154.                   /* a triangle */
  155.  
  156. /* Function prototypes */
  157. void init_object (void);
  158. void cleanup_object (void);
  159. float calc_tpr (GroupTree *gnode);
  160. GroupTree *create_group (void);
  161. void delete_tree (GroupTree *gnode);
  162. void optimize_tree (GroupTree *gnode);
  163. void test_split (GroupTree *gnode, int axis, float *best_rtpr, TriList2 **
  164.     best_loc);
  165. void split_group (GroupTree *gnode, int axis, TriList2 *split_loc, GroupTree *
  166.     *group_a, GroupTree **group_b);
  167. void write_file (void);
  168. void write_box (Vector v1, Vector v2, Triangle *tri);
  169. void write_pov10_tree (FILE *f, GroupTree *gnode, int level);
  170. void write_pov10_texture (FILE *f, Triangle *tri);
  171. void write_pov10_transform (FILE *f, Matrix matrix);
  172. void write_pov10_header (FILE *f);
  173. void write_pov10_triangle (FILE *f, Triangle *tri, int one_texture);
  174. void write_pov10_bound (FILE *f, GroupTree *gnode);
  175. void write_pov20_tree (FILE *f, GroupTree *gnode, int level);
  176. void write_pov20_texture (FILE *f, Triangle *tri);
  177. void write_pov20_transform (FILE *f, Matrix matrix);
  178. void write_pov20_header (FILE *f);
  179. void write_pov20_triangle (FILE *f, Triangle *tri, int one_texture);
  180. void write_pov20_bound (FILE *f, GroupTree *gnode);
  181. void write_vivid_tree (FILE *f, GroupTree *gnode);
  182. void write_vivid_transform (FILE *f, Matrix matrix);
  183. void write_vivid_texture (FILE *f, Triangle *tri);
  184. void write_vivid_header (FILE *f);
  185. void write_vivid_triangle (FILE *f, Triangle *tri);
  186. void write_polyray_tree (FILE *f, GroupTree *gnode);
  187. void write_polyray_transform (FILE *f, Matrix matrix);
  188. void write_polyray_texture (FILE *f, Triangle *tri);
  189. void write_polyray_header (FILE *f);
  190. void write_polyray_triangle (FILE *f, Triangle *tri);
  191. void update_node (GroupTree *gnode);
  192. void sort_indexes (GroupTree *gnode);
  193. void quick_sort (TriList2 *start, TriList2 *end, int axis);
  194. float surf_area (float a, float b, float c);
  195. float max_vertex (Triangle *tri, int axis);
  196. float min_vertex (Triangle *tri, int axis);
  197. float avg_vertex (Triangle *tri, int axis);
  198. void build_tri_index (void);
  199. void dump_tri_index (void);
  200. void vert_normal (Triangle *t, Vector *norm);
  201. void tri_normal (Triangle *t, Vector normal);
  202. unsigned pal_lookup (float red, float green, float blue);
  203. unsigned texture_lookup (char *texture_name);
  204. unsigned vert_lookup (float x, float y, float z);
  205. int degen_tri (float ax, float ay, float az, float bx, float by, float bz,
  206.      float cx, float cy, float cz);
  207. void abortmsg (char *msg, int exit_code);
  208. float fmin (float a, float b);
  209. float fmax (float a, float b);
  210. void add_ext (char *fname, char *ext, int force);
  211. void cleanup_name (char *name);
  212.  
  213.  
  214. void opt_set_format (int format)
  215. {
  216.     if (format != POV10 && format != POV20 && format != VIVID && format != POLYRAY)
  217.     abortmsg ("ERROR: Invalid parameter passed to opt_set_format.", 1);
  218.  
  219.     out_format = format;
  220. }
  221.  
  222.  
  223. void opt_set_fname (char *out_name, char *inc_name)
  224. {
  225.     FILE *f;
  226.  
  227.     strcpy (out_file, out_name);
  228.  
  229.     if (strlen(inc_name) > 0)
  230.     strcpy (inc_file, inc_name);
  231.     else {
  232.     strcpy (inc_file, out_file);
  233.  
  234.     switch (out_format) {
  235.         case POV10:
  236.         case POV20:   add_ext (inc_file, "inc", 1);
  237.               break;
  238.         case VIVID:   add_ext (inc_file, "vo", 1);
  239.               break;
  240.         case POLYRAY: add_ext (inc_file, "inc", 1);
  241.               break;
  242.     }
  243.     }
  244.  
  245.     if (strcmp (out_file, inc_file) == 0)
  246.     abortmsg ("Main file and include file cannot have the same name", 1);
  247.  
  248.     if ((f = fopen (out_file, "w")) == NULL) {
  249.     printf ("Cannot open output file %s\n", out_file);
  250.     exit (1);
  251.     }
  252.  
  253.     fclose (f);
  254.  
  255.     if ((f = fopen (inc_file, "w")) == NULL) {
  256.     printf ("Cannot open output file %s\n", inc_file);
  257.     exit (1);
  258.     }
  259.  
  260.     fclose (f);
  261. }
  262.  
  263.  
  264. void opt_set_quiet (int quiet)
  265. {
  266.     if (quiet != 0 && quiet != 1)
  267.     abortmsg ("ERROR: Invalid parameter passed to opt_set_quiet.", 1);
  268.  
  269.     quiet_mode = quiet;
  270. }
  271.  
  272.  
  273. void opt_set_bound (int bound)
  274. {
  275.     if (bound != 0 && bound != 1 && bound != 2)
  276.     abortmsg ("ERROR: Invalid parameter passed to opt_set_bound.", 1);
  277.  
  278.     bound_mode = bound;
  279. }
  280.  
  281.  
  282. void opt_set_smooth (float  smooth)
  283. {
  284.     if (smooth < 0.0 || smooth > 180.0)
  285.     abortmsg ("ERROR: Invalid parameter passed to opt_set_smooth.", 1);
  286.  
  287.     smooth_angle = smooth;
  288. }
  289.  
  290.  
  291. void opt_set_vert (unsigned vert)
  292. {
  293.     vert_init = vert;
  294. }
  295.  
  296.  
  297. void opt_set_dec (int dec)
  298. {
  299.     if (dec < 0 || dec > 9)
  300.     abortmsg ("ERROR: Invalid parameter passed to opt_set_dec.", 1);
  301.  
  302.     dec_point = dec;
  303. }
  304.  
  305.  
  306. void opt_set_color (float  red, float  green, float  blue)
  307. {
  308.     if (!initialized)
  309.     init_object();
  310.  
  311.     if (last_pal.red != red || last_pal.green != green ||
  312.                    last_pal.blue != blue || psize == 0)
  313.     {
  314.     last_pal.red   = red;
  315.     last_pal.green = green;
  316.     last_pal.blue  = blue;
  317.  
  318.     texture_index = pal_lookup (red, green, blue);
  319.     }
  320.  
  321.     texture_type = 0;   /* An RGB texture */
  322. }
  323.  
  324.  
  325. void opt_set_texture (char *texture_name)
  326. {
  327.     char new_texture[64];
  328.  
  329.     if (!initialized)
  330.     init_object();
  331.  
  332.     strcpy (new_texture, texture_name);
  333.     cleanup_name (new_texture);
  334.  
  335.     if (strcmp (last_texture, new_texture) != 0) {
  336.     strcpy (last_texture, new_texture);
  337.     texture_index = texture_lookup (new_texture);
  338.     }
  339.  
  340.     texture_type = 1;   /* A named texture */
  341. }
  342.  
  343.  
  344. /* Set a transformation matrix for the next object */
  345. void opt_set_transform (Matrix mat)
  346. {
  347.     int i, j;
  348.  
  349.     for (i = 0; i < 4; i++) {
  350.     for (j = 0; j < 3; j++)
  351.         trans_matrix[i][j] = mat[i][j];
  352.     }
  353.  
  354.     use_transform = 1;
  355. }
  356.  
  357.  
  358. void opt_clear_transform()
  359. {
  360.     use_transform = 0;
  361. }
  362.  
  363.  
  364. /* Add a new triangle to the database */
  365. int opt_add_tri (float  ax, float  ay, float  az,
  366.          float  bx, float  by, float  bz,
  367.          float  cx, float  cy, float  cz)
  368. {
  369.     TriList2 *new_node;
  370.     Triangle *new_tri;
  371.     int      i;
  372.  
  373.     /* Check if the triangle is degenerate (zero area), if so return -1 */
  374.     if (degen_tri (ax, ay, az, bx, by, bz, cx, cy, cz))
  375.     return -1;
  376.  
  377.     if (!initialized)
  378.     init_object();
  379.  
  380.     /* Allocate memory for the new triangle */
  381.     new_tri = malloc (sizeof(Triangle));
  382.     if (new_tri == NULL)
  383.     abortmsg ("Insufficient memory for new triangles.", 1);
  384.  
  385.     /* Look up the vertex and texture indexes */
  386.     new_tri->vert[0] = vert_lookup (ax, ay, az);
  387.     new_tri->vert[1] = vert_lookup (bx, by, bz);
  388.     new_tri->vert[2] = vert_lookup (cx, cy, cz);
  389.  
  390.     new_tri->text_index = texture_index;
  391.     new_tri->text_type  = texture_type;
  392.  
  393.     new_tri->flag = 0;
  394.  
  395.     for (i = 0; i < 3; i++) {
  396.     /* Create a new index node */
  397.     new_node = malloc (sizeof(TriList2));
  398.     if (new_node == NULL)
  399.         abortmsg ("Insufficient memory for triangles.", 1);
  400.  
  401.     /* Point the index entry to the new triangle */
  402.     new_node->tri = new_tri;
  403.  
  404.     /* Insert the new index node into the list */
  405.     new_node->next = groot->index[i];
  406.     new_node->prev = groot->index[i]->prev;
  407.     groot->index[i]->prev->next = new_node;
  408.     groot->index[i]->prev = new_node;
  409.     }
  410.  
  411.     ++(groot->obj_cnt);
  412.  
  413.     return 0;
  414. }
  415.  
  416.  
  417. /* For compatability */
  418. void opt_write_pov (char *obj_name)
  419. {
  420.     opt_write_file (obj_name);
  421. }
  422.  
  423.  
  424. /* Optimize and write file */
  425. void opt_write_file (char *obj_name)
  426. {
  427.     VertList *temp;
  428.     int      i;
  429.  
  430.     if (out_format != POV10 && out_format != POV20)
  431.     bound_mode = 2;
  432.  
  433.     if (!initialized || groot->obj_cnt == 0) {
  434.     orig_tpr = 1.0;
  435.     final_tpr = 0.0;
  436.     tot_bounds = 0;
  437.     return;   /* No triangles where ever added, nothing to write */
  438.     }
  439.  
  440.     strcpy (object_name, obj_name);
  441.     cleanup_name (object_name);
  442.  
  443.     ++object_cnt;
  444.  
  445.     /* Dump the hash table, don't need it any more */
  446.     for (i = 0; i < HASHSIZE; i++) {
  447.     while (vert_hash[i] != NULL) {
  448.         temp = vert_hash[i];
  449.         vert_hash[i] = vert_hash[i]->next;
  450.         free (temp);
  451.     }
  452.     }
  453.  
  454.     /* Build the vertice index */
  455.     build_tri_index();
  456.  
  457.     if (bound_mode != 2) {
  458.     if (!quiet_mode)
  459.         printf ("Building indexes\n");
  460.  
  461.     sort_indexes (groot);
  462.     }
  463.  
  464.     update_node (groot);
  465.  
  466.     if (!quiet_mode) {
  467.     printf ("Adding bounds (1)\r");
  468.     fflush(stdout);;
  469.     }
  470.  
  471.     /* Optimize the tree */
  472.     orig_tpr = calc_tpr (groot);
  473.  
  474.     if (bound_mode != 2)
  475.     optimize_tree (groot);
  476.  
  477.     final_tpr = calc_tpr (groot);
  478.  
  479.     /* Write the file */
  480.     write_file();
  481.  
  482.     /* Free up the vertex index */
  483.     dump_tri_index();
  484.  
  485.     cleanup_object();
  486. }
  487.  
  488.  
  489. void opt_write_box (char *obj_name)
  490. {
  491.     VertList *temp;
  492.     int i;
  493.  
  494.     if (!initialized || groot->obj_cnt == 0) {
  495.     orig_tpr = 1.0;
  496.     final_tpr = 0.0;
  497.     tot_bounds = 0;
  498.     return;   /* No triangles where ever added, nothing to write */
  499.     }
  500.  
  501.     strcpy (object_name, obj_name);
  502.     cleanup_name (object_name);
  503.  
  504.     ++object_cnt;
  505.  
  506.     /* Dump the hash table, don't need it any more */
  507.     for (i = 0; i < HASHSIZE; i++) {
  508.     while (vert_hash[i] != NULL) {
  509.         temp = vert_hash[i];
  510.         vert_hash[i] = vert_hash[i]->next;
  511.         free (temp);
  512.     }
  513.     }
  514.  
  515.     orig_tpr = final_tpr = 1.0;
  516.  
  517.     update_node (groot);
  518.  
  519.     write_box (groot->vmin, groot->vmax, groot->index[0]->next->tri);
  520.  
  521.     cleanup_object();
  522. }
  523.  
  524.  
  525. void opt_finish()
  526. {
  527.     FILE *f;
  528.  
  529.     f = fopen (out_file, "a");
  530.  
  531.     switch (out_format) {
  532.     case POV10:
  533.             if (object_cnt > 2 && bound_mode == 0)
  534.             fprintf (f, "composite {  /* All Objects */\n    ");
  535.  
  536.         fprintf (f, "#include \"%s\"\n", inc_file);
  537.  
  538.         if (object_cnt > 2 && bound_mode == 0) {
  539.         fprintf (f, "\n");
  540.         fprintf (f, "    bounded_by {\n");
  541.         fprintf (f, "        box { <%.4f %.4f %.4f> <%.4f %.4f %.4f> }\n",
  542.                      gmin[X], gmin[Y], gmin[Z],
  543.                      gmax[X], gmax[Y], gmax[Z]);
  544.         fprintf (f, "    }\n");
  545.             fprintf (f, "}\n\n");
  546.             }
  547.         break;
  548.  
  549.     case POV20:
  550.             if (object_cnt > 2 && bound_mode == 0)
  551.                 fprintf (f, "union {\n    ");
  552.  
  553.         fprintf (f, "#include \"%s\"\n", inc_file);
  554.  
  555.         if (object_cnt > 2 && bound_mode == 0) {
  556.         fprintf (f, "\n");
  557.         fprintf (f, "    bounded_by {\n");
  558.         fprintf (f, "        box { <%.4f, %.4f, %.4f>, <%.4f, %.4f, %.4f> }\n",
  559.                      gmin[X], gmin[Y], gmin[Z],
  560.                      gmax[X], gmax[Y], gmax[Z]);
  561.         fprintf (f, "    }\n");
  562.                 fprintf (f, "}\n\n");
  563.             }
  564.         break;
  565.  
  566.     case VIVID:
  567.         fprintf (f, "#include %s\n\n", inc_file);
  568.         break;
  569.  
  570.     case POLYRAY:
  571.         fprintf (f, "include \"%s\"\n\n", inc_file);
  572.         break;
  573.     }
  574.  
  575.     fclose (f);
  576. }
  577.  
  578.  
  579.  
  580. void opt_get_limits (float  *min_x, float  *min_y, float  *min_z,
  581.              float  *max_x, float  *max_y, float  *max_z)
  582. {
  583.     *min_x = last_vmin[X];
  584.     *min_y = last_vmin[Y];
  585.     *min_z = last_vmin[Z];
  586.  
  587.     *max_x = last_vmax[X];
  588.     *max_y = last_vmax[Y];
  589.     *max_z = last_vmax[Z];
  590. }
  591.  
  592.  
  593. void opt_get_glimits (float  *min_x, float  *min_y, float  *min_z,
  594.               float  *max_x, float  *max_y, float  *max_z)
  595. {
  596.     *min_x = gmin[X];
  597.     *min_y = gmin[Y];
  598.     *min_z = gmin[Z];
  599.  
  600.     *max_x = gmax[X];
  601.     *max_y = gmax[Y];
  602.     *max_z = gmax[Z];
  603. }
  604.  
  605.  
  606. unsigned opt_get_vert_cnt()
  607. {
  608.     return last_vert_cnt;
  609. }
  610.  
  611.  
  612. unsigned opt_get_tri_cnt()
  613. {
  614.     return last_tri_cnt;
  615. }
  616.  
  617.  
  618. float  opt_get_index()
  619. {
  620.     return last_index;
  621. }
  622.  
  623.  
  624. unsigned opt_get_bounds()
  625. {
  626.     return last_bounds;
  627. }
  628.  
  629.  
  630. void init_object()
  631. {
  632.     int i;
  633.  
  634.     last_pal.red   = 0.0;
  635.     last_pal.green = 0.0;
  636.     last_pal.blue  = 0.0;
  637.  
  638.     strcpy (last_texture, "");
  639.  
  640.     bound_cost = 1.6;
  641.  
  642.     /* Allocate memory for palette lookup table */
  643.     pmax   = 10;
  644.     psize  = 0;
  645.     ptable = malloc (pmax * sizeof(Palette));
  646.     if (ptable == NULL)
  647.     abortmsg ("Insufficient memory for palette.", 1);
  648.  
  649.     /* Allocate memory for texture table */
  650.     tmax   = 10;
  651.     tsize  = 0;
  652.     ttable = malloc (tmax * sizeof(Texture));
  653.     if (ttable == NULL)
  654.     abortmsg ("Insufficient memory for textures.", 1);
  655.  
  656.     /* Allocate memory for vertex lookup table */
  657.     vmax = (vert_init > 0) ? vert_init : 1000;
  658.     vsize  = 0;
  659.     vtable = malloc (vmax * sizeof(Vector));
  660.     if (vtable == NULL)
  661.     abortmsg ("Insufficient memory for vertices.", 1);
  662.  
  663.     /* Allocate memory for vertex hash table */
  664.     vert_hash = malloc (sizeof(VertList*)*HASHSIZE);
  665.     if (vert_hash == NULL)
  666.     abortmsg ("Insufficient memory for vertex hash table.", 1);
  667.  
  668.     /* Initialize the vertex lookup hash table */
  669.     for (i = 0; i < HASHSIZE; i++)
  670.     vert_hash[i] = NULL;
  671.  
  672.     /* Start with an empty root node */
  673.     groot = create_group();
  674.  
  675.     tot_bounds = 1;
  676.     initialized = 1;
  677. }
  678.  
  679.  
  680. void cleanup_object()
  681. {
  682.     int i;
  683.     Vector corners[8];  /* Corners of box */
  684.  
  685.     last_vert_cnt = vsize;
  686.     last_tri_cnt  = groot->obj_cnt;
  687.     last_index    = orig_tpr/final_tpr;
  688.     last_bounds   = tot_bounds;
  689.  
  690.     vect_copy (last_vmin, groot->vmin);
  691.     vect_copy (last_vmax, groot->vmax);
  692.  
  693.     /* Calculate the corners of the bounding box */
  694.     corners[0][X] =  groot->vmin[X];
  695.     corners[0][Y] =  groot->vmin[Y];
  696.     corners[0][Z] =  groot->vmin[Z];
  697.  
  698.     corners[1][X] =  groot->vmin[X];
  699.     corners[1][Y] =  groot->vmin[Y];
  700.     corners[1][Z] =  groot->vmax[Z];
  701.  
  702.     corners[2][X] =  groot->vmax[X];
  703.     corners[2][Y] =  groot->vmin[Y];
  704.     corners[2][Z] =  groot->vmin[Z];
  705.  
  706.     corners[3][X] =  groot->vmax[X];
  707.     corners[3][Y] =  groot->vmin[Y];
  708.     corners[3][Z] =  groot->vmax[Z];
  709.  
  710.     corners[4][X] =  groot->vmin[X];
  711.     corners[4][Y] =  groot->vmax[Y];
  712.     corners[4][Z] =  groot->vmin[Z];
  713.  
  714.     corners[5][X] =  groot->vmax[X];
  715.     corners[5][Y] =  groot->vmax[Y];
  716.     corners[5][Z] =  groot->vmin[Z];
  717.  
  718.     corners[6][X] =  groot->vmin[X];
  719.     corners[6][Y] =  groot->vmax[Y];
  720.     corners[6][Z] =  groot->vmax[Z];
  721.  
  722.     corners[7][X] =  groot->vmax[X];
  723.     corners[7][Y] =  groot->vmax[Y];
  724.     corners[7][Z] =  groot->vmax[Z];
  725.  
  726.     /* Include any transformation in the box calcs */
  727.     if (use_transform) {
  728.     for (i = 0; i < 8; i++)
  729.         vect_transform (corners[i], corners[i], trans_matrix);
  730.     }
  731.  
  732.     for (i = 0; i < 8; i++) {
  733.     gmin[X] = (corners[i][X] < gmin[X]) ? corners[i][X] : gmin[X];
  734.     gmin[Y] = (corners[i][Y] < gmin[Y]) ? corners[i][Y] : gmin[Y];
  735.     gmin[Z] = (corners[i][Z] < gmin[Z]) ? corners[i][Z] : gmin[Z];
  736.  
  737.     gmax[X] = (corners[i][X] > gmax[X]) ? corners[i][X] : gmax[X];
  738.     gmax[Y] = (corners[i][Y] > gmax[Y]) ? corners[i][Y] : gmax[Y];
  739.     gmax[Z] = (corners[i][Z] > gmax[Z]) ? corners[i][Z] : gmax[Z];
  740.     }
  741.  
  742.     free (ptable);
  743.     free (vtable);
  744.     free (vert_hash);
  745.  
  746.     for (i = 0; i < tsize; i++)
  747.     free (ttable[i]);
  748.  
  749.     free (ttable);
  750.  
  751.     delete_tree (groot);
  752.  
  753.     initialized = 0;
  754. }
  755.  
  756.  
  757. /* Calculate the number of Tests Per Ray (tpr) required for this group */
  758. float  calc_tpr (GroupTree *gnode)
  759. {
  760.     GroupTree *g;
  761.     float     tpr;
  762.  
  763.     if (gnode->child_cnt == 0)
  764.     return gnode->obj_cnt;
  765.  
  766.     tpr = bound_cost * gnode->child_cnt;
  767.  
  768.     for (g = gnode->child; g != NULL; g = g->next)
  769.     tpr = tpr + (g->area/gnode->area) * calc_tpr(g);
  770.  
  771.     return tpr;
  772. }
  773.  
  774.  
  775. /* Create an empty group node */
  776. GroupTree *create_group()
  777. {
  778.     GroupTree *new_group;
  779.     int       i;
  780.  
  781.     new_group = malloc (sizeof(GroupTree));
  782.     if (new_group == NULL)
  783.     abortmsg ("Insufficient memory for group list.", 1);
  784.  
  785.     for (i = 0; i < 3; i++) {
  786.     new_group->index[i] = malloc (sizeof(TriList2));
  787.     if (new_group->index[i] == NULL)
  788.         abortmsg ("Insufficient memory for tree.", 1);
  789.  
  790.     new_group->index[i]->tri = NULL;
  791.     new_group->index[i]->prev = new_group->index[i];
  792.     new_group->index[i]->next = new_group->index[i];
  793.     }
  794.  
  795.     vect_init (new_group->vmin, +MAXFLOAT, +MAXFLOAT, +MAXFLOAT);
  796.     vect_init (new_group->vmax, -MAXFLOAT, -MAXFLOAT, -MAXFLOAT);
  797.     new_group->area      = 0.0;
  798.     new_group->obj_cnt   = 0;
  799.     new_group->child_cnt = 0;
  800.     new_group->split_cnt = 0;
  801.     new_group->parent    = NULL;
  802.     new_group->next      = NULL;
  803.     new_group->child     = NULL;
  804.  
  805.     return new_group;
  806. }
  807.  
  808.  
  809. /* Delete this node and all sub-nodes of tree */
  810. void delete_tree (GroupTree *gnode)
  811. {
  812.     GroupTree *g, *g_temp;
  813.     TriList2  *t, *t_temp;
  814.     int       i;
  815.  
  816.     for (g = gnode->child; g != NULL; ) {
  817.     g_temp = g->next;
  818.     delete_tree (g);
  819.     g = g_temp;
  820.     }
  821.  
  822.     /* Free the indexes for this node (if any exist) */
  823.     for (i = 0; i < 3; i++) {
  824.     if ((gnode->index[i] != NULL) && (gnode->index[i]->prev != NULL)) {
  825.         /* Drop a link so the list isn't circular any more */
  826.         gnode->index[i]->prev->next = NULL;
  827.  
  828.         /* Delete the list */
  829.         for (t = gnode->index[i]; t != NULL; ) {
  830.         if (i == 0 && (t->tri != NULL))
  831.             free (t->tri);
  832.  
  833.         t_temp = t;
  834.         t = t->next;
  835.         free (t_temp);
  836.         }
  837.     }
  838.     }
  839.  
  840.     /* And finally free the root node */
  841.     free (gnode);
  842. }
  843.  
  844.  
  845. /* Optimize the bounds for this sub-tree */
  846. void optimize_tree (GroupTree *gnode)
  847. {
  848.     GroupTree *group_a, *group_b;
  849.     int axis, best_axis;
  850.     float     best_rtpr, new_rtpr;
  851.     TriList2  *best_loc, *new_loc;
  852.  
  853.     best_rtpr = 0.0;
  854.     best_loc  = NULL;
  855.     best_axis = -1;
  856.  
  857.     /* Try splitting the group in each of the three axis' (x,y,z) */
  858.     for (axis = 0; axis < 3; axis++) {
  859.     test_split (gnode, axis, &new_rtpr, &new_loc);
  860.  
  861.     if (new_rtpr < best_rtpr) {
  862.         best_rtpr = new_rtpr;
  863.         best_loc  = new_loc;
  864.         best_axis = axis;
  865.     }
  866.     }
  867.  
  868.     if (best_axis != -1) {
  869.     /* Split this node into two nodes */
  870.     split_group (gnode, best_axis, best_loc, &group_a, &group_b);
  871.  
  872.     optimize_tree (group_a);
  873.     optimize_tree (group_b);
  874.     }
  875. }
  876.  
  877.  
  878.  
  879. /* Test the effectiveness of splitting this group (but don't do it yet) */
  880. void test_split (GroupTree *gnode, int axis, float  *best_rtpr,
  881.          TriList2 **best_loc)
  882. {
  883.     float    dim1, dim2;
  884.     float    area1, area2, p_area;
  885.     float    new_min1, new_max1, new_min2, new_max2;
  886.     float    best_index, new_index;
  887.     TriList2 *t;
  888.     int      cnt, best_cnt;
  889.  
  890.     *best_loc  = NULL;
  891.     best_index = +MAXFLOAT ;
  892.     best_cnt   = 0;
  893.     cnt = 0;
  894.  
  895.     dim1 = gnode->vmax[(axis+1) % 3] - gnode->vmin[(axis+1) % 3];
  896.     dim2 = gnode->vmax[(axis+2) % 3] - gnode->vmin[(axis+2) % 3];
  897.  
  898.     for (t = gnode->index[axis]->next; t != gnode->index[axis]; t = t->next) {
  899.     if (t->next == gnode->index[axis])
  900.         break;
  901.  
  902.     ++cnt;
  903.  
  904.     /* Make an estimate of the new min/max limits, doing the full */
  905.     /* calculation is just tooooo slooowww. */
  906.     new_min1 = gnode->vmin[axis];
  907.     new_max1 = max_vertex (t->tri, axis);
  908.     new_min2 = min_vertex (t->next->tri, axis);
  909.     new_max2 = gnode->vmax[axis];
  910.  
  911.     /* Calculate the surface area of the new groups */
  912.     area1 = surf_area (dim1, dim2, new_max1 - new_min1);
  913.     area2 = surf_area (dim1, dim2, new_max2 - new_min2);
  914.  
  915.     new_index = (cnt * area1) + ((gnode->obj_cnt - cnt) * area2);
  916.  
  917.     /* Keep track of the best one */
  918.     if (new_index < best_index) {
  919.         best_index = new_index;
  920.         *best_loc  = t->next;
  921.         best_cnt   = cnt;
  922.     }
  923.     }
  924.  
  925.     /* The former was just an estimate, verify the numbers */
  926.     if (*best_loc != NULL) {
  927.     new_min1 = gnode->vmin[axis];
  928.     new_max1 = -MAXFLOAT;
  929.     new_min2 = +MAXFLOAT;
  930.     new_max2 = gnode->vmax[axis];
  931.  
  932.     for (t = gnode->index[axis]->next; t != *best_loc; t = t->next)
  933.         new_max1 = fmax (new_max1, max_vertex (t->tri, axis));
  934.  
  935.     for (t = *best_loc; t != gnode->index[axis]; t = t->next)
  936.         new_min2 = fmin (new_min2, min_vertex (t->tri, axis));
  937.  
  938.     area1 = surf_area (dim1, dim2, new_max1 - new_min1);
  939.     area2 = surf_area (dim1, dim2, new_max2 - new_min2);
  940.  
  941.     best_index = (best_cnt * area1) +
  942.              ((gnode->obj_cnt - best_cnt) * area2);
  943.     }
  944.  
  945.     if (gnode->parent == NULL || gnode->split_cnt >= 2) {
  946.     p_area = gnode->area;
  947.  
  948.     *best_rtpr = -1.0*((gnode->area/p_area) * gnode->obj_cnt) +
  949.              (gnode->area/p_area) * ((best_index/p_area) +
  950.              2.0*bound_cost);
  951.     }
  952.     else {
  953.     p_area = gnode->parent->area;
  954.  
  955.     *best_rtpr = -1.0*((gnode->area/p_area) * gnode->obj_cnt) +
  956.              (best_index/p_area) + bound_cost;
  957.     }
  958. }
  959.  
  960.  
  961. /* Split the group along the specified axis into two sub-groups */
  962. void split_group (GroupTree *gnode, int axis, TriList2 *split_loc,
  963.           GroupTree **group_a, GroupTree **group_b)
  964. {
  965.     GroupTree *new_a, *new_b;
  966.     TriList2  *t, *next_t, *new_index;
  967.     char      new_flag;
  968.     int       i;
  969.  
  970.     COOPERATE    /* support multitasking */
  971.  
  972.     /* Mark the triangles as to which group they will belong */
  973.     new_flag = 0;
  974.     for (t = gnode->index[axis]->next; t != gnode->index[axis]; t = t->next) {
  975.     if (t == split_loc)
  976.         new_flag = 1;
  977.  
  978.     t->tri->flag = new_flag;
  979.     }
  980.  
  981.     new_a = create_group();
  982.     new_b = create_group();
  983.  
  984.     for (i = 0; i < 3; i++) {
  985.     t = gnode->index[i]->next;
  986.  
  987.     while (t != gnode->index[i]) {
  988.         next_t = t->next;
  989.  
  990.         if (t->tri->flag == 0)
  991.         new_index = new_a->index[i];
  992.         else
  993.         new_index = new_b->index[i];
  994.  
  995.         /* Remove this node from the list */
  996.         t->prev->next = t->next;
  997.         t->next->prev = t->prev;
  998.  
  999.         /* Insert node into its new group */
  1000.         t->prev = new_index->prev;
  1001.         t->next = new_index;
  1002.         new_index->prev->next = t;
  1003.         new_index->prev = t;
  1004.  
  1005.         t = next_t;
  1006.     }
  1007.     }
  1008.  
  1009.     for (i = 0; i < 3; i++) {
  1010.     free (gnode->index[i]);
  1011.     gnode->index[i] = NULL;
  1012.     }
  1013.  
  1014.     if (gnode->parent == NULL || gnode->split_cnt >= 2) {
  1015.     /* Add the new groups as children of original */
  1016.     gnode->child  = new_a;
  1017.     new_a->parent = gnode;
  1018.     new_a->next   = new_b;
  1019.     new_b->parent = gnode;
  1020.  
  1021.     new_a->split_cnt = 0;
  1022.     new_b->split_cnt = 0;
  1023.  
  1024.     tot_bounds = tot_bounds + 2;
  1025.     }
  1026.     else {
  1027.     /* Remove the original group and replace with the new groups */
  1028.     for (i = 0; i < 3; i++)
  1029.         gnode->index[i] = new_a->index[i];
  1030.  
  1031.     free (new_a);
  1032.     new_a = gnode;
  1033.  
  1034.     new_b->next = new_a->next;
  1035.     new_a->next = new_b;
  1036.  
  1037.     new_a->parent = gnode->parent;
  1038.     new_b->parent = gnode->parent;
  1039.  
  1040.     new_a->split_cnt = gnode->split_cnt + 1;
  1041.     new_b->split_cnt = gnode->split_cnt + 1;
  1042.  
  1043.     tot_bounds = tot_bounds + 1;
  1044.     }
  1045.  
  1046.     update_node (new_a);
  1047.     update_node (new_b);
  1048.  
  1049.     if (new_a->parent != NULL)
  1050.     update_node (new_a->parent);
  1051.  
  1052.     if (!quiet_mode) {
  1053.     printf ("Adding bounds (%d)\r", tot_bounds);
  1054.     fflush(stdout);
  1055.     }
  1056.  
  1057.     *group_a = new_a;
  1058.     *group_b = new_b;
  1059. }
  1060.  
  1061.  
  1062. /* Write the optimized POV file */
  1063. void write_file()
  1064. {
  1065.     FILE  *f;
  1066.  
  1067.     if (!quiet_mode)
  1068.     printf ("\nWriting files %s and %s\n", out_file, inc_file);
  1069.  
  1070.     f = fopen (out_file, "a");
  1071.     if (f == NULL)
  1072.     abortmsg ("Error opening output file.", 1);
  1073.  
  1074.     switch (out_format) {
  1075.     case POV10:   write_pov10_header (f);
  1076.               break;
  1077.     case POV20:   write_pov20_header (f);
  1078.               break;
  1079.     case VIVID:   write_vivid_header (f);
  1080.               break;
  1081.     case POLYRAY: write_polyray_header (f);
  1082.               break;
  1083.     }
  1084.  
  1085.     fclose (f);
  1086.  
  1087.     f = fopen (inc_file, "a");
  1088.     if (f == NULL)
  1089.     abortmsg ("Error opening output file.", 1);
  1090.  
  1091.     switch (out_format) {
  1092.     case POV10:   write_pov10_tree (f, groot, 1);
  1093.               break;
  1094.     case POV20:   write_pov20_tree (f, groot, 1);
  1095.               break;
  1096.     case VIVID:   write_vivid_tree (f, groot);
  1097.               break;
  1098.     case POLYRAY: write_polyray_tree (f, groot);
  1099.               break;
  1100.     }
  1101.  
  1102.     fclose (f);
  1103.  
  1104.     if (!quiet_mode) {
  1105.     printf ("Triangles: %u, ", groot->obj_cnt);
  1106.     printf ("Vertices: %u, ", vsize);
  1107.     printf ("Bounding index: %.2f\n\n", orig_tpr/final_tpr);
  1108.     }
  1109. }
  1110.  
  1111.  
  1112. void write_box (Vector v1, Vector v2, Triangle *tri)
  1113. {
  1114.     FILE  *f;
  1115.  
  1116.     if (!quiet_mode)
  1117.     printf ("\nWriting files %s and %s\n", out_file, inc_file);
  1118.  
  1119.     f = fopen (inc_file, "a");
  1120.     if (f == NULL)
  1121.     abortmsg ("Error opening output file.", 1);
  1122.  
  1123.     switch (out_format) {
  1124.     case POV10:
  1125.         fprintf (f, "\n/* Object '%s' */\n", object_name);
  1126.         fprintf (f, "object {\n");
  1127.         fprintf (f, "\tbox { <%.4f %.4f %.4f> <%.4f %.4f %.4f> }\n",
  1128.             v1[X], v1[Y], v1[Z], v2[X], v2[Y], v2[Z]);
  1129.         fprintf (f, "\t");
  1130.         write_pov10_texture (f, tri);
  1131.         fprintf (f, "\n");
  1132.  
  1133.         if (use_transform)
  1134.         write_pov10_transform (f, trans_matrix);
  1135.  
  1136.         fprintf (f, "}\n\n");
  1137.         break;
  1138.  
  1139.     case POV20:
  1140.         fprintf (f, "\n/* Object '%s' */\n", object_name);
  1141.         fprintf (f, "box {\n");
  1142.         fprintf (f, "\t<%.4f, %.4f, %.4f>, <%.4f, %.4f, %.4f>\n",
  1143.             v1[X], v1[Y], v1[Z], v2[X], v2[Y], v2[Z]);
  1144.         fprintf (f, "\t");
  1145.         write_pov20_texture (f, tri);
  1146.         fprintf (f, "\n");
  1147.  
  1148.         if (use_transform)
  1149.         write_pov20_transform (f, trans_matrix);
  1150.  
  1151.         fprintf (f, "}\n\n");
  1152.         break;
  1153.  
  1154.     case VIVID:
  1155.         fprintf (f, "\n/* Object '%s' */\n", object_name);
  1156.  
  1157.         if (use_transform)
  1158.         write_vivid_transform (f, trans_matrix);
  1159.  
  1160.         write_vivid_texture (f, tri);
  1161.  
  1162.         fprintf (f, "polygon { points 4 vertex %.4f %.4f %.4f vertex %.4f %.4f %.4f vertex %.4f %.4f %.4f vertex %.4f %.4f %.4f }\n",
  1163.              v1[X], v1[Y], v1[Z], v2[X], v1[Y], v1[Z], v2[X], v2[Y], v1[Z], v1[X], v2[Y], v1[Z]);
  1164.         fprintf (f, "polygon { points 4 vertex %.4f %.4f %.4f vertex %.4f %.4f %.4f vertex %.4f %.4f %.4f vertex %.4f %.4f %.4f }\n",
  1165.              v1[X], v1[Y], v1[Z], v1[X], v2[Y], v1[Z], v1[X], v2[Y], v2[Z], v1[X], v1[Y], v2[Z]);
  1166.         fprintf (f, "polygon { points 4 vertex %.4f %.4f %.4f vertex %.4f %.4f %.4f vertex %.4f %.4f %.4f vertex %.4f %.4f %.4f }\n",
  1167.              v1[X], v2[Y], v1[Z], v2[X], v2[Y], v1[Z], v2[X], v2[Y], v2[Z], v1[X], v2[Y], v2[Z]);
  1168.         fprintf (f, "polygon { points 4 vertex %.4f %.4f %.4f vertex %.4f %.4f %.4f vertex %.4f %.4f %.4f vertex %.4f %.4f %.4f }\n",
  1169.              v2[X], v2[Y], v1[Z], v2[X], v1[Y], v1[Z], v2[X], v1[Y], v2[Z], v2[X], v2[Y], v2[Z]);
  1170.         fprintf (f, "polygon { points 4 vertex %.4f %.4f %.4f vertex %.4f %.4f %.4f vertex %.4f %.4f %.4f vertex %.4f %.4f %.4f }\n",
  1171.              v2[X], v1[Y], v1[Z], v1[X], v1[Y], v1[Z], v1[X], v1[Y], v2[Z], v2[X], v1[Y], v2[Z]);
  1172.         fprintf (f, "polygon { points 4 vertex %.4f %.4f %.4f vertex %.4f %.4f %.4f vertex %.4f %.4f %.4f vertex %.4f %.4f %.4f }\n",
  1173.              v1[X], v1[Y], v2[Z], v1[X], v2[Y], v2[Z], v2[X], v2[Y], v2[Z], v2[X], v1[Y], v2[Z]);
  1174.  
  1175.         if (use_transform)
  1176.         fprintf (f, "transform_pop\n\n");
  1177.         break;
  1178.  
  1179.     case POLYRAY:
  1180.         fprintf (f, "\n// Object '%s'\n", object_name);
  1181.         fprintf (f, "object {\n");
  1182.         fprintf (f, "\tbox <%.4f, %.4f, %.4f>, <%.4f, %.4f, %.4f>\n",
  1183.             v1[X], v1[Y], v1[Z], v2[X], v2[Y], v2[Z]);
  1184.         fprintf (f, "\t");
  1185.         write_polyray_texture (f, tri);
  1186.         fprintf (f, "\n");
  1187.  
  1188.         if (use_transform)
  1189.         write_polyray_transform (f, trans_matrix);
  1190.  
  1191.         fprintf (f, "}\n\n");
  1192.         break;
  1193.     }
  1194.  
  1195.     fclose (f);
  1196. }
  1197.  
  1198.  
  1199. /* Write a sub-tree to file */
  1200. void write_pov10_tree (FILE *f, GroupTree *gnode, int level)
  1201. {
  1202.     GroupTree *g;
  1203.     TriList2  *t;
  1204.     Triangle  *first_tri;
  1205.     int       one_texture;
  1206.  
  1207.     if (level == 1)
  1208.     fprintf (f, "\n/* Object '%s' */\n", object_name);
  1209.  
  1210.     fprintf (f, "composite {\n");
  1211.  
  1212.     if (gnode->child != NULL) {
  1213.     for (g = gnode->child; g != NULL; g = g->next)
  1214.         write_pov10_tree (f, g, level+1);
  1215.     }
  1216.     else {
  1217.     first_tri = gnode->index[0]->next->tri;
  1218.     one_texture = 1;
  1219.  
  1220.     for (t = gnode->index[0]->next; t != gnode->index[0]; t = t->next) {
  1221.         if (t->tri->text_index != first_tri->text_index ||
  1222.         t->tri->text_type  != first_tri->text_type) {
  1223.            one_texture = 0;
  1224.            break;
  1225.         }
  1226.     }
  1227.  
  1228.     if (one_texture) {
  1229.         fprintf (f, "\tobject {\n");
  1230.         fprintf (f, "\t\tunion {\n");
  1231.     }
  1232.  
  1233.     for (t = gnode->index[0]->next; t != gnode->index[0]; t = t->next)
  1234.         write_pov10_triangle (f, t->tri, one_texture);
  1235.  
  1236.     if (one_texture) {
  1237.         fprintf (f, "\t\t}\n\n\t\t");
  1238.         write_pov10_texture (f, first_tri);
  1239.         fprintf (f, "\n\t}\n");
  1240.     }
  1241.     }
  1242.  
  1243.     if (bound_mode == 0)
  1244.         write_pov10_bound (f, gnode);
  1245.  
  1246.     if (level == 1 && use_transform)
  1247.     write_pov10_transform (f, trans_matrix);
  1248.  
  1249.     fprintf (f, "}\n");
  1250. }
  1251.  
  1252.  
  1253. void write_pov10_texture (FILE *f, Triangle *tri)
  1254. {
  1255.     if (tri->text_type == 1)
  1256.     fprintf (f, "texture { %s }", ttable[tri->text_index]);
  1257.     else if (psize < MAX_TEX)
  1258.     fprintf (f, "texture { %s_%u }",
  1259.          object_name, tri->text_index + 1);
  1260.     else
  1261.     fprintf (f, "texture { %s color red %.3f green %.3f blue %.3f }",
  1262.          object_name, ptable[tri->text_index].red,
  1263.          ptable[tri->text_index].green, ptable[tri->text_index].blue);
  1264. }
  1265.  
  1266.  
  1267. /*
  1268.    Writes a transformation matrix as separate POV-Ray scale< >,
  1269.    rotate< >, and translate< > commands
  1270. */
  1271. void write_pov10_transform (FILE *f, Matrix matrix)
  1272. {
  1273.     Vector scale, shear, rotate, transl;
  1274.  
  1275.     /* Decode the matrix into separate operations */
  1276.     mat_decode (matrix, scale, shear, rotate, transl);
  1277.  
  1278.     fprintf (f, "\n\t/* Object transformation */\n");
  1279.  
  1280.     if (fabs(scale[X] - 1.0) > 0.001 || fabs(scale[Y] - 1.0) > 0.001 || fabs(scale[Z] - 1.0) > 0.001)
  1281.     fprintf (f, "\tscale <%.3f %.3f %.3f>\n", scale[X], scale[Y], scale[Z]);
  1282.  
  1283.     if (fabs(rotate[X]) > 0.01 || fabs(rotate[Y]) > 0.01 || fabs(rotate[Z]) > 0.01)
  1284.     fprintf (f, "\trotate <%.2f %.2f %.2f>\n", rotate[X], rotate[Y], rotate[Z]);
  1285.  
  1286.     if (fabs(transl[X]) > 0.0001 || fabs(transl[Y]) > 0.0001 || fabs(transl[Z]) > 0.0001)
  1287.     fprintf (f, "\ttranslate <%.4f %.4f %.4f>\n", transl[X], transl[Y], transl[Z]);
  1288.  
  1289.     /* Can't handle shear but warn if it's there */
  1290.     if (fabs(shear[X]) > 0.01 || fabs(shear[Y]) > 0.01 || fabs(shear[Z]) > 0.01)
  1291.     printf ("Warning: Significant shear in transformation (ignored)\n");
  1292. }
  1293.  
  1294.  
  1295. /* Write the POV file header */
  1296. void write_pov10_header (FILE *f)
  1297. {
  1298.     int i;
  1299.  
  1300.     if (psize >= MAX_TEX) {
  1301.     fprintf (f, "/* Too many textures, textures generated in-line */\n\n");
  1302.     fprintf (f, "#declare %s = texture {\n", object_name);
  1303.     fprintf (f, "    ambient 0.1\n");
  1304.     fprintf (f, "    diffuse 0.7\n");
  1305.     fprintf (f, "    phong 1.0\n");
  1306.     fprintf (f, "    phong_size 70.0\n");
  1307.     fprintf (f, "}\n\n");
  1308.     }
  1309.     else {
  1310.     if (psize > 0)
  1311.         fprintf (f, "/* Texture declarations for object '%s' */\n", object_name);
  1312.  
  1313.     for (i = 0; i < psize; i++) {
  1314.         fprintf (f, "#declare %s_%u = texture {\n", object_name, i + 1);
  1315.         fprintf (f, "    ambient 0.1\n");
  1316.         fprintf (f, "    diffuse 0.7\n");
  1317.         fprintf (f, "    phong 1.0\n");
  1318.         fprintf (f, "    phong_size 70.0\n");
  1319.         fprintf (f, "    color red %.3f green %.3f blue %.3f\n",
  1320.              ptable[i].red, ptable[i].green, ptable[i].blue);
  1321.         fprintf (f, "}\n\n");
  1322.     }
  1323.     }
  1324. }
  1325.  
  1326.  
  1327. /* Write a triangle (smooth or regular) */
  1328. void write_pov10_triangle (FILE *f, Triangle *tri, int one_texture)
  1329. {
  1330.     Vector norm[3];
  1331.     int    no_smooth = 0;
  1332.  
  1333.     COOPERATE    /* support multitasking */
  1334.  
  1335.     if (one_texture)
  1336.     fprintf (f, "\t\t");
  1337.     else
  1338.     fprintf (f, "\tobject { ");
  1339.  
  1340.     if (smooth_angle > 0.0) {
  1341.     vert_normal (tri, norm);
  1342.  
  1343.     if (vect_equal (norm[0], norm[1]) && vect_equal (norm[1], norm[2]))
  1344.         no_smooth = 1;
  1345.     }
  1346.  
  1347.     if (smooth_angle > 0.0 && !no_smooth) {
  1348.     fprintf (f, "smooth_triangle { <");
  1349.     vect_print (f, vtable[tri->vert[0]], dec_point, ' ');
  1350.     fprintf (f, "> <");
  1351.     vect_print (f, norm[0], 3, ' ');
  1352.     fprintf (f, "> <");
  1353.     vect_print (f, vtable[tri->vert[1]], dec_point, ' ');
  1354.     fprintf (f, "> <");
  1355.     vect_print (f, norm[1], 3, ' ');
  1356.     fprintf (f, "> <");
  1357.     vect_print (f, vtable[tri->vert[2]], dec_point, ' ');
  1358.     fprintf (f, "> <");
  1359.     vect_print (f, norm[2], 3, ' ');
  1360.     fprintf (f, "> }");
  1361.     }
  1362.     else {
  1363.     fprintf (f, "triangle { <");
  1364.     vect_print (f, vtable[tri->vert[0]], dec_point, ' ');
  1365.     fprintf (f, "> <");
  1366.     vect_print (f, vtable[tri->vert[1]], dec_point, ' ');
  1367.     fprintf (f, "> <");
  1368.     vect_print (f, vtable[tri->vert[2]], dec_point, ' ');
  1369.     fprintf (f, "> }");
  1370.     }
  1371.  
  1372.     if (!one_texture) {
  1373.     fprintf (f, " ");
  1374.     write_pov10_texture (f, tri);
  1375.     fprintf (f, " }");
  1376.     }
  1377.  
  1378.     fprintf (f, "\n");
  1379. }
  1380.  
  1381.  
  1382. /* Write a bounding shape */
  1383. void write_pov10_bound (FILE *f, GroupTree *gnode)
  1384. {
  1385.     if (gnode->obj_cnt > 1) {
  1386.     fprintf (f, "\n\tbounded_by { box { <");
  1387.     vect_print (f, gnode->vmin, dec_point + 1, ' ');
  1388.     fprintf (f, "> <");
  1389.     vect_print (f, gnode->vmax, dec_point + 1, ' ');
  1390.     fprintf (f, "> } }\n");
  1391.     }
  1392. }
  1393.  
  1394.  
  1395. /* Write a sub-tree to file */
  1396. void write_pov20_tree (FILE *f, GroupTree *gnode, int level)
  1397. {
  1398.     GroupTree *g;
  1399.     TriList2  *t;
  1400.     Triangle  *first_tri;
  1401.     int       one_texture;
  1402.  
  1403.     if (level == 1)
  1404.     fprintf (f, "\n/* Object '%s' */\n", object_name);
  1405.  
  1406.     if (gnode->obj_cnt > 1)
  1407.         fprintf (f, "union {\n");
  1408.     else
  1409.         fprintf (f, "object {\n");
  1410.  
  1411.     if (gnode->child != NULL) {
  1412.     for (g = gnode->child; g != NULL; g = g->next)
  1413.         write_pov20_tree (f, g, level+1);
  1414.     }
  1415.     else {
  1416.     first_tri = gnode->index[0]->next->tri;
  1417.     one_texture = 1;
  1418.  
  1419.     for (t = gnode->index[0]->next; t != gnode->index[0]; t = t->next) {
  1420.         if (t->tri->text_index != first_tri->text_index ||
  1421.         t->tri->text_type  != first_tri->text_type) {
  1422.            one_texture = 0;
  1423.            break;
  1424.         }
  1425.     }
  1426.  
  1427.     for (t = gnode->index[0]->next; t != gnode->index[0]; t = t->next) {
  1428.             fprintf (f, "\t");
  1429.         write_pov20_triangle (f, t->tri, one_texture);
  1430.         }
  1431.  
  1432.     if (one_texture) {
  1433.         fprintf (f, "\n\t");
  1434.         write_pov20_texture (f, first_tri);
  1435.     }
  1436.     }
  1437.  
  1438.     fprintf (f, "\n");
  1439.  
  1440.     if (bound_mode == 0)
  1441.     write_pov20_bound (f, gnode);
  1442.  
  1443.     if (level == 1 && use_transform)
  1444.     write_pov20_transform (f, trans_matrix);
  1445.  
  1446.     fprintf (f, "}\n");
  1447. }
  1448.  
  1449.  
  1450. void write_pov20_texture (FILE *f, Triangle *tri)
  1451. {
  1452.     if (tri->text_type == 1)
  1453.     fprintf (f, "texture { %s }", ttable[tri->text_index]);
  1454.     else if (psize < MAX_TEX)
  1455.     fprintf (f, "texture { %s_%u }",
  1456.          object_name, tri->text_index + 1);
  1457.     else
  1458.     fprintf (f, "texture { %s pigment { color red %.3f green %.3f blue %.3f } }",
  1459.          object_name, ptable[tri->text_index].red,
  1460.          ptable[tri->text_index].green, ptable[tri->text_index].blue);
  1461. }
  1462.  
  1463.  
  1464. /*
  1465.    Writes a transformation matrix as separate POV-Ray scale< >,
  1466.    rotate< >, and translate< > commands
  1467. */
  1468. void write_pov20_transform (FILE *f, Matrix matrix)
  1469. {
  1470.     Vector scale, shear, rotate, transl;
  1471.  
  1472.     /* Decode the matrix into separate operations */
  1473.     mat_decode (matrix, scale, shear, rotate, transl);
  1474.  
  1475.     fprintf (f, "\n\t/* Object transformation */\n");
  1476.  
  1477.     if (fabs(scale[X] - 1.0) > 0.001 || fabs(scale[Y] - 1.0) > 0.001 || fabs(scale[Z] - 1.0) > 0.001)
  1478.     fprintf (f, "\tscale <%.3f, %.3f, %.3f>\n", scale[X], scale[Y], scale[Z]);
  1479.  
  1480.     if (fabs(rotate[X]) > 0.01 || fabs(rotate[Y]) > 0.01 || fabs(rotate[Z]) > 0.01)
  1481.     fprintf (f, "\trotate <%.2f, %.2f, %.2f>\n", rotate[X], rotate[Y], rotate[Z]);
  1482.  
  1483.     if (fabs(transl[X]) > 0.0001 || fabs(transl[Y]) > 0.0001 || fabs(transl[Z]) > 0.0001)
  1484.     fprintf (f, "\ttranslate <%.4f, %.4f, %.4f>\n", transl[X], transl[Y], transl[Z]);
  1485.  
  1486.     /* Can't handle shear but warn if it's there */
  1487.     if (fabs(shear[X]) > 0.01 || fabs(shear[Y]) > 0.01 || fabs(shear[Z]) > 0.01)
  1488.     printf ("Warning: Significant shear in transformation (ignored)\n");
  1489. }
  1490.  
  1491.  
  1492. /* Write the POV file header */
  1493. void write_pov20_header (FILE *f)
  1494. {
  1495.     int i;
  1496.  
  1497.     if (psize >= MAX_TEX) {
  1498.     fprintf (f, "/* Too many textures, textures generated in-line */\n\n");
  1499.     fprintf (f, "#declare %s = texture {\n", object_name);
  1500.     fprintf (f, "    finish { Shiny }\n");
  1501.     fprintf (f, "    pigment { White }\n");
  1502.     fprintf (f, "}\n\n");
  1503.     }
  1504.     else {
  1505.     if (psize > 0)
  1506.         fprintf (f, "/* Texture declarations for object '%s' */\n", object_name);
  1507.  
  1508.     for (i = 0; i < psize; i++) {
  1509.         fprintf (f, "#declare %s_%u = texture {\n", object_name, i + 1);
  1510.         fprintf (f, "    finish { Shiny }\n");
  1511.         fprintf (f, "    pigment { color red %.3f green %.3f blue %.3f }\n",
  1512.              ptable[i].red, ptable[i].green, ptable[i].blue);
  1513.         fprintf (f, "}\n\n");
  1514.     }
  1515.     }
  1516. }
  1517.  
  1518.  
  1519. /* Write a triangle (smooth or regular) */
  1520. void write_pov20_triangle (FILE *f, Triangle *tri, int one_texture)
  1521. {
  1522.     Vector norm[3];
  1523.     int    no_smooth = 0;
  1524.  
  1525.     COOPERATE    /* support multitasking */
  1526.  
  1527.     if (smooth_angle > 0.0) {
  1528.     vert_normal (tri, norm);
  1529.  
  1530.     if (vect_equal (norm[0], norm[1]) && vect_equal (norm[1], norm[2]))
  1531.         no_smooth = 1;
  1532.     }
  1533.  
  1534.     if (smooth_angle > 0.0 && !no_smooth) {
  1535.     fprintf (f, "smooth_triangle { <");
  1536.     vect_print (f, vtable[tri->vert[0]], dec_point, ',');
  1537.     fprintf (f, ">, <");
  1538.     vect_print (f, norm[0], 3, ',');
  1539.     fprintf (f, ">, <");
  1540.     vect_print (f, vtable[tri->vert[1]], dec_point, ',');
  1541.     fprintf (f, ">, <");
  1542.     vect_print (f, norm[1], 3, ',');
  1543.     fprintf (f, ">, <");
  1544.     vect_print (f, vtable[tri->vert[2]], dec_point, ',');
  1545.     fprintf (f, ">, <");
  1546.     vect_print (f, norm[2], 3, ',');
  1547.     fprintf (f, "> ");
  1548.     }
  1549.     else {
  1550.     fprintf (f, "triangle { <");
  1551.     vect_print (f, vtable[tri->vert[0]], dec_point, ',');
  1552.     fprintf (f, ">, <");
  1553.     vect_print (f, vtable[tri->vert[1]], dec_point, ',');
  1554.     fprintf (f, ">, <");
  1555.     vect_print (f, vtable[tri->vert[2]], dec_point, ',');
  1556.     fprintf (f, "> ");
  1557.     }
  1558.  
  1559.     if (!one_texture)
  1560.     write_pov20_texture (f, tri);
  1561.  
  1562.     fprintf (f, "}\n");
  1563. }
  1564.  
  1565.  
  1566. /* Write a bounding shape */
  1567. void write_pov20_bound (FILE *f, GroupTree *gnode)
  1568. {
  1569.     if (gnode->obj_cnt > 1) {
  1570.     fprintf (f, "\tbounded_by { box { <");
  1571.     vect_print (f, gnode->vmin, dec_point + 1, ',');
  1572.     fprintf (f, ">, <");
  1573.     vect_print (f, gnode->vmax, dec_point + 1, ',');
  1574.     fprintf (f, "> } }\n");
  1575.     }
  1576. }
  1577.  
  1578.  
  1579. /* Write a sub-tree to file */
  1580. void write_vivid_tree (FILE *f, GroupTree *gnode)
  1581. {
  1582.     TriList2  *t;
  1583.     int       last_index, last_type;
  1584.  
  1585.     last_index = -1;
  1586.     last_type  = -1;
  1587.  
  1588.     fprintf (f, "\n/* Object '%s' */\n", object_name);
  1589.  
  1590.     if (use_transform)
  1591.     write_vivid_transform (f, trans_matrix);
  1592.  
  1593.     if (gnode->child != NULL)
  1594.     abortmsg ("Internal error", 1);
  1595.  
  1596.     for (t = gnode->index[0]->next; t != gnode->index[0]; t = t->next) {
  1597.     if (t->tri->text_index != last_index ||
  1598.         t->tri->text_type != last_type)
  1599.     {
  1600.         write_vivid_texture (f, t->tri);
  1601.         last_index = t->tri->text_index;
  1602.         last_type  = t->tri->text_type;
  1603.     }
  1604.  
  1605.     write_vivid_triangle (f, t->tri);
  1606.     }
  1607.  
  1608.     if (use_transform)
  1609.     fprintf (f, "transform_pop\n\n");
  1610. }
  1611.  
  1612.  
  1613. /*
  1614.    Writes a transformation matrix as separate Vivid scale,
  1615.    rotate, and translate commands
  1616. */
  1617. void write_vivid_transform (FILE *f, Matrix matrix)
  1618. {
  1619.     Vector scale, shear, rotate, transl;
  1620.  
  1621.     /* Decode the matrix into separate operations */
  1622.     mat_decode (matrix, scale, shear, rotate, transl);
  1623.  
  1624.     fprintf (f, "\n/* Object transformation */\n");
  1625.  
  1626.     fprintf (f, "transform {\n");
  1627.  
  1628.     if (fabs(scale[X] - 1.0) > 0.001 || fabs(scale[Y] - 1.0) > 0.001 || fabs(scale[Z] - 1.0) > 0.001)
  1629.     fprintf (f, "\tscale %.3f %.3f %.3f\n", scale[X], scale[Y], scale[Z]);
  1630.  
  1631.     if (fabs(rotate[X]) > 0.01 || fabs(rotate[Y]) > 0.01 || fabs(rotate[Z]) > 0.01)
  1632.     fprintf (f, "\trotate %.2f %.2f %.2f\n", rotate[X], rotate[Y], rotate[Z]);
  1633.  
  1634.     if (fabs(transl[X]) > 0.0001 || fabs(transl[Y]) > 0.0001 || fabs(transl[Z]) > 0.0001)
  1635.     fprintf (f, "\ttranslate %.4f %.4f %.4f\n", transl[X], transl[Y], transl[Z]);
  1636.     else
  1637.     fprintf (f, "\ttranslate 0 0 0 // Null transformation\n");
  1638.  
  1639.     /* Can't handle shear but warn if it's there */
  1640.     if (fabs(shear[X]) > 0.01 || fabs(shear[Y]) > 0.01 || fabs(shear[Z]) > 0.01)
  1641.     printf ("Warning: Significant shear in transformation (ignored)\n");
  1642.  
  1643.     fprintf (f, "}\n\n");
  1644. }
  1645.  
  1646.  
  1647. void write_vivid_texture (FILE *f, Triangle *tri)
  1648. {
  1649.     if (tri->text_type == 1)
  1650.     fprintf (f, "\n%s /* New texture */\n\n", ttable[tri->text_index]);
  1651.     else
  1652.     fprintf (f, "\n%s_%u /* New texture */\n\n",
  1653.          object_name, tri->text_index + 1);
  1654. }
  1655.  
  1656.  
  1657. /* Write the Vivid file header */
  1658. void write_vivid_header (FILE *f)
  1659. {
  1660.     int i;
  1661.  
  1662.     if (psize > 0)
  1663.     fprintf (f, "/* Texture declarations for object '%s' */\n", object_name);
  1664.  
  1665.     for (i = 0; i < psize; i++) {
  1666.     fprintf (f, "#define %s_%u \\ \n", object_name, i + 1);
  1667.     fprintf (f, "    surface {           \\ \n");
  1668.     fprintf (f, "        diffuse %.3f %.3f %.3f \\ \n",
  1669.             ptable[i].red, ptable[i].green, ptable[i].blue);
  1670.     fprintf (f, "        shine 70 white  \\ \n");
  1671.     fprintf (f, "    }\n\n");
  1672.     }
  1673. }
  1674.  
  1675.  
  1676. /* Write a Vivid triangle patch */
  1677. void write_vivid_triangle (FILE *f, Triangle *tri)
  1678. {
  1679.     Vector norm[3];
  1680.  
  1681.     COOPERATE    /* support multitasking */
  1682.  
  1683.     vert_normal (tri, norm);
  1684.  
  1685.     fprintf (f, "patch {\n");
  1686.     fprintf (f, "\tvertex ");
  1687.     vect_print (f, vtable[tri->vert[0]], dec_point, ' ');
  1688.     fprintf (f, " normal ");
  1689.     vect_print (f, norm[0], 3, ' ');
  1690.     fprintf (f, "\n");
  1691.  
  1692.     fprintf (f, "\tvertex ");
  1693.     vect_print (f, vtable[tri->vert[1]], dec_point, ' ');
  1694.     fprintf (f, " normal ");
  1695.     vect_print (f, norm[1], 3, ' ');
  1696.     fprintf (f, "\n");
  1697.  
  1698.     fprintf (f, "\tvertex ");
  1699.     vect_print (f, vtable[tri->vert[2]], dec_point, ' ');
  1700.     fprintf (f, " normal ");
  1701.     vect_print (f, norm[2], 3, ' ');
  1702.     fprintf (f, "\n");
  1703.  
  1704.     fprintf (f, "}\n\n");
  1705. }
  1706.  
  1707.  
  1708. /* Write a sub-tree to file */
  1709. void write_polyray_tree (FILE *f, GroupTree *gnode)
  1710. {
  1711.     TriList2  *t;
  1712.  
  1713.     fprintf (f, "\n// Object '%s'\n\n", object_name);
  1714.  
  1715.     fprintf (f, "object {\n");
  1716.  
  1717.     if (gnode->child != NULL)
  1718.     abortmsg ("Internal error", 1);
  1719.  
  1720.     for (t = gnode->index[0]->next; t != gnode->index[0]; t = t->next) {
  1721.     if (t != gnode->index[0]->next)
  1722.         fprintf (f, "\t+\n");
  1723.  
  1724.     write_polyray_triangle (f, t->tri);
  1725.  
  1726.     fprintf (f, "\t\t");
  1727.     write_polyray_texture (f, t->tri);
  1728.     fprintf (f, "\n\t}\n\n");
  1729.     }
  1730.  
  1731.     if (use_transform)
  1732.     write_polyray_transform (f, trans_matrix);
  1733.  
  1734.     fprintf (f, "}\n\n");
  1735. }
  1736.  
  1737.  
  1738. /*
  1739.    Writes a transformation matrix as separate Polyray scale< >,
  1740.    rotate< >, and translate< > commands
  1741. */
  1742. void write_polyray_transform (FILE *f, Matrix matrix)
  1743. {
  1744.     Vector scale, shear, rotate, transl;
  1745.  
  1746.     /* Decode the matrix into separate operations */
  1747.     mat_decode (matrix, scale, shear, rotate, transl);
  1748.  
  1749.     fprintf (f, "\n\t// Object transformation\n");
  1750.  
  1751.     if (fabs(scale[X] - 1.0) > 0.001 || fabs(scale[Y] - 1.0) > 0.001 || fabs(scale[Z] - 1.0) > 0.001)
  1752.     fprintf (f, "\tscale <%.3f, %.3f, %.3f>\n", scale[X], scale[Y], scale[Z]);
  1753.  
  1754.     if (fabs(rotate[X]) > 0.01 || fabs(rotate[Y]) > 0.01 || fabs(rotate[Z]) > 0.01)
  1755.     fprintf (f, "\trotate <%.2f, %.2f, %.2f>\n", rotate[X], rotate[Y], rotate[Z]);
  1756.  
  1757.     if (fabs(transl[X]) > 0.0001 || fabs(transl[Y]) > 0.0001 || fabs(transl[Z]) > 0.0001)
  1758.     fprintf (f, "\ttranslate <%.4f, %.4f, %.4f>\n", transl[X], transl[Y], transl[Z]);
  1759.  
  1760.     /* Can't handle shear but warn if it's there */
  1761.     if (fabs(shear[X]) > 0.01 || fabs(shear[Y]) > 0.01 || fabs(shear[Z]) > 0.01)
  1762.     printf ("Warning: Significant shear in transformation (ignored)\n");
  1763. }
  1764.  
  1765.  
  1766. void write_polyray_texture (FILE *f, Triangle *tri)
  1767. {
  1768.     if (tri->text_type == 1)
  1769.     fprintf (f, "%s", ttable[tri->text_index]);
  1770.     else
  1771.     fprintf (f, "%s_%u",
  1772.          object_name, tri->text_index + 1);
  1773. }
  1774.  
  1775.  
  1776. /* Write the Polyray file header */
  1777. void write_polyray_header (FILE *f)
  1778. {
  1779.     int i;
  1780.  
  1781.     if (psize > 0)
  1782.     fprintf (f, "// Texture declarations for object '%s'\n", object_name);
  1783.  
  1784.     for (i = 0; i < psize; i++) {
  1785.     fprintf (f, "define %s_%u\n", object_name, i + 1);
  1786.     fprintf (f, "texture {\n");
  1787.     fprintf (f, "    surface {\n");
  1788.     fprintf (f, "        ambient <%.3f, %.3f, %.3f>, 0.1\n",
  1789.             ptable[i].red, ptable[i].green, ptable[i].blue);
  1790.     fprintf (f, "        diffuse <%.3f, %.3f, %.3f>, 0.7\n",
  1791.             ptable[i].red, ptable[i].green, ptable[i].blue);
  1792.     fprintf (f, "        specular white, 1.0\n");
  1793.     fprintf (f, "        microfacet Reitz 10\n");
  1794.     fprintf (f, "    }\n");
  1795.     fprintf (f, "}\n\n");
  1796.     }
  1797. }
  1798.  
  1799.  
  1800. /* Write a Polyray triangle patch */
  1801. void write_polyray_triangle (FILE *f, Triangle *tri)
  1802. {
  1803.     Vector norm[3];
  1804.  
  1805.     COOPERATE    /* support multitasking */
  1806.  
  1807.     vert_normal (tri, norm);
  1808.  
  1809.     fprintf (f, "\tobject {\n");
  1810.  
  1811.     fprintf (f, "\t\tpatch\t <");
  1812.     vect_print (f, vtable[tri->vert[0]], dec_point, ',');
  1813.     fprintf (f, ">, <");
  1814.     vect_print (f, norm[0], 3, ',');
  1815.     fprintf (f, ">,\n");
  1816.  
  1817.     fprintf (f, "\t\t\t <");
  1818.     vect_print (f, vtable[tri->vert[1]], dec_point, ',');
  1819.     fprintf (f, ">, <");
  1820.     vect_print (f, norm[1], 3, ',');
  1821.     fprintf (f, ">,\n");
  1822.  
  1823.     fprintf (f, "\t\t\t <");
  1824.     vect_print (f, vtable[tri->vert[2]], dec_point, ',');
  1825.     fprintf (f, ">, <");
  1826.     vect_print (f, norm[2], 3, ',');
  1827.     fprintf (f, ">\n");
  1828. }
  1829.  
  1830.  
  1831. /* Update the stats (area, vmin/vmax, child_cnt, etc.) for this node */
  1832. void update_node (GroupTree *gnode)
  1833. {
  1834.     GroupTree *g;
  1835.     TriList2  *t;
  1836.     int       i;
  1837.  
  1838.     vect_init (gnode->vmin, +MAXFLOAT, +MAXFLOAT, +MAXFLOAT);
  1839.     vect_init (gnode->vmax, -MAXFLOAT, -MAXFLOAT, -MAXFLOAT);
  1840.  
  1841.     gnode->obj_cnt   = 0;
  1842.     gnode->child_cnt = 0;
  1843.  
  1844.     if (gnode->index[0] == NULL) {
  1845.     /* Not a leaf node, calc the info from the child nodes */
  1846.  
  1847.     for (g = gnode->child; g != NULL; g = g->next) {
  1848.         ++(gnode->child_cnt);
  1849.  
  1850.         gnode->obj_cnt += g->obj_cnt;
  1851.  
  1852.         for (i = 0; i < 3; i++) {
  1853.         gnode->vmin[i] = fmin (gnode->vmin[i], g->vmin[i]);
  1854.         gnode->vmax[i] = fmax (gnode->vmax[i], g->vmax[i]);
  1855.         }
  1856.     }
  1857.     }
  1858.     else {
  1859.     /* A leaf node, calc the info from the triangle list */
  1860.  
  1861.     for (t = gnode->index[0]->next; t != gnode->index[0]; t = t->next) {
  1862.         ++(gnode->obj_cnt);
  1863.  
  1864.         for (i = 0; i < 3; i++) {
  1865.         gnode->vmin[i] = fmin (gnode->vmin[i], min_vertex (t->tri, i));
  1866.         gnode->vmax[i] = fmax (gnode->vmax[i], max_vertex (t->tri, i));
  1867.         }
  1868.     }
  1869.     }
  1870.  
  1871.     /* Update total surface area of region */
  1872.     gnode->area = surf_area (gnode->vmax[X] - gnode->vmin[X],
  1873.                  gnode->vmax[Y] - gnode->vmin[Y],
  1874.                  gnode->vmax[Z] - gnode->vmin[Z]);
  1875. }
  1876.  
  1877.  
  1878. void sort_indexes (GroupTree *gnode)
  1879. {
  1880.     int i;
  1881.  
  1882.     for (i = 0; i < 3; i++)
  1883.     quick_sort (gnode->index[i]->next, gnode->index[i]->prev, i);
  1884. }
  1885.  
  1886.  
  1887. void quick_sort (TriList2 *start, TriList2 *end, int axis)
  1888. {
  1889.     TriList2 *a, *b;
  1890.     Triangle *temp;
  1891.     float  middle;
  1892.  
  1893.     if (start == end)
  1894.     return;
  1895.  
  1896.     a = start;
  1897.     b = end;
  1898.     middle = avg_vertex (a->tri, axis);
  1899.  
  1900.     do {
  1901.     while (avg_vertex (b->tri, axis) >= middle && a != b)
  1902.         b = b->prev;
  1903.  
  1904.     if (a != b) {
  1905.         temp   = a->tri;
  1906.         a->tri = b->tri;
  1907.         b->tri = temp;
  1908.  
  1909.         while (avg_vertex (a->tri, axis) <= middle && a != b)
  1910.         a = a->next;
  1911.  
  1912.         if (a != b) {
  1913.         temp   = a->tri;
  1914.         a->tri = b->tri;
  1915.         b->tri = temp;
  1916.         }
  1917.     }
  1918.     } while (a != b);
  1919.  
  1920.     if (a != start)
  1921.     quick_sort (start, a->prev, axis);
  1922.  
  1923.     if (b != end)
  1924.     quick_sort (b->next, end, axis);
  1925. }
  1926.  
  1927.  
  1928. /* Calculate the surface area of a box */
  1929. float surf_area (float  a, float  b, float  c)
  1930. {
  1931.     return 2.0*(a*b + b*c + c*a);
  1932. }
  1933.  
  1934.  
  1935. float max_vertex (Triangle *tri, int axis)
  1936. {
  1937.     float  max_v, val;
  1938.     int i;
  1939.  
  1940.     max_v = -MAXFLOAT;
  1941.  
  1942.     for (i = 0; i < 3; i++) {
  1943.     val = vtable[tri->vert[i]][axis];
  1944.  
  1945.     if (val > max_v)
  1946.         max_v = val;
  1947.     }
  1948.  
  1949.     return max_v;
  1950. }
  1951.  
  1952.  
  1953. float min_vertex (Triangle *tri, int axis)
  1954. {
  1955.     float  min_v, val;
  1956.     int i;
  1957.  
  1958.     min_v = +MAXFLOAT;
  1959.  
  1960.     for (i = 0; i < 3; i++) {
  1961.     val = vtable[tri->vert[i]][axis];
  1962.  
  1963.     if (val < min_v)
  1964.         min_v = val;
  1965.     }
  1966.  
  1967.     return min_v;
  1968. }
  1969.  
  1970.  
  1971. float avg_vertex (Triangle *tri, int axis)
  1972. {
  1973.     float  avg;
  1974.  
  1975.     avg = (vtable[tri->vert[0]][axis] + vtable[tri->vert[1]][axis] +
  1976.        vtable[tri->vert[2]][axis])/3.0;
  1977.  
  1978.     return avg;
  1979. }
  1980.  
  1981.  
  1982. /* Build an index of which triangles touch each vertex.  Used to */
  1983. /* speed up smooth triangle normal calculations. */
  1984. void build_tri_index()
  1985. {
  1986.     GroupTree *g;
  1987.     TriList   *temp;
  1988.     TriList2  *t;
  1989.     unsigned  i, vert_no;
  1990.  
  1991.     if (vsize == 0)
  1992.     return;
  1993.  
  1994.     tri_index = malloc (vsize * sizeof(TriList));
  1995.     if (tri_index == NULL)
  1996.     abortmsg ("Insufficient memory for smooth triangles.", 1);
  1997.  
  1998.     for (i = 0; i < vsize; i++)
  1999.     tri_index[i] = NULL;
  2000.  
  2001.     for (g = groot; g != NULL; g = g->next) {
  2002.     for (t = g->index[0]->next; t != g->index[0]; t = t->next) {
  2003.         for (i = 0; i < 3; i++) {
  2004.         vert_no = t->tri->vert[i];
  2005.         temp = tri_index[vert_no];
  2006.         tri_index[vert_no] = malloc (sizeof(TriList));
  2007.         if (tri_index[vert_no] == NULL)
  2008.             abortmsg ("Insufficient memory for smooth triangles.\n", 1);
  2009.  
  2010.         tri_index[vert_no]->tri = t->tri;
  2011.         tri_index[vert_no]->next = temp;
  2012.         }
  2013.     }
  2014.     }
  2015.  
  2016. }
  2017.  
  2018.  
  2019. void dump_tri_index()
  2020. {
  2021.     TriList *temp;
  2022.     int     i;
  2023.  
  2024.     for (i = 0; i < vsize; i++) {
  2025.     while (tri_index[i] != NULL) {
  2026.         temp = tri_index[i];
  2027.         tri_index[i] = tri_index[i]->next;
  2028.         free (temp);
  2029.     }
  2030.     }
  2031.  
  2032.     free (tri_index);
  2033. }
  2034.  
  2035.  
  2036. /* Calculates the smooth triangle normal for this vertex */
  2037. void vert_normal (Triangle *t, Vector *norm)
  2038. {
  2039.     Vector  curr_norm, new_norm;
  2040.     TriList *p;
  2041.     int     i;
  2042.  
  2043.     tri_normal (t, curr_norm);
  2044.  
  2045.     if (smooth_angle <= 0.0) {
  2046.     for (i = 0; i < 3; i++)
  2047.         vect_copy (norm[i], curr_norm);
  2048.  
  2049.     return;
  2050.     }
  2051.  
  2052.     for (i = 0; i < 3; i++) {
  2053.     vect_init (norm[i], 0.0, 0.0, 0.0);
  2054.  
  2055.     for (p = tri_index[t->vert[i]]; p != NULL; p = p->next) {
  2056.         tri_normal (p->tri, new_norm);
  2057.         if (vect_angle (curr_norm, new_norm) < smooth_angle)
  2058.         vect_add (norm[i], norm[i], new_norm);
  2059.     }
  2060.  
  2061.     vect_normalize (norm[i]);
  2062.     }
  2063. }
  2064.  
  2065.  
  2066. /* Calculates the normal to the specified triangle */
  2067. void tri_normal (Triangle *t, Vector normal)
  2068. {
  2069.     Vector ab, ac;
  2070.  
  2071.     vect_sub (ab, vtable[t->vert[1]], vtable[t->vert[0]]);
  2072.     vect_sub (ac, vtable[t->vert[2]], vtable[t->vert[0]]);
  2073.     vect_cross (normal, ac, ab);
  2074.  
  2075.     vect_normalize (normal);
  2076. }
  2077.  
  2078.  
  2079. /* Find the specified rgb values in the palette table */
  2080. unsigned pal_lookup (float  red, float  green, float  blue)
  2081. {
  2082.     int i;
  2083.  
  2084.     /* The palette table is usually small so just do a simple linear search */
  2085.     for (i = psize-1; i >= 0; i--) {
  2086.     if (ptable[i].red   == red &&
  2087.         ptable[i].green == green &&
  2088.         ptable[i].blue  == blue)
  2089.       break;
  2090.     }
  2091.  
  2092.     if (i >= 0)
  2093.     return i;    /* found, return the table index */
  2094.  
  2095.     /* not found, insert the new palette into the table */
  2096.     ++psize;
  2097.     if (psize > pmax) {
  2098.     /* table not big enough, resize it */
  2099.     pmax = pmax + 10;
  2100.     ptable = realloc (ptable, pmax * sizeof(Palette));
  2101.     if (ptable == NULL)
  2102.         abortmsg ("Insufficient memory to expand palette table.", 1);
  2103.     }
  2104.  
  2105.     ptable[psize-1].red   = red;
  2106.     ptable[psize-1].green = green;
  2107.     ptable[psize-1].blue  = blue;
  2108.  
  2109.     return (psize-1);
  2110. }
  2111.  
  2112.  
  2113. /* Find the specified named texture in the texture table */
  2114. unsigned texture_lookup (char *texture_name)
  2115. {
  2116.     int i;
  2117.  
  2118.     /* The texture table is usually small so just do a simple linear search */
  2119.     for (i = tsize-1; i >= 0; i--) {
  2120.     if (strcmp (ttable[i], texture_name) == 0)
  2121.         break;
  2122.     }
  2123.  
  2124.     if (i >= 0)
  2125.     return i;    /* found, return the table index */
  2126.  
  2127.     /* not found, insert the new texture into the table */
  2128.     ++tsize;
  2129.     if (tsize > tmax) {
  2130.     /* table not big enough, resize it */
  2131.     tmax = tmax + 10;
  2132.     ttable = realloc (ttable, tmax * sizeof(Texture));
  2133.     if (ttable == NULL)
  2134.         abortmsg ("Insufficient memory to expand palette table.", 1);
  2135.     }
  2136.  
  2137.     ttable[tsize-1] = malloc (strlen(texture_name) + 1);
  2138.     if (ttable[tsize-1] == NULL)
  2139.     abortmsg ("Insufficient memory for texture name.", 1);
  2140.  
  2141.     strcpy (ttable[tsize-1], texture_name);
  2142.  
  2143.     return (tsize-1);
  2144. }
  2145.  
  2146.  
  2147. /* Find the specified vertex in the vertex table */
  2148. unsigned vert_lookup (float  x, float  y, float  z)
  2149. {
  2150.     VertList *p, *new_node;
  2151.     unsigned hash;
  2152.  
  2153.     /* Vertex table is usually very large, use hash lookup */
  2154.     hash = (unsigned)((int)(326.4*x) ^ (int)(694.7*y) ^ (int)(1423.6*z)) % HASHSIZE;
  2155.  
  2156.     for (p = vert_hash[hash]; p != NULL; p = p->next) {
  2157.     if (vtable[p->vert][0] == x && vtable[p->vert][1] == y &&
  2158.         vtable[p->vert][2] == z) break;
  2159.     }
  2160.  
  2161.     if (p != NULL)
  2162.     return (p->vert);   /* found, return the table index */
  2163.  
  2164.     /* not found, insert the new vertex into the table */
  2165.     ++vsize;
  2166.     if (vsize > vmax) {
  2167.     /* table not big enough, expand it */
  2168.     vmax = vmax + 100;
  2169.     vtable = realloc (vtable, vmax * sizeof(Vector));
  2170.     if (vtable == NULL)
  2171.         abortmsg ("Insufficient memory for vertices.\n", 1);
  2172.     }
  2173.  
  2174.     vect_init (vtable[vsize-1], x, y, z);
  2175.  
  2176.     new_node = malloc (sizeof(VertList));
  2177.     if (new_node == NULL)
  2178.     abortmsg ("Insufficient memory for hash table.", 1);
  2179.  
  2180.     new_node->vert  = vsize-1;
  2181.     new_node->next  = vert_hash[hash];
  2182.     vert_hash[hash] = new_node;
  2183.  
  2184.     return (vsize-1);
  2185. }
  2186.  
  2187.  
  2188. /* Checks if triangle is degenerate (zero area) */
  2189. int  degen_tri (float  ax, float  ay, float  az,
  2190.         float  bx, float  by, float  bz,
  2191.         float  cx, float  cy, float  cz)
  2192. {
  2193.     Vector  ab, ac, norm;
  2194.     double  mag, fact;
  2195.  
  2196.     fact = pow (10.0, dec_point);
  2197.  
  2198.     /* Round the coords off to the output precision before checking */
  2199.     ax = floor((ax*fact) + 0.5)/fact;
  2200.     ay = floor((ay*fact) + 0.5)/fact;
  2201.     az = floor((az*fact) + 0.5)/fact;
  2202.     bx = floor((bx*fact) + 0.5)/fact;
  2203.     by = floor((by*fact) + 0.5)/fact;
  2204.     bz = floor((bz*fact) + 0.5)/fact;
  2205.     cx = floor((cx*fact) + 0.5)/fact;
  2206.     cy = floor((cy*fact) + 0.5)/fact;
  2207.     cz = floor((cz*fact) + 0.5)/fact;
  2208.  
  2209.     vect_init (ab, ax-bx, ay-by, az-bz);
  2210.     vect_init (ac, ax-cx, ay-cy, az-cz);
  2211.     vect_cross (norm, ab, ac);
  2212.  
  2213.     mag = vect_mag(norm);
  2214.  
  2215.     return (mag < DEGEN_TOL);
  2216. }
  2217.  
  2218.  
  2219. void abortmsg (char *msg, int exit_code)
  2220. {
  2221.     printf ("\n%s\n", msg);
  2222.     exit (exit_code);
  2223. }
  2224.  
  2225.  
  2226. float  fmin (float  a, float  b)
  2227. {
  2228.     if (a < b)
  2229.     return a;
  2230.     else
  2231.     return b;
  2232. }
  2233.  
  2234.  
  2235. float  fmax (float  a, float  b)
  2236. {
  2237.     if (a > b)
  2238.     return a;
  2239.     else
  2240.     return b;
  2241. }
  2242.  
  2243.  
  2244. void add_ext (char *fname, char *ext, int force)
  2245. {
  2246.     int i;
  2247.  
  2248.     for (i = 0; i < strlen(fname); i++)
  2249.     if (fname[i] == '.') break;
  2250.  
  2251.     if (fname[i] == '\0' || force) {
  2252.     if (strlen(ext) > 0)
  2253.         fname[i++] = '.';
  2254.  
  2255.     strcpy (&fname[i], ext);
  2256.     }
  2257. }
  2258.  
  2259.  
  2260. void cleanup_name (char *name)
  2261. {
  2262.     char *tmp = malloc (strlen(name)+1);
  2263.     int  i;
  2264.  
  2265.     /* Remove any leading blanks or quotes */
  2266.     i = 0;
  2267.     while ((name[i] == ' ' || name[i] == '"') && name[i] != '\0')
  2268.     i++;
  2269.  
  2270.     strcpy (tmp, &name[i]);
  2271.  
  2272.     /* Remove any trailing blanks or quotes */
  2273.     for (i = strlen(tmp)-1; i >= 0; i--) {
  2274.     if (isprint(tmp[i]) && !isspace(tmp[i]) && tmp[i] != '"')
  2275.         break;
  2276.     else
  2277.         tmp[i] = '\0';
  2278.     }
  2279.  
  2280.     strcpy (name, tmp);
  2281.  
  2282.     /* Prefix the letter 'N' to materials that begin with a digit */
  2283.     if (!isdigit (name[0]))
  2284.        strcpy (tmp, name);
  2285.     else {
  2286.        tmp[0] = 'N';
  2287.        strcpy (&tmp[1], name);
  2288.     }
  2289.  
  2290.     /* Replace all illegal charaters in name with underscores */
  2291.     for (i = 0; tmp[i] != '\0'; i++) {
  2292.        if (!isalnum(tmp[i]))
  2293.        tmp[i] = '_';
  2294.     }
  2295.  
  2296.     strcpy (name, tmp);
  2297.  
  2298.     free (tmp);
  2299. }
  2300.  
  2301.  
  2302.