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

File Contents

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