/******************************************************************************  ATTENTION!!!**  THIS FILE HAS BEEN MODIFIED!!! IT IS NOT PART OF THE OFFICAL*  POV-RAY 2.2 DISTRIBUTION!!!**  THIS FILE IS PART OF "FASTER THAN POV-RAY" (VERSION 1.1),*  A SPED-UP VERSION OF POV-RAY 2.2. USE AT YOUR OWN RISK!!!!!!**  New files: addon0.c, addon1.c, addon2.c, addon3.c, addon.h**  The additional modules were written by Dieter Bayer.**  Send comments, suggestions, bugs, ideas ... to:**  dieter@cip.e-technik.uni-erlangen.de**  All changed/added lines are enclosed in #ifdef DB_CODE ... #endif**  The vista projection was taken from:**    A. Hashimoto, T. Akimoto, K. Mase, and Y. Suenaga, *    "Vista Ray-Tracing: High Speed Ray Tracing Using Perspective*    Projection Image", New Advances in Computer Graphics, Proceedings*    of CG International '89, R. A. Earnshaw, B. Wyvill (Eds.), *    Springer, ..., pp. 549-560**  The idea for the light buffer was taken from:**    E. Haines and D. Greenberg, "The Light Buffer: A Shadow-Testing *    Accelerator", IEEE CG&A, Vol. 6, No. 9, Sept. 1986, pp. 6-16******************************************************************************//*****************************************************************************  addon1.c**  This module was written by Dieter Bayer.**  This module contains functions used only for the vista buffer.**  01.03.1994 : Creation**  29.04.1994 : Version 2.0*******************************************************************************/#include <time.h>#include "frame.h"#include "vector.h"#include "povproto.h"#include "addon.h"#ifdef DB_CODE/* count project tests */#define COUNT_PROJECT_TESTS#define NUMBER_OF_TYPES      18#define TYPE_BICUBIC_PATCH    0#define TYPE_BLOB             1#define TYPE_BOX              2#define TYPE_CONE             3#define TYPE_CSG_INTERSECTION 4#define TYPE_CSG_MERGE        5#define TYPE_CSG_UNION        6#define TYPE_DISC             7#define TYPE_ELLIPSOID        8#define TYPE_HEIGHT_FIELD     9#define TYPE_LIGHT_SOURCE    10#define TYPE_PLANE           11#define TYPE_POLY            12#define TYPE_QUADRIC         13#define TYPE_SMOOTH_TRIANGLE 14#define TYPE_SPHERE          15#define TYPE_TRIANGLE        16#define TYPE_UNKNOWN         17#define NUMBER_OF_FLAGS     9#define FLAG_SUM            0#define FLAG_INFINITE       1#define FLAG_SCREEN_FILLING 2#define FLAG_USED_IN_CSG    3#define FLAG_INVISIBLE      4#define FLAG_BOUNDED        5#define FLAG_CLIPPED        6#define FLAG_BOUND_OBJECT   7#define FLAG_CLIP_OBJECT    8/****************************************************************************** external variables******************************************************************************/extern long Number_Of_Rays;extern FRAME Frame;extern int Trace_Level;extern int Use_Slabs;extern DBL Max_Trace_Level;extern time_t tstart, tstop;extern unsigned int Options;extern OBJECT *Root_Object;extern METHODS Bicubic_Patch_Methods;extern METHODS Blob_Methods;extern METHODS Box_Methods;extern METHODS Cone_Methods;extern METHODS Csg_Height_Field_Methods;extern METHODS CSG_Intersection_Methods;extern METHODS CSG_Merge_Methods;extern METHODS CSG_Union_Methods;extern METHODS Disc_Methods;extern METHODS Ellipsoid_Methods;extern METHODS Height_Field_Methods;extern METHODS Light_Source_Methods;extern METHODS Plane_Methods;extern METHODS Poly_Methods;extern METHODS Quadric_Methods;extern METHODS Smooth_Triangle_Methods;extern METHODS Sphere_Methods;extern METHODS Triangle_Methods;extern unsigned MAXQUEUE;extern unsigned long totalQueues, totalQueueResets, nChecked, nEnqueued;extern size_t Mem_Vista_Buffer;/****************************************************************************** Non-static variables******************************************************************************/PROJECT_TREE_NODE *Root_Vista;unsigned long Project_Tests = 0, Project_Tests_Succeeded = 0;unsigned Project_Algorithm = PROJECTIONS_WITH_LEAF_SLABS;/****************************************************************************** Static variables******************************************************************************/static DBL distance;static MATRIX WC2VC, WC2VCinv;static VECTOR O, U, V, W;/* Planes for 3d-clipping */static VECTOR VIEW_VX1 = {-0.8944271910, 0.0, -0.4472135955};static VECTOR VIEW_VX2 = { 0.8944271910, 0.0, -0.4472135955};static VECTOR VIEW_VY1 = {0.0, -0.8944271910, -0.4472135955};static VECTOR VIEW_VY2 = {0.0,  0.8944271910, -0.4472135955};static DBL VIEW_DX1 = 0.4472135955;static DBL VIEW_DX2 = 0.4472135955;static DBL VIEW_DY1 = 0.4472135955;static DBL VIEW_DY2 = 0.4472135955;/* Queues */static Qelem *Tree_Leaf_Queue;static PROJECT_TREE_NODE **Tree_Node_Queue;/****************************************************************************** Static functions******************************************************************************/static void Project_rectangle PARAMS((PROJECT *Project, VECTOR P1, VECTOR P2, VECTOR P3, VECTOR P4, int *visible));static void Project_triangle PARAMS((PROJECT *Project, VECTOR P1, VECTOR P2, VECTOR P3, int *visible));static void Project_Bbox PARAMS((PROJECT *Project, VECTOR *Points, int *visible));static void Project_Bounds PARAMS((PROJECT *Project, BBOX *Bounds, int *visible));static void Get_Perspective_Projection PARAMS((OBJECT *Object, PROJECT *Project, int infinite));static void Project_Object PARAMS((OBJECT *Object, PROJECT *Project));static void Project_Bicubic_Patch PARAMS((PROJECT *Project, OBJECT *Object));static void Project_Box PARAMS((PROJECT *Project, OBJECT *Object, int *visible));static void Project_Height_Field PARAMS((PROJECT *Project, OBJECT *Object, int *visible));static void Project_Sphere PARAMS((PROJECT *Project, OBJECT *Object));static void Project_Triangle PARAMS((PROJECT *Project, OBJECT *Object, int *visible));static void Project_Smooth_Triangle PARAMS((PROJECT *Project, OBJECT *Object, int *visible));static void Get_Ellipse_Projection PARAMS((PROJECT *Project, DBL a20, DBL a02, DBL a11, DBL a10, DBL a01, DBL a00));static void Transform_Point PARAMS((VECTOR *P));static void Project_Bounding_Slab PARAMS((PROJECT *Project, PROJECT_TREE_NODE **Tree, OBJECT *Object));static void Create_Rayinfo PARAMS((RAY *Ray, RAYINFO *rayinfo));static int Intersect_Vista_Tree PARAMS((RAY *Ray, PROJECT_TREE_NODE *Tree, int x, INTERSECTION *Best_Intersection));/******************************************************************************* FUNCTION      : Init_Project_Tree_Queues** ARGUMENTS     : none** MODIFIED ARGS : none** RETURN VALUE  : none** AUTHOR        : Dieter Bayer, May 1994** DESCRIPTION**   Init queues for descending project tress, i.e. allocate memory needed.** CHANGES**   -*******************************************************************************/void Init_Project_Tree_Queues(){  Tree_Leaf_Queue = (Qelem *)VB_malloc(MAXQUEUE*sizeof(Qelem));  if (Tree_Leaf_Queue == NULL)  {    Fatal_MAError("priority queue for vista/light buffer");  }  Tree_Node_Queue = (PROJECT_TREE_NODE **)VB_malloc(MAXQUEUE*sizeof(PROJECT_TREE_NODE *));  if (Tree_Node_Queue == NULL)  {    Fatal_MAError("priority queue for vista/light buffer");  }}/******************************************************************************* FUNCTION      : Prune_Vista_Tree** ARGUMENTS     : y - Current scanline number** MODIFIED ARGS : none** RETURN VALUE  : none** AUTHOR        : Dieter Bayer, May 1994** DESCRIPTION**   Prune vista tree, i.e. mark all nodes not on the current line inactive.** CHANGES**   -*******************************************************************************/void Prune_Vista_Tree(y)int y;{  unsigned size;  unsigned short i;  PROJECT_TREE_NODE *Node, *Sib;  size = 0;#ifdef COUNT_PROJECT_TESTS  Project_Tests++;#endif  if ((y < Root_Vista->Project.y1) || (y > Root_Vista->Project.y2))  {    /* Root doesn't lie on current line --> prune root */    Root_Vista->is_leaf |= PRUNE_TEMPORARY;  }  else  {    /* Root lies on current line --> unprune root */#ifdef COUNT_PROJECT_TESTS    Project_Tests_Succeeded++;#endif    Root_Vista->is_leaf &= PRUNE_TEMPORARY_INVERS;    Tree_Node_Queue[size++] = Root_Vista;  }  while (size > 0)  {    Node = Tree_Node_Queue[--size];    if (Node->is_leaf & TRUE)    {#ifdef COUNT_PROJECT_TESTS      Project_Tests++;#endif      if ((y < Node->Project.y1) || (y > Node->Project.y2))      {	/* Leaf doesn't lie on current line --> prune leaf */	Node->is_leaf |= PRUNE_TEMPORARY;      }      else      {	/* Leaf lies on current line --> unprune leaf */#ifdef COUNT_PROJECT_TESTS	Project_Tests_Succeeded++;#endif	Node->is_leaf &= PRUNE_TEMPORARY_INVERS;      }    }    else    {      /* Check siblings of the node */      for (i = 0; i < Node->Entries; i++)      {	Sib = Node->Entry[i];#ifdef COUNT_PROJECT_TESTS	Project_Tests++;#endif	if ((y < Sib->Project.y1) || (y > Sib->Project.y2))	{	  /* Sibling doesn't lie on current line --> prune sibling */	  Sib->is_leaf |= PRUNE_TEMPORARY;	}	else	{	  /* Sibling lies on current line --> unprune sibling */#ifdef COUNT_PROJECT_TESTS	  Project_Tests_Succeeded++;#endif	  Sib->is_leaf &= PRUNE_TEMPORARY_INVERS;	  /* Add sibling to list */	  Tree_Node_Queue[size++] = Sib;	}      }    }  }}/******************************************************************************* FUNCTION      : Trace_Primary_Ray** ARGUMENTS     : Ray    - Current ray*                 Colour - Ray's colour*                 x      - Current x-coordinate** MODIFIED ARGS : colour** RETURN VALUE  : none** AUTHOR        : Dieter Bayer, May 1994** DESCRIPTION**   Trace a primary ray using the vista tree.** CHANGES**   -*******************************************************************************/void Trace_Primary_Ray (Ray, Colour, x)RAY *Ray;COLOUR *Colour;int x;{  INTERSECTION Best_Intersection;  COOPERATE  Number_Of_Rays++;  if (Trace_Level > (int)Max_Trace_Level)    return;  Colour->Red = Colour->Green = Colour->Blue = 0.0;  Best_Intersection.Depth = BOUND_HUGE;  /* What objects does this ray intersect? */  if (Intersect_Vista_Tree(Ray, Root_Vista, x, &Best_Intersection))  {    Determine_Apparent_Colour (&Best_Intersection, Colour, Ray);  }  else  {    if (Frame.Fog_Distance > 0.0)    {      *Colour = Frame.Fog_Colour;    }    else    {      *Colour = Frame.Background_Colour;    }  }}/******************************************************************************* FUNCTION      : Create_Rayinfo** ARGUMENTS     : Ray     - Current ray*                 rayinfo - Rayinfo structure** MODIFIED ARGS : rayinfo** RETURN VALUE  : none** AUTHOR        : Dieter Bayer, May 1994** DESCRIPTION**   Calculate the rayinfo structure for a given ray. It's need for*   intersection the ray with bounding boxes.** CHANGES**   -*******************************************************************************/static void Create_Rayinfo(Ray, rayinfo)RAY *Ray;RAYINFO *rayinfo;{  DBL t;  /* Create the direction vectors for this ray */  rayinfo->slab_num = Ray->Initial;  if ((rayinfo->nonzero.x = ((t = Ray->Direction.x) != 0.0)) != 0)  {    rayinfo->slab_den.x = 1.0 / t;    rayinfo->positive.x = (Ray->Direction.x > 0.0);  }  if ((rayinfo->nonzero.y = ((t = Ray->Direction.y) != 0.0)) != 0)  {    rayinfo->slab_den.y = 1.0 / t;    rayinfo->positive.y = (Ray->Direction.y > 0.0);  }  if ((rayinfo->nonzero.z = ((t = Ray->Direction.z) != 0.0)) != 0)  {    rayinfo->slab_den.z = 1.0 / t;    rayinfo->positive.z = (Ray->Direction.z > 0.0);  }}/******************************************************************************* FUNCTION      : Intersect_Vista_Tree** ARGUMENTS     : Ray               - Primary ray*                 Tree              - Vista tree's top-node*                 x                 - Current x-coordinate*                 Best_Intersection - Intersection found** MODIFIED ARGS : Best_Intersection** RETURN VALUE  : none** AUTHOR        : Dieter Bayer, May 1994** DESCRIPTION**   Intersect a PRIMARY ray with the vista tree*   (tree pruning is used can be primary ray!!!).** CHANGES**   -*******************************************************************************/static int Intersect_Vista_Tree(Ray, Tree, x, Best_Intersection)RAY *Ray;PROJECT_TREE_NODE *Tree;int x;INTERSECTION *Best_Intersection;{  INTERSECTION New_Intersection;  unsigned short i;  unsigned Qsize, size;  int Found;  RAYINFO rayinfo;  DBL key;  OBJECT *Object;  PROJECT_TREE_NODE *Node;  /* Start with an empty priority queue */  Qsize = 0;  Found = FALSE;  totalQueueResets++;  /* Which algorithm to use? */  switch (Project_Algorithm)  {    /************************************************************************    * Do not use any bounding slab tests. just use their projections.    *************************************************************************/    case PROJECTIONS_WITHOUT_SLABS :      /* Check root */#ifdef COUNT_PROJECT_TESTS      Project_Tests++;#endif      if ((x >= Tree->Project.x1) && (x <= Tree->Project.x2))      {#ifdef COUNT_PROJECT_TESTS	Project_Tests_Succeeded++;#endif	Tree_Node_Queue[Qsize++] = Tree;      }      while (Qsize > 0)      {	Tree = Tree_Node_Queue[--Qsize];	switch (Tree->is_leaf)	{	  case FALSE:	    /* Check siblings of the unpruned node in 2d */	    for (i = 0; i < Tree->Entries; i++)	    {	      Node = Tree->Entry[i];	      /* Check unpruned siblings only */	      if (Node->is_leaf < PRUNE_CHECK)	      {#ifdef COUNT_PROJECT_TESTS		Project_Tests++;#endif		if ((x >= Node->Project.x1) && (x <= Node->Project.x2))		{#ifdef COUNT_PROJECT_TESTS		  Project_Tests_Succeeded++;#endif		  /* Add node to node queue */		  if (Qsize >= MAXQUEUE)		    Fatal_Error("Node queue overflow.\n");		  Tree_Node_Queue[Qsize++] = Node;		}	      }	    }	    break;	  case TRUE:	    /* Unpruned leaf --> test object */	    if (Intersection(&New_Intersection, ((PROJECT_TREE_LEAF *)Tree)->Object, Ray))	    {	      if (New_Intersection.Depth < Best_Intersection->Depth)	      {		*Best_Intersection = New_Intersection;		Found = TRUE;	      }	    }	    break;       /* default:	    The node/leaf is pruned and needn't be checked */	}      }      break;    /************************************************************************    * Use bounding slab tests for leaves (i.e. objects) in the tree.    *************************************************************************/    case PROJECTIONS_WITH_LEAF_SLABS :      /* Create the direction vectors for this ray */      Create_Rayinfo(Ray, &rayinfo);      /* Fill the priority queue with all possible candidates */      size = 0;      /* Check root */#ifdef COUNT_PROJECT_TESTS      Project_Tests++;#endif      if ((x >= Tree->Project.x1) && (x <= Tree->Project.x2))      {#ifdef COUNT_PROJECT_TESTS	Project_Tests_Succeeded++;#endif	Tree_Node_Queue[size++] = Tree;      }      while (size > 0)      {	Tree = Tree_Node_Queue[--size];	switch (Tree->is_leaf)	{	  case FALSE:	    /* Check siblings of the unpruned node in 2d */	    for (i = 0; i < Tree->Entries; i++)	    {	      Node = Tree->Entry[i];	      /* Check unpruned siblings only */	      if (Node->is_leaf < PRUNE_CHECK)	      {#ifdef COUNT_PROJECT_TESTS		Project_Tests++;#endif		if ((x >= Node->Project.x1) && (x <= Node->Project.x2))		{#ifdef COUNT_PROJECT_TESTS		  Project_Tests_Succeeded++;#endif		  /* add node to node queue */		  if (size >= MAXQUEUE)		    Fatal_Error("Node queue overflow.\n");		  Tree_Node_Queue[size++] = Node;		}	      }	    }	break;	  case TRUE:	    /* Unpruned leaf --> test object's bounding box in 3d */	    CheckAndEnqueue(Tree_Leaf_Queue, &Qsize, ((PROJECT_TREE_LEAF *)Tree)->Object,	      &((PROJECT_TREE_LEAF *)Tree)->Object->Bounds, &rayinfo);	    break;       /* default:	    The node/leaf is pruned and needn't be checked */	}      }      /* Now test the candidates in the priority queue */      while (Qsize > 0)      {	PriorityQueueDelete(Tree_Leaf_Queue, &Qsize, &key, &Object);	if (key > Best_Intersection->Depth)	  break;	if (Intersection(&New_Intersection, Object, Ray))	{	  if (New_Intersection.Depth < Best_Intersection->Depth)	  {	    *Best_Intersection = New_Intersection;	    Found = TRUE;	  }	}      }      break;    /************************************************************************    * Use bounding slab tests for all nodes that pass the projection test.    *************************************************************************/    case PROJECTIONS_WITH_NODE_SLABS :      /* Create the direction vectors for this ray */      Create_Rayinfo(Ray, &rayinfo);      /* Check root */#ifdef COUNT_PROJECT_TESTS      Project_Tests++;#endif      if ((x >= Tree->Project.x1) && (x <= Tree->Project.x2))      {#ifdef COUNT_PROJECT_TESTS	Project_Tests_Succeeded++;#endif	CheckAndEnqueue(Tree_Leaf_Queue, &Qsize, (OBJECT *)Tree,	  &Tree->Object->Bounds, &rayinfo);      }      while (Qsize > 0)      {	PriorityQueueDelete(Tree_Leaf_Queue, &Qsize, &key, &Object);	if (key > Best_Intersection->Depth)	  break;	Tree = (PROJECT_TREE_NODE *)Object;	switch (Tree->is_leaf)	{	  case FALSE:	    /* Check siblings of the unpruned node in 2d */	    for (i = 0; i < Tree->Entries; i++)	    {	      Node = Tree->Entry[i];	      /* Check unpruned siblings only */	      if (Node->is_leaf < PRUNE_CHECK)	      {#ifdef COUNT_PROJECT_TESTS		Project_Tests++;#endif		if ((x >= Node->Project.x1) && (x <= Node->Project.x2))		{#ifdef COUNT_PROJECT_TESTS		  Project_Tests_Succeeded++;#endif		  CheckAndEnqueue(Tree_Leaf_Queue, &Qsize, (OBJECT *)Node,		    &Node->Object->Bounds, &rayinfo);		}	      }	    }	    break;	  case TRUE:	    /* Unpruned leaf --> test object */	    if (Intersection(&New_Intersection, ((PROJECT_TREE_LEAF *)Tree)->Object, Ray))	    {	      if (New_Intersection.Depth < Best_Intersection->Depth)	      {		*Best_Intersection = New_Intersection;		Found = TRUE;	      }	    }	    break;       /* default:	    The node/leaf is pruned and needn't be checked */	}      }      break;    default :      Fatal_Error("Unkown algorithm.\n");  }  return(Found);}/******************************************************************************* FUNCTION      : Intersect_Light_Tree** ARGUMENTS     : Ray               - Shadow ray*                 Tree              - Light tree's top-node*                 x                 - X-coordinate of the shadow ray*                 y                 - Y-coordinate of the shadow ray*                 Best_Intersection - Intersection found*                 Best_Object       - Object found** MODIFIED ARGS : Best_Intersection, Best_Object** RETURN VALUE  : none** AUTHOR        : Dieter Bayer, May 1994** DESCRIPTION**   Intersect a shadow ray with the light tree*   (same as for the vista tree but without pruning).** CHANGES**   -*******************************************************************************/int Intersect_Light_Tree(Ray, Tree, x, y, Best_Intersection, Best_Object)RAY *Ray;PROJECT_TREE_NODE *Tree;int x, y;INTERSECTION *Best_Intersection;OBJECT **Best_Object;{  INTERSECTION New_Intersection;  unsigned short i;  unsigned Qsize, size;  int Found;  RAYINFO rayinfo;  DBL key;  OBJECT *Object;  PROJECT_TREE_NODE *Node;  /* Start with an empty priority queue */  Qsize = 0;  Found = FALSE;  totalQueueResets++;  /* which algorithm to use? */  switch (Project_Algorithm)  {    /************************************************************************    * Do not use any bounding slab tests. just use their projections.    *************************************************************************/    case PROJECTIONS_WITHOUT_SLABS :      /* Check root */#ifdef COUNT_PROJECT_TESTS      Project_Tests++;#endif      if ((x >= Tree->Project.x1) && (x <= Tree->Project.x2) &&	  (y >= Tree->Project.y1) && (y <= Tree->Project.y2))      {#ifdef COUNT_PROJECT_TESTS	Project_Tests_Succeeded++;#endif	Tree_Node_Queue[Qsize++] = Tree;      }      while (Qsize > 0)      {	Tree = Tree_Node_Queue[--Qsize];	if (Tree->is_leaf)	{	  /* Leaf --> test object */	  if (Intersection(&New_Intersection, ((PROJECT_TREE_LEAF *)Tree)->Object, Ray))	  {	    if (New_Intersection.Depth < Best_Intersection->Depth)	    {	      *Best_Intersection = New_Intersection;	      *Best_Object = ((PROJECT_TREE_LEAF *)Tree)->Object;	      Found = TRUE;	    }	  }	}	else	{	  /* Check siblings of the node in 2d */	  for (i = 0; i < Tree->Entries; i++)	  {	    Node = Tree->Entry[i];#ifdef COUNT_PROJECT_TESTS	    Project_Tests++;#endif	    if ((x >= Node->Project.x1) && (x <= Node->Project.x2) &&		(y >= Node->Project.y1) && (y <= Node->Project.y2))	    {#ifdef COUNT_PROJECT_TESTS	      Project_Tests_Succeeded++;#endif	      /* Add node to node queue */	      if (Qsize >= MAXQUEUE)		Fatal_Error("Node queue overflow.\n");	      Tree_Node_Queue[Qsize++] = Node;	    }	  }	}      }      break;    /************************************************************************    * Use bounding slab tests for leaves (i.e. objects) in the tree.    *************************************************************************/    case PROJECTIONS_WITH_LEAF_SLABS :      /* Create the direction vectors for this ray */      Create_Rayinfo(Ray, &rayinfo);      /* Fill the priority queue with all possible candidates */      size = 0;      /* Check root */#ifdef COUNT_PROJECT_TESTS      Project_Tests++;#endif      if ((x >= Tree->Project.x1) && (x <= Tree->Project.x2) &&	  (y >= Tree->Project.y1) && (y <= Tree->Project.y2))      {#ifdef COUNT_PROJECT_TESTS	Project_Tests_Succeeded++;#endif	Tree_Node_Queue[size++] = Tree;      }      while (size > 0)      {	Tree = Tree_Node_Queue[--size];	if (Tree->is_leaf)	{	  /* Leaf --> test object's bounding box in 3d */	  CheckAndEnqueue(Tree_Leaf_Queue, &Qsize, ((PROJECT_TREE_LEAF *)Tree)->Object,	    &((PROJECT_TREE_LEAF *)Tree)->Object->Bounds, &rayinfo);	}	else	{	  /* Check siblings of the node in 2d */	  for (i = 0; i < Tree->Entries; i++)	  {	    Node = Tree->Entry[i];#ifdef COUNT_PROJECT_TESTS	    Project_Tests++;#endif	    if ((x >= Node->Project.x1) && (x <= Node->Project.x2) &&		(y >= Node->Project.y1) && (y <= Node->Project.y2))	    {#ifdef COUNT_PROJECT_TESTS	      Project_Tests_Succeeded++;#endif	      /* Add node to node queue */	      if (size >= MAXQUEUE)		Fatal_Error("Node queue overflow.\n");	      Tree_Node_Queue[size++] = Node;	    }	  }	}      }      /* Now test the candidates in the priority queue */      while (Qsize > 0)      {	PriorityQueueDelete(Tree_Leaf_Queue, &Qsize, &key, &Object);	if (key > Best_Intersection->Depth)	  break;	if (Intersection(&New_Intersection, Object, Ray))	{	  if (New_Intersection.Depth < Best_Intersection->Depth)	  {	    *Best_Intersection = New_Intersection;	    *Best_Object = Object;	    Found = TRUE;	  }	}      }      break;    /************************************************************************    * Use bounding slab tests for all nodes that pass the projection test.    *************************************************************************/    case PROJECTIONS_WITH_NODE_SLABS :      /* Create the direction vectors for this ray */      Create_Rayinfo(Ray, &rayinfo);      /* Check root */#ifdef COUNT_PROJECT_TESTS      Project_Tests++;#endif      if ((x >= Tree->Project.x1) && (x <= Tree->Project.x2) &&	  (y >= Tree->Project.y1) && (y <= Tree->Project.y2))      {#ifdef COUNT_PROJECT_TESTS	Project_Tests_Succeeded++;#endif	CheckAndEnqueue(Tree_Leaf_Queue, &Qsize, (OBJECT *)Tree,	  &Tree->Object->Bounds, &rayinfo);      }      while (Qsize > 0)      {	PriorityQueueDelete(Tree_Leaf_Queue, &Qsize, &key, &Object);	if (key > Best_Intersection->Depth)	  break;	Tree = (PROJECT_TREE_NODE *)Object;	if (Tree->is_leaf)	{	  /* Leaf --> test object */	  if (Intersection(&New_Intersection, ((PROJECT_TREE_LEAF *)Tree)->Object, Ray))	  {	    if (New_Intersection.Depth < Best_Intersection->Depth)	    {	      *Best_Intersection = New_Intersection;	      *Best_Object = ((PROJECT_TREE_LEAF *)Tree)->Object;	      Found = TRUE;	    }	  }	}	else	{	  /* Check siblings of the unpruned node in 2d */	  for (i = 0; i < Tree->Entries; i++)	  {	    Node = Tree->Entry[i];#ifdef COUNT_PROJECT_TESTS	    Project_Tests++;#endif	    if ((x >= Node->Project.x1) && (x <= Node->Project.x2) &&		(y >= Node->Project.y1) && (y <= Node->Project.y2))	    {#ifdef COUNT_PROJECT_TESTS	      Project_Tests_Succeeded++;#endif	      CheckAndEnqueue(Tree_Leaf_Queue, &Qsize, (OBJECT *)Node,		&Node->Object->Bounds, &rayinfo);	    }	  }	}      }      break;    default :      Fatal_Error("Unkown algorithm.\n");  }  return(Found);}/******************************************************************************* FUNCTION      : Project_triangle** ARGUMENTS     : Project    - Triangle's projection*                 P1, P2, P3 - Triangle's edges*                 visible    - Flag if triangle is visible** MODIFIED ARGS : Project, visible** RETURN VALUE  : none** AUTHOR        : Dieter Bayer, May 1994** DESCRIPTION**   Project a triangle onto the screen.** CHANGES**   -*******************************************************************************/static void Project_triangle (Project, P1, P2, P3, visible)PROJECT *Project;VECTOR P1, P2, P3;int *visible;{  VECTOR Points[MAX_CLIP_POINTS];  int i, number;  int x, y;  Points[0] = P1;  Points[1] = P2;  Points[2] = P3;  number = 3;  /* Clip triangle only if some quick tests say it's necessary.     Assuming that only a few triangles need clipping this saves some time.     (I don't need to write fabs(1+P?.z) since the tests succeed anyway if      P?.z < -1. Hope the compiler doesn't change the tests' order!) */  if ((P1.z < -1.0) || (P2.z < -1.0) || (P3.z < -1.0) ||      (fabs(P1.x) > 0.5*(1.0+P1.z)) || (fabs(P1.y) > 0.5*(1.0+P1.z)) ||      (fabs(P2.x) > 0.5*(1.0+P2.z)) || (fabs(P2.y) > 0.5*(1.0+P2.z)) ||      (fabs(P3.x) > 0.5*(1.0+P3.z)) || (fabs(P3.y) > 0.5*(1.0+P3.z)))  {    Clip_Polygon(Points, &number, &VIEW_VX1, &VIEW_VX2, &VIEW_VY1, &VIEW_VY2,				   VIEW_DX1,  VIEW_DX2,  VIEW_DY1,  VIEW_DY2);  }  if (!number)    return;  for (i = 0; i < number; i++)  {    if (Points[i].z == -1.0)    {      Points[i].x = Points[i].y = 0.0;    }    else    {      Points[i].x = Points[i].x / (1.0 + Points[i].z);      Points[i].y = Points[i].y / (1.0 + Points[i].z);    }    x = Frame.Screen_Width/2  + (int)(Frame.Screen_Width  * Points[i].x);    y = Frame.Screen_Height/2 - (int)(Frame.Screen_Height * Points[i].y);    if (x < Project->x1) Project->x1 = x;    if (x > Project->x2) Project->x2 = x;    if (y < Project->y1) Project->y1 = y;    if (y > Project->y2) Project->y2 = y;  }  *visible = TRUE;}/******************************************************************************* FUNCTION      : Project_rectangle** ARGUMENTS     : Project        - Rectangle's projection*                 P1, P2, P3, P4 - Rectangle's edges*                 visible        - Flag if rectangle is visible** MODIFIED ARGS : Project, visible** RETURN VALUE  : none** AUTHOR        : Dieter Bayer, May 1994** DESCRIPTION**   Project a rectangle onto the screen.** CHANGES**   -*******************************************************************************/static void Project_rectangle(Project, P1, P2, P3, P4, visible)PROJECT *Project;VECTOR P1, P2, P3, P4;int *visible;{  VECTOR Points[MAX_CLIP_POINTS];  int i, number;  int x, y;  Points[0] = P1;  Points[1] = P2;  Points[2] = P3;  Points[3] = P4;  number = 4;  /* Clip square only if some quick tests say it's necessary.     Assuming that only a few squares need clipping this saves some time.     (I don't need to write fabs(1+P?.z) since the tests succeed anyway if      P?.z < -1. Hope the compiler doesn't change the tests' order!) */  if ((P1.z < -1.0) || (P2.z < -1.0) || (P3.z < -1.0) || (P4.z < -1.0) ||      (fabs(P1.x) > 0.5*(1.0+P1.z)) || (fabs(P1.y) > 0.5*(1.0+P1.z)) ||      (fabs(P2.x) > 0.5*(1.0+P2.z)) || (fabs(P2.y) > 0.5*(1.0+P2.z)) ||      (fabs(P3.x) > 0.5*(1.0+P3.z)) || (fabs(P3.y) > 0.5*(1.0+P3.z)) ||      (fabs(P4.x) > 0.5*(1.0+P4.z)) || (fabs(P4.y) > 0.5*(1.0+P4.z)))  {    Clip_Polygon(Points, &number, &VIEW_VX1, &VIEW_VX2, &VIEW_VY1, &VIEW_VY2,				   VIEW_DX1,  VIEW_DX2,  VIEW_DY1,  VIEW_DY2);  }  if (!number)    return;  for (i = 0; i < number; i++)  {    if (Points[i].z == -1.0)    {      Points[i].x = Points[i].y = 0.0;    }    else    {      Points[i].x = Points[i].x / (1.0 + Points[i].z);      Points[i].y = Points[i].y / (1.0 + Points[i].z);    }    x = Frame.Screen_Width/2  + (int)(Frame.Screen_Width  * Points[i].x);    y = Frame.Screen_Height/2 - (int)(Frame.Screen_Height * Points[i].y);    if (x < Project->x1) Project->x1 = x;    if (x > Project->x2) Project->x2 = x;    if (y < Project->y1) Project->y1 = y;    if (y > Project->y2) Project->y2 = y;  }  *visible = TRUE;}/******************************************************************************* FUNCTION      : Project_BBox** ARGUMENTS     : Project - Box's projection*                 Points  - Box's edges*                 visible - Flag if box is visible** MODIFIED ARGS : Project, visible** RETURN VALUE  : none** AUTHOR        : Dieter Bayer, May 1994** DESCRIPTION**   Project a box onto the screen.** CHANGES**   -*******************************************************************************/static void Project_Bbox(Project, Points, visible)PROJECT *Project;VECTOR *Points;int *visible;{  int vis;  PROJECT New;  New.x1 = MAX_VB_ENTRY;  New.x2 = MIN_VB_ENTRY;  New.y1 = MAX_VB_ENTRY;  New.y2 = MIN_VB_ENTRY;  vis = FALSE;  Project_rectangle(&New, Points[0], Points[1], Points[3], Points[2], &vis);  Project_rectangle(&New, Points[4], Points[5], Points[7], Points[6], &vis);  Project_rectangle(&New, Points[0], Points[1], Points[5], Points[4], &vis);  Project_rectangle(&New, Points[2], Points[3], Points[7], Points[6], &vis);  Project_rectangle(&New, Points[1], Points[3], Points[7], Points[5], &vis);  Project_rectangle(&New, Points[0], Points[2], Points[6], Points[4], &vis);  if (vis)  {    if (New.x1 > Project->x1) Project->x1 = New.x1;    if (New.x2 < Project->x2) Project->x2 = New.x2;    if (New.y1 > Project->y1) Project->y1 = New.y1;    if (New.y2 < Project->y2) Project->y2 = New.y2;    *visible = TRUE;  }}/******************************************************************************* FUNCTION      : Project_Bounds** ARGUMENTS     : Project - Bounding box's projection*                 Bounds  - Bounding box*                 visible - Flag if bounding box is visible** MODIFIED ARGS : Project, visible** RETURN VALUE  : none** AUTHOR        : Dieter Bayer, May 1994** DESCRIPTION**   Project a bounding box onto the screen.** CHANGES**   -*******************************************************************************/static void Project_Bounds(Project, Bounds, visible)PROJECT *Project;BBOX *Bounds;int *visible;{  int i;  VECTOR P[8];  for (i = 0; i<8; i++)  {    P[i] = Bounds->Lower_Left;    P[i].x += ((i & 1) ? Bounds->Lengths.x : 0.0);    P[i].y += ((i & 2) ? Bounds->Lengths.y : 0.0);    P[i].z += ((i & 4) ? Bounds->Lengths.z : 0.0);    Transform_Point (&P[i]);  }  Project_Bbox(Project, &P[0], visible);}/******************************************************************************* FUNCTION      : Project_Bicubic_Patch** ARGUMENTS     : Project - Projection*                 Object  - Object** MODIFIED ARGS : Project** RETURN VALUE  : none** AUTHOR        : Dieter Bayer, May 1994** DESCRIPTION**   Project the bounding sphere of a bicubic patch onto the screen.** CHANGES**   -*******************************************************************************/static void Project_Bicubic_Patch(Project, Object)PROJECT *Project;OBJECT *Object;{  BICUBIC_PATCH *patch;  DBL x, y, z, r, a20, a02, a11, a10, a01, a00;  MATRIX A;  patch = (BICUBIC_PATCH *)Object;  /* Set up 4x4 quadric matrix A */  x = patch->Bounding_Sphere_Center.x;  y = patch->Bounding_Sphere_Center.y;  z = patch->Bounding_Sphere_Center.z;  r = 1.0 / (patch->Bounding_Sphere_Radius * patch->Bounding_Sphere_Radius);  A[0][0] = r;    A[0][1] = 0.0;  A[0][2] = 0.0;  A[0][3] = -x*r;  A[1][0] = 0.0;  A[1][1] = r;    A[1][2] = 0.0;  A[1][3] = -y*r;  A[2][0] = 0.0;  A[2][1] = 0.0;  A[2][2] = r;    A[2][3] = -z*r;  A[3][0] = -x*r; A[3][1] = -y*r; A[3][2] = -z*r; A[3][3] = r*(x*x+y*y+z*z) - 1.0;  Project_Vista(&A, NULL, &a20, &a02, &a11, &a10, &a01, &a00);  /* Get vista's bounding rectangle */  Get_Ellipse_Projection(Project, a20, a02, a11, a10, a01, a00);}/******************************************************************************* FUNCTION      : Project_Box** ARGUMENTS     : Project - Projection*                 Object  - Object*                 visible - Flag if object is visible** MODIFIED ARGS : Project, visible** RETURN VALUE  : none** AUTHOR        : Dieter Bayer, May 1994** DESCRIPTION**   Project a box onto the screen.** CHANGES**   -*******************************************************************************/static void Project_Box(Project, Object, visible)PROJECT *Project;OBJECT *Object;int *visible;{  int i;  VECTOR P[8];  BOX *box;  box = (BOX *)Object;  for (i = 0; i<8; i++)  {    P[i] = box->bounds[0];    if (i & 1) P[i].x = box->bounds[1].x;    if (i & 2) P[i].y = box->bounds[1].y;    if (i & 4) P[i].z = box->bounds[1].z;    if (box->Trans != NULL)      MTransPoint(&P[i], &P[i], box->Trans);    Transform_Point (&P[i]);  }  Project_Bbox(Project, &P[0], visible);}/******************************************************************************* FUNCTION      : Project_Height_Field** ARGUMENTS     : Project - Projection*                 Object  - Object*                 visible - Flag if object is visible** MODIFIED ARGS : Project, visible** RETURN VALUE  : none** AUTHOR        : Dieter Bayer, May 1994** DESCRIPTION**   Project the bounding box of a height field onto the screen.** CHANGES**   -*******************************************************************************/static void Project_Height_Field(Project, Object, visible)PROJECT *Project;OBJECT *Object;int *visible;{  int i;  VECTOR P[8];  HEIGHT_FIELD *hfield;  hfield = (HEIGHT_FIELD *)Object;  for (i = 0; i<8; i++)  {    P[i] = hfield->bounding_box->bounds[0];    if (i & 1) P[i].x = hfield->bounding_box->bounds[1].x;    if (i & 2) P[i].y = hfield->bounding_box->bounds[1].y;    if (i & 4) P[i].z = hfield->bounding_box->bounds[1].z;    if (hfield->Trans != NULL)      MTransPoint(&P[i], &P[i], hfield->Trans);    Transform_Point (&P[i]);  }  Project_Bbox(Project, &P[0], visible);}/******************************************************************************* FUNCTION      : Project_Triangle** ARGUMENTS     : Project - Projection*                 Object  - Object*                 visible - Flag if object is visible** MODIFIED ARGS : Project, visible** RETURN VALUE  : none** AUTHOR        : Dieter Bayer, May 1994** DESCRIPTION**   Project a triangle onto the screen.** CHANGES**   -*******************************************************************************/static void Project_Triangle(Project, Object, visible)PROJECT *Project;OBJECT *Object;int *visible;{  int i, vis;  VECTOR P[3];  PROJECT New;  New.x1 = MAX_VB_ENTRY;  New.x2 = MIN_VB_ENTRY;  New.y1 = MAX_VB_ENTRY;  New.y2 = MIN_VB_ENTRY;  P[0] = ((TRIANGLE *)Object)->P1;  P[1] = ((TRIANGLE *)Object)->P2;  P[2] = ((TRIANGLE *)Object)->P3;  for (i = 0; i < 3; i++)  {    Transform_Point(&P[i]);  }  vis = FALSE;  Project_triangle(&New, P[0], P[1], P[2], &vis);  if (vis)  {    if (New.x1 > Project->x1) Project->x1 = New.x1;    if (New.x2 < Project->x2) Project->x2 = New.x2;    if (New.y1 > Project->y1) Project->y1 = New.y1;    if (New.y2 < Project->y2) Project->y2 = New.y2;    *visible = TRUE;  }}/******************************************************************************* FUNCTION      : Project_Smooth_Triangle** ARGUMENTS     : Project - Projection*                 Object  - Object*                 visible - Flag if object is visible** MODIFIED ARGS : Project, visible** RETURN VALUE  : none** AUTHOR        : Dieter Bayer, May 1994** DESCRIPTION**   Project a smooth triangle onto the screen.** CHANGES**   -*******************************************************************************/static void Project_Smooth_Triangle(Project, Object, visible)PROJECT *Project;OBJECT *Object;int *visible;{  int i, vis;  VECTOR P[3];  PROJECT New;  New.x1 = MAX_VB_ENTRY;  New.x2 = MIN_VB_ENTRY;  New.y1 = MAX_VB_ENTRY;  New.y2 = MIN_VB_ENTRY;  P[0] = ((SMOOTH_TRIANGLE *)Object)->P1;  P[1] = ((SMOOTH_TRIANGLE *)Object)->P2;  P[2] = ((SMOOTH_TRIANGLE *)Object)->P3;  for (i = 0; i < 3; i++)  {    Transform_Point(&P[i]);  }  vis = FALSE;  Project_triangle(&New, P[0], P[1], P[2], &vis);  if (vis)  {    if (New.x1 > Project->x1) Project->x1 = New.x1;    if (New.x2 < Project->x2) Project->x2 = New.x2;    if (New.y1 > Project->y1) Project->y1 = New.y1;    if (New.y2 < Project->y2) Project->y2 = New.y2;    *visible = TRUE;  }}/******************************************************************************* FUNCTION      : Project_Sphere** ARGUMENTS     : Project - Projection*                 Object  - Oject** MODIFIED ARGS : Project** RETURN VALUE  : none** AUTHOR        : Dieter Bayer, May 1994** DESCRIPTION**   Project a sphere onto the screen.** CHANGES**   -*******************************************************************************/static void Project_Sphere(Project, Object)PROJECT *Project;OBJECT *Object;{  SPHERE *sphere;  DBL x, y, z, r, a20, a02, a11, a10, a01, a00;  MATRIX A;  sphere = (SPHERE *)Object;  /* Set up 4x4 quadric matrix A0 */  x = sphere->Center.x;  y = sphere->Center.y;  z = sphere->Center.z;  r = 1.0/sphere->Radius_Squared;  A[0][0] = r;    A[0][1] = 0.0;  A[0][2] = 0.0;  A[0][3] = -x*r;  A[1][0] = 0.0;  A[1][1] = r;    A[1][2] = 0.0;  A[1][3] = -y*r;  A[2][0] = 0.0;  A[2][1] = 0.0;  A[2][2] = r;    A[2][3] = -z*r;  A[3][0] = -x*r; A[3][1] = -y*r; A[3][2] = -z*r; A[3][3] = r*(x*x+y*y+z*z) - 1.0;  Project_Vista(&A, sphere->Trans, &a20, &a02, &a11, &a10, &a01, &a00);  /* get vista's bounding rectangle */  Get_Ellipse_Projection(Project, a20, a02, a11, a10, a01, a00);}/******************************************************************************* FUNCTION      : Get_Ellipse_Projection** ARGUMENTS     : Project        - Projection*                 a20, a02, a11,*                 a10, a01, a00  - Parameters of the quadratic curve** MODIFIED ARGS : Project** RETURN VALUE  : none** AUTHOR        : Dieter Bayer, May 1994** DESCRIPTION**   Get the bounding rectangle around an ellipse, i.e. the*   quadratic curve: a20*x*x + a02*y*y + a11*x*y + a10*x + a01*y + a00 = 0** CHANGES**   -*******************************************************************************/static void Get_Ellipse_Projection(Project, a20, a02, a11, a10, a01, a00)PROJECT *Project;DBL a20, a02, a11, a10, a01, a00;{  int x1i, x2i, y1i, y2i;  DBL x1, y1, x2, y2;  DBL a, b, c, d, k, k1, k2, k3, k4;  x1 = y1 = -0.5;  x2 = y2 = +0.5;  k1 = a11/(-2.0*a20);  k2 = a10/(-2.0*a20);  k3 = a11/(-2.0*a02);  k4 = a01/(-2.0*a02);  a = a20 + a02*k3*k3 + a11*k3;  b = a10 + 2.0*a02*k3*k4 + a01*k3 + a11*k4;  c = a02*k4*k4 + a01*k4 + a00;  d = b*b - 4.0*a*c;  if (d > 0.0)  {    a = 2.0*a;    d = sqrt(d);    x1 = (-b+d)/a;    x2 = (-b-d)/a;    if (x1>x2)    {      k = x1; x1 = x2; x2 = k;    }    a = a02 + a20*k1*k1 + a11*k1;    b = a01 + 2.0*a20*k1*k2 + a10*k1 + a11*k2;    c = a20*k2*k2 + a10*k2 + a00;    d = b*b - 4.0*a*c;    if (d > 0.0)    {      a = 2.0*a;      d = sqrt(d);      y1 = (-b+d)/a;      y2 = (-b-d)/a;      if (y1>y2)      {	k = y1; y1 = y2; y2 = k;      }    }  }  if (x1 < -0.5) x1 = -0.5;  if (x2 > +0.5) x2 = +0.5;  if (y1 < -0.5) y1 = -0.5;  if (y2 > +0.5) y2 = +0.5;  x1i = Frame.Screen_Width/2 + (int)(Frame.Screen_Width * x1) - 1;  x2i = Frame.Screen_Width/2 + (int)(Frame.Screen_Width * x2) + 1;  y1i = Frame.Screen_Height/2 - (int)(Frame.Screen_Height * y2) - 1;  y2i = Frame.Screen_Height/2 - (int)(Frame.Screen_Height * y1) + 1;  if (x1i > Project->x1) Project->x1 = x1i;  if (x2i < Project->x2) Project->x2 = x2i;  if (y1i > Project->y1) Project->y1 = y1i;  if (y2i < Project->y2) Project->y2 = y2i;}/******************************************************************************* FUNCTION      : Project_Vista** ARGUMENTS     : A0             - Matrix defining the quadric surface*                 Trans          - Transformation matrices*                 a20, a02, a11,*                 a10, a01, a00  - Parameters of the projected quadratic curve** MODIFIED ARGS : a20, a02, a11, a10, a01, a00** RETURN VALUE  : none** AUTHOR        : Dieter Bayer, May 1994** DESCRIPTION**   Project a quadric surface onto the screen (perspective projection)*   and get the paramters of the resulting quadratic curve.** CHANGES**   -*******************************************************************************/void Project_Vista(A0, Trans, a20, a02, a11, a10, a01, a00)MATRIX *A0;TRANSFORM *Trans;DBL *a20, *a02, *a11, *a10, *a01, *a00;{  int i, j;  MATRIX Tinv, A1, A2, B, Transposed_Matrix;  DBL k1, k2, k3;  /* Apply object transformations */  if (Trans == NULL)  {    for (i=0;i<4;i++)    {      for (j=0;j<4;j++)      {	A1[i][j] = (*A0)[i][j];      }    }  }  else  {    MTranspose(&Transposed_Matrix, &Trans->inverse);    MTimes(&A1, &Trans->inverse, A0);    MTimes(&A1, &A1, &Transposed_Matrix);  }  /* Transform into viewing system */  MTranspose(&Transposed_Matrix, &WC2VCinv);  MTimes(&A2, &Transposed_Matrix, &A1);  MTimes(&A2, &A2, &WC2VCinv);  /* Calculate quadrics vista */  MIdentity(&Tinv);  Tinv[3][2] = -1.0;  MTranspose(&Transposed_Matrix, &Tinv);  MTimes(&B, &Transposed_Matrix, &A2);  MTimes(&B, &B, &Tinv);  k1 = (B[0][2]+B[2][0])/(-2.0*B[2][2]);  k2 = (B[1][2]+B[2][1])/(-2.0*B[2][2]);  k3 = (B[2][3]+B[3][2])/(-2.0*B[2][2]);  *a20 = B[0][0] + k1*(B[0][2]+B[2][0]) + k1*k1*B[2][2];  *a02 = B[1][1] + k2*(B[1][2]+B[2][1]) + k2*k2*B[2][2];  *a10 = B[0][3]+B[3][0] + k1*(B[2][3]+B[3][2]) + k3*(B[0][2]+B[2][0]) + 2.0*k1*k3*B[2][2];  *a01 = B[1][3]+B[3][1] + k2*(B[2][3]+B[3][2]) + k3*(B[1][2]+B[2][1]) + 2.0*k2*k3*B[2][2];  *a11 = B[0][1]+B[1][0] + k1*(B[1][2]+B[2][1]) + k2*(B[0][2]+B[2][0]) + 2.0*k1*k2*B[2][2];  *a00 = B[3][3] + k3*(B[2][3]+B[3][2]) + k3*k3*B[2][2];}/******************************************************************************* FUNCTION      : Transform_Point** ARGUMENTS     : P - Point to transform** MODIFIED ARGS : P** RETURN VALUE  : none** AUTHOR        : Dieter Bayer, May 1994** DESCRIPTION**   Transform a point from the world coordinate system to the viewer's*   coordinate system.** CHANGES**   -*******************************************************************************/static void Transform_Point(P)VECTOR *P;{  DBL x,y,z;  x = P->x - O.x;  y = P->y - O.y;  z = P->z - O.z;  P->x = U.x * x + U.y * y + U.z * z;  P->y = V.x * x + V.y * y + V.z * z;  P->z = W.x * x + W.y * y + W.z * z;}/******************************************************************************* FUNCTION      : Init_View_Coordinates** ARGUMENTS     : none** MODIFIED ARGS : none** RETURN VALUE  : none** AUTHOR        : Dieter Bayer, May 1994** DESCRIPTION**   Init the matrices and vectors used to transform a point from*   the world coordinate system to the viewer's coordinate system.** CHANGES**   -*******************************************************************************/void Init_View_Coordinates(){  DBL k, up_length, right_length;  MATRIX A, B;  U = Frame.Camera->Right;  V = Frame.Camera->Up;  W = Frame.Camera->Direction;  VAdd (O, Frame.Camera->Location, Frame.Camera->Direction);  VNormalize(U,U);  VNormalize(V,V);  VNormalize(W,W);  VDot(k, U,V);  if (fabs(k) > EPSILON)    Fatal_Error("Camera: Right-vector not perpendicular to Up-vector.\n");  VDot(k, U,W);  if (fabs(k) > EPSILON)    Fatal_Error("Camera: Right-vector not perpendicular to Direction-vector.\n");  VDot(k, V,W);  if (fabs(k) > EPSILON)    Fatal_Error("Camera: Up-vector not perpendicular to Direction-vector.\n");  VLength (distance, Frame.Camera->Direction);  VLength (up_length, Frame.Camera->Up);  VLength (right_length, Frame.Camera->Right);  VScaleEq (U, 1.0/right_length);  VScaleEq (V, 1.0/up_length);  VScaleEq (W, 1.0/distance);  A[0][0] = U.x; A[0][1] = U.y; A[0][2] = U.z; A[0][3] = 0.0;  A[1][0] = V.x; A[1][1] = V.y; A[1][2] = V.z; A[1][3] = 0.0;  A[2][0] = W.x; A[2][1] = W.y; A[2][2] = W.z; A[2][3] = 0.0;  A[3][0] = 0.0; A[3][1] = 0.0; A[3][2] = 0.0; A[3][3] = 1.0;  B[0][0] = 1.0; B[0][1] = 0.0; B[0][2] = 0.0; B[0][3] = -O.x;  B[1][0] = 0.0; B[1][1] = 1.0; B[1][2] = 0.0; B[1][3] = -O.y;  B[2][0] = 0.0; B[2][1] = 0.0; B[2][2] = 1.0; B[2][3] = -O.z;  B[3][0] = 0.0; B[3][1] = 0.0; B[3][2] = 0.0; B[3][3] = 1.0;  MTimes(&WC2VC, &A, &B);  MInvers(&WC2VCinv, &WC2VC);}/******************************************************************************* FUNCTION      : Get_Perspective_Projection** ARGUMENTS     : Object   - Object to project*                 Project  - Projection*                 infinite - Flag if object is infinite** MODIFIED ARGS : Project** RETURN VALUE  : none** AUTHOR        : Dieter Bayer, May 1994** DESCRIPTION**   Get the perspective projection of a single object, i.e.*   the smallest rectangle enclosing the object's image on the screen.** CHANGES**   -*******************************************************************************/static void Get_Perspective_Projection(Object, Project, infinite)OBJECT *Object;PROJECT *Project;int infinite;{  int visible;  METHODS *Methods;  visible = FALSE;  Methods = Object->Methods;  /* If the object is infinite, there's no sense of projecting */  if (!infinite)  {    if ((Methods == &Box_Methods) ||	(Methods == &Smooth_Triangle_Methods) ||	(Methods == &Triangle_Methods) ||	(Methods == &Csg_Height_Field_Methods) ||	(Methods == &Height_Field_Methods))    {      if (Methods == &Box_Methods)	Project_Box(Project, Object, &visible);      if (Methods == &Csg_Height_Field_Methods)	Project_Height_Field(Project, Object, &visible);      if (Methods == &Height_Field_Methods)	Project_Height_Field(Project, Object, &visible);      if (Methods == &Smooth_Triangle_Methods)	Project_Smooth_Triangle(Project, Object, &visible);      if (Methods == &Triangle_Methods)	Project_Triangle(Project, Object, &visible);    }    else    {      Project_Bounds(Project, &Object->Bounds, &visible);/*      if (Object->Methods == &Bicubic_Patch_Methods)	Project_Bicubic_Patch(Project, Object);      if (Object->Methods == &Ellipsoid_Methods)	Project_Sphere(Project, Object);      if (Object->Methods == &Sphere_Methods)	Project_Sphere(Project, Object);*/    }  }  /* We don't want invisible objects to become visible due to     an oversized bouding object, so we project the bounding     object only if the object itself is visible! */  if (visible & (Object->Bound != NULL))  {    if (Object->Bound->Methods == &Box_Methods)      Project_Box(Project, Object->Bound, &visible);    if (Object->Bound->Methods == &Ellipsoid_Methods)      Project_Sphere(Project, Object->Bound);    if (Object->Bound->Methods == &Sphere_Methods)      Project_Sphere(Project, Object->Bound);  }  if (visible)  {    if (Options & ANTIALIAS)    {      /* Increase the rectangle to make sure that nothing will be missed.	 For anti-aliased images increase by a larger amount. */      Project->x1 = max (0,                     Project->x1 - 2);      Project->x2 = min (Frame.Screen_Width-1,  Project->x2 + 2);      Project->y1 = max (-1,                    Project->y1 - 2);      Project->y2 = min (Frame.Screen_Height-1, Project->y2 + 2);    }    else    {      /* Increase the rectangle to make sure that nothing will be missed. */      Project->x1 = max (0,                     Project->x1 - 1);      Project->x2 = min (Frame.Screen_Width-1,  Project->x2 + 1);      Project->y1 = max (0,                     Project->y1 - 1);      Project->y2 = min (Frame.Screen_Height-1, Project->y2 + 1);    }  }  else  {    if (!infinite)    {      /* Object is invisible (the camera can't see it) */      Project->x1 = Project->y1 = MAX_VB_ENTRY;      Project->x2 = Project->y2 = MIN_VB_ENTRY;    }  }}/******************************************************************************* FUNCTION      : Project_Object** ARGUMENTS     : Object   - Object to project*                 Project  - Projection** MODIFIED ARGS : Project** RETURN VALUE  : none** AUTHOR        : Dieter Bayer, May 1994** DESCRIPTION**   Get the projection of a single object depending on the camera*   used (perspective/orthographic).** CHANGES**   -*******************************************************************************/static void Project_Object(Object, Project)OBJECT *Object;PROJECT *Project;{  int infinite;  DBL Volume;  /* Init project fields, assuming the object is visible! */  Project->x1 = Project->y1 = MIN_VB_ENTRY;  Project->x2 = Project->y2 = MAX_VB_ENTRY;  BOUNDS_VOLUME(Volume, Object->Bounds);  infinite = (Volume > INFINITE_VOLUME);  Get_Perspective_Projection(Object, Project, infinite);  Print_Point(POINT_MOD);}/******************************************************************************* FUNCTION      : Project_Bounding_Slab** ARGUMENTS     : Project  - Projection*                 Tree     - Current node/leaf*                 Object   - Node/leaf in bounding slab hierarchy** MODIFIED ARGS : Project, Tree** RETURN VALUE  : none** AUTHOR        : Dieter Bayer, May 1994** DESCRIPTION**   Project the bounding slab hierarchy onto the screen and thus create*   the vista buffer hierarchy.** CHANGES**   -*******************************************************************************/static void Project_Bounding_Slab(Project, Tree, Object)PROJECT *Project;PROJECT_TREE_NODE **Tree;OBJECT *Object;{  unsigned short int i;  COMPOSITE *Comp;  PROJECT Temp;  PROJECT_TREE_LEAF *Leaf;  PROJECT_TREE_NODE New;  if (Object->Type & BOUNDING_OBJECT)  {    /* Current object is a bounding object, i.e. a node in the slab tree */    Comp = (COMPOSITE *)Object;    /* First, init new entry */    New.Entries = 0;    New.Object = Object;    New.Project.x1 = New.Project.y1 = MAX_VB_ENTRY;    New.Project.x2 = New.Project.y2 = MIN_VB_ENTRY;    for (i = 0; i < BUNCHING_FACTOR; i++)    {      New.Entry[i] = NULL;    }    /* This is no leaf */    New.is_leaf = FALSE;    /* Second, get new entry, i.e. project node's entries */    for (i = 0; i < Comp->Entries; i++)    {      Project_Bounding_Slab(&Temp, &New.Entry[New.Entries], Comp->Objects[i]);      /* Use only visible entries */      if (New.Entry[New.Entries] != NULL)      {	New.Project.x1 = min(New.Project.x1, Temp.x1);	New.Project.x2 = max(New.Project.x2, Temp.x2);	New.Project.y1 = min(New.Project.y1, Temp.y1);	New.Project.y2 = max(New.Project.y2, Temp.y2);	New.Entries++;      }    }    /* If the new entry is visible we'll use it */    if (New.Entries > 0)    {      /* If there's only one entry, we won't need a new node. */      if (New.Entries == 1)      {	*Tree    = New.Entry[0];	*Project = New.Project;      }      else      {	/* Allocate memory for new node in the vista tree (never freed!)  */	*Tree = (PROJECT_TREE_NODE *)VB_malloc(sizeof(PROJECT_TREE_NODE));	if (*Tree == NULL)	{	  Fatal_MAError("vista tree node");	}	**Tree = New;	*Project = New.Project;      }    }  }  else  {    /* Current object is a normal object, i.e. a leaf in the slab tree */    /* Get object's projection */    Project_Object(Object, Project);    /* Is the object visible? */    if ((Project->x1 <= Project->x2) && (Project->y1 <= Project->y2))    {      /* Allocate memory for new leaf in the vista tree (never freed!)  */      *Tree = (PROJECT_TREE_NODE *)VB_malloc(sizeof(PROJECT_TREE_LEAF));      if (*Tree == NULL)      {	Fatal_MAError("vista tree leaf");      }      /* Init new leaf */      Leaf = (PROJECT_TREE_LEAF *)(*Tree);      Leaf->Object = Object;      Leaf->Project = *Project;      /* Yes, this is a leaf */      Leaf->is_leaf = TRUE;    }  }}/******************************************************************************* FUNCTION      : Build_Vista_Tree** ARGUMENTS     : none** MODIFIED ARGS : none** RETURN VALUE  : none** AUTHOR        : Dieter Bayer, May 1994** DESCRIPTION**   Build the vista tree, i.e. the 2d representation of the bounding slab*   hierarchy in image space.**   This only works for perspective and orthographic cameras.** CHANGES**   -*******************************************************************************/void Build_Vista_Tree(){  PROJECT Project;  Root_Vista = NULL;  if (Use_Slabs)  {    fprintf(stderr, "Building vista buffer");    Begin_Point();    Project_Bounding_Slab(&Project, &Root_Vista, Root_Object);    End_Point();  }}#endif