windows-nt/Source/XPSP1/NT/multimedia/opengl/server/soft/so_pntaa.c
2020-09-26 16:20:57 +08:00

305 lines
10 KiB
C

/*
** Copyright 1991, Silicon Graphics, Inc.
** All Rights Reserved.
**
** This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
** the contents of this file may not be disclosed to third parties, copied or
** duplicated in any form, in whole or in part, without the prior written
** permission of Silicon Graphics, Inc.
**
** RESTRICTED RIGHTS LEGEND:
** Use, duplication or disclosure by the Government is subject to restrictions
** as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
** and Computer Software clause at DFARS 252.227-7013, and/or in similar or
** successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
** rights reserved under the Copyright Laws of the United States.
**
** $Revision: 1.10 $
** $Date: 1993/06/18 00:30:15 $
*/
#include "precomp.h"
#pragma hdrstop
#include <fixed.h>
/*
** This is a little wierd. What it does is to dither "comp" into the high
** n-4 bits, and add 16 * antiAliasPercent. Dithering of the low bits is
** left to the usual methods (the store and span procs, for example).
*/
__GLfloat __glBuildAntiAliasIndex(__GLfloat index,
__GLfloat antiAliasPercent)
{
GLint newlowbits;
newlowbits = (GLint)((__GL_CI_ANTI_ALIAS_DIVISOR - 1) * antiAliasPercent + (__GLfloat) 0.5);
return (((int) index) & ~(__GL_CI_ANTI_ALIAS_DIVISOR - 1)) | newlowbits;
}
/************************************************************************/
/*
** To anti-alias points the below code operates a simple algrorithim that
** sub-samples the bounding box of the pixel area covered by the point.
** At each sub-sample the distance from the sample to the center of the
** point is computed and compared against the distance from the edge of
** the circle to the center. If the computed distance is <= the edge
** distance then the sample is inside the circle. All the samples for a
** particular pixel center are summed up and then the resulting value is
** divided by the total samples in the pixel. This gives us a coverage value
** to use to adjust the fragment alpha with before storing (there is
** an analagous affect when color index anti-aliasing is being done).
**
** The code below implements this simple algrorithim, but has been tuned
** so it might be difficult to translate. Basically, every possible operation
** that could be moved out of the Coverage code (i.e., invariants across
** the coverage test) has been done. Also, the minimal area is sampled
** over.
*/
/* Code below knows alot about these constants so beware */
#define __GL_FILTER_SIZE __glOne
#define __GL_HALF_FILTER_SIZE __glHalf
#define __GL_SAMPLES 4
#define __GL_SAMPLE_HIT ((__GLfloat) 0.0625) /* 1 / (4*4) */
#define __GL_SAMPLE_DELTA ((__GLfloat) 0.25) /* 1 / 4 */
#define __GL_HALF_SAMPLE_DELTA ((__GLfloat) 0.125)
/* -halffilter + half delta */
#define __GL_COORD_ADJUST ((__GLfloat) -0.375)
/*
** Return an estimate of the pixel coverage using sub-sampling.
**
** NOTE: The subtraction of xCenter,yCenter has been moved into the
** caller to save time. Consequently the starting coordinate may not be
** on a pixel center, but thats ok.
*/
static __GLfloat Coverage(__GLfloat xStart, __GLfloat yStart,
__GLfloat radiusSquared)
{
GLint i;
__GLfloat delta, yBottom, sampleX, sampleY;
__GLfloat hits, hitsInc;
/*
** Get starting sample x & y positions. We take our starting
** coordinate, back off half a filter size then add half a delta to
** it. This constrains the sampling to lie entirely within the
** pixel, never on the edges of the pixel. The constants above
** have this adjustment pre-computed.
*/
sampleX = xStart + __GL_COORD_ADJUST;
yBottom = yStart + __GL_COORD_ADJUST;
delta = __GL_SAMPLE_DELTA;
hits = __glZero;
hitsInc = __GL_SAMPLE_HIT;
for (i = __GL_SAMPLES; --i >= 0; ) {
__GLfloat check = radiusSquared - sampleX * sampleX;
/* Unrolled inner loop - change this code if __GL_SAMPLES changes */
sampleY = yBottom;
if (sampleY * sampleY <= check) {
hits += hitsInc;
}
sampleY += delta;
if (sampleY * sampleY <= check) {
hits += hitsInc;
}
sampleY += delta;
if (sampleY * sampleY <= check) {
hits += hitsInc;
}
sampleY += delta;
if (sampleY * sampleY <= check) {
hits += hitsInc;
}
sampleX += delta;
}
return hits;
}
void FASTCALL __glRenderAntiAliasedRGBPoint(__GLcontext *gc, __GLvertex *vx)
{
__GLfloat xCenter, yCenter, radius, radiusSquared, coverage, x, y;
__GLfloat zero, one, oldAlpha, xStart;
__GLfloat tmp;
__GLfragment frag;
GLint w, width, height, ixLeft, iyBottom;
GLuint modeFlags = gc->polygon.shader.modeFlags;
/*
** Determine area to compute coverage over. The area is bloated by
** the filter's width & height implicitly. By truncating to integer
** (NOTE: the x,y coordinate is always positive here) we are
** guaranteed to find the lowest coordinate that needs examination
** because of the nature of circles. Similarly, by truncating the
** ending coordinate and adding one we get the pixel just past the
** upper/right edge of the circle.
*/
radius = gc->state.point.smoothSize * __glHalf;
radiusSquared = radius * radius;
xCenter = vx->window.x;
yCenter = vx->window.y;
/* Truncate down to get starting coordinate */
tmp = xCenter-radius;
ixLeft = __GL_VERTEX_FLOAT_TO_INT(tmp);
tmp = yCenter-radius;
iyBottom = __GL_VERTEX_FLOAT_TO_INT(tmp);
/*
** Truncate down and add 1 to get the ending coordinate, then subtract
** out the start to get the width & height.
*/
tmp = xCenter+radius;
width = __GL_VERTEX_FLOAT_TO_INT(tmp) + 1 - ixLeft;
tmp = yCenter+radius;
height = __GL_VERTEX_FLOAT_TO_INT(tmp) + 1 - iyBottom;
/*
** Setup fragment. The fragment base color will be constant
** (approximately) across the entire pixel. The only thing that will
** change is the alpha (for rgb) or the red component (for color
** index).
*/
frag.z = (__GLzValue)vx->window.z;
frag.color = *vx->color;
if (modeFlags & __GL_SHADE_TEXTURE) {
(*gc->procs.texture)(gc, &frag.color, vx->texture.x, vx->texture.y,
__glOne);
}
if (gc->polygon.shader.modeFlags & __GL_SHADE_COMPUTE_FOG)
{
(*gc->procs.fogPoint)(gc, &frag, vx->eyeZ);
}
else if ((gc->polygon.shader.modeFlags & __GL_SHADE_INTERP_FOG)
||
((modeFlags & (__GL_SHADE_CHEAP_FOG | __GL_SHADE_SMOOTH_LIGHT))
== __GL_SHADE_CHEAP_FOG))
{
(*gc->procs.fogColor)(gc, &frag.color, &frag.color, vx->fog);
}
/*
** Now render the circle centered on xCenter,yCenter. Move the
** subtraction of xCenter,yCenter outside of the loop to doing
** it up front in xStart and y. This way the coverage code can
** assume the incoming starting coordinate has been properly
** adjusted.
*/
zero = __glZero;
one = __glOne;
oldAlpha = frag.color.a;
xStart = ixLeft + __glHalf - xCenter;
y = iyBottom + __glHalf - yCenter;
frag.y = iyBottom;
while (--height >= 0) {
x = xStart;
frag.x = ixLeft;
for (w = width; --w >= 0; ) {
coverage = Coverage(x, y, radiusSquared);
if (coverage > zero) {
frag.color.a = oldAlpha * coverage;
(*gc->procs.store)(gc->drawBuffer, &frag);
}
x += one;
frag.x++;
}
y += one;
frag.y++;
}
}
void FASTCALL __glRenderAntiAliasedCIPoint(__GLcontext *gc, __GLvertex *vx)
{
__GLfloat xCenter, yCenter, radius, radiusSquared, coverage, x, y;
__GLfloat zero, one, oldIndex, xStart;
__GLfloat tmp;
__GLfragment frag;
GLint w, width, height, ixLeft, iyBottom;
/*
** Determine area to compute coverage over. The area is bloated by
** the filter's width & height implicitly. By truncating to integer
** (NOTE: the x,y coordinate is always positive here) we are
** guaranteed to find the lowest coordinate that needs examination
** because of the nature of circles. Similarly, by truncating the
** ending coordinate and adding one we get the pixel just past the
** upper/right edge of the circle.
*/
radius = gc->state.point.smoothSize * __glHalf;
radiusSquared = radius * radius;
xCenter = vx->window.x;
yCenter = vx->window.y;
/* Truncate down to get starting coordinate */
tmp = xCenter-radius;
ixLeft = __GL_VERTEX_FLOAT_TO_INT(tmp);
tmp = yCenter-radius;
iyBottom = __GL_VERTEX_FLOAT_TO_INT(tmp);
/*
** Truncate down and add 1 to get the ending coordinate, then subtract
** out the start to get the width & height.
*/
tmp = xCenter+radius;
width = __GL_VERTEX_FLOAT_TO_INT(tmp) + 1 - ixLeft;
tmp = yCenter+radius;
height = __GL_VERTEX_FLOAT_TO_INT(tmp) + 1 - iyBottom;
/*
** Setup fragment. The fragment base color will be constant
** (approximately) across the entire pixel. The only thing that will
** change is the alpha (for rgb) or the red component (for color
** index).
*/
frag.z = (__GLzValue)vx->window.z;
frag.color.r = vx->color->r;
if (gc->polygon.shader.modeFlags & __GL_SHADE_COMPUTE_FOG)
{
(*gc->procs.fogPoint)(gc, &frag, vx->eyeZ);
}
else if ((gc->polygon.shader.modeFlags & __GL_SHADE_INTERP_FOG)
||
((gc->polygon.shader.modeFlags & (__GL_SHADE_CHEAP_FOG |
__GL_SHADE_SMOOTH_LIGHT))
== __GL_SHADE_CHEAP_FOG))
{
(*gc->procs.fogColor)(gc, &frag.color, &frag.color, vx->fog);
}
/*
** Now render the circle centered on xCenter,yCenter. Move the
** subtraction of xCenter,yCenter outside of the loop to doing
** it up front in xStart and y. This way the coverage code can
** assume the incoming starting coordinate has been properly
** adjusted.
*/
zero = __glZero;
one = __glOne;
oldIndex = frag.color.r;
xStart = ixLeft + __glHalf - xCenter;
y = iyBottom + __glHalf - yCenter;
frag.y = iyBottom;
while (--height >= 0) {
x = xStart;
frag.x = ixLeft;
for (w = width; --w >= 0; ) {
coverage = Coverage(x, y, radiusSquared);
if (coverage > zero) {
frag.color.r = __glBuildAntiAliasIndex(oldIndex, coverage);
(*gc->procs.store)(gc->drawBuffer, &frag);
}
x += one;
frag.x++;
}
y += one;
frag.y++;
}
}