ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/mgflib/rayopt.c
Revision: 1.4
Committed: Wed Sep 5 01:36:37 2007 UTC (16 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad4R0, rad3R9
Changes since 1.3: +3 -6 lines
Log Message:
Copyright fixes

File Contents

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