ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/rayopt3ds.c
Revision: 2.1
Committed: Fri Feb 18 00:40:25 2011 UTC (13 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R4, rad5R2, rad4R2P2, rad5R0, rad5R1, rad4R2, rad4R1, rad4R2P1, rad5R3, HEAD
Log Message:
Major code reorg, moving mgflib to common and introducing BSDF material

File Contents

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