1428 lines
45 KiB
C
1428 lines
45 KiB
C
/* $Id: s_span.c,v 1.48 2002/10/02 23:24:04 brianp Exp $ */
|
|
|
|
/*
|
|
* Mesa 3-D graphics library
|
|
* Version: 4.1
|
|
*
|
|
* Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
|
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
|
|
/**
|
|
* \file swrast/s_span.c
|
|
* \brief Span processing functions used by all rasterization functions.
|
|
* This is where all the per-fragment tests are performed
|
|
* \author Brian Paul
|
|
*/
|
|
|
|
#include "glheader.h"
|
|
#include "colormac.h"
|
|
#include "context.h"
|
|
#include "macros.h"
|
|
#include "mmath.h"
|
|
#include "mem.h"
|
|
|
|
#include "s_alpha.h"
|
|
#include "s_alphabuf.h"
|
|
#include "s_blend.h"
|
|
#include "s_context.h"
|
|
#include "s_depth.h"
|
|
#include "s_fog.h"
|
|
#include "s_logic.h"
|
|
#include "s_masking.h"
|
|
#include "s_span.h"
|
|
#include "s_stencil.h"
|
|
#include "s_texture.h"
|
|
|
|
|
|
/**
|
|
* Init span's Z interpolation values to the RasterPos Z.
|
|
* Used during setup for glDraw/CopyPixels.
|
|
*/
|
|
void
|
|
_mesa_span_default_z( GLcontext *ctx, struct sw_span *span )
|
|
{
|
|
if (ctx->Visual.depthBits <= 16)
|
|
span->z = FloatToFixed(ctx->Current.RasterPos[2] * ctx->DepthMax);
|
|
else
|
|
span->z = (GLint) (ctx->Current.RasterPos[2] * ctx->DepthMax);
|
|
span->zStep = 0;
|
|
span->interpMask |= SPAN_Z;
|
|
}
|
|
|
|
|
|
/**
|
|
* Init span's fog interpolation values to the RasterPos fog.
|
|
* Used during setup for glDraw/CopyPixels.
|
|
*/
|
|
void
|
|
_mesa_span_default_fog( GLcontext *ctx, struct sw_span *span )
|
|
{
|
|
span->fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterDistance);
|
|
span->fogStep = 0;
|
|
span->interpMask |= SPAN_FOG;
|
|
}
|
|
|
|
|
|
/**
|
|
* Init span's color or index interpolation values to the RasterPos color.
|
|
* Used during setup for glDraw/CopyPixels.
|
|
*/
|
|
void
|
|
_mesa_span_default_color( GLcontext *ctx, struct sw_span *span )
|
|
{
|
|
if (ctx->Visual.rgbMode) {
|
|
GLchan r, g, b, a;
|
|
UNCLAMPED_FLOAT_TO_CHAN(r, ctx->Current.RasterColor[0]);
|
|
UNCLAMPED_FLOAT_TO_CHAN(g, ctx->Current.RasterColor[1]);
|
|
UNCLAMPED_FLOAT_TO_CHAN(b, ctx->Current.RasterColor[2]);
|
|
UNCLAMPED_FLOAT_TO_CHAN(a, ctx->Current.RasterColor[3]);
|
|
#if CHAN_TYPE == GL_FLOAT
|
|
span->red = r;
|
|
span->green = g;
|
|
span->blue = b;
|
|
span->alpha = a;
|
|
#else
|
|
span->red = IntToFixed(r);
|
|
span->green = IntToFixed(g);
|
|
span->blue = IntToFixed(b);
|
|
span->alpha = IntToFixed(a);
|
|
#endif
|
|
span->redStep = 0;
|
|
span->greenStep = 0;
|
|
span->blueStep = 0;
|
|
span->alphaStep = 0;
|
|
span->interpMask |= SPAN_RGBA;
|
|
}
|
|
else {
|
|
span->index = IntToFixed(ctx->Current.RasterIndex);
|
|
span->indexStep = 0;
|
|
span->interpMask |= SPAN_INDEX;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Init span's texcoord interpolation values to the RasterPos texcoords.
|
|
* Used during setup for glDraw/CopyPixels.
|
|
*/
|
|
void
|
|
_mesa_span_default_texcoords( GLcontext *ctx, struct sw_span *span )
|
|
{
|
|
GLuint i;
|
|
for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
|
|
COPY_4V(span->tex[i], ctx->Current.RasterTexCoords[i]);
|
|
ASSIGN_4V(span->texStepX[i], 0.0F, 0.0F, 0.0F, 0.0F);
|
|
ASSIGN_4V(span->texStepY[i], 0.0F, 0.0F, 0.0F, 0.0F);
|
|
}
|
|
span->interpMask |= SPAN_TEXTURE;
|
|
}
|
|
|
|
|
|
/* Fill in the span.color.rgba array from the interpolation values */
|
|
static void
|
|
interpolate_colors(GLcontext *ctx, struct sw_span *span)
|
|
{
|
|
GLfixed r = span->red;
|
|
GLfixed g = span->green;
|
|
GLfixed b = span->blue;
|
|
GLfixed a = span->alpha;
|
|
const GLint dr = span->redStep;
|
|
const GLint dg = span->greenStep;
|
|
const GLint db = span->blueStep;
|
|
const GLint da = span->alphaStep;
|
|
const GLuint n = span->end;
|
|
GLchan (*rgba)[4] = span->array->rgba;
|
|
GLuint i;
|
|
|
|
ASSERT((span->interpMask & SPAN_RGBA) &&
|
|
!(span->arrayMask & SPAN_RGBA));
|
|
|
|
if (span->interpMask & SPAN_FLAT) {
|
|
/* constant color */
|
|
GLchan color[4];
|
|
color[RCOMP] = FixedToChan(r);
|
|
color[GCOMP] = FixedToChan(g);
|
|
color[BCOMP] = FixedToChan(b);
|
|
color[ACOMP] = FixedToChan(a);
|
|
for (i = 0; i < n; i++) {
|
|
COPY_CHAN4(span->array->rgba[i], color);
|
|
}
|
|
}
|
|
else {
|
|
/* interpolate */
|
|
for (i = 0; i < n; i++) {
|
|
rgba[i][RCOMP] = FixedToChan(r);
|
|
rgba[i][GCOMP] = FixedToChan(g);
|
|
rgba[i][BCOMP] = FixedToChan(b);
|
|
rgba[i][ACOMP] = FixedToChan(a);
|
|
r += dr;
|
|
g += dg;
|
|
b += db;
|
|
a += da;
|
|
}
|
|
}
|
|
span->arrayMask |= SPAN_RGBA;
|
|
}
|
|
|
|
|
|
/* Fill in the span.color.index array from the interpolation values */
|
|
static void
|
|
interpolate_indexes(GLcontext *ctx, struct sw_span *span)
|
|
{
|
|
GLfixed index = span->index;
|
|
const GLint indexStep = span->indexStep;
|
|
const GLuint n = span->end;
|
|
GLuint *indexes = span->array->index;
|
|
GLuint i;
|
|
ASSERT((span->interpMask & SPAN_INDEX) &&
|
|
!(span->arrayMask & SPAN_INDEX));
|
|
|
|
if ((span->interpMask & SPAN_FLAT) || (indexStep == 0)) {
|
|
/* constant color */
|
|
index = FixedToInt(index);
|
|
for (i = 0; i < n; i++) {
|
|
indexes[i] = index;
|
|
}
|
|
}
|
|
else {
|
|
/* interpolate */
|
|
for (i = 0; i < n; i++) {
|
|
indexes[i] = FixedToInt(index);
|
|
index += indexStep;
|
|
}
|
|
}
|
|
span->arrayMask |= SPAN_INDEX;
|
|
}
|
|
|
|
|
|
/* Fill in the span.->array->spec array from the interpolation values */
|
|
static void
|
|
interpolate_specular(GLcontext *ctx, struct sw_span *span)
|
|
{
|
|
if (span->interpMask & SPAN_FLAT) {
|
|
/* constant color */
|
|
const GLchan r = FixedToChan(span->specRed);
|
|
const GLchan g = FixedToChan(span->specGreen);
|
|
const GLchan b = FixedToChan(span->specBlue);
|
|
GLuint i;
|
|
for (i = 0; i < span->end; i++) {
|
|
span->array->spec[i][RCOMP] = r;
|
|
span->array->spec[i][GCOMP] = g;
|
|
span->array->spec[i][BCOMP] = b;
|
|
}
|
|
}
|
|
else {
|
|
/* interpolate */
|
|
#if CHAN_TYPE == GL_FLOAT
|
|
GLfloat r = span->specRed;
|
|
GLfloat g = span->specGreen;
|
|
GLfloat b = span->specBlue;
|
|
#else
|
|
GLfixed r = span->specRed;
|
|
GLfixed g = span->specGreen;
|
|
GLfixed b = span->specBlue;
|
|
#endif
|
|
GLuint i;
|
|
for (i = 0; i < span->end; i++) {
|
|
span->array->spec[i][RCOMP] = FixedToChan(r);
|
|
span->array->spec[i][GCOMP] = FixedToChan(g);
|
|
span->array->spec[i][BCOMP] = FixedToChan(b);
|
|
r += span->specRedStep;
|
|
g += span->specGreenStep;
|
|
b += span->specBlueStep;
|
|
}
|
|
}
|
|
span->arrayMask |= SPAN_SPEC;
|
|
}
|
|
|
|
|
|
/* Fill in the span.zArray array from the interpolation values */
|
|
void
|
|
_mesa_span_interpolate_z( const GLcontext *ctx, struct sw_span *span )
|
|
{
|
|
const GLuint n = span->end;
|
|
GLuint i;
|
|
|
|
ASSERT((span->interpMask & SPAN_Z) &&
|
|
!(span->arrayMask & SPAN_Z));
|
|
|
|
if (ctx->Visual.depthBits <= 16) {
|
|
GLfixed zval = span->z;
|
|
GLdepth *z = span->array->z;
|
|
for (i = 0; i < n; i++) {
|
|
z[i] = FixedToInt(zval);
|
|
zval += span->zStep;
|
|
}
|
|
}
|
|
else {
|
|
/* Deep Z buffer, no fixed->int shift */
|
|
GLfixed zval = span->z;
|
|
GLdepth *z = span->array->z;
|
|
for (i = 0; i < n; i++) {
|
|
z[i] = zval;
|
|
zval += span->zStep;
|
|
}
|
|
}
|
|
span->arrayMask |= SPAN_Z;
|
|
}
|
|
|
|
|
|
/*
|
|
* This the ideal solution, as given in the OpenGL spec.
|
|
*/
|
|
#if 0
|
|
static GLfloat
|
|
compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
|
|
GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH,
|
|
GLfloat s, GLfloat t, GLfloat q, GLfloat invQ)
|
|
{
|
|
GLfloat dudx = texW * ((s + dsdx) / (q + dqdx) - s * invQ);
|
|
GLfloat dvdx = texH * ((t + dtdx) / (q + dqdx) - t * invQ);
|
|
GLfloat dudy = texW * ((s + dsdy) / (q + dqdy) - s * invQ);
|
|
GLfloat dvdy = texH * ((t + dtdy) / (q + dqdy) - t * invQ);
|
|
GLfloat x = sqrt(dudx * dudx + dvdx * dvdx);
|
|
GLfloat y = sqrt(dudy * dudy + dvdy * dvdy);
|
|
GLfloat rho = MAX2(x, y);
|
|
GLfloat lambda = LOG2(rho);
|
|
return lambda;
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
* This is a faster approximation
|
|
*/
|
|
static GLfloat
|
|
compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
|
|
GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH,
|
|
GLfloat s, GLfloat t, GLfloat q, GLfloat invQ)
|
|
{
|
|
GLfloat dsdx2 = (s + dsdx) / (q + dqdx) - s * invQ;
|
|
GLfloat dtdx2 = (t + dtdx) / (q + dqdx) - t * invQ;
|
|
GLfloat dsdy2 = (s + dsdy) / (q + dqdy) - s * invQ;
|
|
GLfloat dtdy2 = (t + dtdy) / (q + dqdy) - t * invQ;
|
|
GLfloat maxU, maxV, rho, lambda;
|
|
dsdx2 = FABSF(dsdx2);
|
|
dsdy2 = FABSF(dsdy2);
|
|
dtdx2 = FABSF(dtdx2);
|
|
dtdy2 = FABSF(dtdy2);
|
|
maxU = MAX2(dsdx2, dsdy2) * texW;
|
|
maxV = MAX2(dtdx2, dtdy2) * texH;
|
|
rho = MAX2(maxU, maxV);
|
|
lambda = LOG2(rho);
|
|
return lambda;
|
|
}
|
|
|
|
/*
|
|
* Fill in the span.texcoords array from the interpolation values.
|
|
* XXX We could optimize here for the case when dq = 0. That would
|
|
* usually be the case when using an orthographic projection.
|
|
*/
|
|
static void
|
|
interpolate_texcoords(GLcontext *ctx, struct sw_span *span)
|
|
{
|
|
ASSERT(span->interpMask & SPAN_TEXTURE);
|
|
ASSERT(!(span->arrayMask & SPAN_TEXTURE));
|
|
|
|
if (ctx->Texture._EnabledUnits > 1) {
|
|
/* multitexture */
|
|
GLuint u;
|
|
span->arrayMask |= SPAN_TEXTURE;
|
|
for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
|
|
if (ctx->Texture.Unit[u]._ReallyEnabled) {
|
|
const struct gl_texture_object *obj =ctx->Texture.Unit[u]._Current;
|
|
const struct gl_texture_image *img = obj->Image[obj->BaseLevel];
|
|
GLboolean needLambda = (obj->MinFilter != obj->MagFilter);
|
|
if (needLambda) {
|
|
GLfloat (*texcoord)[4] = span->array->texcoords[u];
|
|
GLfloat *lambda = span->array->lambda[u];
|
|
const GLfloat texW = (GLfloat) img->WidthScale;
|
|
const GLfloat texH = (GLfloat) img->HeightScale;
|
|
const GLfloat dsdx = span->texStepX[u][0];
|
|
const GLfloat dsdy = span->texStepY[u][0];
|
|
const GLfloat dtdx = span->texStepX[u][1];
|
|
const GLfloat dtdy = span->texStepY[u][1];
|
|
const GLfloat drdx = span->texStepX[u][2];
|
|
const GLfloat dqdx = span->texStepX[u][3];
|
|
const GLfloat dqdy = span->texStepY[u][3];
|
|
GLfloat s = span->tex[u][0];
|
|
GLfloat t = span->tex[u][1];
|
|
GLfloat r = span->tex[u][2];
|
|
GLfloat q = span->tex[u][3];
|
|
GLuint i;
|
|
for (i = 0; i < span->end; i++) {
|
|
const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
|
|
texcoord[i][0] = s * invQ;
|
|
texcoord[i][1] = t * invQ;
|
|
texcoord[i][2] = r * invQ;
|
|
lambda[i] = compute_lambda(dsdx, dsdy, dtdx, dtdy,
|
|
dqdx, dqdy, texW, texH,
|
|
s, t, q, invQ);
|
|
s += dsdx;
|
|
t += dtdx;
|
|
r += drdx;
|
|
q += dqdx;
|
|
}
|
|
span->arrayMask |= SPAN_LAMBDA;
|
|
}
|
|
else {
|
|
GLfloat (*texcoord)[4] = span->array->texcoords[u];
|
|
GLfloat *lambda = span->array->lambda[u];
|
|
const GLfloat dsdx = span->texStepX[u][0];
|
|
const GLfloat dtdx = span->texStepX[u][1];
|
|
const GLfloat drdx = span->texStepX[u][2];
|
|
const GLfloat dqdx = span->texStepX[u][3];
|
|
GLfloat s = span->tex[u][0];
|
|
GLfloat t = span->tex[u][1];
|
|
GLfloat r = span->tex[u][2];
|
|
GLfloat q = span->tex[u][3];
|
|
GLuint i;
|
|
if (dqdx == 0.0) {
|
|
/* Ortho projection or polygon's parallel to window X axis */
|
|
const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
|
|
for (i = 0; i < span->end; i++) {
|
|
texcoord[i][0] = s * invQ;
|
|
texcoord[i][1] = t * invQ;
|
|
texcoord[i][2] = r * invQ;
|
|
lambda[i] = 0.0;
|
|
s += dsdx;
|
|
t += dtdx;
|
|
r += drdx;
|
|
}
|
|
}
|
|
else {
|
|
for (i = 0; i < span->end; i++) {
|
|
const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
|
|
texcoord[i][0] = s * invQ;
|
|
texcoord[i][1] = t * invQ;
|
|
texcoord[i][2] = r * invQ;
|
|
lambda[i] = 0.0;
|
|
s += dsdx;
|
|
t += dtdx;
|
|
r += drdx;
|
|
q += dqdx;
|
|
}
|
|
}
|
|
} /* lambda */
|
|
} /* if */
|
|
} /* for */
|
|
}
|
|
else {
|
|
/* single texture */
|
|
const struct gl_texture_object *obj = ctx->Texture.Unit[0]._Current;
|
|
const struct gl_texture_image *img = obj->Image[obj->BaseLevel];
|
|
GLboolean needLambda = (obj->MinFilter != obj->MagFilter);
|
|
span->arrayMask |= SPAN_TEXTURE;
|
|
if (needLambda) {
|
|
/* just texture unit 0, with lambda */
|
|
GLfloat (*texcoord)[4] = span->array->texcoords[0];
|
|
GLfloat *lambda = span->array->lambda[0];
|
|
const GLfloat texW = (GLfloat) img->WidthScale;
|
|
const GLfloat texH = (GLfloat) img->HeightScale;
|
|
const GLfloat dsdx = span->texStepX[0][0];
|
|
const GLfloat dsdy = span->texStepY[0][0];
|
|
const GLfloat dtdx = span->texStepX[0][1];
|
|
const GLfloat dtdy = span->texStepY[0][1];
|
|
const GLfloat drdx = span->texStepX[0][2];
|
|
const GLfloat dqdx = span->texStepX[0][3];
|
|
const GLfloat dqdy = span->texStepY[0][3];
|
|
GLfloat s = span->tex[0][0];
|
|
GLfloat t = span->tex[0][1];
|
|
GLfloat r = span->tex[0][2];
|
|
GLfloat q = span->tex[0][3];
|
|
GLuint i;
|
|
for (i = 0; i < span->end; i++) {
|
|
const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
|
|
lambda[i] = compute_lambda(dsdx, dsdy, dtdx, dtdy,
|
|
dqdx, dqdy, texW, texH,
|
|
s, t, q, invQ);
|
|
texcoord[i][0] = s * invQ;
|
|
texcoord[i][1] = t * invQ;
|
|
texcoord[i][2] = r * invQ;
|
|
s += dsdx;
|
|
t += dtdx;
|
|
r += drdx;
|
|
q += dqdx;
|
|
}
|
|
span->arrayMask |= SPAN_LAMBDA;
|
|
}
|
|
else {
|
|
/* just texture 0, without lambda */
|
|
GLfloat (*texcoord)[4] = span->array->texcoords[0];
|
|
const GLfloat dsdx = span->texStepX[0][0];
|
|
const GLfloat dtdx = span->texStepX[0][1];
|
|
const GLfloat drdx = span->texStepX[0][2];
|
|
const GLfloat dqdx = span->texStepX[0][3];
|
|
GLfloat s = span->tex[0][0];
|
|
GLfloat t = span->tex[0][1];
|
|
GLfloat r = span->tex[0][2];
|
|
GLfloat q = span->tex[0][3];
|
|
GLuint i;
|
|
if (dqdx == 0.0) {
|
|
/* Ortho projection or polygon's parallel to window X axis */
|
|
const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
|
|
for (i = 0; i < span->end; i++) {
|
|
texcoord[i][0] = s * invQ;
|
|
texcoord[i][1] = t * invQ;
|
|
texcoord[i][2] = r * invQ;
|
|
s += dsdx;
|
|
t += dtdx;
|
|
r += drdx;
|
|
}
|
|
}
|
|
else {
|
|
for (i = 0; i < span->end; i++) {
|
|
const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
|
|
texcoord[i][0] = s * invQ;
|
|
texcoord[i][1] = t * invQ;
|
|
texcoord[i][2] = r * invQ;
|
|
s += dsdx;
|
|
t += dtdx;
|
|
r += drdx;
|
|
q += dqdx;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Apply the current polygon stipple pattern to a span of pixels.
|
|
*/
|
|
static void
|
|
stipple_polygon_span( GLcontext *ctx, struct sw_span *span )
|
|
{
|
|
const GLuint highbit = 0x80000000;
|
|
const GLuint stipple = ctx->PolygonStipple[span->y % 32];
|
|
GLubyte *mask = span->array->mask;
|
|
GLuint i, m;
|
|
|
|
ASSERT(ctx->Polygon.StippleFlag);
|
|
ASSERT((span->arrayMask & SPAN_XY) == 0);
|
|
|
|
m = highbit >> (GLuint) (span->x % 32);
|
|
|
|
for (i = 0; i < span->end; i++) {
|
|
if ((m & stipple) == 0) {
|
|
mask[i] = 0;
|
|
}
|
|
m = m >> 1;
|
|
if (m == 0) {
|
|
m = highbit;
|
|
}
|
|
}
|
|
span->writeAll = GL_FALSE;
|
|
}
|
|
|
|
|
|
/**
|
|
* Clip a pixel span to the current buffer/window boundaries:
|
|
* DrawBuffer->_Xmin, _Xmax, _Ymin, _Ymax. This will accomplish
|
|
* window clipping and scissoring.
|
|
* Return: GL_TRUE some pixels still visible
|
|
* GL_FALSE nothing visible
|
|
*/
|
|
static GLuint
|
|
clip_span( GLcontext *ctx, struct sw_span *span )
|
|
{
|
|
const GLint xmin = ctx->DrawBuffer->_Xmin;
|
|
const GLint xmax = ctx->DrawBuffer->_Xmax;
|
|
const GLint ymin = ctx->DrawBuffer->_Ymin;
|
|
const GLint ymax = ctx->DrawBuffer->_Ymax;
|
|
|
|
if (span->arrayMask & SPAN_XY) {
|
|
/* arrays of x/y pixel coords */
|
|
const GLint *x = span->array->x;
|
|
const GLint *y = span->array->y;
|
|
const GLint n = span->end;
|
|
GLubyte *mask = span->array->mask;
|
|
GLint i;
|
|
if (span->arrayMask & SPAN_MASK) {
|
|
/* note: using & intead of && to reduce branches */
|
|
for (i = 0; i < n; i++) {
|
|
mask[i] &= (x[i] >= xmin) & (x[i] < xmax)
|
|
& (y[i] >= ymin) & (y[i] < ymax);
|
|
}
|
|
}
|
|
else {
|
|
/* note: using & intead of && to reduce branches */
|
|
for (i = 0; i < n; i++) {
|
|
mask[i] = (x[i] >= xmin) & (x[i] < xmax)
|
|
& (y[i] >= ymin) & (y[i] < ymax);
|
|
}
|
|
}
|
|
return GL_TRUE; /* some pixels visible */
|
|
}
|
|
else {
|
|
/* horizontal span of pixels */
|
|
const GLint x = span->x;
|
|
const GLint y = span->y;
|
|
const GLint n = span->end;
|
|
|
|
/* Trivial rejection tests */
|
|
if (y < ymin || y >= ymax || x + n <= xmin || x >= xmax) {
|
|
span->end = 0;
|
|
return GL_FALSE; /* all pixels clipped */
|
|
}
|
|
|
|
/* Clip to the left */
|
|
if (x < xmin) {
|
|
ASSERT(x + n > xmin);
|
|
span->writeAll = GL_FALSE;
|
|
BZERO(span->array->mask, (xmin - x) * sizeof(GLubyte));
|
|
}
|
|
|
|
/* Clip to right */
|
|
if (x + n > xmax) {
|
|
ASSERT(x < xmax);
|
|
span->end = xmax - x;
|
|
}
|
|
|
|
return GL_TRUE; /* some pixels visible */
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Draw to more than one color buffer (or none).
|
|
*/
|
|
static void
|
|
multi_write_index_span( GLcontext *ctx, struct sw_span *span )
|
|
{
|
|
SWcontext *swrast = SWRAST_CONTEXT(ctx);
|
|
GLuint bufferBit;
|
|
|
|
/* loop over four possible dest color buffers */
|
|
for (bufferBit = 1; bufferBit <= 8; bufferBit <<= 1) {
|
|
if (bufferBit & ctx->Color._DrawDestMask) {
|
|
GLuint indexTmp[MAX_WIDTH];
|
|
ASSERT(span->end < MAX_WIDTH);
|
|
|
|
if (bufferBit == FRONT_LEFT_BIT)
|
|
(*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, GL_FRONT_LEFT);
|
|
else if (bufferBit == FRONT_RIGHT_BIT)
|
|
(*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, GL_FRONT_RIGHT);
|
|
else if (bufferBit == BACK_LEFT_BIT)
|
|
(*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, GL_BACK_LEFT);
|
|
else
|
|
(*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, GL_BACK_RIGHT);
|
|
|
|
/* make copy of incoming indexes */
|
|
MEMCPY( indexTmp, span->array->index, span->end * sizeof(GLuint) );
|
|
|
|
if (ctx->Color.IndexLogicOpEnabled) {
|
|
_mesa_logicop_ci_span(ctx, span, indexTmp);
|
|
}
|
|
|
|
if (ctx->Color.IndexMask != 0xffffffff) {
|
|
_mesa_mask_index_span(ctx, span, indexTmp);
|
|
}
|
|
|
|
if (span->arrayMask & SPAN_XY) {
|
|
/* array of pixel coords */
|
|
(*swrast->Driver.WriteCI32Pixels)(ctx, span->end,
|
|
span->array->x, span->array->y,
|
|
indexTmp, span->array->mask);
|
|
}
|
|
else {
|
|
/* horizontal run of pixels */
|
|
(*swrast->Driver.WriteCI32Span)(ctx, span->end, span->x, span->y,
|
|
indexTmp, span->array->mask);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* restore default dest buffer */
|
|
_swrast_use_draw_buffer(ctx);
|
|
}
|
|
|
|
|
|
/**
|
|
* Draw to more than one RGBA color buffer (or none).
|
|
* All fragment operations, up to (but not) blending/logicop should
|
|
* have been done first.
|
|
*/
|
|
static void
|
|
multi_write_rgba_span( GLcontext *ctx, struct sw_span *span )
|
|
{
|
|
const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
|
|
GLuint bufferBit;
|
|
SWcontext *swrast = SWRAST_CONTEXT(ctx);
|
|
|
|
ASSERT(colorMask != 0x0);
|
|
|
|
if (ctx->Color.DrawBuffer == GL_NONE)
|
|
return;
|
|
|
|
/* loop over four possible dest color buffers */
|
|
for (bufferBit = 1; bufferBit <= 8; bufferBit <<= 1) {
|
|
if (bufferBit & ctx->Color._DrawDestMask) {
|
|
GLchan rgbaTmp[MAX_WIDTH][4];
|
|
ASSERT(span->end < MAX_WIDTH);
|
|
|
|
if (bufferBit == FRONT_LEFT_BIT) {
|
|
ctx->Color._DriverDrawBuffer = GL_FRONT_LEFT;
|
|
(*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, GL_FRONT_LEFT);
|
|
}
|
|
else if (bufferBit == FRONT_RIGHT_BIT) {
|
|
ctx->Color._DriverDrawBuffer = GL_FRONT_RIGHT;
|
|
(*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, GL_FRONT_RIGHT);
|
|
}
|
|
else if (bufferBit == BACK_LEFT_BIT) {
|
|
ctx->Color._DriverDrawBuffer = GL_BACK_LEFT;
|
|
(*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, GL_BACK_LEFT);
|
|
}
|
|
else {
|
|
ctx->Color._DriverDrawBuffer = GL_BACK_RIGHT;
|
|
(*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, GL_BACK_RIGHT);
|
|
}
|
|
|
|
/* make copy of incoming colors */
|
|
MEMCPY( rgbaTmp, span->array->rgba, 4 * span->end * sizeof(GLchan) );
|
|
|
|
if (ctx->Color.ColorLogicOpEnabled) {
|
|
_mesa_logicop_rgba_span(ctx, span, rgbaTmp);
|
|
}
|
|
else if (ctx->Color.BlendEnabled) {
|
|
_mesa_blend_span(ctx, span, rgbaTmp);
|
|
}
|
|
|
|
if (colorMask != 0xffffffff) {
|
|
_mesa_mask_rgba_span(ctx, span, rgbaTmp);
|
|
}
|
|
|
|
if (span->arrayMask & SPAN_XY) {
|
|
/* array of pixel coords */
|
|
(*swrast->Driver.WriteRGBAPixels)(ctx, span->end,
|
|
span->array->x, span->array->y,
|
|
(const GLchan (*)[4]) rgbaTmp,
|
|
span->array->mask);
|
|
if (SWRAST_CONTEXT(ctx)->_RasterMask & ALPHABUF_BIT) {
|
|
_mesa_write_alpha_pixels(ctx, span->end,
|
|
span->array->x, span->array->y,
|
|
(const GLchan (*)[4]) rgbaTmp,
|
|
span->array->mask);
|
|
}
|
|
}
|
|
else {
|
|
/* horizontal run of pixels */
|
|
(*swrast->Driver.WriteRGBASpan)(ctx, span->end, span->x, span->y,
|
|
(const GLchan (*)[4]) rgbaTmp,
|
|
span->array->mask);
|
|
if (swrast->_RasterMask & ALPHABUF_BIT) {
|
|
_mesa_write_alpha_span(ctx, span->end, span->x, span->y,
|
|
(const GLchan (*)[4]) rgbaTmp,
|
|
span->array->mask);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* restore default dest buffer */
|
|
_swrast_use_draw_buffer(ctx);
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* This function may modify any of the array values in the span.
|
|
* span->interpMask and span->arrayMask may be changed but will be restored
|
|
* to their original values before returning.
|
|
*/
|
|
void
|
|
_mesa_write_index_span( GLcontext *ctx, struct sw_span *span)
|
|
{
|
|
SWcontext *swrast = SWRAST_CONTEXT(ctx);
|
|
const GLuint origInterpMask = span->interpMask;
|
|
const GLuint origArrayMask = span->arrayMask;
|
|
|
|
ASSERT(span->end <= MAX_WIDTH);
|
|
ASSERT(span->primitive == GL_POINT || span->primitive == GL_LINE ||
|
|
span->primitive == GL_POLYGON || span->primitive == GL_BITMAP);
|
|
ASSERT((span->interpMask | span->arrayMask) & SPAN_INDEX);
|
|
ASSERT((span->interpMask & span->arrayMask) == 0);
|
|
|
|
if (span->arrayMask & SPAN_MASK) {
|
|
/* mask was initialized by caller, probably glBitmap */
|
|
span->writeAll = GL_FALSE;
|
|
}
|
|
else {
|
|
MEMSET(span->array->mask, 1, span->end);
|
|
span->writeAll = GL_TRUE;
|
|
}
|
|
|
|
/* Clipping */
|
|
if ((swrast->_RasterMask & CLIP_BIT) || (span->primitive != GL_POLYGON)) {
|
|
if (!clip_span(ctx, span)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
if (span->arrayMask & SPAN_XY) {
|
|
GLuint i;
|
|
for (i = 0; i < span->end; i++) {
|
|
if (span->array->mask[i]) {
|
|
assert(span->array->x[i] >= ctx->DrawBuffer->_Xmin);
|
|
assert(span->array->x[i] < ctx->DrawBuffer->_Xmax);
|
|
assert(span->array->y[i] >= ctx->DrawBuffer->_Ymin);
|
|
assert(span->array->y[i] < ctx->DrawBuffer->_Ymax);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* Polygon Stippling */
|
|
if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) {
|
|
stipple_polygon_span(ctx, span);
|
|
}
|
|
|
|
/* Depth test and stencil */
|
|
if (ctx->Depth.Test || ctx->Stencil.Enabled) {
|
|
if (span->interpMask & SPAN_Z)
|
|
_mesa_span_interpolate_z(ctx, span);
|
|
|
|
if (ctx->Stencil.Enabled) {
|
|
if (!_mesa_stencil_and_ztest_span(ctx, span)) {
|
|
span->arrayMask = origArrayMask;
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
ASSERT(ctx->Depth.Test);
|
|
if (!_mesa_depth_test_span(ctx, span)) {
|
|
span->arrayMask = origArrayMask;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* if we get here, something passed the depth test */
|
|
ctx->OcclusionResult = GL_TRUE;
|
|
|
|
/* we have to wait until after occlusion to do this test */
|
|
if (ctx->Color.DrawBuffer == GL_NONE || ctx->Color.IndexMask == 0) {
|
|
/* write no pixels */
|
|
span->arrayMask = origArrayMask;
|
|
return;
|
|
}
|
|
|
|
/* Interpolate the color indexes if needed */
|
|
if (span->interpMask & SPAN_INDEX) {
|
|
interpolate_indexes(ctx, span);
|
|
/* clear the bit - this allows the WriteMonoCISpan optimization below */
|
|
span->interpMask &= ~SPAN_INDEX;
|
|
}
|
|
|
|
/* Fog */
|
|
if (ctx->Fog.Enabled) {
|
|
_mesa_fog_ci_span(ctx, span);
|
|
}
|
|
|
|
/* Antialias coverage application */
|
|
if (span->arrayMask & SPAN_COVERAGE) {
|
|
GLuint i;
|
|
GLuint *index = span->array->index;
|
|
GLfloat *coverage = span->array->coverage;
|
|
for (i = 0; i < span->end; i++) {
|
|
ASSERT(coverage[i] < 16);
|
|
index[i] = (index[i] & ~0xf) | ((GLuint) coverage[i]);
|
|
}
|
|
}
|
|
|
|
if (swrast->_RasterMask & MULTI_DRAW_BIT) {
|
|
/* draw to zero or two or more buffers */
|
|
multi_write_index_span(ctx, span);
|
|
}
|
|
else {
|
|
/* normal situation: draw to exactly one buffer */
|
|
if (ctx->Color.IndexLogicOpEnabled) {
|
|
_mesa_logicop_ci_span(ctx, span, span->array->index);
|
|
}
|
|
|
|
if (ctx->Color.IndexMask != 0xffffffff) {
|
|
_mesa_mask_index_span(ctx, span, span->array->index);
|
|
}
|
|
|
|
/* write pixels */
|
|
if (span->arrayMask & SPAN_XY) {
|
|
/* array of pixel coords */
|
|
if ((span->interpMask & SPAN_INDEX) && span->indexStep == 0) {
|
|
/* all pixels have same color index */
|
|
(*swrast->Driver.WriteMonoCIPixels)(ctx, span->end,
|
|
span->array->x, span->array->y,
|
|
FixedToInt(span->index),
|
|
span->array->mask);
|
|
}
|
|
else {
|
|
(*swrast->Driver.WriteCI32Pixels)(ctx, span->end, span->array->x,
|
|
span->array->y, span->array->index,
|
|
span->array->mask );
|
|
}
|
|
}
|
|
else {
|
|
/* horizontal run of pixels */
|
|
if ((span->interpMask & SPAN_INDEX) && span->indexStep == 0) {
|
|
/* all pixels have same color index */
|
|
(*swrast->Driver.WriteMonoCISpan)(ctx, span->end, span->x, span->y,
|
|
FixedToInt(span->index),
|
|
span->array->mask);
|
|
}
|
|
else {
|
|
(*swrast->Driver.WriteCI32Span)(ctx, span->end, span->x, span->y,
|
|
span->array->index,
|
|
span->array->mask);
|
|
}
|
|
}
|
|
}
|
|
|
|
span->interpMask = origInterpMask;
|
|
span->arrayMask = origArrayMask;
|
|
}
|
|
|
|
|
|
/**
|
|
* This function may modify any of the array values in the span.
|
|
* span->interpMask and span->arrayMask may be changed but will be restored
|
|
* to their original values before returning.
|
|
*/
|
|
void
|
|
_mesa_write_rgba_span( GLcontext *ctx, struct sw_span *span)
|
|
{
|
|
SWcontext *swrast = SWRAST_CONTEXT(ctx);
|
|
const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
|
|
const GLuint origInterpMask = span->interpMask;
|
|
const GLuint origArrayMask = span->arrayMask;
|
|
GLboolean monoColor;
|
|
|
|
ASSERT(span->end <= MAX_WIDTH);
|
|
ASSERT(span->primitive == GL_POINT || span->primitive == GL_LINE ||
|
|
span->primitive == GL_POLYGON || span->primitive == GL_BITMAP);
|
|
ASSERT((span->interpMask & span->arrayMask) == 0);
|
|
ASSERT((span->interpMask | span->arrayMask) & SPAN_RGBA);
|
|
#ifdef DEBUG
|
|
if (ctx->Fog.Enabled)
|
|
ASSERT((span->interpMask | span->arrayMask) & SPAN_FOG);
|
|
if (ctx->Depth.Test)
|
|
ASSERT((span->interpMask | span->arrayMask) & SPAN_Z);
|
|
#endif
|
|
|
|
if (span->arrayMask & SPAN_MASK) {
|
|
/* mask was initialized by caller, probably glBitmap */
|
|
span->writeAll = GL_FALSE;
|
|
}
|
|
else {
|
|
MEMSET(span->array->mask, 1, span->end);
|
|
span->writeAll = GL_TRUE;
|
|
}
|
|
|
|
/* Determine if we have mono-chromatic colors */
|
|
monoColor = (span->interpMask & SPAN_RGBA) &&
|
|
span->redStep == 0 && span->greenStep == 0 &&
|
|
span->blueStep == 0 && span->alphaStep == 0;
|
|
|
|
/* Clipping */
|
|
if ((swrast->_RasterMask & CLIP_BIT) || (span->primitive != GL_POLYGON)) {
|
|
if (!clip_span(ctx, span)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
if (span->arrayMask & SPAN_XY) {
|
|
GLuint i;
|
|
for (i = 0; i < span->end; i++) {
|
|
if (span->array->mask[i]) {
|
|
assert(span->array->x[i] >= ctx->DrawBuffer->_Xmin);
|
|
assert(span->array->x[i] < ctx->DrawBuffer->_Xmax);
|
|
assert(span->array->y[i] >= ctx->DrawBuffer->_Ymin);
|
|
assert(span->array->y[i] < ctx->DrawBuffer->_Ymax);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* Polygon Stippling */
|
|
if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) {
|
|
stipple_polygon_span(ctx, span);
|
|
}
|
|
|
|
/* Do the alpha test */
|
|
if (ctx->Color.AlphaEnabled) {
|
|
if (!_mesa_alpha_test(ctx, span)) {
|
|
span->interpMask = origInterpMask;
|
|
span->arrayMask = origArrayMask;
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* Stencil and Z testing */
|
|
if (ctx->Stencil.Enabled || ctx->Depth.Test) {
|
|
if (span->interpMask & SPAN_Z)
|
|
_mesa_span_interpolate_z(ctx, span);
|
|
|
|
if (ctx->Stencil.Enabled) {
|
|
if (!_mesa_stencil_and_ztest_span(ctx, span)) {
|
|
span->interpMask = origInterpMask;
|
|
span->arrayMask = origArrayMask;
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
ASSERT(ctx->Depth.Test);
|
|
ASSERT(span->arrayMask & SPAN_Z);
|
|
/* regular depth testing */
|
|
if (!_mesa_depth_test_span(ctx, span)) {
|
|
span->interpMask = origInterpMask;
|
|
span->arrayMask = origArrayMask;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* if we get here, something passed the depth test */
|
|
ctx->OcclusionResult = GL_TRUE;
|
|
|
|
/* can't abort span-writing until after occlusion testing */
|
|
if (colorMask == 0x0) {
|
|
span->interpMask = origInterpMask;
|
|
span->arrayMask = origArrayMask;
|
|
return;
|
|
}
|
|
|
|
/* Now we may need to interpolate the colors */
|
|
if ((span->interpMask & SPAN_RGBA) && (span->arrayMask & SPAN_RGBA) == 0) {
|
|
interpolate_colors(ctx, span);
|
|
/* clear the bit - this allows the WriteMonoCISpan optimization below */
|
|
span->interpMask &= ~SPAN_RGBA;
|
|
}
|
|
|
|
/* Fog */
|
|
if (ctx->Fog.Enabled) {
|
|
_mesa_fog_rgba_span(ctx, span);
|
|
monoColor = GL_FALSE;
|
|
}
|
|
|
|
/* Antialias coverage application */
|
|
if (span->arrayMask & SPAN_COVERAGE) {
|
|
GLchan (*rgba)[4] = span->array->rgba;
|
|
GLfloat *coverage = span->array->coverage;
|
|
GLuint i;
|
|
for (i = 0; i < span->end; i++) {
|
|
rgba[i][ACOMP] = (GLchan) (rgba[i][ACOMP] * coverage[i]);
|
|
}
|
|
monoColor = GL_FALSE;
|
|
}
|
|
|
|
if (swrast->_RasterMask & MULTI_DRAW_BIT) {
|
|
multi_write_rgba_span(ctx, span);
|
|
}
|
|
else {
|
|
/* normal: write to exactly one buffer */
|
|
if (ctx->Color.ColorLogicOpEnabled) {
|
|
_mesa_logicop_rgba_span(ctx, span, span->array->rgba);
|
|
monoColor = GL_FALSE;
|
|
}
|
|
else if (ctx->Color.BlendEnabled) {
|
|
_mesa_blend_span(ctx, span, span->array->rgba);
|
|
monoColor = GL_FALSE;
|
|
}
|
|
|
|
/* Color component masking */
|
|
if (colorMask != 0xffffffff) {
|
|
_mesa_mask_rgba_span(ctx, span, span->array->rgba);
|
|
monoColor = GL_FALSE;
|
|
}
|
|
|
|
/* write pixels */
|
|
if (span->arrayMask & SPAN_XY) {
|
|
/* array of pixel coords */
|
|
/* XXX test for mono color */
|
|
(*swrast->Driver.WriteRGBAPixels)(ctx, span->end, span->array->x,
|
|
span->array->y, (const GLchan (*)[4]) span->array->rgba, span->array->mask);
|
|
if (SWRAST_CONTEXT(ctx)->_RasterMask & ALPHABUF_BIT) {
|
|
_mesa_write_alpha_pixels(ctx, span->end,
|
|
span->array->x, span->array->y,
|
|
(const GLchan (*)[4]) span->array->rgba,
|
|
span->array->mask);
|
|
}
|
|
}
|
|
else {
|
|
/* horizontal run of pixels */
|
|
if (monoColor) {
|
|
/* all pixels have same color */
|
|
GLchan color[4];
|
|
color[RCOMP] = FixedToChan(span->red);
|
|
color[GCOMP] = FixedToChan(span->green);
|
|
color[BCOMP] = FixedToChan(span->blue);
|
|
color[ACOMP] = FixedToChan(span->alpha);
|
|
(*swrast->Driver.WriteMonoRGBASpan)(ctx, span->end, span->x,
|
|
span->y, color, span->array->mask);
|
|
/* XXX software alpha buffer writes! */
|
|
}
|
|
else {
|
|
/* each pixel is a different color */
|
|
(*swrast->Driver.WriteRGBASpan)(ctx, span->end, span->x, span->y,
|
|
(const GLchan (*)[4]) span->array->rgba,
|
|
span->writeAll ? ((const GLubyte *) NULL) : span->array->mask);
|
|
if (swrast->_RasterMask & ALPHABUF_BIT) {
|
|
_mesa_write_alpha_span(ctx, span->end, span->x, span->y,
|
|
(const GLchan (*)[4]) span->array->rgba,
|
|
span->writeAll ? ((const GLubyte *) NULL) : span->array->mask);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
span->interpMask = origInterpMask;
|
|
span->arrayMask = origArrayMask;
|
|
}
|
|
|
|
|
|
/**
|
|
* Add specular color to base color. This is used only when
|
|
* GL_LIGHT_MODEL_COLOR_CONTROL = GL_SEPARATE_SPECULAR_COLOR.
|
|
*/
|
|
static void
|
|
add_colors(GLuint n, GLchan rgba[][4], GLchan specular[][4] )
|
|
{
|
|
GLuint i;
|
|
for (i = 0; i < n; i++) {
|
|
#if CHAN_TYPE == GL_FLOAT
|
|
/* no clamping */
|
|
rgba[i][RCOMP] += specular[i][RCOMP];
|
|
rgba[i][GCOMP] += specular[i][GCOMP];
|
|
rgba[i][BCOMP] += specular[i][BCOMP];
|
|
#else
|
|
GLint r = rgba[i][RCOMP] + specular[i][RCOMP];
|
|
GLint g = rgba[i][GCOMP] + specular[i][GCOMP];
|
|
GLint b = rgba[i][BCOMP] + specular[i][BCOMP];
|
|
rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
|
|
rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
|
|
rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* This function may modify any of the array values in the span.
|
|
* span->interpMask and span->arrayMask may be changed but will be restored
|
|
* to their original values before returning.
|
|
*/
|
|
void
|
|
_mesa_write_texture_span( GLcontext *ctx, struct sw_span *span)
|
|
{
|
|
const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask);
|
|
SWcontext *swrast = SWRAST_CONTEXT(ctx);
|
|
const GLuint origArrayMask = span->arrayMask;
|
|
|
|
ASSERT(span->primitive == GL_POINT || span->primitive == GL_LINE ||
|
|
span->primitive == GL_POLYGON || span->primitive == GL_BITMAP);
|
|
ASSERT(span->end <= MAX_WIDTH);
|
|
ASSERT((span->interpMask & span->arrayMask) == 0);
|
|
ASSERT(ctx->Texture._EnabledUnits);
|
|
|
|
/*
|
|
printf("%s() interp 0x%x array 0x%x\n", __FUNCTION__, span->interpMask, span->arrayMask);
|
|
*/
|
|
|
|
if (span->arrayMask & SPAN_MASK) {
|
|
/* mask was initialized by caller, probably glBitmap */
|
|
span->writeAll = GL_FALSE;
|
|
}
|
|
else {
|
|
MEMSET(span->array->mask, 1, span->end);
|
|
span->writeAll = GL_TRUE;
|
|
}
|
|
|
|
/* Clipping */
|
|
if ((swrast->_RasterMask & CLIP_BIT) || (span->primitive != GL_POLYGON)) {
|
|
if (!clip_span(ctx, span)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
if (span->arrayMask & SPAN_XY) {
|
|
GLuint i;
|
|
for (i = 0; i < span->end; i++) {
|
|
if (span->array->mask[i]) {
|
|
assert(span->array->x[i] >= ctx->DrawBuffer->_Xmin);
|
|
assert(span->array->x[i] < ctx->DrawBuffer->_Xmax);
|
|
assert(span->array->y[i] >= ctx->DrawBuffer->_Ymin);
|
|
assert(span->array->y[i] < ctx->DrawBuffer->_Ymax);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* Polygon Stippling */
|
|
if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) {
|
|
stipple_polygon_span(ctx, span);
|
|
}
|
|
|
|
/* Need texture coordinates now */
|
|
if ((span->interpMask & SPAN_TEXTURE)
|
|
&& (span->arrayMask & SPAN_TEXTURE) == 0)
|
|
interpolate_texcoords(ctx, span);
|
|
|
|
/* Texture with alpha test */
|
|
if (ctx->Color.AlphaEnabled) {
|
|
|
|
/* Now we need the rgba array, fill it in if needed */
|
|
if ((span->interpMask & SPAN_RGBA) && (span->arrayMask & SPAN_RGBA) == 0)
|
|
interpolate_colors(ctx, span);
|
|
|
|
/* Texturing without alpha is done after depth-testing which
|
|
* gives a potential speed-up.
|
|
*/
|
|
_swrast_texture_span( ctx, span );
|
|
|
|
/* Do the alpha test */
|
|
if (!_mesa_alpha_test(ctx, span)) {
|
|
span->arrayMask = origArrayMask;
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* Stencil and Z testing */
|
|
if (ctx->Stencil.Enabled || ctx->Depth.Test) {
|
|
if (span->interpMask & SPAN_Z)
|
|
_mesa_span_interpolate_z(ctx, span);
|
|
|
|
if (ctx->Stencil.Enabled) {
|
|
if (!_mesa_stencil_and_ztest_span(ctx, span)) {
|
|
span->arrayMask = origArrayMask;
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
ASSERT(ctx->Depth.Test);
|
|
ASSERT(span->arrayMask & SPAN_Z);
|
|
/* regular depth testing */
|
|
if (!_mesa_depth_test_span(ctx, span)) {
|
|
span->arrayMask = origArrayMask;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* if we get here, some fragments passed the depth test */
|
|
ctx->OcclusionResult = GL_TRUE;
|
|
|
|
/* We had to wait until now to check for glColorMask(F,F,F,F) because of
|
|
* the occlusion test.
|
|
*/
|
|
if (colorMask == 0x0) {
|
|
span->arrayMask = origArrayMask;
|
|
return;
|
|
}
|
|
|
|
/* Texture without alpha test */
|
|
if (!ctx->Color.AlphaEnabled) {
|
|
|
|
/* Now we need the rgba array, fill it in if needed */
|
|
if ((span->interpMask & SPAN_RGBA) && (span->arrayMask & SPAN_RGBA) == 0)
|
|
interpolate_colors(ctx, span);
|
|
|
|
_swrast_texture_span( ctx, span );
|
|
}
|
|
|
|
ASSERT(span->arrayMask & SPAN_RGBA);
|
|
|
|
/* Add base and specular colors */
|
|
if (ctx->Fog.ColorSumEnabled ||
|
|
(ctx->Light.Enabled &&
|
|
ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)) {
|
|
if (span->interpMask & SPAN_SPEC) {
|
|
interpolate_specular(ctx, span);
|
|
}
|
|
ASSERT(span->arrayMask & SPAN_SPEC);
|
|
add_colors( span->end, span->array->rgba, span->array->spec );
|
|
}
|
|
|
|
/* Fog */
|
|
if (ctx->Fog.Enabled) {
|
|
_mesa_fog_rgba_span(ctx, span);
|
|
}
|
|
|
|
/* Antialias coverage application */
|
|
if (span->arrayMask & SPAN_COVERAGE) {
|
|
GLchan (*rgba)[4] = span->array->rgba;
|
|
GLfloat *coverage = span->array->coverage;
|
|
GLuint i;
|
|
for (i = 0; i < span->end; i++) {
|
|
rgba[i][ACOMP] = (GLchan) (rgba[i][ACOMP] * coverage[i]);
|
|
}
|
|
}
|
|
|
|
if (swrast->_RasterMask & MULTI_DRAW_BIT) {
|
|
multi_write_rgba_span(ctx, span);
|
|
}
|
|
else {
|
|
/* normal: write to exactly one buffer */
|
|
if (ctx->Color.ColorLogicOpEnabled) {
|
|
_mesa_logicop_rgba_span(ctx, span, span->array->rgba);
|
|
}
|
|
else if (ctx->Color.BlendEnabled) {
|
|
_mesa_blend_span(ctx, span, span->array->rgba);
|
|
}
|
|
|
|
if (colorMask != 0xffffffff) {
|
|
_mesa_mask_rgba_span(ctx, span, span->array->rgba);
|
|
}
|
|
|
|
|
|
if (span->arrayMask & SPAN_XY) {
|
|
/* array of pixel coords */
|
|
(*swrast->Driver.WriteRGBAPixels)(ctx, span->end, span->array->x,
|
|
span->array->y, (const GLchan (*)[4]) span->array->rgba, span->array->mask);
|
|
if (SWRAST_CONTEXT(ctx)->_RasterMask & ALPHABUF_BIT) {
|
|
_mesa_write_alpha_pixels(ctx, span->end,
|
|
span->array->x, span->array->y,
|
|
(const GLchan (*)[4]) span->array->rgba,
|
|
span->array->mask);
|
|
}
|
|
}
|
|
else {
|
|
/* horizontal run of pixels */
|
|
(*swrast->Driver.WriteRGBASpan)(ctx, span->end, span->x, span->y,
|
|
(const GLchan (*)[4]) span->array->rgba,
|
|
span->writeAll ? NULL : span->array->mask);
|
|
if (swrast->_RasterMask & ALPHABUF_BIT) {
|
|
_mesa_write_alpha_span(ctx, span->end, span->x, span->y,
|
|
(const GLchan (*)[4]) span->array->rgba,
|
|
span->writeAll ? NULL : span->array->mask);
|
|
}
|
|
}
|
|
}
|
|
|
|
span->arrayMask = origArrayMask;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Read RGBA pixels from frame buffer. Clipping will be done to prevent
|
|
* reading ouside the buffer's boundaries.
|
|
*/
|
|
void
|
|
_mesa_read_rgba_span( GLcontext *ctx, GLframebuffer *buffer,
|
|
GLuint n, GLint x, GLint y, GLchan rgba[][4] )
|
|
{
|
|
SWcontext *swrast = SWRAST_CONTEXT(ctx);
|
|
const GLint bufWidth = (GLint) buffer->Width;
|
|
const GLint bufHeight = (GLint) buffer->Height;
|
|
|
|
if (y < 0 || y >= bufHeight || x + (GLint) n < 0 || x >= bufWidth) {
|
|
/* completely above, below, or right */
|
|
/* XXX maybe leave undefined? */
|
|
BZERO(rgba, 4 * n * sizeof(GLchan));
|
|
}
|
|
else {
|
|
GLint skip, length;
|
|
if (x < 0) {
|
|
/* left edge clippping */
|
|
skip = -x;
|
|
length = (GLint) n - skip;
|
|
if (length < 0) {
|
|
/* completely left of window */
|
|
return;
|
|
}
|
|
if (length > bufWidth) {
|
|
length = bufWidth;
|
|
}
|
|
}
|
|
else if ((GLint) (x + n) > bufWidth) {
|
|
/* right edge clipping */
|
|
skip = 0;
|
|
length = bufWidth - x;
|
|
if (length < 0) {
|
|
/* completely to right of window */
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
/* no clipping */
|
|
skip = 0;
|
|
length = (GLint) n;
|
|
}
|
|
|
|
(*swrast->Driver.ReadRGBASpan)( ctx, length, x + skip, y, rgba + skip );
|
|
if (buffer->UseSoftwareAlphaBuffers) {
|
|
_mesa_read_alpha_span(ctx, length, x + skip, y, rgba + skip);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Read CI pixels from frame buffer. Clipping will be done to prevent
|
|
* reading ouside the buffer's boundaries.
|
|
*/
|
|
void
|
|
_mesa_read_index_span( GLcontext *ctx, GLframebuffer *buffer,
|
|
GLuint n, GLint x, GLint y, GLuint indx[] )
|
|
{
|
|
SWcontext *swrast = SWRAST_CONTEXT(ctx);
|
|
const GLint bufWidth = (GLint) buffer->Width;
|
|
const GLint bufHeight = (GLint) buffer->Height;
|
|
|
|
if (y < 0 || y >= bufHeight || x + (GLint) n < 0 || x >= bufWidth) {
|
|
/* completely above, below, or right */
|
|
BZERO(indx, n * sizeof(GLuint));
|
|
}
|
|
else {
|
|
GLint skip, length;
|
|
if (x < 0) {
|
|
/* left edge clippping */
|
|
skip = -x;
|
|
length = (GLint) n - skip;
|
|
if (length < 0) {
|
|
/* completely left of window */
|
|
return;
|
|
}
|
|
if (length > bufWidth) {
|
|
length = bufWidth;
|
|
}
|
|
}
|
|
else if ((GLint) (x + n) > bufWidth) {
|
|
/* right edge clipping */
|
|
skip = 0;
|
|
length = bufWidth - x;
|
|
if (length < 0) {
|
|
/* completely to right of window */
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
/* no clipping */
|
|
skip = 0;
|
|
length = (GLint) n;
|
|
}
|
|
|
|
(*swrast->Driver.ReadCI32Span)( ctx, length, skip + x, y, indx + skip );
|
|
}
|
|
}
|