#include "glheader.h"
#include "colormac.h"
#include "context.h"
#include "macros.h"
#include "mmath.h"
#include "imports.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"
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 + 0.5F);
else
span->z = (GLint) (ctx->Current.RasterPos[2] * ctx->DepthMax + 0.5F);
span->zStep = 0;
span->interpMask |= SPAN_Z;
}
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;
}
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;
}
}
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;
}
static void
interpolate_colors(GLcontext *ctx, struct sw_span *span)
{
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) {
GLchan color[4];
color[RCOMP] = FixedToChan(span->red);
color[GCOMP] = FixedToChan(span->green);
color[BCOMP] = FixedToChan(span->blue);
color[ACOMP] = FixedToChan(span->alpha);
for (i = 0; i < n; i++) {
COPY_CHAN4(span->array->rgba[i], color);
}
}
else {
#if CHAN_TYPE == GL_FLOAT
GLfloat r = span->red;
GLfloat g = span->green;
GLfloat b = span->blue;
GLfloat a = span->alpha;
const GLfloat dr = span->redStep;
const GLfloat dg = span->greenStep;
const GLfloat db = span->blueStep;
const GLfloat da = span->alphaStep;
#else
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;
#endif
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;
}
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)) {
index = FixedToInt(index);
for (i = 0; i < n; i++) {
indexes[i] = index;
}
}
else {
for (i = 0; i < n; i++) {
indexes[i] = FixedToInt(index);
index += indexStep;
}
}
span->arrayMask |= SPAN_INDEX;
}
static void
interpolate_specular(GLcontext *ctx, struct sw_span *span)
{
if (span->interpMask & SPAN_FLAT) {
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 {
#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;
}
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 {
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;
}
#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
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;
}
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) {
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) {
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;
}
}
}
}
}
}
else {
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) {
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 {
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) {
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;
}
}
}
}
}
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;
}
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) {
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) {
for (i = 0; i < n; i++) {
mask[i] &= (x[i] >= xmin) & (x[i] < xmax)
& (y[i] >= ymin) & (y[i] < ymax);
}
}
else {
for (i = 0; i < n; i++) {
mask[i] = (x[i] >= xmin) & (x[i] < xmax)
& (y[i] >= ymin) & (y[i] < ymax);
}
}
return GL_TRUE;
}
else {
const GLint x = span->x;
const GLint y = span->y;
const GLint n = span->end;
if (y < ymin || y >= ymax || x + n <= xmin || x >= xmax) {
span->end = 0;
return GL_FALSE;
}
if (x < xmin) {
ASSERT(x + n > xmin);
span->writeAll = GL_FALSE;
_mesa_bzero(span->array->mask, (xmin - x) * sizeof(GLubyte));
}
if (x + n > xmax) {
ASSERT(x < xmax);
span->end = xmax - x;
}
return GL_TRUE;
}
}
static void
multi_write_index_span( GLcontext *ctx, struct sw_span *span )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
GLuint bufferBit;
for (bufferBit = 1; bufferBit <= 8; bufferBit <<= 1) {
if (bufferBit & ctx->Color._DrawDestMask) {
GLuint indexTmp[MAX_WIDTH];
ASSERT(span->end < MAX_WIDTH);
swrast->CurrentBuffer = bufferBit;
(*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, bufferBit);
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) {
(*swrast->Driver.WriteCI32Pixels)(ctx, span->end,
span->array->x, span->array->y,
indexTmp, span->array->mask);
}
else {
(*swrast->Driver.WriteCI32Span)(ctx, span->end, span->x, span->y,
indexTmp, span->array->mask);
}
}
}
_swrast_use_draw_buffer(ctx);
}
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;
for (bufferBit = 1; bufferBit <= 8; bufferBit <<= 1) {
if (bufferBit & ctx->Color._DrawDestMask) {
GLchan rgbaTmp[MAX_WIDTH][4];
ASSERT(span->end < MAX_WIDTH);
swrast->CurrentBuffer = bufferBit;
(*swrast->Driver.SetBuffer)(ctx, ctx->DrawBuffer, bufferBit);
MEMCPY( rgbaTmp, span->array->rgba, 4 * span->end * sizeof(GLchan) );
if (ctx->Color._LogicOpEnabled) {
_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) {
(*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 {
(*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);
}
}
}
}
_swrast_use_draw_buffer(ctx);
}
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) {
span->writeAll = GL_FALSE;
}
else {
MEMSET(span->array->mask, 1, span->end);
span->writeAll = GL_TRUE;
}
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
if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) {
stipple_polygon_span(ctx, span);
}
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;
}
}
}
ctx->OcclusionResult = GL_TRUE;
if (ctx->Color.DrawBuffer == GL_NONE || ctx->Color.IndexMask == 0) {
span->arrayMask = origArrayMask;
return;
}
if (span->interpMask & SPAN_INDEX) {
interpolate_indexes(ctx, span);
span->interpMask &= ~SPAN_INDEX;
}
if (ctx->Fog.Enabled) {
_mesa_fog_ci_span(ctx, span);
}
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) {
multi_write_index_span(ctx, span);
}
else {
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);
}
if (span->arrayMask & SPAN_XY) {
if ((span->interpMask & SPAN_INDEX) && span->indexStep == 0) {
(*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 {
if ((span->interpMask & SPAN_INDEX) && span->indexStep == 0) {
(*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;
}
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) {
span->writeAll = GL_FALSE;
}
else {
MEMSET(span->array->mask, 1, span->end);
span->writeAll = GL_TRUE;
}
monoColor = (span->interpMask & SPAN_RGBA) &&
span->redStep == 0 && span->greenStep == 0 &&
span->blueStep == 0 && span->alphaStep == 0;
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
if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) {
stipple_polygon_span(ctx, span);
}
if (ctx->Color.AlphaEnabled) {
if (!_mesa_alpha_test(ctx, span)) {
span->interpMask = origInterpMask;
span->arrayMask = origArrayMask;
return;
}
}
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);
if (!_mesa_depth_test_span(ctx, span)) {
span->interpMask = origInterpMask;
span->arrayMask = origArrayMask;
return;
}
}
}
ctx->OcclusionResult = GL_TRUE;
if (colorMask == 0x0) {
span->interpMask = origInterpMask;
span->arrayMask = origArrayMask;
return;
}
if ((span->interpMask & SPAN_RGBA) && (span->arrayMask & SPAN_RGBA) == 0) {
interpolate_colors(ctx, span);
span->interpMask &= ~SPAN_RGBA;
}
if (ctx->Fog.Enabled) {
_mesa_fog_rgba_span(ctx, span);
monoColor = GL_FALSE;
}
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 {
if (ctx->Color._LogicOpEnabled) {
_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;
}
if (colorMask != 0xffffffff) {
_mesa_mask_rgba_span(ctx, span, span->array->rgba);
monoColor = GL_FALSE;
}
if (span->arrayMask & SPAN_XY) {
(*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 {
if (monoColor) {
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);
if (swrast->_RasterMask & ALPHABUF_BIT) {
_mesa_write_mono_alpha_span(ctx, span->end, span->x, span->y,
color[ACOMP],
span->writeAll ? ((const GLubyte *) NULL) : span->array->mask);
}
}
else {
(*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;
}
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
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
}
}
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);
if (span->arrayMask & SPAN_MASK) {
span->writeAll = GL_FALSE;
}
else {
MEMSET(span->array->mask, 1, span->end);
span->writeAll = GL_TRUE;
}
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
if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) {
stipple_polygon_span(ctx, span);
}
if ((span->interpMask & SPAN_TEXTURE)
&& (span->arrayMask & SPAN_TEXTURE) == 0)
interpolate_texcoords(ctx, span);
if (ctx->Color.AlphaEnabled) {
if ((span->interpMask & SPAN_RGBA) && (span->arrayMask & SPAN_RGBA) == 0)
interpolate_colors(ctx, span);
_swrast_texture_span( ctx, span );
if (!_mesa_alpha_test(ctx, span)) {
span->arrayMask = origArrayMask;
return;
}
}
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);
if (!_mesa_depth_test_span(ctx, span)) {
span->arrayMask = origArrayMask;
return;
}
}
}
ctx->OcclusionResult = GL_TRUE;
if (colorMask == 0x0) {
span->arrayMask = origArrayMask;
return;
}
if (!ctx->Color.AlphaEnabled) {
if ((span->interpMask & SPAN_RGBA) && (span->arrayMask & SPAN_RGBA) == 0)
interpolate_colors(ctx, span);
_swrast_texture_span( ctx, span );
}
ASSERT(span->arrayMask & SPAN_RGBA);
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 );
}
if (ctx->Fog.Enabled) {
_mesa_fog_rgba_span(ctx, span);
}
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 {
if (ctx->Color._LogicOpEnabled) {
_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) {
(*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 {
(*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;
}
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) {
_mesa_bzero(rgba, 4 * n * sizeof(GLchan));
}
else {
GLint skip, length;
if (x < 0) {
skip = -x;
length = (GLint) n - skip;
if (length < 0) {
return;
}
if (length > bufWidth) {
length = bufWidth;
}
}
else if ((GLint) (x + n) > bufWidth) {
skip = 0;
length = bufWidth - x;
if (length < 0) {
return;
}
}
else {
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);
}
}
}
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) {
_mesa_bzero(indx, n * sizeof(GLuint));
}
else {
GLint skip, length;
if (x < 0) {
skip = -x;
length = (GLint) n - skip;
if (length < 0) {
return;
}
if (length > bufWidth) {
length = bufWidth;
}
}
else if ((GLint) (x + n) > bufWidth) {
skip = 0;
length = bufWidth - x;
if (length < 0) {
return;
}
}
else {
skip = 0;
length = (GLint) n;
}
(*swrast->Driver.ReadCI32Span)( ctx, length, skip + x, y, indx + skip );
}
}