ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/cv/mgflib/rayopt.c
Revision: 1.3
Committed: Sat Nov 15 15:53:31 2003 UTC (20 years, 11 months ago) by schorsch
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R7P1, rad3R6, rad3R6P1, rad3R8, rad3R7P2
Changes since 1.2: +2 -2 lines
Log Message:
Fixed missing fprintf() argument to include object name for box.

File Contents

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