ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/mgflib/rayopt.c
Revision: 1.2
Committed: Fri Feb 28 20:11:30 2003 UTC (21 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R5
Changes since 1.1: +0 -0 lines
Log Message:
Updates for 3.5 release

File Contents

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