/****************************************************************************
* vlbuffer.c
*
* This module implements functions that are used by the vista/light buffer.
*
* This module was written by Dieter Bayer [DB].
*
* from Persistence of Vision(tm) Ray Tracer
* Copyright 1996 Persistence of Vision Team
*---------------------------------------------------------------------------
* NOTICE: This source code file is provided so that users may experiment
* with enhancements to POV-Ray and to port the software to platforms other
* than those supported by the POV-Ray Team. There are strict rules under
* which you are permitted to use this file. The rules are in the file
* named POVLEGAL.DOC which should be distributed with this file. If
* POVLEGAL.DOC is not available or for more info please contact the POV-Ray
* Team Coordinator by leaving a message in CompuServe's Graphics Developer's
* Forum. The latest version of POV-Ray may be found there as well.
*
* This program is based on the popular DKB raytracer version 2.12.
* DKBTrace was originally written by David K. Buck.
* DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
*
*****************************************************************************/
/****************************************************************************
*
* Explanation:
*
* -
*
* ---
*
* Mar 1994 : Creation.
*
*****************************************************************************/
#include "frame.h"
#include "vector.h"
#include "povproto.h"
#include "bbox.h"
#include "vlbuffer.h"
/*****************************************************************************
* Local preprocessor defines
******************************************************************************/
#define INITIAL_NUMBER_OF_ENTRIES 256
/*****************************************************************************
* Local typedefs
******************************************************************************/
/*****************************************************************************
* Local variables
******************************************************************************/
/* Tree node queue. */
PROJECT_QUEUE *Node_Queue;
/* Priority queue. */
PRIORITY_QUEUE *VLBuffer_Queue;
/*****************************************************************************
* Static functions
******************************************************************************/
/*****************************************************************************
*
* FUNCTION
*
* Initialize_VLBuffer_Code
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* Dieter Bayer
*
* DESCRIPTION
*
* Init queues used by the light and vista buffer.
*
* CHANGES
*
* May 1994 : Creation.
*
******************************************************************************/
void Initialize_VLBuffer_Code()
{
Node_Queue = (PROJECT_QUEUE *)POV_MALLOC(sizeof(PROJECT_QUEUE),
"vista/light buffer node queue");
Node_Queue->QSize = 0;
Node_Queue->Max_QSize = INITIAL_NUMBER_OF_ENTRIES;
Node_Queue->Queue = (PROJECT_TREE_NODE **)POV_MALLOC(Node_Queue->Max_QSize*sizeof(PROJECT_TREE_NODE *),
"vista/light buffer node queue");
VLBuffer_Queue = Create_Priority_Queue(INITIAL_NUMBER_OF_ENTRIES);
}
/*****************************************************************************
*
* FUNCTION
*
* Reinitialize_VLBuffer_Code
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* Dieter Bayer
*
* DESCRIPTION
*
* Reinit queues used by the light and vista buffer.
*
* Note that only the node queue needs to be reinitialized.
*
* CHANGES
*
* Feb 1995 : Creation.
*
******************************************************************************/
void Reinitialize_VLBuffer_Code()
{
if (Node_Queue->QSize >= Node_Queue->Max_QSize)
{
if (Node_Queue->QSize >= INT_MAX/2)
{
Error("Node queue overflow.\n");
}
Node_Queue->Max_QSize *= 2;
Node_Queue->Queue = (PROJECT_TREE_NODE **)POV_REALLOC(Node_Queue->Queue,
Node_Queue->Max_QSize*sizeof(PROJECT_TREE_NODE *),
"vista/light buffer node queue");
}
}
/*****************************************************************************
*
* FUNCTION
*
* Deinitialize_VLBuffer_Code
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* Dieter Bayer
*
* DESCRIPTION
*
* Deinit queues used by the light and vista buffer.
*
* CHANGES
*
* May 1994 : Creation.
*
******************************************************************************/
void Deinitialize_VLBuffer_Code()
{
if (Node_Queue != NULL)
{
POV_FREE(Node_Queue->Queue);
POV_FREE(Node_Queue);
}
if (VLBuffer_Queue != NULL)
{
Destroy_Priority_Queue(VLBuffer_Queue);
}
Node_Queue = NULL;
VLBuffer_Queue = NULL;
}
/*****************************************************************************
*
* FUNCTION
*
* Clip_Polygon
*
* INPUT
*
* Points - polygon's points
* PointCnt - Number of points in polygon
* VX1, VY1, VX2, VY1 - Normal vectors of the clipping planes
* DX1, DY1, DX2, DY2 - Distances of the clipping planes from
* the origin
*
* OUTPUT
*
* Points, PointCnt
*
* RETURNS
*
* AUTHOR
*
* Dieter Bayer
*
* DESCRIPTION
*
* Clip polygon at the viewing pyramid define by the normal vectors
* VX1, VX2, VY1, VY2 and the distances DX1, DX2, DY1, DY2.
*
* CHANGES
*
* May 1994 : Creation.
*
******************************************************************************/
void Clip_Polygon(Points, PointCnt, VX1, VX2, VY1, VY2, DX1, DX2, DY1, DY2)
VECTOR *Points;
int *PointCnt;
VECTOR VX1, VX2, VY1, VY2;
DBL DX1, DX2, DY1, DY2;
{
DBL aktd, pred, fird, k;
VECTOR aktP, intP, preP, firP, d;
int i, pc;
VECTOR ClipPoints[MAX_CLIP_POINTS];
/********** clip polygon at "left" plane **********/
pc = 0;
Assign_Vector(firP, Points[0]);
fird = VX1[X] * firP[X] + VX1[Y] * firP[Y] + VX1[Z] * firP[Z] - DX1;
if (fird <= 0.0)
{
Assign_Vector(ClipPoints[pc++], firP);
}
Assign_Vector(aktP, firP);
Assign_Vector(preP, firP);
aktd = pred = fird;
for (i = 1; i < *PointCnt; i++)
{
Assign_Vector(aktP, Points[i]);
aktd = VX1[X] * aktP[X] + VX1[Y] * aktP[Y] + VX1[Z] * aktP[Z] - DX1;
if (((aktd < 0.0) && (pred > 0.0)) || ((aktd > 0.0) && (pred < 0.0)))
{
d[X] = preP[X] - aktP[X];
d[Y] = preP[Y] - aktP[Y];
d[Z] = preP[Z] - aktP[Z];
k = -aktd / (VX1[X] * d[X] + VX1[Y] * d[Y] + VX1[Z] * d[Z]);
intP[X] = aktP[X] + k * d[X];
intP[Y] = aktP[Y] + k * d[Y];
intP[Z] = aktP[Z] + k * d[Z];
Assign_Vector(ClipPoints[pc++], intP);
}
if (aktd <= 0.0)
{
Assign_Vector(ClipPoints[pc++], aktP);
}
Assign_Vector(preP, aktP);
pred = aktd;
}
if (((fird < 0.0) && (aktd > 0.0)) || ((fird > 0.0) && (aktd < 0.0)))
{
d[X] = firP[X] - aktP[X];
d[Y] = firP[Y] - aktP[Y];
d[Z] = firP[Z] - aktP[Z];
k = -aktd / (VX1[X] * d[X] + VX1[Y] * d[Y] + VX1[Z] * d[Z]);
intP[X] = aktP[X] + k * d[X];
intP[Y] = aktP[Y] + k * d[Y];
intP[Z] = aktP[Z] + k * d[Z];
Assign_Vector(ClipPoints[pc++], intP);
}
for (i = 0; i < pc; i++)
{
Assign_Vector(Points[i], ClipPoints[i]);
}
if ((*PointCnt = pc) == 0)
return;
/********** clip polygon at "right" plane **********/
pc = 0;
Assign_Vector(firP, Points[0]);
fird = VX2[X] * firP[X] + VX2[Y] * firP[Y] + VX2[Z] * firP[Z] - DX2;
if (fird <= 0.0)
{
Assign_Vector(ClipPoints[pc++], firP);
}
Assign_Vector(aktP, firP);
Assign_Vector(preP, firP);
aktd = pred = fird;
for (i = 1; i < *PointCnt; i++)
{
Assign_Vector(aktP, Points[i]);
aktd = VX2[X] * aktP[X] + VX2[Y] * aktP[Y] + VX2[Z] * aktP[Z] - DX2;
if (((aktd < 0.0) && (pred > 0.0)) || ((aktd > 0.0) && (pred < 0.0)))
{
d[X] = preP[X] - aktP[X];
d[Y] = preP[Y] - aktP[Y];
d[Z] = preP[Z] - aktP[Z];
k = -aktd / (VX2[X] * d[X] + VX2[Y] * d[Y] + VX2[Z] * d[Z]);
intP[X] = aktP[X] + k * d[X];
intP[Y] = aktP[Y] + k * d[Y];
intP[Z] = aktP[Z] + k * d[Z];
Assign_Vector(ClipPoints[pc++], intP);
}
if (aktd <= 0.0)
{
Assign_Vector(ClipPoints[pc++], aktP);
}
Assign_Vector(preP, aktP);
pred = aktd;
}
if (((fird < 0.0) && (aktd > 0.0)) || ((fird > 0.0) && (aktd < 0.0)))
{
d[X] = firP[X] - aktP[X];
d[Y] = firP[Y] - aktP[Y];
d[Z] = firP[Z] - aktP[Z];
k = -aktd / (VX2[X] * d[X] + VX2[Y] * d[Y] + VX2[Z] * d[Z]);
intP[X] = aktP[X] + k * d[X];
intP[Y] = aktP[Y] + k * d[Y];
intP[Z] = aktP[Z] + k * d[Z];
Assign_Vector(ClipPoints[pc++], intP);
}
for (i = 0; i < pc; i++)
{
Assign_Vector(Points[i], ClipPoints[i]);
}
if ((*PointCnt = pc) == 0)
return;
/********** clip polygon at "bottom" plane **********/
pc = 0;
Assign_Vector(firP, Points[0]);
fird = VY1[X] * firP[X] + VY1[Y] * firP[Y] + VY1[Z] * firP[Z] - DY1;
if (fird <= 0.0)
{
Assign_Vector(ClipPoints[pc++], firP);
}
Assign_Vector(aktP, firP);
Assign_Vector(preP, firP);
aktd = pred = fird;
for (i = 1; i < *PointCnt; i++)
{
Assign_Vector(aktP, Points[i]);
aktd = VY1[X] * aktP[X] + VY1[Y] * aktP[Y] + VY1[Z] * aktP[Z] - DY1;
if (((aktd < 0.0) && (pred > 0.0)) || ((aktd > 0.0) && (pred < 0.0)))
{
d[X] = preP[X] - aktP[X];
d[Y] = preP[Y] - aktP[Y];
d[Z] = preP[Z] - aktP[Z];
k = -aktd / (VY1[X] * d[X] + VY1[Y] * d[Y] + VY1[Z] * d[Z]);
intP[X] = aktP[X] + k * d[X];
intP[Y] = aktP[Y] + k * d[Y];
intP[Z] = aktP[Z] + k * d[Z];
Assign_Vector(ClipPoints[pc++], intP);
}
if (aktd <= 0.0)
{
Assign_Vector(ClipPoints[pc++], aktP);
}
Assign_Vector(preP, aktP);
pred = aktd;
}
if (((fird < 0.0) && (aktd > 0.0)) || ((fird > 0.0) && (aktd < 0.0)))
{
d[X] = firP[X] - aktP[X];
d[Y] = firP[Y] - aktP[Y];
d[Z] = firP[Z] - aktP[Z];
k = -aktd / (VY1[X] * d[X] + VY1[Y] * d[Y] + VY1[Z] * d[Z]);
intP[X] = aktP[X] + k * d[X];
intP[Y] = aktP[Y] + k * d[Y];
intP[Z] = aktP[Z] + k * d[Z];
Assign_Vector(ClipPoints[pc++], intP);
}
for (i = 0; i < pc; i++)
{
Assign_Vector(Points[i], ClipPoints[i]);
}
if ((*PointCnt = pc) == 0)
return;
/********** clip polygon at "top" plane **********/
pc = 0;
Assign_Vector(firP, Points[0]);
fird = VY2[X] * firP[X] + VY2[Y] * firP[Y] + VY2[Z] * firP[Z] - DY2;
if (fird <= 0.0)
{
Assign_Vector(ClipPoints[pc++], firP);
}
Assign_Vector(aktP, firP);
Assign_Vector(preP, firP);
aktd = pred = fird;
for (i = pc = 0; i < *PointCnt; i++)
{
Assign_Vector(aktP, Points[i]);
aktd = VY2[X] * aktP[X] + VY2[Y] * aktP[Y] + VY2[Z] * aktP[Z] - DY2;
if (((aktd < 0.0) && (pred > 0.0)) || ((aktd > 0.0) && (pred < 0.0)))
{
d[X] = preP[X] - aktP[X];
d[Y] = preP[Y] - aktP[Y];
d[Z] = preP[Z] - aktP[Z];
k = -aktd / (VY2[X] * d[X] + VY2[Y] * d[Y] + VY2[Z] * d[Z]);
intP[X] = aktP[X] + k * d[X];
intP[Y] = aktP[Y] + k * d[Y];
intP[Z] = aktP[Z] + k * d[Z];
Assign_Vector(ClipPoints[pc++], intP);
}
if (aktd <= 0.0)
{
Assign_Vector(ClipPoints[pc++], aktP);
}
Assign_Vector(preP, aktP);
pred = aktd;
}
if (((fird < 0.0) && (aktd > 0.0)) || ((fird > 0.0) && (aktd < 0.0)))
{
d[X] = firP[X] - aktP[X];
d[Y] = firP[Y] - aktP[Y];
d[Z] = firP[Z] - aktP[Z];
k = -aktd / (VY2[X] * d[X] + VY2[Y] * d[Y] + VY2[Z] * d[Z]);
intP[X] = aktP[X] + k * d[X];
intP[Y] = aktP[Y] + k * d[Y];
intP[Z] = aktP[Z] + k * d[Z];
Assign_Vector(ClipPoints[pc++], intP);
}
for (i = 0; i < pc; i++)
{
Assign_Vector(Points[i], ClipPoints[i]);
}
*PointCnt = pc;
}
/*****************************************************************************
*
* FUNCTION
*
* Destroy_Project_Tree
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* Dieter Bayer
*
* DESCRIPTION
*
* Recursively destroy a node in a projection (i.e. vista/light) tree.
*
* CHANGES
*
* Sep 1994 : Creation.
*
* Dec 1994 : Fixed memory leakage due to pruned branches. [DB]
* Mar 1996 : Added COOPERATE for GUIs. [esp]
*
******************************************************************************/
void Destroy_Project_Tree(Node)
PROJECT_TREE_NODE *Node;
{
unsigned short i;
if (Node->is_leaf & TRUE)
{
COOPERATE_1
POV_FREE(Node);
}
else
{
for (i = 0; i < Node->Entries; i++)
{
Destroy_Project_Tree(Node->Entry[i]);
}
POV_FREE(Node->Entry);
POV_FREE(Node);
}
}