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_PointPipe.c
/****************************************************************************** |
** ** |
** Module: SR_PointPipe.c ** |
** ** |
** ** |
** Purpose: Sample Renderer point pipeline ** |
** ** |
** ** |
** ** |
** Copyright (C) 1996 Apple Computer, Inc. All rights reserved. ** |
** ** |
** ** |
*****************************************************************************/ |
#include <stdlib.h> |
#include <assert.h> |
#include "QD3D.h" |
#include "QD3DMath.h" |
#include "QD3DErrors.h" |
#include "SR.h" |
#include "SR_ClipUtilities.h" |
/*===========================================================================*\ |
* |
* Routine: SR_PointPipe() |
* |
* Comments: Used for points, and for lines and triangles in point mode. |
* |
\*===========================================================================*/ |
TQ3Status SR_PointPipe( |
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; |
PointFunction2D pointFunction; |
/* |
* Get the appropriate rasterization function for the points |
* (depth, whether window is clipped or not, etc. |
*/ |
pointFunction = |
((TSRRasterFunctions *)(srPrivate->currentRasterFunctions))->pointFunction; |
/* |
* 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 = kQ3Success; |
/* |
* Allocate device-coordinate vertices |
*/ |
deviceVertices = malloc(numVertices * sizeof(TQ3RationalPoint4D)); |
if (deviceVertices == NULL) { |
status = kQ3Failure; |
goto bail; |
} |
/* |
* Transform local-space point 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 of 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; |
} |
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) { |
free(deviceVertices); |
free(clipFlags); |
return (kQ3Failure); |
} |
/* |
* Allocate space for clip flags for vertices. Bail if allocation |
* fails. |
*/ |
clippedVerticesFlags = |
malloc((numVertices << 1) * sizeof(long)); |
if (clippedVerticesFlags == NULL) { |
free(clippedVertices); |
free(deviceVertices); |
free(clipFlags); |
return (kQ3Failure); |
} |
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 |
*/ |
SRPointList_WDivide( |
renderVertices, |
numVertices, |
sizeof(TQ3RationalPoint4D)); |
/* |
* Draw each of the points |
*/ |
for (i = 0; i < numVertices; i++) { |
if (!clipFound || |
(clippedVerticesFlags && |
clippedVerticesFlags[i] & SR_DRAW_NEXT)) { |
if ((*pointFunction)( |
srPrivate, |
(TQ3Point3D *)&renderVertices[i], |
color) == kQ3Failure) { |
return (kQ3Failure); |
} |
} |
} |
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