diff options
Diffstat (limited to 'src/mesa/swrast/s_span.c')
-rw-r--r-- | src/mesa/swrast/s_span.c | 1109 |
1 files changed, 1109 insertions, 0 deletions
diff --git a/src/mesa/swrast/s_span.c b/src/mesa/swrast/s_span.c new file mode 100644 index 00000000000..ca02802ceb7 --- /dev/null +++ b/src/mesa/swrast/s_span.c @@ -0,0 +1,1109 @@ +/* $Id: s_span.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 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. + */ + + +/* + * pixel span rasterization: + * These functions implement the rasterization pipeline. + */ + + +#include "glheader.h" +#include "colormac.h" +#include "macros.h" +#include "mem.h" + +#include "s_alpha.h" +#include "s_alphabuf.h" +#include "s_blend.h" +#include "s_depth.h" +#include "s_fog.h" +#include "s_logic.h" +#include "s_masking.h" +#include "s_scissor.h" +#include "s_span.h" +#include "s_stencil.h" +#include "s_texture.h" + + + + +/* + * Apply the current polygon stipple pattern to a span of pixels. + */ +static void stipple_polygon_span( GLcontext *ctx, + GLuint n, GLint x, GLint y, GLubyte mask[] ) +{ + register GLuint i, m, stipple, highbit=0x80000000; + + stipple = ctx->PolygonStipple[y % 32]; + m = highbit >> (GLuint) (x % 32); + + for (i=0;i<n;i++) { + if ((m & stipple)==0) { + mask[i] = 0; + } + m = m >> 1; + if (m==0) { + m = 0x80000000; + } + } +} + + + +/* + * Clip a pixel span to the current buffer/window boundaries. + * Return: 0 = all pixels clipped + * 1 = at least one pixel is visible + */ +static GLuint clip_span( GLcontext *ctx, + GLint n, GLint x, GLint y, GLubyte mask[] ) +{ + GLint i; + + /* Clip to top and bottom */ + if (y < 0 || y >= ctx->DrawBuffer->Height) { + return 0; + } + + /* Clip to left and right */ + if (x >= 0 && x + n <= ctx->DrawBuffer->Width) { + /* no clipping needed */ + return 1; + } + else if (x + n <= 0) { + /* completely off left side */ + return 0; + } + else if (x >= ctx->DrawBuffer->Width) { + /* completely off right side */ + return 0; + } + else { + /* clip-test each pixel, this could be done better */ + for (i=0;i<n;i++) { + if (x + i < 0 || x + i >= ctx->DrawBuffer->Width) { + mask[i] = 0; + } + } + return 1; + } +} + + + +/* + * Draw to more than one color buffer (or none). + */ +static void multi_write_index_span( GLcontext *ctx, GLuint n, + GLint x, GLint y, const GLuint indexes[], + const GLubyte mask[] ) +{ + GLuint bufferBit; + + if (ctx->Color.DrawBuffer == GL_NONE) + return; + + /* loop over four possible dest color buffers */ + for (bufferBit = 1; bufferBit <= 8; bufferBit = bufferBit << 1) { + if (bufferBit & ctx->Color.DrawDestMask) { + GLuint indexTmp[MAX_WIDTH]; + ASSERT(n < MAX_WIDTH); + + if (bufferBit == FRONT_LEFT_BIT) + (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_LEFT); + else if (bufferBit == FRONT_RIGHT_BIT) + (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_RIGHT); + else if (bufferBit == BACK_LEFT_BIT) + (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_LEFT); + else + (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_RIGHT); + + /* make copy of incoming indexes */ + MEMCPY( indexTmp, indexes, n * sizeof(GLuint) ); + if (ctx->Color.IndexLogicOpEnabled) { + _mesa_logicop_ci_span( ctx, n, x, y, indexTmp, mask ); + } + if (ctx->Color.IndexMask == 0) { + break; + } + else if (ctx->Color.IndexMask != 0xffffffff) { + _mesa_mask_index_span( ctx, n, x, y, indexTmp ); + } + (*ctx->Driver.WriteCI32Span)( ctx, n, x, y, indexTmp, mask ); + } + } + + /* restore default dest buffer */ + (void) (*ctx->Driver.SetDrawBuffer)( ctx, ctx->Color.DriverDrawBuffer); +} + + + +/* + * Write a horizontal span of color index pixels to the frame buffer. + * Stenciling, Depth-testing, etc. are done as needed. + * Input: n - number of pixels in the span + * x, y - location of leftmost pixel in the span + * z - array of [n] z-values + * index - array of [n] color indexes + * primitive - either GL_POINT, GL_LINE, GL_POLYGON, or GL_BITMAP + */ +void gl_write_index_span( GLcontext *ctx, + GLuint n, GLint x, GLint y, const GLdepth z[], + const GLfixed fog[], + GLuint indexIn[], GLenum primitive ) +{ + const GLuint modBits = FOG_BIT | BLEND_BIT | MASKING_BIT | LOGIC_OP_BIT; + GLubyte mask[MAX_WIDTH]; + GLuint indexBackup[MAX_WIDTH]; + GLuint *index; /* points to indexIn or indexBackup */ + + /* init mask to 1's (all pixels are to be written) */ + MEMSET(mask, 1, n); + + if ((ctx->RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { + if (clip_span(ctx,n,x,y,mask)==0) { + return; + } + } + + if ((primitive==GL_BITMAP && (ctx->RasterMask & modBits)) + || (ctx->RasterMask & MULTI_DRAW_BIT)) { + /* Make copy of color indexes */ + MEMCPY( indexBackup, indexIn, n * sizeof(GLuint) ); + index = indexBackup; + } + else { + index = indexIn; + } + + /* Per-pixel fog */ + if (ctx->Fog.Enabled) { + if (fog && ctx->Hint.Fog != GL_NICEST) + _mesa_fog_ci_pixels( ctx, n, fog, index ); + else + _mesa_depth_fog_ci_pixels( ctx, n, z, index ); + } + + /* Do the scissor test */ + if (ctx->Scissor.Enabled) { + if (gl_scissor_span( ctx, n, x, y, mask )==0) { + return; + } + } + + /* Polygon Stippling */ + if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { + stipple_polygon_span( ctx, n, x, y, mask ); + } + + if (ctx->Stencil.Enabled) { + /* first stencil test */ + if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) { + return; + } + } + else if (ctx->Depth.Test) { + /* regular depth testing */ + if (_mesa_depth_test_span( ctx, n, x, y, z, mask )==0) return; + } + + /* if we get here, something passed the depth test */ + ctx->OcclusionResult = GL_TRUE; + + if (ctx->RasterMask & MULTI_DRAW_BIT) { + /* draw to zero or two or more buffers */ + multi_write_index_span( ctx, n, x, y, index, mask ); + } + else { + /* normal situation: draw to exactly one buffer */ + if (ctx->Color.IndexLogicOpEnabled) { + _mesa_logicop_ci_span( ctx, n, x, y, index, mask ); + } + + if (ctx->Color.IndexMask == 0) { + return; + } + else if (ctx->Color.IndexMask != 0xffffffff) { + _mesa_mask_index_span( ctx, n, x, y, index ); + } + + /* write pixels */ + (*ctx->Driver.WriteCI32Span)( ctx, n, x, y, index, mask ); + } +} + + + + +void gl_write_monoindex_span( GLcontext *ctx, + GLuint n, GLint x, GLint y, + const GLdepth z[], + const GLfixed fog[], + GLuint index, GLenum primitive ) +{ + GLubyte mask[MAX_WIDTH]; + GLuint i; + + /* init mask to 1's (all pixels are to be written) */ + MEMSET(mask, 1, n); + + if ((ctx->RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { + if (clip_span( ctx, n, x, y, mask)==0) { + return; + } + } + + /* Do the scissor test */ + if (ctx->Scissor.Enabled) { + if (gl_scissor_span( ctx, n, x, y, mask )==0) { + return; + } + } + + /* Polygon Stippling */ + if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { + stipple_polygon_span( ctx, n, x, y, mask ); + } + + if (ctx->Stencil.Enabled) { + /* first stencil test */ + if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) { + return; + } + } + else if (ctx->Depth.Test) { + /* regular depth testing */ + if (_mesa_depth_test_span( ctx, n, x, y, z, mask )==0) return; + } + + /* if we get here, something passed the depth test */ + ctx->OcclusionResult = GL_TRUE; + + if (ctx->Color.DrawBuffer == GL_NONE) { + /* write no pixels */ + return; + } + + if (ctx->Fog.Enabled + || ctx->Color.IndexLogicOpEnabled + || ctx->Color.IndexMask != 0xffffffff) { + /* different index per pixel */ + GLuint indexes[MAX_WIDTH]; + for (i=0;i<n;i++) { + indexes[i] = index; + } + + if (ctx->Fog.Enabled) { + if (fog && ctx->Hint.Fog != GL_NICEST) + _mesa_fog_ci_pixels( ctx, n, fog, indexes ); + else + _mesa_depth_fog_ci_pixels( ctx, n, z, indexes ); + } + + if (ctx->Color.IndexLogicOpEnabled) { + _mesa_logicop_ci_span( ctx, n, x, y, indexes, mask ); + } + + if (ctx->RasterMask & MULTI_DRAW_BIT) { + /* draw to zero or two or more buffers */ + multi_write_index_span( ctx, n, x, y, indexes, mask ); + } + else { + /* normal situation: draw to exactly one buffer */ + if (ctx->Color.IndexLogicOpEnabled) { + _mesa_logicop_ci_span( ctx, n, x, y, indexes, mask ); + } + if (ctx->Color.IndexMask == 0) { + return; + } + else if (ctx->Color.IndexMask != 0xffffffff) { + _mesa_mask_index_span( ctx, n, x, y, indexes ); + } + (*ctx->Driver.WriteCI32Span)( ctx, n, x, y, indexes, mask ); + } + } + else { + /* same color index for all pixels */ + ASSERT(!ctx->Color.IndexLogicOpEnabled); + ASSERT(ctx->Color.IndexMask == 0xffffffff); + if (ctx->RasterMask & MULTI_DRAW_BIT) { + /* draw to zero or two or more buffers */ + GLuint indexes[MAX_WIDTH]; + for (i=0;i<n;i++) + indexes[i] = index; + multi_write_index_span( ctx, n, x, y, indexes, mask ); + } + else { + /* normal situation: draw to exactly one buffer */ + (*ctx->Driver.WriteMonoCISpan)( ctx, n, x, y, mask ); + } + } +} + + + +/* + * Draw to more than one RGBA color buffer (or none). + */ +static void multi_write_rgba_span( GLcontext *ctx, GLuint n, + GLint x, GLint y, CONST GLchan rgba[][4], + const GLubyte mask[] ) +{ + const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask); + GLuint bufferBit; + + if (ctx->Color.DrawBuffer == GL_NONE) + return; + + /* loop over four possible dest color buffers */ + for (bufferBit = 1; bufferBit <= 8; bufferBit = bufferBit << 1) { + if (bufferBit & ctx->Color.DrawDestMask) { + GLchan rgbaTmp[MAX_WIDTH][4]; + ASSERT(n < MAX_WIDTH); + + if (bufferBit == FRONT_LEFT_BIT) { + (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_LEFT); + ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontLeftAlpha; + } + else if (bufferBit == FRONT_RIGHT_BIT) { + (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_RIGHT); + ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontRightAlpha; + } + else if (bufferBit == BACK_LEFT_BIT) { + (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_LEFT); + ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackLeftAlpha; + } + else { + (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_RIGHT); + ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackRightAlpha; + } + + /* make copy of incoming colors */ + MEMCPY( rgbaTmp, rgba, 4 * n * sizeof(GLchan) ); + + if (ctx->Color.ColorLogicOpEnabled) { + _mesa_logicop_rgba_span( ctx, n, x, y, rgbaTmp, mask ); + } + else if (ctx->Color.BlendEnabled) { + _mesa_blend_span( ctx, n, x, y, rgbaTmp, mask ); + } + if (colorMask == 0x0) { + break; + } + else if (colorMask != 0xffffffff) { + _mesa_mask_rgba_span( ctx, n, x, y, rgbaTmp ); + } + + (*ctx->Driver.WriteRGBASpan)( ctx, n, x, y, + (const GLchan (*)[4]) rgbaTmp, mask ); + if (ctx->RasterMask & ALPHABUF_BIT) { + _mesa_write_alpha_span( ctx, n, x, y, + (const GLchan (*)[4])rgbaTmp, mask ); + } + } + } + + /* restore default dest buffer */ + (void) (*ctx->Driver.SetDrawBuffer)( ctx, ctx->Color.DriverDrawBuffer ); +} + + + +void gl_write_rgba_span( GLcontext *ctx, + GLuint n, GLint x, GLint y, const GLdepth z[], + const GLfixed *fog, + GLchan rgbaIn[][4], + GLenum primitive ) +{ + const GLuint modBits = FOG_BIT | BLEND_BIT | MASKING_BIT | + LOGIC_OP_BIT | TEXTURE_BIT; + GLubyte mask[MAX_WIDTH]; + GLboolean write_all = GL_TRUE; + GLchan rgbaBackup[MAX_WIDTH][4]; + GLchan (*rgba)[4]; + const GLubyte *Null = 0; + + /* init mask to 1's (all pixels are to be written) */ + MEMSET(mask, 1, n); + + if ((ctx->RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { + if (clip_span( ctx,n,x,y,mask)==0) { + return; + } + write_all = GL_FALSE; + } + + if ((primitive==GL_BITMAP && (ctx->RasterMask & modBits)) + || (ctx->RasterMask & MULTI_DRAW_BIT)) { + /* must make a copy of the colors since they may be modified */ + MEMCPY( rgbaBackup, rgbaIn, 4 * n * sizeof(GLchan) ); + rgba = rgbaBackup; + } + else { + rgba = rgbaIn; + } + + /* Per-pixel fog */ + if (ctx->Fog.Enabled) { + if (fog && ctx->Hint.Fog != GL_NICEST) + _mesa_fog_rgba_pixels( ctx, n, fog, rgba ); + else + _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba ); + } + + /* Do the scissor test */ + if (ctx->Scissor.Enabled) { + if (gl_scissor_span( ctx, n, x, y, mask )==0) { + return; + } + write_all = GL_FALSE; + } + + /* Polygon Stippling */ + if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { + stipple_polygon_span( ctx, n, x, y, mask ); + write_all = GL_FALSE; + } + + /* Do the alpha test */ + if (ctx->Color.AlphaEnabled) { + if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4]) rgba, mask )==0) { + return; + } + write_all = GL_FALSE; + } + + if (ctx->Stencil.Enabled) { + /* first stencil test */ + if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) { + return; + } + write_all = GL_FALSE; + } + else if (ctx->Depth.Test) { + /* regular depth testing */ + GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask ); + if (m==0) { + return; + } + if (m<n) { + write_all = GL_FALSE; + } + } + + /* if we get here, something passed the depth test */ + ctx->OcclusionResult = GL_TRUE; + + if (ctx->RasterMask & MULTI_DRAW_BIT) { + multi_write_rgba_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, mask ); + } + else { + /* normal: write to exactly one buffer */ + /* logic op or blending */ + const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask); + + if (ctx->Color.ColorLogicOpEnabled) { + _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask ); + } + else if (ctx->Color.BlendEnabled) { + _mesa_blend_span( ctx, n, x, y, rgba, mask ); + } + + /* Color component masking */ + if (colorMask == 0x0) { + return; + } + else if (colorMask != 0xffffffff) { + _mesa_mask_rgba_span( ctx, n, x, y, rgba ); + } + + /* write pixels */ + (*ctx->Driver.WriteRGBASpan)( ctx, n, x, y, + (const GLchan (*)[4]) rgba, + write_all ? Null : mask ); + + if (ctx->RasterMask & ALPHABUF_BIT) { + _mesa_write_alpha_span( ctx, n, x, y, + (const GLchan (*)[4]) rgba, + write_all ? Null : mask ); + } + + } +} + + + +/* + * Write a horizontal span of color pixels to the frame buffer. + * The color is initially constant for the whole span. + * Alpha-testing, stenciling, depth-testing, and blending are done as needed. + * Input: n - number of pixels in the span + * x, y - location of leftmost pixel in the span + * z - array of [n] z-values + * r, g, b, a - the color of the pixels + * primitive - either GL_POINT, GL_LINE, GL_POLYGON or GL_BITMAP. + */ +void gl_write_monocolor_span( GLcontext *ctx, + GLuint n, GLint x, GLint y, const GLdepth z[], + const GLfixed fog[], + const GLchan color[4], + GLenum primitive ) +{ + const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask); + GLuint i; + GLubyte mask[MAX_WIDTH]; + GLboolean write_all = GL_TRUE; + GLchan rgba[MAX_WIDTH][4]; + const GLubyte *Null = 0; + + /* init mask to 1's (all pixels are to be written) */ + MEMSET(mask, 1, n); + + if ((ctx->RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { + if (clip_span( ctx,n,x,y,mask)==0) { + return; + } + write_all = GL_FALSE; + } + + /* Do the scissor test */ + if (ctx->Scissor.Enabled) { + if (gl_scissor_span( ctx, n, x, y, mask )==0) { + return; + } + write_all = GL_FALSE; + } + + /* Polygon Stippling */ + if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { + stipple_polygon_span( ctx, n, x, y, mask ); + write_all = GL_FALSE; + } + + /* Do the alpha test */ + if (ctx->Color.AlphaEnabled) { + for (i=0;i<n;i++) { + rgba[i][ACOMP] = color[ACOMP]; + } + if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4])rgba, mask )==0) { + return; + } + write_all = GL_FALSE; + } + + if (ctx->Stencil.Enabled) { + /* first stencil test */ + if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) { + return; + } + write_all = GL_FALSE; + } + else if (ctx->Depth.Test) { + /* regular depth testing */ + GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask ); + if (m==0) { + return; + } + if (m<n) { + write_all = GL_FALSE; + } + } + + /* if we get here, something passed the depth test */ + ctx->OcclusionResult = GL_TRUE; + + if (ctx->Color.DrawBuffer == GL_NONE) { + /* write no pixels */ + return; + } + + if (ctx->Color.ColorLogicOpEnabled || colorMask != 0xffffffff || + (ctx->RasterMask & (BLEND_BIT | FOG_BIT))) { + /* assign same color to each pixel */ + for (i=0;i<n;i++) { + if (mask[i]) { + COPY_CHAN4(rgba[i], color); + } + } + + /* Per-pixel fog */ + if (ctx->Fog.Enabled) { + if (fog && ctx->Hint.Fog != GL_NICEST) + _mesa_fog_rgba_pixels( ctx, n, fog, rgba ); + else + _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba ); + } + + if (ctx->RasterMask & MULTI_DRAW_BIT) { + multi_write_rgba_span( ctx, n, x, y, + (const GLchan (*)[4]) rgba, mask ); + } + else { + /* normal: write to exactly one buffer */ + if (ctx->Color.ColorLogicOpEnabled) { + _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask ); + } + else if (ctx->Color.BlendEnabled) { + _mesa_blend_span( ctx, n, x, y, rgba, mask ); + } + + /* Color component masking */ + if (colorMask == 0x0) { + return; + } + else if (colorMask != 0xffffffff) { + _mesa_mask_rgba_span( ctx, n, x, y, rgba ); + } + + /* write pixels */ + (*ctx->Driver.WriteRGBASpan)( ctx, n, x, y, + (const GLchan (*)[4]) rgba, + write_all ? Null : mask ); + if (ctx->RasterMask & ALPHABUF_BIT) { + _mesa_write_alpha_span( ctx, n, x, y, + (const GLchan (*)[4]) rgba, + write_all ? Null : mask ); + } + } + } + else { + /* same color for all pixels */ + ASSERT(!ctx->Color.BlendEnabled); + ASSERT(!ctx->Color.ColorLogicOpEnabled); + + if (ctx->RasterMask & MULTI_DRAW_BIT) { + for (i=0;i<n;i++) { + if (mask[i]) { + COPY_CHAN4(rgba[i], color); + } + } + multi_write_rgba_span( ctx, n, x, y, + (const GLchan (*)[4]) rgba, mask ); + } + else { + (*ctx->Driver.WriteMonoRGBASpan)( ctx, n, x, y, mask ); + if (ctx->RasterMask & ALPHABUF_BIT) { + _mesa_write_mono_alpha_span( ctx, n, x, y, (GLchan) color[ACOMP], + write_all ? Null : mask ); + } + } + } +} + + + +/* + * 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], CONST GLchan specular[][4] ) +{ + GLuint i; + for (i=0; i<n; i++) { + 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); + } +} + + +/* + * Write a horizontal span of textured pixels to the frame buffer. + * The color of each pixel is different. + * Alpha-testing, stenciling, depth-testing, and blending are done + * as needed. + * Input: n - number of pixels in the span + * x, y - location of leftmost pixel in the span + * z - array of [n] z-values + * s, t - array of (s,t) texture coordinates for each pixel + * lambda - array of texture lambda values + * rgba - array of [n] color components + * primitive - either GL_POINT, GL_LINE, GL_POLYGON or GL_BITMAP. + */ +void gl_write_texture_span( GLcontext *ctx, + GLuint n, GLint x, GLint y, const GLdepth z[], + const GLfixed fog[], + const GLfloat s[], const GLfloat t[], + const GLfloat u[], GLfloat lambda[], + GLchan rgbaIn[][4], CONST GLchan spec[][4], + GLenum primitive ) +{ + const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask); + GLubyte mask[MAX_WIDTH]; + GLboolean write_all = GL_TRUE; + GLchan rgbaBackup[MAX_WIDTH][4]; + GLchan (*rgba)[4]; /* points to either rgbaIn or rgbaBackup */ + const GLubyte *Null = 0; + + /* init mask to 1's (all pixels are to be written) */ + MEMSET(mask, 1, n); + + if ((ctx->RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { + if (clip_span(ctx, n, x, y, mask)==0) { + return; + } + write_all = GL_FALSE; + } + + + if (primitive==GL_BITMAP || (ctx->RasterMask & MULTI_DRAW_BIT)) { + /* must make a copy of the colors since they may be modified */ + MEMCPY(rgbaBackup, rgbaIn, 4 * n * sizeof(GLchan)); + rgba = rgbaBackup; + } + else { + rgba = rgbaIn; + } + + /* Texture */ + ASSERT(ctx->Texture.ReallyEnabled); + gl_texture_pixels( ctx, 0, n, s, t, u, lambda, rgba, rgba ); + + /* Add base and specular colors */ + if (spec && ctx->Light.Enabled + && ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR) + add_colors( n, rgba, spec ); /* rgba = rgba + spec */ + + /* Per-pixel fog */ + if (ctx->Fog.Enabled) { + if (fog && ctx->Hint.Fog != GL_NICEST) + _mesa_fog_rgba_pixels( ctx, n, fog, rgba ); + else + _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba ); + } + + /* Do the scissor test */ + if (ctx->Scissor.Enabled) { + if (gl_scissor_span( ctx, n, x, y, mask )==0) { + return; + } + write_all = GL_FALSE; + } + + /* Polygon Stippling */ + if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { + stipple_polygon_span( ctx, n, x, y, mask ); + write_all = GL_FALSE; + } + + /* Do the alpha test */ + if (ctx->Color.AlphaEnabled) { + if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4]) rgba, mask )==0) { + return; + } + write_all = GL_FALSE; + } + + if (ctx->Stencil.Enabled) { + /* first stencil test */ + if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) { + return; + } + write_all = GL_FALSE; + } + else if (ctx->Depth.Test) { + /* regular depth testing */ + GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask ); + if (m==0) { + return; + } + if (m<n) { + write_all = GL_FALSE; + } + } + + /* if we get here, something passed the depth test */ + ctx->OcclusionResult = GL_TRUE; + + if (ctx->RasterMask & MULTI_DRAW_BIT) { + multi_write_rgba_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, mask ); + } + else { + /* normal: write to exactly one buffer */ + if (ctx->Color.ColorLogicOpEnabled) { + _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask ); + } + else if (ctx->Color.BlendEnabled) { + _mesa_blend_span( ctx, n, x, y, rgba, mask ); + } + if (colorMask == 0x0) { + return; + } + else if (colorMask != 0xffffffff) { + _mesa_mask_rgba_span( ctx, n, x, y, rgba ); + } + + (*ctx->Driver.WriteRGBASpan)( ctx, n, x, y, (const GLchan (*)[4])rgba, + write_all ? Null : mask ); + if (ctx->RasterMask & ALPHABUF_BIT) { + _mesa_write_alpha_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, + write_all ? Null : mask ); + } + } +} + + + +/* + * As above but perform multiple stages of texture application. + */ +void +gl_write_multitexture_span( GLcontext *ctx, + GLuint n, GLint x, GLint y, + const GLdepth z[], + const GLfixed fog[], + CONST GLfloat s[MAX_TEXTURE_UNITS][MAX_WIDTH], + CONST GLfloat t[MAX_TEXTURE_UNITS][MAX_WIDTH], + CONST GLfloat u[MAX_TEXTURE_UNITS][MAX_WIDTH], + GLfloat lambda[][MAX_WIDTH], + GLchan rgbaIn[MAX_TEXTURE_UNITS][4], + CONST GLchan spec[MAX_TEXTURE_UNITS][4], + GLenum primitive ) +{ + GLubyte mask[MAX_WIDTH]; + GLboolean write_all = GL_TRUE; + GLchan rgbaBackup[MAX_WIDTH][4]; + GLchan (*rgba)[4]; /* points to either rgbaIn or rgbaBackup */ + GLuint i; + const GLubyte *Null = 0; + const GLuint texUnits = ctx->Const.MaxTextureUnits; + + /* init mask to 1's (all pixels are to be written) */ + MEMSET(mask, 1, n); + + if ((ctx->RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { + if (clip_span(ctx, n, x, y, mask)==0) { + return; + } + write_all = GL_FALSE; + } + + + if (primitive==GL_BITMAP || (ctx->RasterMask & MULTI_DRAW_BIT) + || texUnits > 1) { + /* must make a copy of the colors since they may be modified */ + MEMCPY(rgbaBackup, rgbaIn, 4 * n * sizeof(GLchan)); + rgba = rgbaBackup; + } + else { + rgba = rgbaIn; + } + + /* Texture */ + ASSERT(ctx->Texture.ReallyEnabled); + for (i = 0; i < texUnits; i++) + gl_texture_pixels( ctx, i, n, s[i], t[i], u[i], lambda[i], rgbaIn, rgba ); + + /* Add base and specular colors */ + if (spec && ctx->Light.Enabled + && ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR) + add_colors( n, rgba, spec ); /* rgba = rgba + spec */ + + /* Per-pixel fog */ + if (ctx->Fog.Enabled) { + if (fog && ctx->Hint.Fog != GL_NICEST) + _mesa_fog_rgba_pixels( ctx, n, fog, rgba ); + else + _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba ); + } + + /* Do the scissor test */ + if (ctx->Scissor.Enabled) { + if (gl_scissor_span( ctx, n, x, y, mask )==0) { + return; + } + write_all = GL_FALSE; + } + + /* Polygon Stippling */ + if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { + stipple_polygon_span( ctx, n, x, y, mask ); + write_all = GL_FALSE; + } + + /* Do the alpha test */ + if (ctx->Color.AlphaEnabled) { + if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4])rgba, mask )==0) { + return; + } + write_all = GL_FALSE; + } + + if (ctx->Stencil.Enabled) { + /* first stencil test */ + if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) { + return; + } + write_all = GL_FALSE; + } + else if (ctx->Depth.Test) { + /* regular depth testing */ + GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask ); + if (m==0) { + return; + } + if (m<n) { + write_all = GL_FALSE; + } + } + + /* if we get here, something passed the depth test */ + ctx->OcclusionResult = GL_TRUE; + + if (ctx->RasterMask & MULTI_DRAW_BIT) { + multi_write_rgba_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, mask ); + } + else { + /* normal: write to exactly one buffer */ + const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask); + + if (ctx->Color.ColorLogicOpEnabled) { + _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask ); + } + else if (ctx->Color.BlendEnabled) { + _mesa_blend_span( ctx, n, x, y, rgba, mask ); + } + + if (colorMask == 0x0) { + return; + } + else if (colorMask != 0xffffffff) { + _mesa_mask_rgba_span( ctx, n, x, y, rgba ); + } + + (*ctx->Driver.WriteRGBASpan)( ctx, n, x, y, (const GLchan (*)[4])rgba, write_all ? Null : mask ); + if (ctx->RasterMask & ALPHABUF_BIT) { + _mesa_write_alpha_span( ctx, n, x, y, (const GLchan (*)[4])rgba, + write_all ? Null : mask ); + } + } +} + + + +/* + * Read RGBA pixels from frame buffer. Clipping will be done to prevent + * reading ouside the buffer's boundaries. + */ +void gl_read_rgba_span( GLcontext *ctx, GLframebuffer *buffer, + GLuint n, GLint x, GLint y, + GLchan rgba[][4] ) +{ + if (y < 0 || y >= buffer->Height + || x + (GLint) n < 0 || x >= buffer->Width) { + /* 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 > buffer->Width) { + length = buffer->Width; + } + } + else if ((GLint) (x + n) > buffer->Width) { + /* right edge clipping */ + skip = 0; + length = buffer->Width - x; + if (length < 0) { + /* completely to right of window */ + return; + } + } + else { + /* no clipping */ + skip = 0; + length = (GLint) n; + } + + (*ctx->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 gl_read_index_span( GLcontext *ctx, GLframebuffer *buffer, + GLuint n, GLint x, GLint y, GLuint indx[] ) +{ + if (y < 0 || y >= buffer->Height + || x + (GLint) n < 0 || x >= buffer->Width) { + /* 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 > buffer->Width) { + length = buffer->Width; + } + } + else if ((GLint) (x + n) > buffer->Width) { + /* right edge clipping */ + skip = 0; + length = buffer->Width - x; + if (length < 0) { + /* completely to right of window */ + return; + } + } + else { + /* no clipping */ + skip = 0; + length = (GLint) n; + } + + (*ctx->Driver.ReadCI32Span)( ctx, length, skip + x, y, indx + skip ); + } +} |