1 /****************************************************************************
2 * vbuffer.cpp
3 *
4 * This module implements functions that implement the vista buffer.
5 *
6 * This module was written by Dieter Bayer [DB].
7 *
8 * from Persistence of Vision(tm) Ray Tracer version 3.6.
9 * Copyright 1991-2003 Persistence of Vision Team
10 * Copyright 2003-2004 Persistence of Vision Raytracer Pty. Ltd.
11 *---------------------------------------------------------------------------
12 * NOTICE: This source code file is provided so that users may experiment
13 * with enhancements to POV-Ray and to port the software to platforms other
14 * than those supported by the POV-Ray developers. There are strict rules
15 * regarding how you are permitted to use this file. These rules are contained
16 * in the distribution and derivative versions licenses which should have been
17 * provided with this file.
18 *
19 * These licences may be found online, linked from the end-user license
20 * agreement that is located at http://www.povray.org/povlegal.html
21 *---------------------------------------------------------------------------
22 * This program is based on the popular DKB raytracer version 2.12.
23 * DKBTrace was originally written by David K. Buck.
24 * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
25 *---------------------------------------------------------------------------
26 * $File: //depot/povray/3.6-release/source/vbuffer.cpp $
27 * $Revision: #3 $
28 * $Change: 3032 $
29 * $DateTime: 2004/08/02 18:43:41 $
30 * $Author: chrisc $
31 * $Log$
32 *****************************************************************************/
33
34 #include "frame.h"
35 #include "vector.h"
36 #include "povray.h"
37 #include "bbox.h"
38 #include "boxes.h"
39 #include "hfield.h"
40 #include "lightgrp.h"
41 #include "lighting.h"
42 #include "matrices.h"
43 #include "objects.h"
44 #include "render.h"
45 #include "triangle.h"
46 #include "vbuffer.h"
47 #include "vlbuffer.h"
48 #include "userio.h"
49 #include "userdisp.h"
50 #include "optout.h"
51 #include "photons.h"
52 #include "povmsend.h"
53
54 #include <algorithm>
55
56 BEGIN_POV_NAMESPACE
57
58 /*****************************************************************************
59 * Global variabls
60 ******************************************************************************/
61
62 extern PRIORITY_QUEUE *VLBuffer_Queue; // GLOBAL VARIABLE
63 extern PROJECT_QUEUE *Node_Queue; // GLOBAL VARIABLE
64
65
66 /*****************************************************************************
67 * Local preprocessor defines
68 ******************************************************************************/
69
70
71
72 /*****************************************************************************
73 * Local typedefs
74 ******************************************************************************/
75
76
77
78 /*****************************************************************************
79 * Local variables
80 ******************************************************************************/
81
82 static DBL Distance; // GLOBAL VARIABLE
83 static MATRIX WC2VC, WC2VCinv; // GLOBAL VARIABLE
84 static VECTOR gO, gU, gV, gW; // GLOBAL VARIABLE
85
86
87 /* Planes for 3d-clipping. */
88
89 const VECTOR VIEW_VX1 = {-0.8944271910, 0.0, -0.4472135955};
90 const VECTOR VIEW_VX2 = { 0.8944271910, 0.0, -0.4472135955};
91 const VECTOR VIEW_VY1 = {0.0, -0.8944271910, -0.4472135955};
92 const VECTOR VIEW_VY2 = {0.0, 0.8944271910, -0.4472135955};
93 const DBL VIEW_DX1 = 0.4472135955;
94 const DBL VIEW_DX2 = 0.4472135955;
95 const DBL VIEW_DY1 = 0.4472135955;
96 const DBL VIEW_DY2 = 0.4472135955;
97
98 static PROJECT_TREE_NODE *Root_Vista; // GLOBAL VARIABLE
99
100
101 /*****************************************************************************
102 * Static functions
103 ******************************************************************************/
104
105 static void init_view_coordinates (void);
106
107 static void project_raw_rectangle (PROJECT *Project, VECTOR P1, VECTOR P2, VECTOR P3, VECTOR P4, int *visible);
108 static void project_raw_triangle (PROJECT *Project, VECTOR P1, VECTOR P2, VECTOR P3, int *visible);
109
110 static void project_bbox (PROJECT *Project, VECTOR *P, int *visible);
111 static void project_bounds (PROJECT *Project, BBOX *BBox, int *visible);
112
113 static void get_perspective_projection (OBJECT *Object, PROJECT *Project, int infinite);
114 static void get_orthographic_projection (OBJECT *Object, PROJECT *Project, int infinite);
115
116 static void project_object (OBJECT *Object, PROJECT *Project);
117
118 static void project_box (PROJECT *Project, OBJECT *Object, int *visible);
119 static void project_hfield (PROJECT *Project, OBJECT *Object, int *visible);
120 static void project_triangle (PROJECT *Project, OBJECT *Object, int *visible);
121 static void project_smooth_triangle (PROJECT *Project, OBJECT *Object, int *visible);
122
123 static void transform_point (VECTOR P);
124
125 static void project_bounding_slab (PROJECT *Project, PROJECT_TREE_NODE **Tree, BBOX_TREE *Node);
126
127 static int intersect_vista_tree (RAY *Ray, PROJECT_TREE_NODE *Tree, int x, INTERSECTION *Best_Intersection);
128
129 static void draw_projection (PROJECT *Project, int color, int *BigRed, int *BigBlue);
130 static void draw_vista (PROJECT_TREE_NODE *Tree, int *BigRed, int *BigBlue);
131
132 /*****************************************************************************
133 *
134 * FUNCTION
135 *
136 * Prune_Vista_Tree
137 *
138 * INPUT
139 *
140 * y - Current scanline number
141 *
142 * OUTPUT
143 *
144 * RETURNS
145 *
146 * AUTHOR
147 *
148 * Dieter Bayer
149 *
150 * DESCRIPTION
151 *
152 * Prune vista tree, i.e. mark all nodes not on the current line inactive.
153 *
154 * CHANGES
155 *
156 * May 1994 : Creation.
157 *
158 ******************************************************************************/
159
Prune_Vista_Tree(int y)160 void Prune_Vista_Tree(int y)
161 {
162 unsigned short i;
163 PROJECT_TREE_NODE *Node, *Sib;
164
165 /* If there's no vista tree then return. */
166
167 if (Root_Vista == NULL)
168 {
169 return;
170 }
171
172 Node_Queue->QSize = 0;
173
174 Increase_Counter(stats[VBuffer_Tests]);
175
176 if ((y < Root_Vista->Project.y1) || (y > Root_Vista->Project.y2))
177 {
178 /* Root doesn't lie on current line --> prune root */
179
180 Root_Vista->is_leaf |= PRUNE_TEMPORARY;
181 }
182 else
183 {
184 /* Root lies on current line --> unprune root */
185
186 Increase_Counter(stats[VBuffer_Tests_Succeeded]);
187
188 Root_Vista->is_leaf &= ~PRUNE_TEMPORARY;
189
190 Node_Queue->Queue[(Node_Queue->QSize)++] = Root_Vista;
191 }
192
193 while (Node_Queue->QSize > 0)
194 {
195 Node = Node_Queue->Queue[--(Node_Queue->QSize)];
196
197 if (Node->is_leaf & true)
198 {
199 Increase_Counter(stats[VBuffer_Tests]);
200
201 if ((y < Node->Project.y1) || (y > Node->Project.y2))
202 {
203 /* Leaf doesn't lie on current line --> prune leaf */
204
205 Node->is_leaf |= PRUNE_TEMPORARY;
206 }
207 else
208 {
209 /* Leaf lies on current line --> unprune leaf */
210
211 Increase_Counter(stats[VBuffer_Tests_Succeeded]);
212
213 Node->is_leaf &= ~PRUNE_TEMPORARY;
214 }
215 }
216 else
217 {
218 /* Check siblings of the node */
219
220 for (i = 0; i < Node->Entries; i++)
221 {
222 Sib = Node->Entry[i];
223
224 Increase_Counter(stats[VBuffer_Tests]);
225
226 if ((y < Sib->Project.y1) || (y > Sib->Project.y2))
227 {
228 /* Sibling doesn't lie on current line --> prune sibling */
229
230 Sib->is_leaf |= PRUNE_TEMPORARY;
231 }
232 else
233 {
234 /* Sibling lies on current line --> unprune sibling */
235
236 Increase_Counter(stats[VBuffer_Tests_Succeeded]);
237
238 Sib->is_leaf &= ~PRUNE_TEMPORARY;
239
240 /* Add sibling to list */
241
242 /* Reallocate queue if it's too small. */
243
244 Reinitialize_VLBuffer_Code();
245
246 Node_Queue->Queue[(Node_Queue->QSize)++] = Sib;
247 }
248 }
249 }
250 }
251 }
252
253
254
255 /*****************************************************************************
256 *
257 * FUNCTION
258 *
259 * Trace_Primary_Ray
260 *
261 * INPUT
262 *
263 * Ray - Current ray
264 * Colour - Ray's colour
265 * x - Current x-coordinate
266 *
267 * OUTPUT
268 *
269 * colour
270 *
271 * RETURNS
272 *
273 * AUTHOR
274 *
275 * Dieter Bayer
276 *
277 * DESCRIPTION
278 *
279 * Trace a primary ray using the vista tree.
280 *
281 * CHANGES
282 *
283 * May 1994 : Creation.
284 *
285 * Nov 1994 : Rearranged calls to Fog, Ranibow and Skyblend.
286 * Added call to Atmosphere for atmospheric effects. [DB]
287 *
288 * Jan 1995 : Set intersection depth to Max_Distance for infinte rays. [DB]
289 * Jul 1995 : Added code to support alpha channel. [DB]
290 *
291 ******************************************************************************/
292
Trace_Primary_Ray(RAY * Ray,COLOUR Colour,DBL Weight,int x)293 DBL Trace_Primary_Ray (RAY *Ray, COLOUR Colour, DBL Weight, int x)
294 {
295 int i, Intersection_Found, all_hollow;
296 INTERSECTION Best_Intersection;
297
298 Do_Cooperate(1);
299 Increase_Counter(stats[Number_Of_Rays]);
300
301 Make_ColourA(Colour, 0.0, 0.0, 0.0, 0.0, 0.0);
302
303 if ((Trace_Level > Max_Trace_Level) || (Weight < ADC_Bailout))
304 {
305 if (Weight < ADC_Bailout)
306 {
307 Increase_Counter(stats[ADC_Saves]);
308 }
309
310 return BOUND_HUGE;
311 }
312
313 if (Trace_Level > Highest_Trace_Level)
314 {
315 Highest_Trace_Level = Trace_Level;
316 }
317
318 Best_Intersection.Depth = BOUND_HUGE;
319 Best_Intersection.Object = NULL;
320
321 /* What objects does this ray intersect? */
322
323 Intersection_Found = intersect_vista_tree(Ray, Root_Vista, x, &Best_Intersection);
324
325 if (Intersection_Found)
326 {
327 Determine_Apparent_Colour(&Best_Intersection, Colour, Ray, 1.0);
328 }
329 else
330 {
331 /* Infinite ray, set intersection distance. */
332
333 Best_Intersection.Depth = Max_Distance;
334
335 Do_Infinite_Atmosphere(Ray, Colour);
336 }
337
338 /* Test if all contained objects are hollow. */
339
340 all_hollow = true;
341
342 if (Ray->Index > -1)
343 {
344 for (i = 0; i <= Ray->Index; i++)
345 {
346 if (!Ray->Interiors[i]->hollow)
347 {
348 all_hollow = false;
349
350 break;
351 }
352 }
353 }
354
355 /* Apply finite atmospheric effects. */
356 if (all_hollow && (opts.Quality_Flags & Q_VOLUME))
357 {
358 Do_Finite_Atmosphere(Ray, &Best_Intersection, Colour, false);
359 }
360
361 return (Best_Intersection.Depth);
362 }
363
364
365
366 /*****************************************************************************
367 *
368 * FUNCTION
369 *
370 * intersect_vista_tree
371 *
372 * INPUT
373 *
374 * Ray - Primary ray
375 * Tree - Vista tree's top-node
376 * x - Current x-coordinate
377 * Best_Intersection - Intersection found
378 *
379 * OUTPUT
380 *
381 * Best_Intersection
382 *
383 * RETURNS
384 *
385 * AUTHOR
386 *
387 * Dieter Bayer
388 *
389 * DESCRIPTION
390 *
391 * Intersect a PRIMARY ray with the vista tree
392 * (tree pruning is used can be primary ray!!!).
393 *
394 * CHANGES
395 *
396 * May 1994 : Creation.
397 * Aug 1997 : Add object-ray options. Test whether the ray should
398 * intersect with objects based on "no_image" and
399 * "no_reflection" tags. [ENB]
400 *
401 ******************************************************************************/
402
intersect_vista_tree(RAY * Ray,PROJECT_TREE_NODE * Tree,int x,INTERSECTION * Best_Intersection)403 static int intersect_vista_tree(RAY *Ray, PROJECT_TREE_NODE *Tree, int x, INTERSECTION *Best_Intersection)
404 {
405 INTERSECTION New_Intersection;
406 unsigned short i;
407 int Found;
408 RAYINFO rayinfo;
409 DBL key;
410 BBOX_TREE *BBox_Node;
411 PROJECT_TREE_NODE *Node;
412
413 /* If there's no vista tree then return. */
414
415 if (Tree == NULL)
416 {
417 return(false);
418 }
419
420 /* Start with an empty priority queue */
421
422 New_Intersection.Object = NULL;
423
424 VLBuffer_Queue->QSize = 0;
425
426 Found = false;
427
428 #ifdef BBOX_EXTRA_STATS
429 Increase_Counter(stats[totalQueueResets]);
430 #endif
431
432 /* Descend tree. */
433
434 Node_Queue->QSize = 0;
435
436 /* Create the direction vectors for this ray */
437
438 Create_Rayinfo(Ray, &rayinfo);
439
440 /* Fill the priority queue with all possible candidates */
441
442 /* Check root */
443
444 Increase_Counter(stats[VBuffer_Tests]);
445
446 if ((x >= Tree->Project.x1) && (x <= Tree->Project.x2))
447 {
448 Increase_Counter(stats[VBuffer_Tests_Succeeded]);
449
450 Node_Queue->Queue[(Node_Queue->QSize)++] = Tree;
451 }
452
453 while (Node_Queue->QSize > 0)
454 {
455 Tree = Node_Queue->Queue[--(Node_Queue->QSize)];
456
457 switch (Tree->is_leaf)
458 {
459 case false:
460
461 /* Check siblings of the unpruned node in 2d */
462
463 for (i = 0; i < Tree->Entries; i++)
464 {
465 Node = Tree->Entry[i];
466
467 /* Check unpruned siblings only */
468
469 if (Node->is_leaf < PRUNE_CHECK)
470 {
471 Increase_Counter(stats[VBuffer_Tests]);
472
473 if ((x >= Node->Project.x1) && (x <= Node->Project.x2))
474 {
475 /* Add node to node queue. */
476
477 Increase_Counter(stats[VBuffer_Tests_Succeeded]);
478
479 /* Reallocate queue if it's too small. */
480
481 Reinitialize_VLBuffer_Code();
482
483 Node_Queue->Queue[(Node_Queue->QSize)++] = Node;
484 }
485 }
486 }
487
488 break;
489
490 case true:
491
492 /* Unpruned leaf --> test object's bounding box in 3d */
493
494 Check_And_Enqueue(VLBuffer_Queue,
495 ((PROJECT_TREE_LEAF *)Tree)->Node,
496 &(((PROJECT_TREE_LEAF *)Tree)->Node->BBox),
497 &rayinfo);
498
499 break;
500
501 /* default:
502
503 The node/leaf is pruned and needn't be checked */
504
505 }
506 }
507
508 /* Now test the candidates in the priority queue */
509
510 while (VLBuffer_Queue->QSize > 0)
511 {
512 Priority_Queue_Delete(VLBuffer_Queue, &key, &BBox_Node);
513
514 if (key > Best_Intersection->Depth)
515 break;
516
517 /* Add Object-Ray options [ENB 9/97] */
518 if ( TEST_RAY_FLAGS((OBJECT *)BBox_Node->Node) )
519 {
520 if (Intersection(&New_Intersection, (OBJECT *)BBox_Node->Node, Ray))
521 {
522 if (New_Intersection.Depth < Best_Intersection->Depth)
523 {
524 *Best_Intersection = New_Intersection;
525 Found = true;
526 }
527 }
528 }
529 }
530
531 return(Found);
532 }
533
534
535 /*****************************************************************************
536 *
537 * FUNCTION
538 *
539 * project_raw_triangle
540 *
541 * INPUT
542 *
543 * Project - Triangle's projection
544 * P1, P2, P3 - Triangle's edges
545 * visible - Flag if triangle is visible
546 *
547 * OUTPUT
548 *
549 * Project, visible
550 *
551 * RETURNS
552 *
553 * AUTHOR
554 *
555 * Dieter Bayer
556 *
557 * DESCRIPTION
558 *
559 * Project a triangle onto the screen.
560 *
561 * CHANGES
562 *
563 * May 1994 : Creation.
564 *
565 ******************************************************************************/
566
project_raw_triangle(PROJECT * Project,VECTOR P1,VECTOR P2,VECTOR P3,int * visible)567 static void project_raw_triangle (PROJECT *Project, VECTOR P1, VECTOR P2, VECTOR P3, int *visible)
568 {
569 VECTOR Points[MAX_CLIP_POINTS];
570 int i, number;
571 int x, y;
572
573 Assign_Vector(Points[0], P1);
574 Assign_Vector(Points[1], P2);
575 Assign_Vector(Points[2], P3);
576
577 number = 3;
578
579 /* Clip triangle only if some quick tests say it's necessary.
580 Assuming that only a few triangles need clipping this saves some time.
581 (I don't need to write fabs(1+P?[Z]) since the tests succeed anyway if
582 P?[Z] < -1. Hope the compiler doesn't change the tests' order!) */
583
584 if ((P1[Z] < -1.0) || (P2[Z] < -1.0) || (P3[Z] < -1.0) ||
585 (fabs(P1[X]) > 0.5*(1.0+P1[Z])) || (fabs(P1[Y]) > 0.5*(1.0+P1[Z])) ||
586 (fabs(P2[X]) > 0.5*(1.0+P2[Z])) || (fabs(P2[Y]) > 0.5*(1.0+P2[Z])) ||
587 (fabs(P3[X]) > 0.5*(1.0+P3[Z])) || (fabs(P3[Y]) > 0.5*(1.0+P3[Z])))
588 {
589 Clip_Polygon(Points, &number, VIEW_VX1, VIEW_VX2, VIEW_VY1, VIEW_VY2,
590 VIEW_DX1, VIEW_DX2, VIEW_DY1, VIEW_DY2);
591 }
592
593 if (number)
594 {
595 for (i = 0; i < number; i++)
596 {
597 if (Points[i][Z] < -1.0 + EPSILON)
598 {
599 Points[i][X] = Points[i][Y] = 0.0;
600 }
601 else
602 {
603 Points[i][X] /= 1.0 + Points[i][Z];
604 Points[i][Y] /= 1.0 + Points[i][Z];
605 }
606
607 x = Frame.Screen_Width/2 + (int)(Frame.Screen_Width * Points[i][X]);
608 y = Frame.Screen_Height/2 - (int)(Frame.Screen_Height * Points[i][Y]);
609
610 if (x < Project->x1) Project->x1 = x;
611 if (x > Project->x2) Project->x2 = x;
612 if (y < Project->y1) Project->y1 = y;
613 if (y > Project->y2) Project->y2 = y;
614 }
615
616 *visible = true;
617 }
618 }
619
620
621
622 /*****************************************************************************
623 *
624 * FUNCTION
625 *
626 * project_raw_rectangle
627 *
628 * INPUT
629 *
630 * Project - Rectangle's projection
631 * P1, P2, P3, P4 - Rectangle's edges
632 * visible - Flag if rectangle is visible
633 *
634 * OUTPUT
635 *
636 * Project, visible
637 *
638 * RETURNS
639 *
640 * AUTHOR
641 *
642 * Dieter Bayer
643 *
644 * DESCRIPTION
645 *
646 * Project a rectangle onto the screen.
647 *
648 * CHANGES
649 *
650 * May 1994 : Creation.
651 *
652 ******************************************************************************/
653
project_raw_rectangle(PROJECT * Project,VECTOR P1,VECTOR P2,VECTOR P3,VECTOR P4,int * visible)654 static void project_raw_rectangle(PROJECT *Project, VECTOR P1, VECTOR P2, VECTOR P3, VECTOR P4, int *visible)
655 {
656 VECTOR Points[MAX_CLIP_POINTS];
657 int i, number;
658 int x, y;
659
660 Assign_Vector(Points[0], P1);
661 Assign_Vector(Points[1], P2);
662 Assign_Vector(Points[2], P3);
663 Assign_Vector(Points[3], P4);
664
665 number = 4;
666
667 Clip_Polygon(Points, &number, VIEW_VX1, VIEW_VX2, VIEW_VY1, VIEW_VY2,
668 VIEW_DX1, VIEW_DX2, VIEW_DY1, VIEW_DY2);
669
670 if (number)
671 {
672 for (i = 0; i < number; i++)
673 {
674 if (Points[i][Z] < -1.0 + EPSILON)
675 {
676 Points[i][X] = Points[i][Y] = 0.0;
677 }
678 else
679 {
680 Points[i][X] /= 1.0 + Points[i][Z];
681 Points[i][Y] /= 1.0 + Points[i][Z];
682 }
683
684 x = Frame.Screen_Width/2 + (int)(Frame.Screen_Width * Points[i][X]);
685 y = Frame.Screen_Height/2 - (int)(Frame.Screen_Height * Points[i][Y]);
686
687 if (x < Project->x1) Project->x1 = x;
688 if (x > Project->x2) Project->x2 = x;
689 if (y < Project->y1) Project->y1 = y;
690 if (y > Project->y2) Project->y2 = y;
691 }
692
693 *visible = true;
694 }
695 }
696
697
698
699
700 /*****************************************************************************
701 *
702 * FUNCTION
703 *
704 * project_bbox
705 *
706 * INPUT
707 *
708 * Project - Box's projection
709 * P - Box's edges
710 * visible - Flag if box is visible
711 *
712 * OUTPUT
713 *
714 * Project, visible
715 *
716 * RETURNS
717 *
718 * AUTHOR
719 *
720 * Dieter Bayer
721 *
722 * DESCRIPTION
723 *
724 * Project a box onto the screen.
725 *
726 * CHANGES
727 *
728 * May 1994 : Creation.
729 *
730 ******************************************************************************/
731
project_bbox(PROJECT * Project,VECTOR * P,int * visible)732 static void project_bbox(PROJECT *Project, VECTOR *P, int *visible)
733 {
734 int vis, i, x, y;
735 PROJECT New;
736
737 New.x1 = MAX_BUFFER_ENTRY;
738 New.x2 = MIN_BUFFER_ENTRY;
739 New.y1 = MAX_BUFFER_ENTRY;
740 New.y2 = MIN_BUFFER_ENTRY;
741
742 vis = false;
743
744 /* Check if all points lie "in front" of the viewer. */
745
746 if ((P[0][Z] > -1.0) && (P[1][Z] > -1.0) && (P[2][Z] > -1.0) && (P[3][Z] > -1.0) &&
747 (P[4][Z] > -1.0) && (P[5][Z] > -1.0) && (P[6][Z] > -1.0) && (P[7][Z] > -1.0))
748 {
749 /* Check if all points lie inside the "viewing pyramid". */
750
751 if ((fabs(P[0][X]) <= 0.5*(1.0+P[0][Z])) && (fabs(P[1][X]) <= 0.5*(1.0+P[1][Z])) &&
752 (fabs(P[2][X]) <= 0.5*(1.0+P[2][Z])) && (fabs(P[3][X]) <= 0.5*(1.0+P[3][Z])) &&
753 (fabs(P[4][X]) <= 0.5*(1.0+P[4][Z])) && (fabs(P[5][X]) <= 0.5*(1.0+P[5][Z])) &&
754 (fabs(P[6][X]) <= 0.5*(1.0+P[6][Z])) && (fabs(P[7][X]) <= 0.5*(1.0+P[7][Z])) &&
755 (fabs(P[0][Y]) <= 0.5*(1.0+P[0][Z])) && (fabs(P[1][Y]) <= 0.5*(1.0+P[1][Z])) &&
756 (fabs(P[2][Y]) <= 0.5*(1.0+P[2][Z])) && (fabs(P[3][Y]) <= 0.5*(1.0+P[3][Z])) &&
757 (fabs(P[4][Y]) <= 0.5*(1.0+P[4][Z])) && (fabs(P[5][Y]) <= 0.5*(1.0+P[5][Z])) &&
758 (fabs(P[6][Y]) <= 0.5*(1.0+P[6][Z])) && (fabs(P[7][Y]) <= 0.5*(1.0+P[7][Z])))
759 {
760 /* No clipping is needed. Just project the points. */
761
762 vis = true;
763
764 for (i = 0; i < 8; i++)
765 {
766 if (P[i][Z] < -1.0 + EPSILON)
767 {
768 P[i][X] = P[i][Y] = 0.0;
769 }
770 else
771 {
772 P[i][X] /= 1.0 + P[i][Z];
773 P[i][Y] /= 1.0 + P[i][Z];
774 }
775
776 x = Frame.Screen_Width/2 + (int)(Frame.Screen_Width * P[i][X]);
777 y = Frame.Screen_Height/2 - (int)(Frame.Screen_Height * P[i][Y]);
778
779 if (x < New.x1) New.x1 = x;
780 if (x > New.x2) New.x2 = x;
781 if (y < New.y1) New.y1 = y;
782 if (y > New.y2) New.y2 = y;
783 }
784 }
785 }
786
787 if (!vis)
788 {
789 project_raw_rectangle(&New, P[0], P[1], P[3], P[2], &vis);
790 project_raw_rectangle(&New, P[4], P[5], P[7], P[6], &vis);
791 project_raw_rectangle(&New, P[0], P[1], P[5], P[4], &vis);
792 project_raw_rectangle(&New, P[2], P[3], P[7], P[6], &vis);
793 project_raw_rectangle(&New, P[1], P[3], P[7], P[5], &vis);
794 project_raw_rectangle(&New, P[0], P[2], P[6], P[4], &vis);
795 }
796
797 if (vis)
798 {
799 if (New.x1 > Project->x1) Project->x1 = New.x1;
800 if (New.x2 < Project->x2) Project->x2 = New.x2;
801 if (New.y1 > Project->y1) Project->y1 = New.y1;
802 if (New.y2 < Project->y2) Project->y2 = New.y2;
803 *visible = true;
804 }
805 }
806
807
808
809 /*****************************************************************************
810 *
811 * FUNCTION
812 *
813 * project_bounds
814 *
815 * INPUT
816 *
817 * Project - Bounding box's projection
818 * BBox - Bounding box
819 * visible - Flag if bounding box is visible
820 *
821 * OUTPUT
822 *
823 * Project, visible
824 *
825 * RETURNS
826 *
827 * AUTHOR
828 *
829 * Dieter Bayer
830 *
831 * DESCRIPTION
832 *
833 * Project a bounding box onto the screen.
834 *
835 * CHANGES
836 *
837 * May 1994 : Creation.
838 *
839 ******************************************************************************/
840
project_bounds(PROJECT * Project,BBOX * BBox,int * visible)841 static void project_bounds(PROJECT *Project, BBOX *BBox, int *visible)
842 {
843 int i;
844 VECTOR P[8];
845
846 for (i = 0; i<8; i++)
847 {
848 P[i][X] = ((i & 1) ? BBox->Lengths[X] : 0.0) + BBox->Lower_Left[X];
849 P[i][Y] = ((i & 2) ? BBox->Lengths[Y] : 0.0) + BBox->Lower_Left[Y];
850 P[i][Z] = ((i & 4) ? BBox->Lengths[Z] : 0.0) + BBox->Lower_Left[Z];
851
852 transform_point(P[i]);
853 }
854
855 project_bbox(Project, P, visible);
856 }
857
858
859
860 /*****************************************************************************
861 *
862 * FUNCTION
863 *
864 * project_box
865 *
866 * INPUT
867 *
868 * Project - Projection
869 * Object - Object
870 * visible - Flag if object is visible
871 *
872 * OUTPUT
873 *
874 * Project, visible
875 *
876 * RETURNS
877 *
878 * AUTHOR
879 *
880 * Dieter Bayer
881 *
882 * DESCRIPTION
883 *
884 * Project a box onto the screen.
885 *
886 * CHANGES
887 *
888 * May 1994 : Creation.
889 *
890 ******************************************************************************/
891
project_box(PROJECT * Project,OBJECT * Object,int * visible)892 static void project_box(PROJECT *Project, OBJECT *Object, int *visible)
893 {
894 int i;
895 VECTOR P[8];
896 BOX *box;
897
898 box = (BOX *)Object;
899
900 for (i = 0; i<8; i++)
901 {
902 P[i][X] = (i & 1) ? box->bounds[1][X] : box->bounds[0][X];
903 P[i][Y] = (i & 2) ? box->bounds[1][Y] : box->bounds[0][Y];
904 P[i][Z] = (i & 4) ? box->bounds[1][Z] : box->bounds[0][Z];
905
906 if (box->Trans != NULL)
907 {
908 MTransPoint(P[i], P[i], box->Trans);
909 }
910
911 transform_point(P[i]);
912 }
913
914 project_bbox(Project, P, visible);
915 }
916
917
918
919 /*****************************************************************************
920 *
921 * FUNCTION
922 *
923 * project_hfield
924 *
925 * INPUT
926 *
927 * Project - Projection
928 * Object - Object
929 * visible - Flag if object is visible
930 *
931 * OUTPUT
932 *
933 * Project, visible
934 *
935 * RETURNS
936 *
937 * AUTHOR
938 *
939 * Dieter Bayer
940 *
941 * DESCRIPTION
942 *
943 * Project the bounding box of a height field onto the screen.
944 *
945 * CHANGES
946 *
947 * May 1994 : Creation.
948 *
949 ******************************************************************************/
950
project_hfield(PROJECT * Project,OBJECT * Object,int * visible)951 static void project_hfield(PROJECT *Project, OBJECT *Object, int *visible)
952 {
953 int i;
954 VECTOR P[8];
955 HFIELD *hfield;
956
957 hfield = (HFIELD *)Object;
958
959 for (i = 0; i<8; i++)
960 {
961 Assign_Vector(P[i], hfield->bounding_corner1);
962
963 P[i][X] = (i & 1) ? hfield->bounding_corner2[X] : hfield->bounding_corner1[X];
964 P[i][Y] = (i & 2) ? hfield->bounding_corner2[Y] : hfield->bounding_corner1[Y];
965 P[i][Z] = (i & 4) ? hfield->bounding_corner2[Z] : hfield->bounding_corner1[Z];
966
967 if (hfield->Trans != NULL)
968 {
969 MTransPoint(P[i], P[i], hfield->Trans);
970 }
971
972 transform_point(P[i]);
973 }
974
975 project_bbox(Project, P, visible);
976 }
977
978
979
980 /*****************************************************************************
981 *
982 * FUNCTION
983 *
984 * project_triangle
985 *
986 * INPUT
987 *
988 * Project - Projection
989 * Object - Object
990 * visible - Flag if object is visible
991 *
992 * OUTPUT
993 *
994 * Project, visible
995 *
996 * RETURNS
997 *
998 * AUTHOR
999 *
1000 * Dieter Bayer
1001 *
1002 * DESCRIPTION
1003 *
1004 * Project a triangle onto the screen.
1005 *
1006 * CHANGES
1007 *
1008 * May 1994 : Creation.
1009 *
1010 ******************************************************************************/
1011
project_triangle(PROJECT * Project,OBJECT * Object,int * visible)1012 static void project_triangle(PROJECT *Project, OBJECT *Object, int *visible)
1013 {
1014 int i, vis;
1015 VECTOR P[3];
1016 PROJECT New;
1017
1018 New.x1 = MAX_BUFFER_ENTRY;
1019 New.x2 = MIN_BUFFER_ENTRY;
1020 New.y1 = MAX_BUFFER_ENTRY;
1021 New.y2 = MIN_BUFFER_ENTRY;
1022
1023 Assign_Vector(P[0], ((TRIANGLE *)Object)->P1);
1024 Assign_Vector(P[1], ((TRIANGLE *)Object)->P2);
1025 Assign_Vector(P[2], ((TRIANGLE *)Object)->P3);
1026
1027 for (i = 0; i < 3; i++)
1028 {
1029 transform_point(P[i]);
1030 }
1031
1032 vis = false;
1033
1034 project_raw_triangle(&New, P[0], P[1], P[2], &vis);
1035
1036 if (vis)
1037 {
1038 if (New.x1 > Project->x1) Project->x1 = New.x1;
1039 if (New.x2 < Project->x2) Project->x2 = New.x2;
1040 if (New.y1 > Project->y1) Project->y1 = New.y1;
1041 if (New.y2 < Project->y2) Project->y2 = New.y2;
1042
1043 *visible = true;
1044 }
1045 }
1046
1047
1048
1049 /*****************************************************************************
1050 *
1051 * FUNCTION
1052 *
1053 * project_smooth_triangle
1054 *
1055 * INPUT
1056 *
1057 * Project - Projection
1058 * Object - Object
1059 * visible - Flag if object is visible
1060 *
1061 * OUTPUT
1062 *
1063 * Project, visible
1064 *
1065 * RETURNS
1066 *
1067 * AUTHOR
1068 *
1069 * Dieter Bayer
1070 *
1071 * DESCRIPTION
1072 *
1073 * Project a smooth triangle onto the screen.
1074 *
1075 * CHANGES
1076 *
1077 * May 1994 : Creation.
1078 *
1079 ******************************************************************************/
1080
project_smooth_triangle(PROJECT * Project,OBJECT * Object,int * visible)1081 static void project_smooth_triangle(PROJECT *Project, OBJECT *Object, int *visible)
1082 {
1083 int i, vis;
1084 VECTOR P[3];
1085 PROJECT New;
1086
1087 New.x1 = MAX_BUFFER_ENTRY;
1088 New.x2 = MIN_BUFFER_ENTRY;
1089 New.y1 = MAX_BUFFER_ENTRY;
1090 New.y2 = MIN_BUFFER_ENTRY;
1091
1092 Assign_Vector(P[0], ((SMOOTH_TRIANGLE *)Object)->P1);
1093 Assign_Vector(P[1], ((SMOOTH_TRIANGLE *)Object)->P2);
1094 Assign_Vector(P[2], ((SMOOTH_TRIANGLE *)Object)->P3);
1095
1096 for (i = 0; i < 3; i++)
1097 {
1098 transform_point(P[i]);
1099 }
1100
1101 vis = false;
1102
1103 project_raw_triangle(&New, P[0], P[1], P[2], &vis);
1104
1105 if (vis)
1106 {
1107 if (New.x1 > Project->x1) Project->x1 = New.x1;
1108 if (New.x2 < Project->x2) Project->x2 = New.x2;
1109 if (New.y1 > Project->y1) Project->y1 = New.y1;
1110 if (New.y2 < Project->y2) Project->y2 = New.y2;
1111
1112 *visible = true;
1113 }
1114 }
1115
1116
1117
1118 /*****************************************************************************
1119 *
1120 * FUNCTION
1121 *
1122 * transform_point
1123 *
1124 * INPUT
1125 *
1126 * P - Point to transform
1127 *
1128 * OUTPUT
1129 *
1130 * P
1131 *
1132 * RETURNS
1133 *
1134 * AUTHOR
1135 *
1136 * Dieter Bayer
1137 *
1138 * DESCRIPTION
1139 *
1140 * Transform a point from the world coordinate system to the viewer's
1141 * coordinate system.
1142 *
1143 * CHANGES
1144 *
1145 * May 1994 : Creation.
1146 *
1147 ******************************************************************************/
1148
transform_point(VECTOR P)1149 static void transform_point(VECTOR P)
1150 {
1151 DBL x,y,z;
1152
1153 x = P[X] - gO[X];
1154 y = P[Y] - gO[Y];
1155 z = P[Z] - gO[Z];
1156
1157 P[X] = gU[X] * x + gU[Y] * y + gU[Z] * z;
1158 P[Y] = gV[X] * x + gV[Y] * y + gV[Z] * z;
1159 P[Z] = gW[X] * x + gW[Y] * y + gW[Z] * z;
1160 }
1161
1162
1163
1164 /*****************************************************************************
1165 *
1166 * FUNCTION
1167 *
1168 * Init_View_Coordinates
1169 *
1170 * INPUT
1171 *
1172 * OUTPUT
1173 *
1174 * RETURNS
1175 *
1176 * AUTHOR
1177 *
1178 * Dieter Bayer
1179 *
1180 * DESCRIPTION
1181 *
1182 * Init the matrices and vectors used to transform a point from
1183 * the world coordinate system to the viewer's coordinate system.
1184 *
1185 * CHANGES
1186 *
1187 * May 1994 : Creation.
1188 *
1189 ******************************************************************************/
1190
init_view_coordinates()1191 static void init_view_coordinates()
1192 {
1193 DBL k1, k2, k3, up_length, right_length;
1194 MATRIX A, B;
1195
1196 Assign_Vector(gU, Frame.Camera->Right);
1197 Assign_Vector(gV, Frame.Camera->Up);
1198 Assign_Vector(gW, Frame.Camera->Direction);
1199
1200 VAdd (gO, Frame.Camera->Location, Frame.Camera->Direction);
1201
1202 VNormalize(gU,gU);
1203 VNormalize(gV,gV);
1204 VNormalize(gW,gW);
1205
1206 VDot(k1, gU, gV);
1207 VDot(k2, gU, gW);
1208 VDot(k3, gV, gW);
1209
1210 if ((fabs(k1) > EPSILON) || (fabs(k2) > EPSILON) || (fabs(k3) > EPSILON))
1211 {
1212 Error("Cannot use non-perpendicular camera vectors with vista buffer.");
1213 }
1214
1215 VLength (Distance, Frame.Camera->Direction);
1216
1217 VLength (up_length, Frame.Camera->Up);
1218 VLength (right_length, Frame.Camera->Right);
1219
1220 VScaleEq (gU, 1.0/right_length);
1221 VScaleEq (gV, 1.0/up_length);
1222 VScaleEq (gW, 1.0/Distance);
1223
1224 A[0][0] = gU[X]; A[0][1] = gU[Y]; A[0][2] = gU[Z]; A[0][3] = 0.0;
1225 A[1][0] = gV[X]; A[1][1] = gV[Y]; A[1][2] = gV[Z]; A[1][3] = 0.0;
1226 A[2][0] = gW[X]; A[2][1] = gW[Y]; A[2][2] = gW[Z]; A[2][3] = 0.0;
1227 A[3][0] = 0.0; A[3][1] = 0.0; A[3][2] = 0.0; A[3][3] = 1.0;
1228
1229 B[0][0] = 1.0; B[0][1] = 0.0; B[0][2] = 0.0; B[0][3] = -gO[X];
1230 B[1][0] = 0.0; B[1][1] = 1.0; B[1][2] = 0.0; B[1][3] = -gO[Y];
1231 B[2][0] = 0.0; B[2][1] = 0.0; B[2][2] = 1.0; B[2][3] = -gO[Z];
1232 B[3][0] = 0.0; B[3][1] = 0.0; B[3][2] = 0.0; B[3][3] = 1.0;
1233
1234 MTimesC(WC2VC, A, B);
1235 MInvers(WC2VCinv, WC2VC);
1236 }
1237
1238
1239
1240 /*****************************************************************************
1241 *
1242 * FUNCTION
1243 *
1244 * get_perspective_projection
1245 *
1246 * INPUT
1247 *
1248 * Object - Object to project
1249 * Project - Projection
1250 * infinite - Flag if object is infinite
1251 *
1252 * OUTPUT
1253 *
1254 * Project
1255 *
1256 * RETURNS
1257 *
1258 * AUTHOR
1259 *
1260 * Dieter Bayer
1261 *
1262 * DESCRIPTION
1263 *
1264 * Get the perspective projection of a single object, i.e.
1265 * the smallest rectangle enclosing the object's image on the screen.
1266 *
1267 * CHANGES
1268 *
1269 * May 1994 : Creation.
1270 *
1271 ******************************************************************************/
1272
get_perspective_projection(OBJECT * Object,PROJECT * Project,int infinite)1273 static void get_perspective_projection(OBJECT *Object, PROJECT *Project, int infinite)
1274 {
1275 int visible;
1276 METHODS *Methods;
1277
1278 visible = false;
1279
1280 Methods = Object->Methods;
1281
1282 /* If the object is infinite, there's no sense of projecting */
1283
1284 if (!infinite)
1285 {
1286 if ((Methods == &Box_Methods) ||
1287 (Methods == &Smooth_Triangle_Methods) ||
1288 (Methods == &Triangle_Methods) ||
1289 (Methods == &HField_Methods))
1290 {
1291 if (Methods == &Box_Methods)
1292 project_box(Project, Object, &visible);
1293
1294 if (Methods == &HField_Methods)
1295 project_hfield(Project, Object, &visible);
1296
1297 if (Methods == &Smooth_Triangle_Methods)
1298 project_smooth_triangle(Project, Object, &visible);
1299
1300 if (Methods == &Triangle_Methods)
1301 project_triangle(Project, Object, &visible);
1302 }
1303 else
1304 {
1305 project_bounds(Project, &Object->BBox, &visible);
1306 }
1307 }
1308
1309 if (visible)
1310 {
1311 if (opts.Options & ANTIALIAS)
1312 {
1313 /* Increase the rectangle to make sure that nothing will be missed.
1314 For anti-aliased images increase by a larger amount. */
1315
1316 Project->x1 = max (0, Project->x1 - 2);
1317 Project->x2 = min (Frame.Screen_Width-1, Project->x2 + 2);
1318 Project->y1 = max (-1, Project->y1 - 2);
1319 Project->y2 = min (Frame.Screen_Height-1, Project->y2 + 2);
1320 }
1321 else
1322 {
1323 /* Increase the rectangle to make sure that nothing will be missed. */
1324
1325 Project->x1 = max (0, Project->x1 - 1);
1326 Project->x2 = min (Frame.Screen_Width-1, Project->x2 + 1);
1327 Project->y1 = max (0, Project->y1 - 1);
1328 Project->y2 = min (Frame.Screen_Height-1, Project->y2 + 1);
1329 }
1330 }
1331 else
1332 {
1333 if (!infinite)
1334 {
1335 /* Object is invisible (the camera can't see it) */
1336
1337 Project->x1 = Project->y1 = MAX_BUFFER_ENTRY;
1338 Project->x2 = Project->y2 = MIN_BUFFER_ENTRY;
1339 }
1340 }
1341 }
1342
1343
1344
1345 /*****************************************************************************
1346 *
1347 * FUNCTION
1348 *
1349 * get_orthographic_projection
1350 *
1351 * INPUT
1352 *
1353 * Object - Object to project
1354 * Project - Projection
1355 * infinite - Flag if object is infinite
1356 *
1357 * OUTPUT
1358 *
1359 * Project
1360 *
1361 * RETURNS
1362 *
1363 * AUTHOR
1364 *
1365 * Dieter Bayer
1366 *
1367 * DESCRIPTION
1368 *
1369 * Get the orthographic projection of a single object, i.e.
1370 * the smallest rectangle enclosing the object's image on the screen.
1371 *
1372 * CHANGES
1373 *
1374 * May 1994 : Creation.
1375 *
1376 ******************************************************************************/
1377
get_orthographic_projection(OBJECT * Object,PROJECT * Project,int infinite)1378 static void get_orthographic_projection(OBJECT *Object, PROJECT *Project, int infinite)
1379 {
1380 int visible, i, x, y;
1381 VECTOR P[8];
1382
1383 visible = false;
1384
1385 /* If the object is infinite, there's no sense of projecting */
1386
1387 if (!infinite)
1388 {
1389 /* The following could be done better but since only a minority of all
1390 objects in a scene are partially visible I don't think it's worth it. */
1391
1392 for (i = 0; i < 8; i++)
1393 {
1394 P[i][X] = ((i & 1) ? Object->BBox.Lengths[X] : 0.0) + Object->BBox.Lower_Left[X];
1395 P[i][Y] = ((i & 2) ? Object->BBox.Lengths[Y] : 0.0) + Object->BBox.Lower_Left[Y];
1396 P[i][Z] = ((i & 4) ? Object->BBox.Lengths[Z] : 0.0) + Object->BBox.Lower_Left[Z];
1397
1398 transform_point(P[i]);
1399
1400 /* Check if bounding box is visible */
1401
1402 if (P[i][Z] >= 0.0) visible = true;
1403 }
1404
1405 /* Now get the projection */
1406
1407 if (visible)
1408 {
1409 Project->x1 = Project->y1 = MAX_BUFFER_ENTRY;
1410 Project->x2 = Project->y2 = MIN_BUFFER_ENTRY;
1411
1412 for (i = 0; i < 8; i++)
1413 {
1414 /* The visible area is -0.5...+0.5/-0.5...+0.5 */
1415
1416 if (P[i][X] < -0.5) P[i][X] = -0.5;
1417 if (P[i][X] > 0.5) P[i][X] = 0.5;
1418 if (P[i][Y] < -0.5) P[i][Y] = -0.5;
1419 if (P[i][Y] > 0.5) P[i][Y] = 0.5;
1420
1421 x = Frame.Screen_Width/2 + (int)(Frame.Screen_Width * P[i][X]);
1422 y = Frame.Screen_Height/2 - (int)(Frame.Screen_Height * P[i][Y]);
1423
1424 if (x < Project->x1) Project->x1 = x;
1425 if (x > Project->x2) Project->x2 = x;
1426 if (y < Project->y1) Project->y1 = y;
1427 if (y > Project->y2) Project->y2 = y;
1428 }
1429 }
1430 }
1431
1432 if (visible)
1433 {
1434 if (opts.Options & ANTIALIAS)
1435 {
1436 /* Increase the rectangle to make sure that nothing will be missed.
1437 For anti-aliased images decrease the lower borders. */
1438
1439 Project->x1 = max (0, Project->x1 - 2);
1440 Project->x2 = min (Frame.Screen_Width-1, Project->x2 + 1);
1441 Project->y1 = max (-1, Project->y1 - 2);
1442 Project->y2 = min (Frame.Screen_Height-1, Project->y2 + 1);
1443 }
1444 else
1445 {
1446 /* Increase the rectangle to make sure that nothing will be missed. */
1447
1448 Project->x1 = max (0, Project->x1 - 1);
1449 Project->x2 = min (Frame.Screen_Width-1, Project->x2 + 1);
1450 Project->y1 = max (0, Project->y1 - 1);
1451 Project->y2 = min (Frame.Screen_Height-1, Project->y2 + 1);
1452 }
1453 }
1454 else
1455 {
1456 if (!infinite)
1457 {
1458 /* Object is invisible (the camera can't see it) */
1459
1460 Project->x1 = Project->y1 = MAX_BUFFER_ENTRY;
1461 Project->x2 = Project->y2 = MIN_BUFFER_ENTRY;
1462 }
1463 }
1464 }
1465
1466
1467
1468 /*****************************************************************************
1469 *
1470 * FUNCTION
1471 *
1472 * project_object
1473 *
1474 * INPUT
1475 *
1476 * Object - Object to project
1477 * Project - Projection
1478 *
1479 * OUTPUT
1480 *
1481 * Project
1482 *
1483 * RETURNS
1484 *
1485 * AUTHOR
1486 *
1487 * Dieter Bayer
1488 *
1489 * DESCRIPTION
1490 *
1491 * Get the projection of a single object depending on the camera
1492 * used (perspective/orthographic).
1493 *
1494 * CHANGES
1495 *
1496 * May 1994 : Creation.
1497 *
1498 ******************************************************************************/
1499
project_object(OBJECT * Object,PROJECT * Project)1500 static void project_object(OBJECT *Object, PROJECT *Project)
1501 {
1502 int infinite;
1503
1504 /* Init project fields, assuming the object is visible! */
1505
1506 Project->x1 = Project->y1 = MIN_BUFFER_ENTRY;
1507 Project->x2 = Project->y2 = MAX_BUFFER_ENTRY;
1508
1509 infinite = Test_Flag(Object, INFINITE_FLAG);
1510
1511 switch (Frame.Camera->Type)
1512 {
1513 case PERSPECTIVE_CAMERA:
1514
1515 get_perspective_projection(Object, Project, infinite);
1516 break;
1517
1518 case ORTHOGRAPHIC_CAMERA:
1519
1520 get_orthographic_projection(Object, Project, infinite);
1521 break;
1522
1523 default:
1524
1525 Error("Wrong camera type in project_object().");
1526 break;
1527 }
1528 }
1529
1530
1531
1532 /*****************************************************************************
1533 *
1534 * FUNCTION
1535 *
1536 * project_bounding_slab
1537 *
1538 * INPUT
1539 *
1540 * Project - Projection
1541 * Tree - Current node/leaf
1542 * Object - Node/leaf in bounding slab hierarchy
1543 *
1544 * OUTPUT
1545 *
1546 * Project, Tree
1547 *
1548 * RETURNS
1549 *
1550 * AUTHOR
1551 *
1552 * Dieter Bayer
1553 *
1554 * DESCRIPTION
1555 *
1556 * Project the bounding slab hierarchy onto the screen and thus create
1557 * the vista buffer hierarchy.
1558 *
1559 * CHANGES
1560 *
1561 * May 1994 : Creation.
1562 *
1563 ******************************************************************************/
1564
project_bounding_slab(PROJECT * Project,PROJECT_TREE_NODE ** Tree,BBOX_TREE * Node)1565 static void project_bounding_slab(PROJECT *Project, PROJECT_TREE_NODE **Tree, BBOX_TREE *Node)
1566 {
1567 short int i;
1568 PROJECT Temp;
1569 PROJECT_TREE_LEAF *Leaf;
1570 PROJECT_TREE_NODE New;
1571
1572 if (Node->Entries)
1573 {
1574 /* Current object is a bounding object, i.e. a node in the slab tree. */
1575
1576 /* First, init new entry. */
1577
1578 New.Entries = 0;
1579
1580 New.Node = Node;
1581
1582 New.Project.x1 = New.Project.y1 = MAX_BUFFER_ENTRY;
1583 New.Project.x2 = New.Project.y2 = MIN_BUFFER_ENTRY;
1584
1585 /* Allocate temporary memory for node/leaf entries. */
1586
1587 New.Entry = (PROJECT_TREE_NODE **)POV_MALLOC(Node->Entries*sizeof(PROJECT_TREE_NODE *), "temporary tree entry");
1588
1589 /* This is no leaf, it's a node. */
1590
1591 New.is_leaf = false;
1592
1593 /* Second, get new entry, i.e. project node's entries. */
1594
1595 for (i = 0; i < Node->Entries; i++)
1596 {
1597 New.Entry[i] = NULL;
1598
1599 project_bounding_slab(&Temp, &New.Entry[New.Entries], Node->Node[i]);
1600
1601 /* Use only visible entries. */
1602
1603 if (New.Entry[New.Entries] != NULL)
1604 {
1605 New.Project.x1 = min(New.Project.x1, Temp.x1);
1606 New.Project.x2 = max(New.Project.x2, Temp.x2);
1607 New.Project.y1 = min(New.Project.y1, Temp.y1);
1608 New.Project.y2 = max(New.Project.y2, Temp.y2);
1609
1610 New.Entries++;
1611 }
1612 }
1613
1614 /* If there are any visible entries, we'll use them. */
1615
1616 if (New.Entries > 0)
1617 {
1618 /* If there's only one entry, we won't need a new node. */
1619
1620 if (New.Entries == 1)
1621 {
1622 *Tree = New.Entry[0];
1623 *Project = New.Project;
1624 }
1625 else
1626 {
1627 /* Allocate memory for new node in the vista tree. */
1628
1629 *Tree = (PROJECT_TREE_NODE *)POV_MALLOC(sizeof(PROJECT_TREE_NODE), "vista tree node");
1630
1631 **Tree = New;
1632
1633 /* Allocate memory for node/leaf entries. */
1634
1635 (*Tree)->Entry = (PROJECT_TREE_NODE **)POV_MALLOC(New.Entries*sizeof(PROJECT_TREE_NODE *), "vista tree node");
1636
1637 POV_MEMCPY((*Tree)->Entry, New.Entry, New.Entries*sizeof(PROJECT_TREE_NODE *));
1638
1639 *Project = New.Project;
1640 }
1641 }
1642
1643 /* Get rid of temporary node/leaf entries. */
1644
1645 POV_FREE(New.Entry);
1646 }
1647 else
1648 {
1649 Do_Cooperate(0);
1650
1651 /* Current object is a normal object, i.e. a leaf in the slab tree. */
1652
1653 /* Get object's projection. */
1654
1655 project_object((OBJECT *)Node->Node, Project);
1656
1657 /* Is the object visible? */
1658
1659 if ((Project->x1 <= Project->x2) && (Project->y1 <= Project->y2))
1660 {
1661 /* Allocate memory for new leaf in the vista tree. */
1662
1663 *Tree = (PROJECT_TREE_NODE *)POV_MALLOC(sizeof(PROJECT_TREE_LEAF), "vista tree leaf");
1664
1665 /* Init new leaf. */
1666
1667 Leaf = (PROJECT_TREE_LEAF *)(*Tree);
1668
1669 Leaf->Node = Node;
1670
1671 Leaf->Project = *Project;
1672
1673 /* Yes, this is a leaf. */
1674
1675 Leaf->is_leaf = true;
1676 }
1677 }
1678 }
1679
1680
1681
1682 /*****************************************************************************
1683 *
1684 * FUNCTION
1685 *
1686 * Build_Vista_Buffer
1687 *
1688 * INPUT
1689 *
1690 * OUTPUT
1691 *
1692 * RETURNS
1693 *
1694 * AUTHOR
1695 *
1696 * Dieter Bayer
1697 *
1698 * DESCRIPTION
1699 *
1700 * Build the vista tree, i.e. the 2d representation of the bounding slab
1701 * hierarchy in image space.
1702 *
1703 * This only works for perspective and orthographic cameras.
1704 *
1705 * CHANGES
1706 *
1707 * May 1994 : Creation.
1708 *
1709 ******************************************************************************/
1710
Build_Vista_Buffer()1711 void Build_Vista_Buffer()
1712 {
1713 PROJECT Project;
1714
1715 Root_Vista = NULL;
1716
1717 /* Check if vista buffer can be used. */
1718
1719 if ((!opts.Use_Slabs) ||
1720 (Frame.Camera->Tnormal != NULL) ||
1721 ((Frame.Camera->Type != PERSPECTIVE_CAMERA) && (Frame.Camera->Type != ORTHOGRAPHIC_CAMERA)) ||
1722 ((Frame.Camera->Aperture != 0.0) && (Frame.Camera->Blur_Samples > 0)))
1723 {
1724 opts.Options &= ~USE_VISTA_BUFFER;
1725 }
1726
1727 if (opts.Options & USE_VISTA_BUFFER)
1728 {
1729 Send_Progress("Creating vista buffer", PROGRESS_CREATING_VISTA_BUFFER);
1730
1731 init_view_coordinates();
1732
1733 project_bounding_slab(&Project, &Root_Vista, Root_Object);
1734 }
1735 }
1736
1737
1738
1739 /*****************************************************************************
1740 *
1741 * FUNCTION
1742 *
1743 * Destroy_Vista_Buffer
1744 *
1745 * INPUT
1746 *
1747 * OUTPUT
1748 *
1749 * RETURNS
1750 *
1751 * AUTHOR
1752 *
1753 * Dieter Bayer
1754 *
1755 * DESCRIPTION
1756 *
1757 * Destroy the vista tree.
1758 *
1759 * CHANGES
1760 *
1761 * Sep 1994 : Creation.
1762 *
1763 ******************************************************************************/
1764
Destroy_Vista_Buffer()1765 void Destroy_Vista_Buffer()
1766 {
1767 if ((opts.Options & USE_VISTA_BUFFER) && (Root_Vista != NULL))
1768 {
1769 Destroy_Project_Tree(Root_Vista);
1770
1771 Root_Vista = NULL;
1772 }
1773 }
1774
1775
1776
1777 /*****************************************************************************
1778 *
1779 * FUNCTION
1780 *
1781 * draw_projection
1782 *
1783 * INPUT
1784 *
1785 * Project - projection to draw
1786 * color - Color to be used
1787 *
1788 * OUTPUT
1789 *
1790 * RETURNS
1791 *
1792 * AUTHOR
1793 *
1794 * Dieter Bayer
1795 *
1796 * DESCRIPTION
1797 *
1798 * Draws a projection in the specified color.
1799 *
1800 * CHANGES
1801 *
1802 * May 1994 : Creation.
1803 * Jul 1996 : Draw boxes in white when doing grayscale preview
1804 *
1805 ******************************************************************************/
1806
draw_projection(PROJECT * Project,int color,int * BigRed,int * BigBlue)1807 static void draw_projection(PROJECT *Project, int color, int *BigRed, int *BigBlue)
1808 {
1809 int x1, x2, y1, y2, draw_it;
1810 unsigned char r, g, b, gray;
1811 unsigned char a=0;
1812
1813 gray = (opts.PaletteOption == GREY) ? 255 : 0;
1814
1815 switch (color)
1816 {
1817 case pRED : r = 255; g = b = gray; break;
1818 case pGREEN : g = 255; r = b = gray; break;
1819 case pBLUE : b = 255; r = g = gray; break;
1820 default : r = g = b = 255;
1821 }
1822
1823 x1 = Project->x1;
1824 x2 = Project->x2;
1825 y1 = Project->y1;
1826 y2 = Project->y2;
1827
1828 if ((x1 <= x2) && (y1 <= y2))
1829 {
1830 if (x1 < 0) x1 = 0;
1831 if (x2 < 0) x2 = 0;
1832 if (y1 < 0) y1 = 0;
1833 if (y2 < 0) y2 = 0;
1834
1835 if (x1 >= Frame.Screen_Width) x1 = Frame.Screen_Width - 1;
1836 if (x2 >= Frame.Screen_Width) x2 = Frame.Screen_Width - 1;
1837 if (y1 >= Frame.Screen_Height) y1 = Frame.Screen_Height - 1;
1838 if (y2 >= Frame.Screen_Height) y2 = Frame.Screen_Height - 1;
1839
1840 /* Check for full-screen rectangle. */
1841
1842 draw_it = true;
1843
1844 if ((x1 == 0) && (x2 == Frame.Screen_Width - 1) &&
1845 (y1 == 0) && (y2 == Frame.Screen_Height - 1))
1846 {
1847 draw_it = false;
1848
1849 switch (color)
1850 {
1851 case pRED : if (!(*BigRed)) { *BigRed = draw_it = true; } break;
1852 case pBLUE : if (!(*BigBlue)) { *BigBlue = draw_it = true; } break;
1853 }
1854 }
1855
1856 if (draw_it)
1857 {
1858 if(Display_Started)
1859 POV_DISPLAY_PLOT_BOX(opts.Preview_RefCon, x1, y1, x2, y2, r, g, b, a);
1860 }
1861 }
1862 }
1863
1864
1865
1866 /*****************************************************************************
1867 *
1868 * FUNCTION
1869 *
1870 * draw_vista
1871 *
1872 * INPUT
1873 *
1874 * Tree - current node/leaf in the vista tree
1875 *
1876 * OUTPUT
1877 *
1878 * RETURNS
1879 *
1880 * AUTHOR
1881 *
1882 * Dieter Bayer
1883 *
1884 * DESCRIPTION
1885 *
1886 * Draws recursively all projections of subnodes in the current node.
1887 *
1888 * CHANGES
1889 *
1890 * May 1994 : Creation.
1891 *
1892 ******************************************************************************/
1893
draw_vista(PROJECT_TREE_NODE * Tree,int * BigRed,int * BigBlue)1894 static void draw_vista(PROJECT_TREE_NODE *Tree, int *BigRed, int *BigBlue)
1895 {
1896 unsigned short i;
1897 PROJECT_TREE_LEAF *Leaf;
1898
1899 Do_Cooperate(1);
1900
1901 Check_User_Abort(false);
1902
1903 if (Tree->is_leaf)
1904 {
1905 Leaf = (PROJECT_TREE_LEAF *)Tree;
1906
1907 if (((OBJECT *)Leaf->Node->Node)->Type & IS_COMPOUND_OBJECT)
1908 {
1909 draw_projection(&Leaf->Project, pBLUE, BigRed, BigBlue);
1910 }
1911 else
1912 {
1913 draw_projection(&Leaf->Project, pRED, BigRed, BigBlue);
1914 }
1915 }
1916 else
1917 {
1918 for (i = 0; i < Tree->Entries; i++)
1919 {
1920 draw_vista(Tree->Entry[i], BigRed, BigBlue);
1921 }
1922 }
1923
1924 /* draw bounding object's vista */
1925
1926 /*
1927 draw_projection(&Tree->Project, pGREEN);
1928 */
1929 }
1930
1931
1932
1933 /*****************************************************************************
1934 *
1935 * FUNCTION
1936 *
1937 * Draw_Vista_Buffer
1938 *
1939 * INPUT
1940 *
1941 * OUTPUT
1942 *
1943 * RETURNS
1944 *
1945 * AUTHOR
1946 *
1947 * Dieter Bayer
1948 *
1949 * DESCRIPTION
1950 *
1951 * Draw the vista tree.
1952 *
1953 * CHANGES
1954 *
1955 * May 1994 : Creation.
1956 *
1957 ******************************************************************************/
1958
Draw_Vista_Buffer()1959 void Draw_Vista_Buffer()
1960 {
1961 int BigRed, BigBlue;
1962
1963 BigRed = BigBlue = false;
1964
1965 if ((Root_Vista != NULL) && (opts.Options & USE_VISTA_DRAW))
1966 {
1967 draw_vista(Root_Vista, &BigRed, &BigBlue);
1968 }
1969 }
1970
1971 END_POV_NAMESPACE
1972