Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
Source/SR_LinePipe.c
/****************************************************************************** |
** ** |
** Module: SR_LinePipe.c ** |
** ** |
** ** |
** Purpose: Sample Renderer polygon edge pipeline code ** |
** ** |
** ** |
** ** |
** Copyright (C) 1996 Apple Computer, Inc. All rights reserved. ** |
** ** |
** ** |
*****************************************************************************/ |
#include <stdlib.h> |
#include <assert.h> |
#include "QD3D.h" |
#include "QD3DErrors.h" |
#include "QD3DMath.h" |
#include "SR_Math.h" |
#include "SR.h" |
#include "SR_ClipUtilities.h" |
/*===========================================================================*\ |
* |
* Routine: SR_LinePipe() |
* |
* Comments: Handles lines as well as triangles. |
* |
\*===========================================================================*/ |
TQ3Status SR_LinePipe( |
TSRPrivate *srPrivate, |
TQ3Point3D *localVertices, |
long numVertices, |
long sizeOfLocalVertices, |
TQ3ColorRGB *color, |
TQ3Vector3D *normal, |
long mode) |
{ |
TQ3Status status; |
unsigned long i; |
TQ3RationalPoint4D *deviceVertices = NULL; |
TQ3RationalPoint4D *clippedVertices = NULL; |
TQ3RationalPoint4D *renderVertices = NULL; |
long clipFound, allOut; |
unsigned long *clipFlags = NULL; |
long *clippedVerticesFlags = NULL; |
LineFunction2D lineFunction; |
/* |
* Get the appropriate rasterization function for the lines |
* (depth, whether window is clipped or not, etc. |
*/ |
lineFunction = ((TSRRasterFunctions *) |
(srPrivate->currentRasterFunctions))->lineFunction; |
/* |
* If we're in "DO_POLYGON" mode, then we have to consider whether |
* we need to cull or not. |
*/ |
if (mode == DO_POLYGON) { |
assert(normal != NULL); |
/* |
* We will attempt to do culling if the rank of the upper-left 3x3 |
* submatrix of the local-to-world matrix is at least 2. A rank of 3 |
* means that volumes are transformed into volumes. A rank of 2 means |
* that volumes are transformed onto a plane. For a rank of 1 (line) or |
* 0 (point), we bypass the culling stage and just render the line or |
* point. |
*/ |
if (srPrivate->backfacingStyle == kQ3BackfacingStyleRemove && |
(srPrivate->normalLocalToWorldRank >= 2)) { |
if (normal->x * normal->x + |
normal->y * normal->y + |
normal->z * normal->z < 1.e-10) { |
/* |
* Normal vector's length is < 1.e-10 meaning the polygon is |
* degenerate |
*/ |
return (kQ3Success); |
} |
/* |
* If the local-to-world matrix has a rank of 2, then the eye |
* in local coordinates is a vector even if the view is a |
* perspective transformation. |
*/ |
if ((srPrivate->cameraType == kQ3CameraTypeOrthographic) || |
(srPrivate->normalLocalToWorldRank == 2)) { |
/* Orthographic projection */ |
if ((normal->x * srPrivate->eyeVectorInLocalCoords.x + |
normal->y * srPrivate->eyeVectorInLocalCoords.y + |
normal->z * srPrivate->eyeVectorInLocalCoords.z < 0.0) ^ |
((srPrivate->orientationStyle == |
kQ3OrientationStyleClockwise))) { |
/* |
* Backfacing, so cull it |
*/ |
return (kQ3Success); |
} |
} else { |
TQ3Point3D *point; |
TQ3Vector3D eyeVector; |
/* Perspective projection */ |
point = localVertices; |
eyeVector.x = srPrivate->eyePointInLocalCoords.x - point->x; |
eyeVector.y = srPrivate->eyePointInLocalCoords.y - point->y; |
eyeVector.z = srPrivate->eyePointInLocalCoords.z - point->z; |
if ((normal->x * eyeVector.x + |
normal->y * eyeVector.y + |
normal->z * eyeVector.z < 0.0) ^ |
((srPrivate->orientationStyle == |
kQ3OrientationStyleClockwise))) { |
/* |
* Backfacing, so cull it |
*/ |
return (kQ3Success); |
} |
} |
} |
} |
/* |
* Status set to success - if a subsequent memory allocation fails, or a |
* called function fails, set to failure and bail out. |
*/ |
status = kQ3Success; |
/* |
* Allocate device-coordinate vertices |
*/ |
deviceVertices = malloc(numVertices * sizeof(TQ3RationalPoint4D)); |
if (deviceVertices == NULL) { |
status = kQ3Failure; |
goto bail; |
} |
/* |
* Transform local-space line vertices to device space |
*/ |
Q3Point3D_To4DTransformArray( |
localVertices, |
&srPrivate->transforms.localToDC, |
deviceVertices, |
numVertices, |
sizeOfLocalVertices, |
sizeof(TQ3RationalPoint4D)); |
/* |
* renderVertices are those that will be rendered. If there is a clip, |
* then we'll set this to the clipped vertices instead. |
*/ |
renderVertices = deviceVertices; |
/* |
* Allocate a clip flag for each vertex. Bail if allocation fails. |
*/ |
clipFlags = malloc(numVertices * sizeof(unsigned long)); |
if (clipFlags == NULL) { |
status = kQ3Failure; |
goto bail; |
} |
/* |
* See if we have a clip |
*/ |
SRPointList_ClipTestVertices( |
deviceVertices, |
clipFlags, |
numVertices, |
&srPrivate->clipPlanesInDC[0], |
&clipFound, |
&allOut, |
sizeof(TQ3RationalPoint4D)); |
if (allOut) { |
/* |
* Return now, as nothing need be drawn |
*/ |
goto bail; |
} |
/* |
* We've found a clip, so generate the clipped vertext list |
*/ |
if (clipFound) { |
long numberOfClippedVertices; |
/* |
* Allocate space for clipped vertices. There will be at most |
* twice as many of these as there are in the original geometric |
* primitive. Bail if allocation fails. |
*/ |
clippedVertices = |
malloc((numVertices << 1) * sizeof(TQ3RationalPoint4D)); |
if (clippedVertices == NULL) { |
status = kQ3Failure; |
goto bail; |
} |
/* |
* Allocate space for clip flags for vertices. Bail if allocation |
* fails. |
*/ |
clippedVerticesFlags = malloc((numVertices << 1) * sizeof(long)); |
if (clippedVerticesFlags == NULL) { |
status = kQ3Failure; |
goto bail; |
} |
/* |
* Generate the clipped vertex list |
*/ |
SRPointList_ClipVertices( |
deviceVertices, |
sizeof(TQ3RationalPoint4D), |
clippedVertices, |
sizeof(TQ3RationalPoint4D), |
clipFlags, |
clippedVerticesFlags, |
numVertices, |
&numberOfClippedVertices, |
&srPrivate->clipPlanesInDC[0], |
mode); |
if (numberOfClippedVertices == 0) { |
goto bail; |
} |
renderVertices = clippedVertices; |
numVertices = numberOfClippedVertices; |
} |
/* |
* Divide by homogeneous coordinate, but only if |
* we've NOT found a clip - in that case, the w divide has |
* already been done... |
*/ |
if (!clipFound) { |
SRPointList_WDivide( |
renderVertices, |
numVertices, |
sizeof(TQ3RationalPoint4D)); |
} |
#if DEBUGGING |
if (FLOAT_ROUND_TO_LONG_POSITIVE(renderVertices[0].x) < srPrivate->clipPlanesInDC[0]) { |
goto bail; |
} |
if (FLOAT_ROUND_TO_LONG_POSITIVE(renderVertices[0].x) > srPrivate->clipPlanesInDC[1]) { |
goto bail; |
} |
if (FLOAT_ROUND_TO_LONG_POSITIVE(renderVertices[0].y) < srPrivate->clipPlanesInDC[2]) { |
goto bail; |
} |
if (FLOAT_ROUND_TO_LONG_POSITIVE(renderVertices[0].y) > srPrivate->clipPlanesInDC[3]) { |
goto bail; |
} |
if (FLOAT_ROUND_TO_LONG_POSITIVE(renderVertices[1].x) < srPrivate->clipPlanesInDC[0]) { |
goto bail; |
} |
if (FLOAT_ROUND_TO_LONG_POSITIVE(renderVertices[1].x) > srPrivate->clipPlanesInDC[1]) { |
goto bail; |
} |
if (FLOAT_ROUND_TO_LONG_POSITIVE(renderVertices[1].y) < srPrivate->clipPlanesInDC[2]) { |
goto bail; |
} |
if (FLOAT_ROUND_TO_LONG_POSITIVE(renderVertices[1].y) > srPrivate->clipPlanesInDC[3]) { |
goto bail; |
} |
#endif /* DEBUGGING */ |
/* |
* Draw line segments between each pair of vertices, taking into |
* account the clipping information where appropriate. |
*/ |
for (i = 0; i < numVertices - 1; i++) { |
if (!clipFound || |
(clippedVerticesFlags && |
clippedVerticesFlags[i] & SR_DRAW_NEXT)) { |
if ((*lineFunction)( |
srPrivate, |
(TQ3Point3D *)&renderVertices[i], |
(TQ3Point3D *)&renderVertices[i + 1], |
color) == kQ3Failure) { |
status = kQ3Failure; |
goto bail; |
} |
} |
} |
/* |
* If we're in "polygon" mode, then we have to connect the last |
* vertex with the first. |
*/ |
if (mode == DO_POLYGON) { |
if (!clipFound || |
(clippedVerticesFlags && |
clippedVerticesFlags[numVertices - 1] & SR_DRAW_NEXT)) { |
if ((*lineFunction)( |
srPrivate, |
(TQ3Point3D *)&renderVertices[numVertices - 1], |
(TQ3Point3D *)&renderVertices[0], |
color) == kQ3Failure) { |
status = kQ3Failure; |
goto bail; |
} |
} |
} |
bail: |
/* |
* Free up any allocated memory |
*/ |
if (deviceVertices != NULL) { |
free(deviceVertices); |
} |
if (clipFlags != NULL) { |
free(clipFlags); |
} |
if (clippedVertices != NULL) { |
free(clippedVertices); |
} |
if (clippedVerticesFlags != NULL) { |
free(clippedVerticesFlags); |
} |
/* |
* Status may be success or failure, the latter being the case if |
* an allocation failed or if the line rasterization function returns |
* failure. |
*/ |
return (status); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14