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, 7 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

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rayopt.c,v 1.3 2003/11/15 15:53:31 schorsch 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 "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 if (object_name[0]) fprintf (f, "o %s\n", object_name);
1218 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