summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKeith Whitwell <keith@tungstengraphics.com>2000-10-31 18:00:04 +0000
committerKeith Whitwell <keith@tungstengraphics.com>2000-10-31 18:00:04 +0000
commite3a051e0538a605551f4d58294c94f5eb00ed07f (patch)
treeea5ccfd6d578fee1f8adb5a5c7f34f12d601c1c9 /src
parent6e0f0f51e0371688a434ed65c4ae0da1b061a4b5 (diff)
Moved software rasterizer functionality to new directory.
Diffstat (limited to 'src')
-rw-r--r--src/mesa/swrast/s_aatriangle.c413
-rw-r--r--src/mesa/swrast/s_aatriangle.h40
-rw-r--r--src/mesa/swrast/s_aatritemp.h517
-rw-r--r--src/mesa/swrast/s_accum.c499
-rw-r--r--src/mesa/swrast/s_accum.h45
-rw-r--r--src/mesa/swrast/s_alpha.c99
-rw-r--r--src/mesa/swrast/s_alpha.h42
-rw-r--r--src/mesa/swrast/s_alphabuf.c313
-rw-r--r--src/mesa/swrast/s_alphabuf.h82
-rw-r--r--src/mesa/swrast/s_bitmap.c131
-rw-r--r--src/mesa/swrast/s_blend.c667
-rw-r--r--src/mesa/swrast/s_blend.h49
-rw-r--r--src/mesa/swrast/s_buffers.c257
-rw-r--r--src/mesa/swrast/s_context.c49
-rw-r--r--src/mesa/swrast/s_copypix.c821
-rw-r--r--src/mesa/swrast/s_depth.c1632
-rw-r--r--src/mesa/swrast/s_depth.h69
-rw-r--r--src/mesa/swrast/s_drawpix.c885
-rw-r--r--src/mesa/swrast/s_drawpix.h42
-rw-r--r--src/mesa/swrast/s_fog.c188
-rw-r--r--src/mesa/swrast/s_fog.h63
-rw-r--r--src/mesa/swrast/s_imaging.c105
-rw-r--r--src/mesa/swrast/s_lines.c1173
-rw-r--r--src/mesa/swrast/s_linetemp.h682
-rw-r--r--src/mesa/swrast/s_logic.c360
-rw-r--r--src/mesa/swrast/s_logic.h59
-rw-r--r--src/mesa/swrast/s_masking.c180
-rw-r--r--src/mesa/swrast/s_masking.h76
-rw-r--r--src/mesa/swrast/s_pixeltex.c80
-rw-r--r--src/mesa/swrast/s_pixeltex.h39
-rw-r--r--src/mesa/swrast/s_points.c1193
-rw-r--r--src/mesa/swrast/s_readpix.c765
-rw-r--r--src/mesa/swrast/s_span.c1109
-rw-r--r--src/mesa/swrast/s_span.h99
-rw-r--r--src/mesa/swrast/s_stencil.c1303
-rw-r--r--src/mesa/swrast/s_stencil.h64
-rw-r--r--src/mesa/swrast/s_texture.c2539
-rw-r--r--src/mesa/swrast/s_texture.h46
-rw-r--r--src/mesa/swrast/s_triangle.c2448
-rw-r--r--src/mesa/swrast/s_triangle.h44
-rw-r--r--src/mesa/swrast/s_tritemp.h1191
-rw-r--r--src/mesa/swrast/s_zoom.c453
-rw-r--r--src/mesa/swrast/s_zoom.h62
-rw-r--r--src/mesa/swrast/swrast.h108
44 files changed, 21081 insertions, 0 deletions
diff --git a/src/mesa/swrast/s_aatriangle.c b/src/mesa/swrast/s_aatriangle.c
new file mode 100644
index 0000000000..347322cf65
--- /dev/null
+++ b/src/mesa/swrast/s_aatriangle.c
@@ -0,0 +1,413 @@
+/* $Id: s_aatriangle.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.
+ */
+
+
+/*
+ * Antialiased Triangle rasterizers
+ */
+
+
+#include "s_aatriangle.h"
+#include "s_span.h"
+
+
+/*
+ * Compute coefficients of a plane using the X,Y coords of the v0, v1, v2
+ * vertices and the given Z values.
+ */
+static INLINE void
+compute_plane(const GLfloat v0[], const GLfloat v1[], const GLfloat v2[],
+ GLfloat z0, GLfloat z1, GLfloat z2, GLfloat plane[4])
+{
+ const GLfloat px = v1[0] - v0[0];
+ const GLfloat py = v1[1] - v0[1];
+ const GLfloat pz = z1 - z0;
+
+ const GLfloat qx = v2[0] - v0[0];
+ const GLfloat qy = v2[1] - v0[1];
+ const GLfloat qz = z2 - z0;
+
+ const GLfloat a = py * qz - pz * qy;
+ const GLfloat b = pz * qx - px * qz;
+ const GLfloat c = px * qy - py * qx;
+ const GLfloat d = -(a * v0[0] + b * v0[1] + c * z0);
+
+ plane[0] = a;
+ plane[1] = b;
+ plane[2] = c;
+ plane[3] = d;
+}
+
+
+/*
+ * Compute coefficients of a plane with a constant Z value.
+ */
+static INLINE void
+constant_plane(GLfloat value, GLfloat plane[4])
+{
+ plane[0] = 0.0;
+ plane[1] = 0.0;
+ plane[2] = -1.0;
+ plane[3] = value;
+}
+
+#define CONSTANT_PLANE(VALUE, PLANE) \
+do { \
+ PLANE[0] = 0.0F; \
+ PLANE[1] = 0.0F; \
+ PLANE[2] = -1.0F; \
+ PLANE[3] = VALUE; \
+} while (0)
+
+
+
+/*
+ * Solve plane equation for Z at (X,Y).
+ */
+static INLINE GLfloat
+solve_plane(GLfloat x, GLfloat y, const GLfloat plane[4])
+{
+ GLfloat z = (plane[3] + plane[0] * x + plane[1] * y) / -plane[2];
+ return z;
+}
+
+
+#define SOLVE_PLANE(X, Y, PLANE) \
+ ((PLANE[3] + PLANE[0] * (X) + PLANE[1] * (Y)) / -PLANE[2])
+
+
+/*
+ * Return 1 / solve_plane().
+ */
+static INLINE GLfloat
+solve_plane_recip(GLfloat x, GLfloat y, const GLfloat plane[4])
+{
+ GLfloat z = -plane[2] / (plane[3] + plane[0] * x + plane[1] * y);
+ return z;
+}
+
+
+
+/*
+ * Solve plane and return clamped GLchan value.
+ */
+static INLINE GLchan
+solve_plane_chan(GLfloat x, GLfloat y, const GLfloat plane[4])
+{
+ GLfloat z = (plane[3] + plane[0] * x + plane[1] * y) / -plane[2] + 0.5F;
+ if (z < 0.0F)
+ return 0;
+ else if (z > CHAN_MAXF)
+ return CHAN_MAXF;
+ return (GLchan) (GLint) z;
+}
+
+
+
+/*
+ * Compute how much (area) of the given pixel is inside the triangle.
+ * Vertices MUST be specified in counter-clockwise order.
+ * Return: coverage in [0, 1].
+ */
+static GLfloat
+compute_coveragef(const GLfloat v0[3], const GLfloat v1[3],
+ const GLfloat v2[3], GLint winx, GLint winy)
+{
+ static const GLfloat samples[16][2] = {
+ /* start with the four corners */
+ { 0.00, 0.00 },
+ { 0.75, 0.00 },
+ { 0.00, 0.75 },
+ { 0.75, 0.75 },
+ /* continue with interior samples */
+ { 0.25, 0.00 },
+ { 0.50, 0.00 },
+ { 0.00, 0.25 },
+ { 0.25, 0.25 },
+ { 0.50, 0.25 },
+ { 0.75, 0.25 },
+ { 0.00, 0.50 },
+ { 0.25, 0.50 },
+ { 0.50, 0.50 },
+ { 0.75, 0.50 },
+ { 0.25, 0.75 },
+ { 0.50, 0.75 }
+ };
+ const GLfloat x = (GLfloat) winx;
+ const GLfloat y = (GLfloat) winy;
+ const GLfloat dx0 = v1[0] - v0[0];
+ const GLfloat dy0 = v1[1] - v0[1];
+ const GLfloat dx1 = v2[0] - v1[0];
+ const GLfloat dy1 = v2[1] - v1[1];
+ const GLfloat dx2 = v0[0] - v2[0];
+ const GLfloat dy2 = v0[1] - v2[1];
+ GLint stop = 4, i;
+ GLfloat insideCount = 16.0F;
+
+#ifdef DEBUG
+ {
+ const GLfloat area = dx0 * dy1 - dx1 * dy0;
+ assert(area >= 0.0);
+ }
+#endif
+
+ for (i = 0; i < stop; i++) {
+ const GLfloat sx = x + samples[i][0];
+ const GLfloat sy = y + samples[i][1];
+ const GLfloat fx0 = sx - v0[0];
+ const GLfloat fy0 = sy - v0[1];
+ const GLfloat fx1 = sx - v1[0];
+ const GLfloat fy1 = sy - v1[1];
+ const GLfloat fx2 = sx - v2[0];
+ const GLfloat fy2 = sy - v2[1];
+ /* cross product determines if sample is inside or outside each edge */
+ GLfloat cross0 = (dx0 * fy0 - dy0 * fx0);
+ GLfloat cross1 = (dx1 * fy1 - dy1 * fx1);
+ GLfloat cross2 = (dx2 * fy2 - dy2 * fx2);
+ /* Check if the sample is exactly on an edge. If so, let cross be a
+ * positive or negative value depending on the direction of the edge.
+ */
+ if (cross0 == 0.0F)
+ cross0 = dx0 + dy0;
+ if (cross1 == 0.0F)
+ cross1 = dx1 + dy1;
+ if (cross2 == 0.0F)
+ cross2 = dx2 + dy2;
+ if (cross0 < 0.0F || cross1 < 0.0F || cross2 < 0.0F) {
+ /* point is outside triangle */
+ insideCount -= 1.0F;
+ stop = 16;
+ }
+ }
+ if (stop == 4)
+ return 1.0F;
+ else
+ return insideCount * (1.0F / 16.0F);
+}
+
+
+
+/*
+ * Compute how much (area) of the given pixel is inside the triangle.
+ * Vertices MUST be specified in counter-clockwise order.
+ * Return: coverage in [0, 15].
+ */
+static GLint
+compute_coveragei(const GLfloat v0[3], const GLfloat v1[3],
+ const GLfloat v2[3], GLint winx, GLint winy)
+{
+ /* NOTE: 15 samples instead of 16.
+ * A better sample distribution could be used.
+ */
+ static const GLfloat samples[15][2] = {
+ /* start with the four corners */
+ { 0.00, 0.00 },
+ { 0.75, 0.00 },
+ { 0.00, 0.75 },
+ { 0.75, 0.75 },
+ /* continue with interior samples */
+ { 0.25, 0.00 },
+ { 0.50, 0.00 },
+ { 0.00, 0.25 },
+ { 0.25, 0.25 },
+ { 0.50, 0.25 },
+ { 0.75, 0.25 },
+ { 0.00, 0.50 },
+ { 0.25, 0.50 },
+ /*{ 0.50, 0.50 },*/
+ { 0.75, 0.50 },
+ { 0.25, 0.75 },
+ { 0.50, 0.75 }
+ };
+ const GLfloat x = (GLfloat) winx;
+ const GLfloat y = (GLfloat) winy;
+ const GLfloat dx0 = v1[0] - v0[0];
+ const GLfloat dy0 = v1[1] - v0[1];
+ const GLfloat dx1 = v2[0] - v1[0];
+ const GLfloat dy1 = v2[1] - v1[1];
+ const GLfloat dx2 = v0[0] - v2[0];
+ const GLfloat dy2 = v0[1] - v2[1];
+ GLint stop = 4, i;
+ GLint insideCount = 15;
+
+#ifdef DEBUG
+ {
+ const GLfloat area = dx0 * dy1 - dx1 * dy0;
+ assert(area >= 0.0);
+ }
+#endif
+
+ for (i = 0; i < stop; i++) {
+ const GLfloat sx = x + samples[i][0];
+ const GLfloat sy = y + samples[i][1];
+ const GLfloat fx0 = sx - v0[0];
+ const GLfloat fy0 = sy - v0[1];
+ const GLfloat fx1 = sx - v1[0];
+ const GLfloat fy1 = sy - v1[1];
+ const GLfloat fx2 = sx - v2[0];
+ const GLfloat fy2 = sy - v2[1];
+ /* cross product determines if sample is inside or outside each edge */
+ GLfloat cross0 = (dx0 * fy0 - dy0 * fx0);
+ GLfloat cross1 = (dx1 * fy1 - dy1 * fx1);
+ GLfloat cross2 = (dx2 * fy2 - dy2 * fx2);
+ /* Check if the sample is exactly on an edge. If so, let cross be a
+ * positive or negative value depending on the direction of the edge.
+ */
+ if (cross0 == 0.0F)
+ cross0 = dx0 + dy0;
+ if (cross1 == 0.0F)
+ cross1 = dx1 + dy1;
+ if (cross2 == 0.0F)
+ cross2 = dx2 + dy2;
+ if (cross0 < 0.0F || cross1 < 0.0F || cross2 < 0.0F) {
+ /* point is outside triangle */
+ insideCount--;
+ stop = 15;
+ }
+ }
+ if (stop == 4)
+ return 15;
+ else
+ return insideCount;
+}
+
+
+
+static void
+rgba_aa_tri(GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv)
+{
+#define DO_Z
+#define DO_RGBA
+#include "s_aatritemp.h"
+}
+
+
+static void
+index_aa_tri(GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv)
+{
+#define DO_Z
+#define DO_INDEX
+#include "s_aatritemp.h"
+}
+
+
+/*
+ * Compute mipmap level of detail.
+ */
+static INLINE GLfloat
+compute_lambda(const GLfloat sPlane[4], const GLfloat tPlane[4],
+ GLfloat invQ, GLfloat width, GLfloat height)
+{
+ GLfloat dudx = sPlane[0] / sPlane[2] * invQ * width;
+ GLfloat dudy = sPlane[1] / sPlane[2] * invQ * width;
+ GLfloat dvdx = tPlane[0] / tPlane[2] * invQ * height;
+ GLfloat dvdy = tPlane[1] / tPlane[2] * invQ * height;
+ GLfloat r1 = dudx * dudx + dudy * dudy;
+ GLfloat r2 = dvdx * dvdx + dvdy * dvdy;
+ GLfloat rho2 = r1 + r2;
+ /* return log base 2 of rho */
+ return log(rho2) * 1.442695 * 0.5; /* 1.442695 = 1/log(2) */
+}
+
+
+static void
+tex_aa_tri(GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv)
+{
+#define DO_Z
+#define DO_RGBA
+#define DO_TEX
+#include "s_aatritemp.h"
+}
+
+
+static void
+spec_tex_aa_tri(GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv)
+{
+#define DO_Z
+#define DO_RGBA
+#define DO_TEX
+#define DO_SPEC
+#include "s_aatritemp.h"
+}
+
+
+static void
+multitex_aa_tri(GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv)
+{
+#define DO_Z
+#define DO_RGBA
+#define DO_MULTITEX
+#include "s_aatritemp.h"
+}
+
+static void
+spec_multitex_aa_tri(GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv)
+{
+#define DO_Z
+#define DO_RGBA
+#define DO_MULTITEX
+#define DO_SPEC
+#include "s_aatritemp.h"
+}
+
+
+/*
+ * Examine GL state and set ctx->Driver.TriangleFunc to an
+ * appropriate antialiased triangle rasterizer function.
+ */
+void
+_mesa_set_aa_triangle_function(GLcontext *ctx)
+{
+ ASSERT(ctx->Polygon.SmoothFlag);
+ if (ctx->Texture.ReallyEnabled) {
+ if (ctx->Light.Enabled &&
+ ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR) {
+ if (ctx->Texture.MultiTextureEnabled) {
+ ctx->Driver.TriangleFunc = spec_multitex_aa_tri;
+ }
+ else {
+ ctx->Driver.TriangleFunc = spec_tex_aa_tri;
+ }
+ }
+ else {
+ if (ctx->Texture.MultiTextureEnabled) {
+ ctx->Driver.TriangleFunc = multitex_aa_tri;
+ }
+ else {
+ ctx->Driver.TriangleFunc = tex_aa_tri;
+ }
+ }
+ }
+ else {
+ if (ctx->Visual.RGBAflag) {
+ ctx->Driver.TriangleFunc = rgba_aa_tri;
+ }
+ else {
+ ctx->Driver.TriangleFunc = index_aa_tri;
+ }
+ }
+ ASSERT(ctx->Driver.TriangleFunc);
+}
diff --git a/src/mesa/swrast/s_aatriangle.h b/src/mesa/swrast/s_aatriangle.h
new file mode 100644
index 0000000000..d28a10d8eb
--- /dev/null
+++ b/src/mesa/swrast/s_aatriangle.h
@@ -0,0 +1,40 @@
+/* $Id: s_aatriangle.h,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ *
+ * 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.
+ */
+
+
+#ifndef S_AATRIANGLE_H
+#define S_AATRIANGLE_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+extern void
+_mesa_set_aa_triangle_function(GLcontext *ctx);
+
+
+#endif
diff --git a/src/mesa/swrast/s_aatritemp.h b/src/mesa/swrast/s_aatritemp.h
new file mode 100644
index 0000000000..30cc1647c7
--- /dev/null
+++ b/src/mesa/swrast/s_aatritemp.h
@@ -0,0 +1,517 @@
+/* $Id: s_aatritemp.h,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.
+ */
+
+
+/*
+ * Antialiased Triangle Rasterizer Template
+ *
+ * This file is #include'd to generate custom AA triangle rasterizers.
+ * NOTE: this code hasn't been optimized yet. That'll come after it
+ * works correctly.
+ *
+ * The following macros may be defined to indicate what auxillary information
+ * must be copmuted across the triangle:
+ * DO_Z - if defined, compute Z values
+ * DO_RGBA - if defined, compute RGBA values
+ * DO_INDEX - if defined, compute color index values
+ * DO_SPEC - if defined, compute specular RGB values
+ * DO_TEX - if defined, compute unit 0 STRQ texcoords
+ * DO_MULTITEX - if defined, compute all unit's STRQ texcoords
+ */
+
+/*void triangle( GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv )*/
+{
+ const struct vertex_buffer *VB = ctx->VB;
+ const GLfloat *p0 = VB->Win.data[v0];
+ const GLfloat *p1 = VB->Win.data[v1];
+ const GLfloat *p2 = VB->Win.data[v2];
+ GLint vMin, vMid, vMax;
+ GLint iyMin, iyMax;
+ GLfloat yMin, yMax;
+ GLboolean ltor;
+ GLfloat majDx, majDy;
+#ifdef DO_Z
+ GLfloat zPlane[4]; /* Z (depth) */
+ GLdepth z[MAX_WIDTH];
+ GLfloat fogPlane[4];
+ GLfixed fog[MAX_WIDTH];
+#endif
+#ifdef DO_RGBA
+ GLfloat rPlane[4], gPlane[4], bPlane[4], aPlane[4]; /* color */
+ GLchan rgba[MAX_WIDTH][4];
+#endif
+#ifdef DO_INDEX
+ GLfloat iPlane[4]; /* color index */
+ GLuint index[MAX_WIDTH];
+#endif
+#ifdef DO_SPEC
+ GLfloat srPlane[4], sgPlane[4], sbPlane[4]; /* spec color */
+ GLchan spec[MAX_WIDTH][4];
+#endif
+#ifdef DO_TEX
+ GLfloat sPlane[4], tPlane[4], uPlane[4], vPlane[4];
+ GLfloat texWidth, texHeight;
+ GLfloat s[MAX_WIDTH], t[MAX_WIDTH], u[MAX_WIDTH];
+ GLfloat lambda[MAX_WIDTH];
+#elif defined(DO_MULTITEX)
+ GLfloat sPlane[MAX_TEXTURE_UNITS][4];
+ GLfloat tPlane[MAX_TEXTURE_UNITS][4];
+ GLfloat uPlane[MAX_TEXTURE_UNITS][4];
+ GLfloat vPlane[MAX_TEXTURE_UNITS][4];
+ GLfloat texWidth[MAX_TEXTURE_UNITS], texHeight[MAX_TEXTURE_UNITS];
+ GLfloat s[MAX_TEXTURE_UNITS][MAX_WIDTH];
+ GLfloat t[MAX_TEXTURE_UNITS][MAX_WIDTH];
+ GLfloat u[MAX_TEXTURE_UNITS][MAX_WIDTH];
+ GLfloat lambda[MAX_TEXTURE_UNITS][MAX_WIDTH];
+#endif
+ GLfloat bf = ctx->backface_sign;
+
+ /* determine bottom to top order of vertices */
+ {
+ GLfloat y0 = VB->Win.data[v0][1];
+ GLfloat y1 = VB->Win.data[v1][1];
+ GLfloat y2 = VB->Win.data[v2][1];
+ if (y0 <= y1) {
+ if (y1 <= y2) {
+ vMin = v0; vMid = v1; vMax = v2; /* y0<=y1<=y2 */
+ }
+ else if (y2 <= y0) {
+ vMin = v2; vMid = v0; vMax = v1; /* y2<=y0<=y1 */
+ }
+ else {
+ vMin = v0; vMid = v2; vMax = v1; bf = -bf; /* y0<=y2<=y1 */
+ }
+ }
+ else {
+ if (y0 <= y2) {
+ vMin = v1; vMid = v0; vMax = v2; bf = -bf; /* y1<=y0<=y2 */
+ }
+ else if (y2 <= y1) {
+ vMin = v2; vMid = v1; vMax = v0; bf = -bf; /* y2<=y1<=y0 */
+ }
+ else {
+ vMin = v1; vMid = v2; vMax = v0; /* y1<=y2<=y0 */
+ }
+ }
+ }
+
+ majDx = VB->Win.data[vMax][0] - VB->Win.data[vMin][0];
+ majDy = VB->Win.data[vMax][1] - VB->Win.data[vMin][1];
+
+ {
+ const GLfloat botDx = VB->Win.data[vMid][0] - VB->Win.data[vMin][0];
+ const GLfloat botDy = VB->Win.data[vMid][1] - VB->Win.data[vMin][1];
+ const GLfloat area = majDx * botDy - botDx * majDy;
+ ltor = (GLboolean) (area < 0.0F);
+ /* Do backface culling */
+ if (area * bf < 0 || area * area < .0025)
+ return;
+ }
+
+#ifndef DO_OCCLUSION_TEST
+ ctx->OcclusionResult = GL_TRUE;
+#endif
+
+ /* plane setup */
+#ifdef DO_Z
+ compute_plane(p0, p1, p2, p0[2], p1[2], p2[2], zPlane);
+ compute_plane(p0, p1, p2,
+ VB->FogCoordPtr->data[v0],
+ VB->FogCoordPtr->data[v1],
+ VB->FogCoordPtr->data[v2],
+ fogPlane);
+#endif
+#ifdef DO_RGBA
+ if (ctx->Light.ShadeModel == GL_SMOOTH) {
+ GLchan (*rgba)[4] = VB->ColorPtr->data;
+ compute_plane(p0, p1, p2, rgba[v0][0], rgba[v1][0], rgba[v2][0], rPlane);
+ compute_plane(p0, p1, p2, rgba[v0][1], rgba[v1][1], rgba[v2][1], gPlane);
+ compute_plane(p0, p1, p2, rgba[v0][2], rgba[v1][2], rgba[v2][2], bPlane);
+ compute_plane(p0, p1, p2, rgba[v0][3], rgba[v1][3], rgba[v2][3], aPlane);
+ }
+ else {
+ constant_plane(VB->ColorPtr->data[pv][RCOMP], rPlane);
+ constant_plane(VB->ColorPtr->data[pv][GCOMP], gPlane);
+ constant_plane(VB->ColorPtr->data[pv][BCOMP], bPlane);
+ constant_plane(VB->ColorPtr->data[pv][ACOMP], aPlane);
+ }
+#endif
+#ifdef DO_INDEX
+ if (ctx->Light.ShadeModel == GL_SMOOTH) {
+ compute_plane(p0, p1, p2, VB->IndexPtr->data[v0],
+ VB->IndexPtr->data[v1], VB->IndexPtr->data[v2], iPlane);
+ }
+ else {
+ constant_plane(VB->IndexPtr->data[pv], iPlane);
+ }
+#endif
+#ifdef DO_SPEC
+ {
+ GLchan (*spec)[4] = VB->SecondaryColorPtr->data;
+ compute_plane(p0, p1, p2, spec[v0][0], spec[v1][0], spec[v2][0],srPlane);
+ compute_plane(p0, p1, p2, spec[v0][1], spec[v1][1], spec[v2][1],sgPlane);
+ compute_plane(p0, p1, p2, spec[v0][2], spec[v1][2], spec[v2][2],sbPlane);
+ }
+#endif
+#ifdef DO_TEX
+ {
+ const struct gl_texture_object *obj = ctx->Texture.Unit[0].Current;
+ const struct gl_texture_image *texImage = obj->Image[obj->BaseLevel];
+ const GLint tSize = 3;
+ const GLfloat invW0 = VB->Win.data[v0][3];
+ const GLfloat invW1 = VB->Win.data[v1][3];
+ const GLfloat invW2 = VB->Win.data[v2][3];
+ GLfloat (*texCoord)[4] = VB->TexCoordPtr[0]->data;
+ const GLfloat s0 = texCoord[v0][0] * invW0;
+ const GLfloat s1 = texCoord[v1][0] * invW1;
+ const GLfloat s2 = texCoord[v2][0] * invW2;
+ const GLfloat t0 = (tSize > 1) ? texCoord[v0][1] * invW0 : 0.0F;
+ const GLfloat t1 = (tSize > 1) ? texCoord[v1][1] * invW1 : 0.0F;
+ const GLfloat t2 = (tSize > 1) ? texCoord[v2][1] * invW2 : 0.0F;
+ const GLfloat r0 = (tSize > 2) ? texCoord[v0][2] * invW0 : 0.0F;
+ const GLfloat r1 = (tSize > 2) ? texCoord[v1][2] * invW1 : 0.0F;
+ const GLfloat r2 = (tSize > 2) ? texCoord[v2][2] * invW2 : 0.0F;
+ const GLfloat q0 = (tSize > 3) ? texCoord[v0][3] * invW0 : invW0;
+ const GLfloat q1 = (tSize > 3) ? texCoord[v1][3] * invW1 : invW1;
+ const GLfloat q2 = (tSize > 3) ? texCoord[v2][3] * invW2 : invW2;
+ compute_plane(p0, p1, p2, s0, s1, s2, sPlane);
+ compute_plane(p0, p1, p2, t0, t1, t2, tPlane);
+ compute_plane(p0, p1, p2, r0, r1, r2, uPlane);
+ compute_plane(p0, p1, p2, q0, q1, q2, vPlane);
+ texWidth = (GLfloat) texImage->Width;
+ texHeight = (GLfloat) texImage->Height;
+ }
+#elif defined(DO_MULTITEX)
+ {
+ GLuint u;
+ 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 *texImage = obj->Image[obj->BaseLevel];
+ const GLint tSize = VB->TexCoordPtr[u]->size;
+ const GLfloat invW0 = VB->Win.data[v0][3];
+ const GLfloat invW1 = VB->Win.data[v1][3];
+ const GLfloat invW2 = VB->Win.data[v2][3];
+ GLfloat (*texCoord)[4] = VB->TexCoordPtr[u]->data;
+ const GLfloat s0 = texCoord[v0][0] * invW0;
+ const GLfloat s1 = texCoord[v1][0] * invW1;
+ const GLfloat s2 = texCoord[v2][0] * invW2;
+ const GLfloat t0 = (tSize > 1) ? texCoord[v0][1] * invW0 : 0.0F;
+ const GLfloat t1 = (tSize > 1) ? texCoord[v1][1] * invW1 : 0.0F;
+ const GLfloat t2 = (tSize > 1) ? texCoord[v2][1] * invW2 : 0.0F;
+ const GLfloat r0 = (tSize > 2) ? texCoord[v0][2] * invW0 : 0.0F;
+ const GLfloat r1 = (tSize > 2) ? texCoord[v1][2] * invW1 : 0.0F;
+ const GLfloat r2 = (tSize > 2) ? texCoord[v2][2] * invW2 : 0.0F;
+ const GLfloat q0 = (tSize > 3) ? texCoord[v0][3] * invW0 : invW0;
+ const GLfloat q1 = (tSize > 3) ? texCoord[v1][3] * invW1 : invW1;
+ const GLfloat q2 = (tSize > 3) ? texCoord[v2][3] * invW2 : invW2;
+ compute_plane(p0, p1, p2, s0, s1, s2, sPlane[u]);
+ compute_plane(p0, p1, p2, t0, t1, t2, tPlane[u]);
+ compute_plane(p0, p1, p2, r0, r1, r2, uPlane[u]);
+ compute_plane(p0, p1, p2, q0, q1, q2, vPlane[u]);
+ texWidth[u] = (GLfloat) texImage->Width;
+ texHeight[u] = (GLfloat) texImage->Height;
+ }
+ }
+ }
+#endif
+
+ yMin = VB->Win.data[vMin][1];
+ yMax = VB->Win.data[vMax][1];
+ iyMin = (int) yMin;
+ iyMax = (int) yMax + 1;
+
+ if (ltor) {
+ /* scan left to right */
+ const float *pMin = VB->Win.data[vMin];
+ const float *pMid = VB->Win.data[vMid];
+ const float *pMax = VB->Win.data[vMax];
+ const float dxdy = majDx / majDy;
+ const float xAdj = dxdy < 0.0F ? -dxdy : 0.0F;
+ float x = VB->Win.data[vMin][0] - (yMin - iyMin) * dxdy;
+ int iy;
+ for (iy = iyMin; iy < iyMax; iy++, x += dxdy) {
+ GLint ix, startX = (GLint) (x - xAdj);
+ GLuint count, n;
+ GLfloat coverage = 0.0F;
+ /* skip over fragments with zero coverage */
+ while (startX < MAX_WIDTH) {
+ coverage = compute_coveragef(pMin, pMid, pMax, startX, iy);
+ if (coverage > 0.0F)
+ break;
+ startX++;
+ }
+
+ /* enter interior of triangle */
+ ix = startX;
+ count = 0;
+ while (coverage > 0.0F) {
+#ifdef DO_Z
+ z[count] = (GLdepth) solve_plane(ix, iy, zPlane);
+ fog[count] = FloatToFixed(solve_plane(ix, iy, fogPlane));
+#endif
+#ifdef DO_RGBA
+ rgba[count][RCOMP] = solve_plane_chan(ix, iy, rPlane);
+ rgba[count][GCOMP] = solve_plane_chan(ix, iy, gPlane);
+ rgba[count][BCOMP] = solve_plane_chan(ix, iy, bPlane);
+ rgba[count][ACOMP] = (GLchan) (solve_plane_chan(ix, iy, aPlane) * coverage);
+#endif
+#ifdef DO_INDEX
+ {
+ GLint frac = compute_coveragei(pMin, pMid, pMax, ix, iy);
+ GLint indx = (GLint) solve_plane(ix, iy, iPlane);
+ index[count] = (indx & ~0xf) | frac;
+ }
+#endif
+#ifdef DO_SPEC
+ spec[count][RCOMP] = solve_plane_chan(ix, iy, srPlane);
+ spec[count][GCOMP] = solve_plane_chan(ix, iy, sgPlane);
+ spec[count][BCOMP] = solve_plane_chan(ix, iy, sbPlane);
+#endif
+#ifdef DO_TEX
+ {
+ GLfloat invQ = solve_plane_recip(ix, iy, vPlane);
+ s[count] = solve_plane(ix, iy, sPlane) * invQ;
+ t[count] = solve_plane(ix, iy, tPlane) * invQ;
+ u[count] = solve_plane(ix, iy, uPlane) * invQ;
+ lambda[count] = compute_lambda(sPlane, tPlane, invQ,
+ texWidth, texHeight);
+ }
+#elif defined(DO_MULTITEX)
+ {
+ GLuint unit;
+ for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
+ if (ctx->Texture.Unit[unit].ReallyEnabled) {
+ GLfloat invQ = solve_plane_recip(ix, iy, vPlane[unit]);
+ s[unit][count] = solve_plane(ix, iy, sPlane[unit]) * invQ;
+ t[unit][count] = solve_plane(ix, iy, tPlane[unit]) * invQ;
+ u[unit][count] = solve_plane(ix, iy, uPlane[unit]) * invQ;
+ lambda[unit][count] = compute_lambda(sPlane[unit],
+ tPlane[unit], invQ, texWidth[unit], texHeight[unit]);
+ }
+ }
+ }
+#endif
+ ix++;
+ count++;
+ coverage = compute_coveragef(pMin, pMid, pMax, ix, iy);
+ }
+
+ n = (GLuint) ix - (GLuint) startX;
+#ifdef DO_MULTITEX
+# ifdef DO_SPEC
+ gl_write_multitexture_span(ctx, n, startX, iy, z, fog,
+ (const GLfloat (*)[MAX_WIDTH]) s,
+ (const GLfloat (*)[MAX_WIDTH]) t,
+ (const GLfloat (*)[MAX_WIDTH]) u,
+ (GLfloat (*)[MAX_WIDTH]) lambda,
+ rgba, (const GLchan (*)[4]) spec,
+ GL_POLYGON);
+# else
+ gl_write_multitexture_span(ctx, n, startX, iy, z, fog,
+ (const GLfloat (*)[MAX_WIDTH]) s,
+ (const GLfloat (*)[MAX_WIDTH]) t,
+ (const GLfloat (*)[MAX_WIDTH]) u,
+ lambda, rgba, NULL, GL_POLYGON);
+# endif
+#elif defined(DO_TEX)
+# ifdef DO_SPEC
+ gl_write_texture_span(ctx, n, startX, iy, z, fog,
+ s, t, u, lambda, rgba,
+ (const GLchan (*)[4]) spec, GL_POLYGON);
+# else
+ gl_write_texture_span(ctx, n, startX, iy, z, fog,
+ s, t, u, lambda,
+ rgba, NULL, GL_POLYGON);
+# endif
+#elif defined(DO_RGBA)
+ gl_write_rgba_span(ctx, n, startX, iy, z, fog, rgba, GL_POLYGON);
+#elif defined(DO_INDEX)
+ gl_write_index_span(ctx, n, startX, iy, z, fog, index, GL_POLYGON);
+#endif
+ }
+ }
+ else {
+ /* scan right to left */
+ const GLfloat *pMin = VB->Win.data[vMin];
+ const GLfloat *pMid = VB->Win.data[vMid];
+ const GLfloat *pMax = VB->Win.data[vMax];
+ const GLfloat dxdy = majDx / majDy;
+ const GLfloat xAdj = dxdy > 0 ? dxdy : 0.0F;
+ GLfloat x = VB->Win.data[vMin][0] - (yMin - iyMin) * dxdy;
+ GLint iy;
+ for (iy = iyMin; iy < iyMax; iy++, x += dxdy) {
+ GLint ix, left, startX = (GLint) (x + xAdj);
+ GLuint count, n;
+ GLfloat coverage = 0.0F;
+ /* skip fragments with zero coverage */
+ while (startX >= 0) {
+ coverage = compute_coveragef(pMin, pMax, pMid, startX, iy);
+ if (coverage > 0.0F)
+ break;
+ startX--;
+ }
+
+ /* enter interior of triangle */
+ ix = startX;
+ count = 0;
+ while (coverage > 0.0F) {
+#ifdef DO_Z
+ z[ix] = (GLdepth) solve_plane(ix, iy, zPlane);
+ fog[ix] = FloatToFixed(solve_plane(ix, iy, fogPlane));
+#endif
+#ifdef DO_RGBA
+ rgba[ix][RCOMP] = solve_plane_chan(ix, iy, rPlane);
+ rgba[ix][GCOMP] = solve_plane_chan(ix, iy, gPlane);
+ rgba[ix][BCOMP] = solve_plane_chan(ix, iy, bPlane);
+ rgba[ix][ACOMP] = (GLchan) (solve_plane_chan(ix, iy, aPlane) * coverage);
+#endif
+#ifdef DO_INDEX
+ {
+ GLint frac = compute_coveragei(pMin, pMax, pMid, ix, iy);
+ GLint indx = (GLint) solve_plane(ix, iy, iPlane);
+ index[ix] = (indx & ~0xf) | frac;
+ }
+#endif
+#ifdef DO_SPEC
+ spec[ix][RCOMP] = solve_plane_chan(ix, iy, srPlane);
+ spec[ix][GCOMP] = solve_plane_chan(ix, iy, sgPlane);
+ spec[ix][BCOMP] = solve_plane_chan(ix, iy, sbPlane);
+#endif
+#ifdef DO_TEX
+ {
+ GLfloat invQ = solve_plane_recip(ix, iy, vPlane);
+ s[ix] = solve_plane(ix, iy, sPlane) * invQ;
+ t[ix] = solve_plane(ix, iy, tPlane) * invQ;
+ u[ix] = solve_plane(ix, iy, uPlane) * invQ;
+ lambda[ix] = compute_lambda(sPlane, tPlane, invQ,
+ texWidth, texHeight);
+ }
+#elif defined(DO_MULTITEX)
+ {
+ GLuint unit;
+ for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
+ if (ctx->Texture.Unit[unit].ReallyEnabled) {
+ GLfloat invQ = solve_plane_recip(ix, iy, vPlane[unit]);
+ s[unit][ix] = solve_plane(ix, iy, sPlane[unit]) * invQ;
+ t[unit][ix] = solve_plane(ix, iy, tPlane[unit]) * invQ;
+ u[unit][ix] = solve_plane(ix, iy, uPlane[unit]) * invQ;
+ lambda[unit][ix] = compute_lambda(sPlane[unit],
+ tPlane[unit], invQ, texWidth[unit], texHeight[unit]);
+ }
+ }
+ }
+#endif
+ ix--;
+ count++;
+ coverage = compute_coveragef(pMin, pMax, pMid, ix, iy);
+ }
+
+ n = (GLuint) startX - (GLuint) ix;
+ left = ix + 1;
+#ifdef DO_MULTITEX
+ {
+ GLuint unit;
+ for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
+ if (ctx->Texture.Unit[unit].ReallyEnabled) {
+ GLint j;
+ for (j = 0; j < n; j++) {
+ s[unit][j] = s[unit][j + left];
+ t[unit][j] = t[unit][j + left];
+ u[unit][j] = u[unit][j + left];
+ lambda[unit][j] = lambda[unit][j + left];
+ }
+ }
+ }
+ }
+# ifdef DO_SPEC
+ gl_write_multitexture_span(ctx, n, left, iy, z + left, fog + left,
+ (const GLfloat (*)[MAX_WIDTH]) s,
+ (const GLfloat (*)[MAX_WIDTH]) t,
+ (const GLfloat (*)[MAX_WIDTH]) u,
+ lambda, rgba + left,
+ (const GLchan (*)[4]) (spec + left),
+ GL_POLYGON);
+# else
+ gl_write_multitexture_span(ctx, n, left, iy, z + left, fog + left,
+ (const GLfloat (*)[MAX_WIDTH]) s,
+ (const GLfloat (*)[MAX_WIDTH]) t,
+ (const GLfloat (*)[MAX_WIDTH]) u,
+ lambda,
+ rgba + left, NULL, GL_POLYGON);
+# endif
+#elif defined(DO_TEX)
+# ifdef DO_SPEC
+ gl_write_texture_span(ctx, n, left, iy, z + left, fog + left,
+ s + left, t + left, u + left,
+ lambda + left, rgba + left,
+ (const GLchan (*)[4]) (spec + left),
+ GL_POLYGON);
+# else
+ gl_write_texture_span(ctx, n, left, iy, z + left, fog + left,
+ s + left, t + left,
+ u + left, lambda + left,
+ rgba + left, NULL, GL_POLYGON);
+# endif
+#elif defined(DO_RGBA)
+ gl_write_rgba_span(ctx, n, left, iy, z + left, fog + left,
+ rgba + left, GL_POLYGON);
+#elif defined(DO_INDEX)
+ gl_write_index_span(ctx, n, left, iy, z + left, fog + left,
+ index + left, GL_POLYGON);
+#endif
+ }
+ }
+}
+
+
+#ifdef DO_Z
+#undef DO_Z
+#endif
+
+#ifdef DO_RGBA
+#undef DO_RGBA
+#endif
+
+#ifdef DO_INDEX
+#undef DO_INDEX
+#endif
+
+#ifdef DO_SPEC
+#undef DO_SPEC
+#endif
+
+#ifdef DO_TEX
+#undef DO_TEX
+#endif
+
+#ifdef DO_MULTITEX
+#undef DO_MULTITEX
+#endif
+
+#ifdef DO_OCCLUSION_TEST
+#undef DO_OCCLUSION_TEST
+#endif
diff --git a/src/mesa/swrast/s_accum.c b/src/mesa/swrast/s_accum.c
new file mode 100644
index 0000000000..21ac29153c
--- /dev/null
+++ b/src/mesa/swrast/s_accum.c
@@ -0,0 +1,499 @@
+/* $Id: s_accum.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.
+ */
+
+
+#include "context.h"
+#include "macros.h"
+#include "mem.h"
+
+#include "s_accum.h"
+#include "s_masking.h"
+#include "s_span.h"
+
+
+/*
+ * Accumulation buffer notes
+ *
+ * Normally, accumulation buffer values are GLshorts with values in
+ * [-32767, 32767] which represent floating point colors in [-1, 1],
+ * as suggested by the OpenGL specification.
+ *
+ * We optimize for the common case used for full-scene antialiasing:
+ * // start with accum buffer cleared to zero
+ * glAccum(GL_LOAD, w); // or GL_ACCUM the first image
+ * glAccum(GL_ACCUM, w);
+ * ...
+ * glAccum(GL_ACCUM, w);
+ * glAccum(GL_RETURN, 1.0);
+ * That is, we start with an empty accumulation buffer and accumulate
+ * n images, each with weight w = 1/n.
+ * In this scenario, we can simply store unscaled integer values in
+ * the accum buffer instead of scaled integers. We'll also keep track
+ * of the w value so when we do GL_RETURN we simply divide the accumulated
+ * values by n (=1/w).
+ * This lets us avoid _many_ int->float->int conversions.
+ */
+
+
+#if CHAN_BITS == 8
+#define USE_OPTIMIZED_ACCUM /* enable the optimization */
+#endif
+
+
+
+void
+_mesa_alloc_accum_buffer( GLcontext *ctx )
+{
+ GLint n;
+
+ if (ctx->DrawBuffer->Accum) {
+ FREE( ctx->DrawBuffer->Accum );
+ ctx->DrawBuffer->Accum = NULL;
+ }
+
+ /* allocate accumulation buffer if not already present */
+ n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height * 4 * sizeof(GLaccum);
+ ctx->DrawBuffer->Accum = (GLaccum *) MALLOC( n );
+ if (!ctx->DrawBuffer->Accum) {
+ /* unable to setup accumulation buffer */
+ gl_error( ctx, GL_OUT_OF_MEMORY, "glAccum" );
+ }
+#ifdef USE_OPTIMIZED_ACCUM
+ ctx->IntegerAccumMode = GL_TRUE;
+#else
+ ctx->IntegerAccumMode = GL_FALSE;
+#endif
+ ctx->IntegerAccumScaler = 0.0;
+}
+
+
+
+
+
+
+/*
+ * This is called when we fall out of optimized/unscaled accum buffer mode.
+ * That is, we convert each unscaled accum buffer value into a scaled value
+ * representing the range[-1, 1].
+ */
+static void rescale_accum( GLcontext *ctx )
+{
+ const GLuint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height * 4;
+ const GLfloat fChanMax = (1 << (sizeof(GLchan) * 8)) - 1;
+ const GLfloat s = ctx->IntegerAccumScaler * (32767.0 / fChanMax);
+ GLaccum *accum = ctx->DrawBuffer->Accum;
+ GLuint i;
+
+ assert(ctx->IntegerAccumMode);
+ assert(accum);
+
+ for (i = 0; i < n; i++) {
+ accum[i] = (GLaccum) (accum[i] * s);
+ }
+
+ ctx->IntegerAccumMode = GL_FALSE;
+}
+
+
+
+void
+_swrast_Accum( GLcontext *ctx, GLenum op, GLfloat value,
+ GLint xpos, GLint ypos,
+ GLint width, GLint height )
+
+{
+ GLuint width4;
+ GLfloat acc_scale;
+ GLchan rgba[MAX_WIDTH][4];
+ const GLuint colorMask = *((GLuint *) &ctx->Color.ColorMask);
+ const GLint iChanMax = (1 << (sizeof(GLchan) * 8)) - 1;
+ const GLfloat fChanMax = (1 << (sizeof(GLchan) * 8)) - 1;
+
+
+ if (!ctx->DrawBuffer->Accum) {
+ _mesa_warning(ctx, "Calling glAccum() without an accumulation buffer (low memory?)");
+ return;
+ }
+
+ if (sizeof(GLaccum)==1) {
+ acc_scale = 127.0;
+ }
+ else if (sizeof(GLaccum)==2) {
+ acc_scale = 32767.0;
+ }
+ else {
+ /* sizeof(GLaccum) > 2 (Cray) */
+ acc_scale = (float) SHRT_MAX;
+ }
+
+ width4 = 4 * width;
+
+ switch (op) {
+ case GL_ADD:
+ if (value != 0.0F) {
+ const GLaccum intVal = (GLaccum) (value * acc_scale);
+ GLuint j;
+ /* Leave optimized accum buffer mode */
+ if (ctx->IntegerAccumMode)
+ rescale_accum(ctx);
+ for (j = 0; j < height; j++) {
+ GLaccum * acc = ctx->DrawBuffer->Accum + ypos * width4 + 4 * xpos;
+ GLuint i;
+ for (i = 0; i < width4; i++) {
+ acc[i] += intVal;
+ }
+ ypos++;
+ }
+ }
+ break;
+
+ case GL_MULT:
+ if (value != 1.0F) {
+ GLuint j;
+ /* Leave optimized accum buffer mode */
+ if (ctx->IntegerAccumMode)
+ rescale_accum(ctx);
+ for (j = 0; j < height; j++) {
+ GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + 4 * xpos;
+ GLuint i;
+ for (i = 0; i < width4; i++) {
+ acc[i] = (GLaccum) ( (GLfloat) acc[i] * value );
+ }
+ ypos++;
+ }
+ }
+ break;
+
+ case GL_ACCUM:
+ if (value == 0.0F)
+ return;
+
+ (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
+ ctx->Pixel.DriverReadBuffer );
+
+ /* May have to leave optimized accum buffer mode */
+ if (ctx->IntegerAccumScaler == 0.0 && value > 0.0 && value <= 1.0)
+ ctx->IntegerAccumScaler = value;
+ if (ctx->IntegerAccumMode && value != ctx->IntegerAccumScaler)
+ rescale_accum(ctx);
+
+ RENDER_START(ctx);
+
+ if (ctx->IntegerAccumMode) {
+ /* simply add integer color values into accum buffer */
+ GLuint j;
+ GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos * 4;
+ assert(ctx->IntegerAccumScaler > 0.0);
+ assert(ctx->IntegerAccumScaler <= 1.0);
+ for (j = 0; j < height; j++) {
+
+ GLuint i, i4;
+ gl_read_rgba_span(ctx, ctx->DrawBuffer, width, xpos, ypos, rgba);
+ for (i = i4 = 0; i < width; i++, i4+=4) {
+ acc[i4+0] += rgba[i][RCOMP];
+ acc[i4+1] += rgba[i][GCOMP];
+ acc[i4+2] += rgba[i][BCOMP];
+ acc[i4+3] += rgba[i][ACOMP];
+ }
+ acc += width4;
+ ypos++;
+ }
+ }
+ else {
+ /* scaled integer accum buffer */
+ const GLfloat rscale = value * acc_scale / fChanMax;
+ const GLfloat gscale = value * acc_scale / fChanMax;
+ const GLfloat bscale = value * acc_scale / fChanMax;
+ const GLfloat ascale = value * acc_scale / fChanMax;
+ GLuint j;
+ for (j=0;j<height;j++) {
+ GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos * 4;
+ GLuint i;
+ gl_read_rgba_span(ctx, ctx->DrawBuffer, width, xpos, ypos, rgba);
+ for (i=0;i<width;i++) {
+ *acc += (GLaccum) ( (GLfloat) rgba[i][RCOMP] * rscale ); acc++;
+ *acc += (GLaccum) ( (GLfloat) rgba[i][GCOMP] * gscale ); acc++;
+ *acc += (GLaccum) ( (GLfloat) rgba[i][BCOMP] * bscale ); acc++;
+ *acc += (GLaccum) ( (GLfloat) rgba[i][ACOMP] * ascale ); acc++;
+ }
+ ypos++;
+ }
+ }
+ /* restore read buffer = draw buffer (the default) */
+ (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
+ ctx->Color.DriverDrawBuffer );
+ RENDER_FINISH(ctx);
+ break;
+
+ case GL_LOAD:
+ (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
+ ctx->Pixel.DriverReadBuffer );
+
+ /* This is a change to go into optimized accum buffer mode */
+ if (value > 0.0 && value <= 1.0) {
+#ifdef USE_OPTIMIZED_ACCUM
+ ctx->IntegerAccumMode = GL_TRUE;
+#else
+ ctx->IntegerAccumMode = GL_FALSE;
+#endif
+ ctx->IntegerAccumScaler = value;
+ }
+ else {
+ ctx->IntegerAccumMode = GL_FALSE;
+ ctx->IntegerAccumScaler = 0.0;
+ }
+
+ RENDER_START(ctx);
+ if (ctx->IntegerAccumMode) {
+ /* just copy values into accum buffer */
+ GLuint j;
+ GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos * 4;
+ assert(ctx->IntegerAccumScaler > 0.0);
+ assert(ctx->IntegerAccumScaler <= 1.0);
+ for (j = 0; j < height; j++) {
+ GLuint i, i4;
+ gl_read_rgba_span(ctx, ctx->DrawBuffer, width, xpos, ypos, rgba);
+ for (i = i4 = 0; i < width; i++, i4 += 4) {
+ acc[i4+0] = rgba[i][RCOMP];
+ acc[i4+1] = rgba[i][GCOMP];
+ acc[i4+2] = rgba[i][BCOMP];
+ acc[i4+3] = rgba[i][ACOMP];
+ }
+ acc += width4;
+ ypos++;
+ }
+ }
+ else {
+ /* scaled integer accum buffer */
+ const GLfloat rscale = value * acc_scale / fChanMax;
+ const GLfloat gscale = value * acc_scale / fChanMax;
+ const GLfloat bscale = value * acc_scale / fChanMax;
+ const GLfloat ascale = value * acc_scale / fChanMax;
+ const GLfloat d = 3.0 / acc_scale;
+ GLuint i, j;
+ for (j = 0; j < height; j++) {
+ GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos * 4;
+ gl_read_rgba_span(ctx, ctx->DrawBuffer, width, xpos, ypos, rgba);
+ for (i=0;i<width;i++) {
+ *acc++ = (GLaccum) ((GLfloat) rgba[i][RCOMP] * rscale + d);
+ *acc++ = (GLaccum) ((GLfloat) rgba[i][GCOMP] * gscale + d);
+ *acc++ = (GLaccum) ((GLfloat) rgba[i][BCOMP] * bscale + d);
+ *acc++ = (GLaccum) ((GLfloat) rgba[i][ACOMP] * ascale + d);
+ }
+ ypos++;
+ }
+ }
+
+ /* restore read buffer = draw buffer (the default) */
+ (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
+ ctx->Color.DriverDrawBuffer );
+ RENDER_FINISH(ctx);
+ break;
+
+ case GL_RETURN:
+ /* May have to leave optimized accum buffer mode */
+ if (ctx->IntegerAccumMode && value != 1.0)
+ rescale_accum(ctx);
+
+ RENDER_START(ctx);
+ if (ctx->IntegerAccumMode && ctx->IntegerAccumScaler > 0) {
+ /* build lookup table to avoid many floating point multiplies */
+ static GLchan multTable[32768];
+ static GLfloat prevMult = 0.0;
+ const GLfloat mult = ctx->IntegerAccumScaler;
+ const GLint max = MIN2((GLint) (256 / mult), 32767);
+ GLuint j;
+ if (mult != prevMult) {
+ for (j = 0; j < max; j++)
+ multTable[j] = (GLint) ((GLfloat) j * mult + 0.5F);
+ prevMult = mult;
+ }
+
+ assert(ctx->IntegerAccumScaler > 0.0);
+ assert(ctx->IntegerAccumScaler <= 1.0);
+ for (j = 0; j < height; j++) {
+ const GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos*4;
+ GLuint i, i4;
+ for (i = i4 = 0; i < width; i++, i4 += 4) {
+ ASSERT(acc[i4+0] < max);
+ ASSERT(acc[i4+1] < max);
+ ASSERT(acc[i4+2] < max);
+ ASSERT(acc[i4+3] < max);
+ rgba[i][RCOMP] = multTable[acc[i4+0]];
+ rgba[i][GCOMP] = multTable[acc[i4+1]];
+ rgba[i][BCOMP] = multTable[acc[i4+2]];
+ rgba[i][ACOMP] = multTable[acc[i4+3]];
+ }
+ if (colorMask != 0xffffffff) {
+ _mesa_mask_rgba_span( ctx, width, xpos, ypos, rgba );
+ }
+ (*ctx->Driver.WriteRGBASpan)( ctx, width, xpos, ypos,
+ (const GLchan (*)[4])rgba, NULL );
+ ypos++;
+ }
+ }
+ else {
+ const GLfloat rscale = value / acc_scale * fChanMax;
+ const GLfloat gscale = value / acc_scale * fChanMax;
+ const GLfloat bscale = value / acc_scale * fChanMax;
+ const GLfloat ascale = value / acc_scale * fChanMax;
+ GLuint i, j;
+ for (j=0;j<height;j++) {
+ const GLaccum *acc = ctx->DrawBuffer->Accum + ypos * width4 + xpos*4;
+ for (i=0;i<width;i++) {
+ GLint r, g, b, a;
+ r = (GLint) ( (GLfloat) (*acc++) * rscale + 0.5F );
+ g = (GLint) ( (GLfloat) (*acc++) * gscale + 0.5F );
+ b = (GLint) ( (GLfloat) (*acc++) * bscale + 0.5F );
+ a = (GLint) ( (GLfloat) (*acc++) * ascale + 0.5F );
+ rgba[i][RCOMP] = CLAMP( r, 0, iChanMax );
+ rgba[i][GCOMP] = CLAMP( g, 0, iChanMax );
+ rgba[i][BCOMP] = CLAMP( b, 0, iChanMax );
+ rgba[i][ACOMP] = CLAMP( a, 0, iChanMax );
+ }
+ if (colorMask != 0xffffffff) {
+ _mesa_mask_rgba_span( ctx, width, xpos, ypos, rgba );
+ }
+ (*ctx->Driver.WriteRGBASpan)( ctx, width, xpos, ypos,
+ (const GLchan (*)[4])rgba, NULL );
+ ypos++;
+ }
+ }
+ RENDER_FINISH(ctx);
+ break;
+
+ default:
+ gl_error( ctx, GL_INVALID_ENUM, "glAccum" );
+ }
+}
+
+
+
+/*
+ * Clear the accumulation Buffer.
+ */
+void
+_mesa_clear_accum_buffer( GLcontext *ctx )
+{
+ GLuint buffersize;
+ GLfloat acc_scale;
+
+ if (ctx->Visual.AccumRedBits==0) {
+ /* No accumulation buffer! */
+ return;
+ }
+
+ if (sizeof(GLaccum)==1) {
+ acc_scale = 127.0;
+ }
+ else if (sizeof(GLaccum)==2) {
+ acc_scale = 32767.0;
+ }
+ else {
+ /* sizeof(GLaccum) > 2 (Cray) */
+ acc_scale = (float) SHRT_MAX;
+ }
+
+ /* number of pixels */
+ buffersize = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
+
+ if (!ctx->DrawBuffer->Accum) {
+ /* try to alloc accumulation buffer */
+ ctx->DrawBuffer->Accum = (GLaccum *)
+ MALLOC( buffersize * 4 * sizeof(GLaccum) );
+ }
+
+ if (ctx->DrawBuffer->Accum) {
+ if (ctx->Scissor.Enabled) {
+ /* Limit clear to scissor box */
+ GLaccum r, g, b, a;
+ GLint i, j;
+ GLint width, height;
+ GLaccum *row;
+ r = (GLaccum) (ctx->Accum.ClearColor[0] * acc_scale);
+ g = (GLaccum) (ctx->Accum.ClearColor[1] * acc_scale);
+ b = (GLaccum) (ctx->Accum.ClearColor[2] * acc_scale);
+ a = (GLaccum) (ctx->Accum.ClearColor[3] * acc_scale);
+ /* size of region to clear */
+ width = 4 * (ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin);
+ height = ctx->DrawBuffer->Ymax - ctx->DrawBuffer->Ymin;
+ /* ptr to first element to clear */
+ row = ctx->DrawBuffer->Accum
+ + 4 * (ctx->DrawBuffer->Ymin * ctx->DrawBuffer->Width
+ + ctx->DrawBuffer->Xmin);
+ for (j=0;j<height;j++) {
+ for (i=0;i<width;i+=4) {
+ row[i+0] = r;
+ row[i+1] = g;
+ row[i+2] = b;
+ row[i+3] = a;
+ }
+ row += 4 * ctx->DrawBuffer->Width;
+ }
+ }
+ else {
+ /* clear whole buffer */
+ if (ctx->Accum.ClearColor[0]==0.0 &&
+ ctx->Accum.ClearColor[1]==0.0 &&
+ ctx->Accum.ClearColor[2]==0.0 &&
+ ctx->Accum.ClearColor[3]==0.0) {
+ /* Black */
+ BZERO( ctx->DrawBuffer->Accum, buffersize * 4 * sizeof(GLaccum) );
+ }
+ else {
+ /* Not black */
+ GLaccum *acc, r, g, b, a;
+ GLuint i;
+
+ acc = ctx->DrawBuffer->Accum;
+ r = (GLaccum) (ctx->Accum.ClearColor[0] * acc_scale);
+ g = (GLaccum) (ctx->Accum.ClearColor[1] * acc_scale);
+ b = (GLaccum) (ctx->Accum.ClearColor[2] * acc_scale);
+ a = (GLaccum) (ctx->Accum.ClearColor[3] * acc_scale);
+ for (i=0;i<buffersize;i++) {
+ *acc++ = r;
+ *acc++ = g;
+ *acc++ = b;
+ *acc++ = a;
+ }
+ }
+ }
+
+ /* update optimized accum state vars */
+ if (ctx->Accum.ClearColor[0] == 0.0 && ctx->Accum.ClearColor[1] == 0.0 &&
+ ctx->Accum.ClearColor[2] == 0.0 && ctx->Accum.ClearColor[3] == 0.0) {
+#ifdef USE_OPTIMIZED_ACCUM
+ ctx->IntegerAccumMode = GL_TRUE;
+#else
+ ctx->IntegerAccumMode = GL_FALSE;
+#endif
+ ctx->IntegerAccumScaler = 0.0; /* denotes empty accum buffer */
+ }
+ else {
+ ctx->IntegerAccumMode = GL_FALSE;
+ }
+ }
+}
diff --git a/src/mesa/swrast/s_accum.h b/src/mesa/swrast/s_accum.h
new file mode 100644
index 0000000000..7ec2236ec1
--- /dev/null
+++ b/src/mesa/swrast/s_accum.h
@@ -0,0 +1,45 @@
+/* $Id: s_accum.h,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.1
+ *
+ * Copyright (C) 1999 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.
+ */
+
+
+#ifndef S_ACCUM_H
+#define S_ACCUM_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+extern void
+_mesa_alloc_accum_buffer( GLcontext *ctx );
+
+
+extern void
+_mesa_clear_accum_buffer( GLcontext *ctx );
+
+
+
+#endif
diff --git a/src/mesa/swrast/s_alpha.c b/src/mesa/swrast/s_alpha.c
new file mode 100644
index 0000000000..07e8dacd4a
--- /dev/null
+++ b/src/mesa/swrast/s_alpha.c
@@ -0,0 +1,99 @@
+/* $Id: s_alpha.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ *
+ * 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.
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "colormac.h"
+#include "macros.h"
+#include "mmath.h"
+
+#include "s_alpha.h"
+
+
+
+
+
+/*
+ * Apply the alpha test to a span of pixels.
+ * In: rgba - array of pixels
+ * In/Out: mask - current pixel mask. Pixels which fail the alpha test
+ * will set the corresponding mask flag to 0.
+ * Return: 0 = all pixels in the span failed the alpha test.
+ * 1 = one or more pixels passed the alpha test.
+ */
+GLint
+_mesa_alpha_test( const GLcontext *ctx,
+ GLuint n, CONST GLchan rgba[][4], GLubyte mask[] )
+{
+ GLuint i;
+ GLchan ref = ctx->Color.AlphaRef;
+
+ /* switch cases ordered from most frequent to less frequent */
+ switch (ctx->Color.AlphaFunc) {
+ case GL_LESS:
+ for (i=0;i<n;i++) {
+ mask[i] &= (rgba[i][ACOMP] < ref);
+ }
+ return 1;
+ case GL_LEQUAL:
+ for (i=0;i<n;i++) {
+ mask[i] &= (rgba[i][ACOMP] <= ref);
+ }
+ return 1;
+ case GL_GEQUAL:
+ for (i=0;i<n;i++) {
+ mask[i] &= (rgba[i][ACOMP] >= ref);
+ }
+ return 1;
+ case GL_GREATER:
+ for (i=0;i<n;i++) {
+ mask[i] &= (rgba[i][ACOMP] > ref);
+ }
+ return 1;
+ case GL_NOTEQUAL:
+ for (i=0;i<n;i++) {
+ mask[i] &= (rgba[i][ACOMP] != ref);
+ }
+ return 1;
+ case GL_EQUAL:
+ for (i=0;i<n;i++) {
+ mask[i] &= (rgba[i][ACOMP] == ref);
+ }
+ return 1;
+ case GL_ALWAYS:
+ /* do nothing */
+ return 1;
+ case GL_NEVER:
+ /* caller should check for zero! */
+ return 0;
+ default:
+ gl_problem( ctx, "Invalid alpha test in gl_alpha_test" );
+ return 0;
+ }
+ /* Never get here */
+ /*return 1;*/
+}
diff --git a/src/mesa/swrast/s_alpha.h b/src/mesa/swrast/s_alpha.h
new file mode 100644
index 0000000000..6688a89142
--- /dev/null
+++ b/src/mesa/swrast/s_alpha.h
@@ -0,0 +1,42 @@
+/* $Id: s_alpha.h,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ *
+ * 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.
+ */
+
+
+#ifndef S_ALPHA_H
+#define S_ALPHA_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+extern GLint
+_mesa_alpha_test( const GLcontext *ctx, GLuint n,
+ CONST GLchan rgba[][4], GLubyte mask[] );
+
+
+
+#endif
diff --git a/src/mesa/swrast/s_alphabuf.c b/src/mesa/swrast/s_alphabuf.c
new file mode 100644
index 0000000000..ed7b9cbded
--- /dev/null
+++ b/src/mesa/swrast/s_alphabuf.c
@@ -0,0 +1,313 @@
+
+/*
+ * 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.
+ */
+
+
+/*
+ * Software alpha planes. Many frame buffers don't have alpha bits so
+ * we simulate them in software.
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "mem.h"
+
+#include "s_alphabuf.h"
+
+
+
+
+#define ALPHA_DRAW_ADDR(X,Y) \
+ (ctx->DrawBuffer->Alpha + (Y) * ctx->DrawBuffer->Width + (X))
+
+#define ALPHA_READ_ADDR(X,Y) \
+ (ctx->ReadBuffer->Alpha + (Y) * ctx->ReadBuffer->Width + (X))
+
+
+
+/*
+ * Allocate new front/back/left/right alpha buffers.
+ * Input: ctx - the context
+ *
+ */
+static void
+alloc_alpha_buffers( GLcontext *ctx, GLframebuffer *buf )
+{
+ GLint bytes = buf->Width * buf->Height * sizeof(GLchan);
+
+ ASSERT(ctx->DrawBuffer->UseSoftwareAlphaBuffers);
+
+ if (buf->FrontLeftAlpha) {
+ FREE( buf->FrontLeftAlpha );
+ }
+ buf->FrontLeftAlpha = (GLchan *) MALLOC( bytes );
+ if (!buf->FrontLeftAlpha) {
+ /* out of memory */
+ gl_error( ctx, GL_OUT_OF_MEMORY,
+ "Couldn't allocate front-left alpha buffer" );
+ }
+
+ if (ctx->Visual.DBflag) {
+ if (buf->BackLeftAlpha) {
+ FREE( buf->BackLeftAlpha );
+ }
+ buf->BackLeftAlpha = (GLchan *) MALLOC( bytes );
+ if (!buf->BackLeftAlpha) {
+ /* out of memory */
+ gl_error( ctx, GL_OUT_OF_MEMORY,
+ "Couldn't allocate back-left alpha buffer" );
+ }
+ }
+
+ if (ctx->Visual.StereoFlag) {
+ if (buf->FrontRightAlpha) {
+ FREE( buf->FrontRightAlpha );
+ }
+ buf->FrontRightAlpha = (GLchan *) MALLOC( bytes );
+ if (!buf->FrontRightAlpha) {
+ /* out of memory */
+ gl_error( ctx, GL_OUT_OF_MEMORY,
+ "Couldn't allocate front-right alpha buffer" );
+ }
+
+ if (ctx->Visual.DBflag) {
+ if (buf->BackRightAlpha) {
+ FREE( buf->BackRightAlpha );
+ }
+ buf->BackRightAlpha = (GLchan *) MALLOC( bytes );
+ if (!buf->BackRightAlpha) {
+ /* out of memory */
+ gl_error( ctx, GL_OUT_OF_MEMORY,
+ "Couldn't allocate back-right alpha buffer" );
+ }
+ }
+ }
+
+ if (ctx->Color.DriverDrawBuffer == GL_FRONT_LEFT)
+ buf->Alpha = buf->FrontLeftAlpha;
+ else if (ctx->Color.DriverDrawBuffer == GL_BACK_LEFT)
+ buf->Alpha = buf->BackLeftAlpha;
+ else if (ctx->Color.DriverDrawBuffer == GL_FRONT_RIGHT)
+ buf->Alpha = buf->FrontRightAlpha;
+ else if (ctx->Color.DriverDrawBuffer == GL_BACK_RIGHT)
+ buf->Alpha = buf->BackRightAlpha;
+}
+
+
+/*
+ * Allocate a new front and back alpha buffer.
+ */
+void
+_mesa_alloc_alpha_buffers( GLcontext *ctx )
+{
+ alloc_alpha_buffers( ctx, ctx->DrawBuffer );
+ if (ctx->ReadBuffer != ctx->DrawBuffer) {
+ alloc_alpha_buffers( ctx, ctx->ReadBuffer );
+ }
+}
+
+
+/*
+ * Clear all the alpha buffers
+ */
+void
+_mesa_clear_alpha_buffers( GLcontext *ctx )
+{
+ const GLchan aclear = (GLint) (ctx->Color.ClearColor[3] * CHAN_MAXF);
+ GLuint bufferBit;
+
+ ASSERT(ctx->DrawBuffer->UseSoftwareAlphaBuffers);
+ ASSERT(ctx->Color.ColorMask[ACOMP]);
+
+ /* loop over four possible alpha buffers */
+ for (bufferBit = 1; bufferBit <= 8; bufferBit = bufferBit << 1) {
+ if (bufferBit & ctx->Color.DrawDestMask) {
+ GLchan *buffer;
+ if (bufferBit == FRONT_LEFT_BIT) {
+ buffer = ctx->DrawBuffer->FrontLeftAlpha;
+ }
+ else if (bufferBit == FRONT_RIGHT_BIT) {
+ buffer = ctx->DrawBuffer->FrontRightAlpha;
+ }
+ else if (bufferBit == BACK_LEFT_BIT) {
+ buffer = ctx->DrawBuffer->BackLeftAlpha;
+ }
+ else {
+ buffer = ctx->DrawBuffer->BackRightAlpha;
+ }
+
+ if (ctx->Scissor.Enabled) {
+ /* clear scissor region */
+ GLint j;
+ GLint rowLen = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin + 1;
+ GLint rows = ctx->DrawBuffer->Ymax - ctx->DrawBuffer->Ymin + 1;
+ GLchan *aptr = buffer
+ + ctx->DrawBuffer->Ymin * ctx->DrawBuffer->Width
+ + ctx->DrawBuffer->Xmin;
+ for (j = 0; j < rows; j++) {
+#if CHAN_BITS == 8
+ MEMSET( aptr, aclear, rowLen );
+#elif CHAN_BITS == 16
+ MEMSET16( aptr, aclear, rowLen );
+#else
+#error unexpected CHAN_BITS value
+#endif
+ aptr += rowLen;
+ }
+ }
+ else {
+ /* clear whole buffer */
+ GLuint bytes = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
+ MEMSET( buffer, aclear, bytes );
+ }
+ }
+ }
+}
+
+
+
+void
+_mesa_write_alpha_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
+ CONST GLchan rgba[][4], const GLubyte mask[] )
+{
+ GLchan *aptr = ALPHA_DRAW_ADDR( x, y );
+ GLuint i;
+
+ if (mask) {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ *aptr = rgba[i][ACOMP];
+ }
+ aptr++;
+ }
+ }
+ else {
+ for (i=0;i<n;i++) {
+ *aptr++ = rgba[i][ACOMP];
+ }
+ }
+}
+
+
+void
+_mesa_write_mono_alpha_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
+ GLchan alpha, const GLubyte mask[] )
+{
+ GLchan *aptr = ALPHA_DRAW_ADDR( x, y );
+ GLuint i;
+
+ if (mask) {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ *aptr = alpha;
+ }
+ aptr++;
+ }
+ }
+ else {
+ for (i=0;i<n;i++) {
+ *aptr++ = alpha;
+ }
+ }
+}
+
+
+void
+_mesa_write_alpha_pixels( GLcontext *ctx,
+ GLuint n, const GLint x[], const GLint y[],
+ CONST GLchan rgba[][4], const GLubyte mask[] )
+{
+ GLuint i;
+
+ if (mask) {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLchan *aptr = ALPHA_DRAW_ADDR( x[i], y[i] );
+ *aptr = rgba[i][ACOMP];
+ }
+ }
+ }
+ else {
+ for (i=0;i<n;i++) {
+ GLchan *aptr = ALPHA_DRAW_ADDR( x[i], y[i] );
+ *aptr = rgba[i][ACOMP];
+ }
+ }
+}
+
+
+void
+_mesa_write_mono_alpha_pixels( GLcontext *ctx,
+ GLuint n, const GLint x[], const GLint y[],
+ GLchan alpha, const GLubyte mask[] )
+{
+ GLuint i;
+
+ if (mask) {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLchan *aptr = ALPHA_DRAW_ADDR( x[i], y[i] );
+ *aptr = alpha;
+ }
+ }
+ }
+ else {
+ for (i=0;i<n;i++) {
+ GLchan *aptr = ALPHA_DRAW_ADDR( x[i], y[i] );
+ *aptr = alpha;
+ }
+ }
+}
+
+
+
+void
+_mesa_read_alpha_span( GLcontext *ctx,
+ GLuint n, GLint x, GLint y, GLchan rgba[][4] )
+{
+ GLchan *aptr = ALPHA_READ_ADDR( x, y );
+ GLuint i;
+ for (i=0;i<n;i++) {
+ rgba[i][ACOMP] = *aptr++;
+ }
+}
+
+
+void
+_mesa_read_alpha_pixels( GLcontext *ctx,
+ GLuint n, const GLint x[], const GLint y[],
+ GLchan rgba[][4], const GLubyte mask[] )
+{
+ GLuint i;
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLchan *aptr = ALPHA_READ_ADDR( x[i], y[i] );
+ rgba[i][ACOMP] = *aptr;
+ }
+ }
+}
+
+
+
diff --git a/src/mesa/swrast/s_alphabuf.h b/src/mesa/swrast/s_alphabuf.h
new file mode 100644
index 0000000000..b24a4b8eeb
--- /dev/null
+++ b/src/mesa/swrast/s_alphabuf.h
@@ -0,0 +1,82 @@
+/* $Id: s_alphabuf.h,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.
+ */
+
+
+#ifndef S_ALPHABUF_H
+#define S_ALPHABUF_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+extern void
+_mesa_alloc_alpha_buffers( GLcontext *ctx );
+
+
+extern void
+_mesa_clear_alpha_buffers( GLcontext *ctx );
+
+
+extern void
+_mesa_write_alpha_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
+ CONST GLchan rgba[][4], const GLubyte mask[] );
+
+
+extern void
+_mesa_write_mono_alpha_span( GLcontext *ctx,
+ GLuint n, GLint x, GLint y,
+ GLchan alpha, const GLubyte mask[] );
+
+
+
+extern void
+_mesa_write_alpha_pixels( GLcontext* ctx,
+ GLuint n, const GLint x[], const GLint y[],
+ CONST GLchan rgba[][4],
+ const GLubyte mask[] );
+
+
+extern void
+_mesa_write_mono_alpha_pixels( GLcontext* ctx,
+ GLuint n, const GLint x[],
+ const GLint y[], GLchan alpha,
+ const GLubyte mask[] );
+
+
+extern void
+_mesa_read_alpha_span( GLcontext* ctx,
+ GLuint n, GLint x, GLint y, GLchan rgba[][4] );
+
+
+extern void
+_mesa_read_alpha_pixels( GLcontext* ctx,
+ GLuint n, const GLint x[], const GLint y[],
+ GLchan rgba[][4], const GLubyte mask[] );
+
+
+#endif
+
diff --git a/src/mesa/swrast/s_bitmap.c b/src/mesa/swrast/s_bitmap.c
new file mode 100644
index 0000000000..646081b83e
--- /dev/null
+++ b/src/mesa/swrast/s_bitmap.c
@@ -0,0 +1,131 @@
+/* $Id: s_bitmap.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ *
+ * Copyright (C) 1999 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.
+ */
+
+
+#include "glheader.h"
+#include "image.h"
+#include "macros.h"
+#include "pixel.h"
+
+#include "s_fog.h"
+#include "s_pb.h"
+
+
+
+/*
+ * Render a bitmap.
+ */
+void
+_swrast_Bitmap( GLcontext *ctx, GLint px, GLint py,
+ GLsizei width, GLsizei height,
+ const struct gl_pixelstore_attrib *unpack,
+ const GLubyte *bitmap )
+{
+ struct pixel_buffer *PB = ctx->PB;
+ GLint row, col;
+ GLdepth fragZ;
+ GLfixed fogCoord;
+
+ ASSERT(ctx->RenderMode == GL_RENDER);
+ ASSERT(bitmap);
+
+ if (ctx->PB->primitive != GL_BITMAP) {
+ gl_flush_pb( ctx );
+ ctx->PB->primitive = GL_BITMAP;
+ }
+
+ /* Set bitmap drawing color */
+ if (ctx->Visual.RGBAflag) {
+ GLint r, g, b, a;
+ r = (GLint) (ctx->Current.RasterColor[0] * CHAN_MAXF);
+ g = (GLint) (ctx->Current.RasterColor[1] * CHAN_MAXF);
+ b = (GLint) (ctx->Current.RasterColor[2] * CHAN_MAXF);
+ a = (GLint) (ctx->Current.RasterColor[3] * CHAN_MAXF);
+ PB_SET_COLOR( PB, r, g, b, a );
+ }
+ else {
+ PB_SET_INDEX( PB, ctx->Current.RasterIndex );
+ }
+
+ fragZ = (GLdepth) ( ctx->Current.RasterPos[2] * ctx->Visual.DepthMaxF);
+
+ _mesa_win_fog_coords_from_z( ctx, 1, &fragZ, &fogCoord );
+
+ for (row=0; row<height; row++) {
+ const GLubyte *src = (const GLubyte *) _mesa_image_address( unpack,
+ bitmap, width, height, GL_COLOR_INDEX, GL_BITMAP, 0, row, 0 );
+
+ if (unpack->LsbFirst) {
+ /* Lsb first */
+ GLubyte mask = 1U << (unpack->SkipPixels & 0x7);
+ for (col=0; col<width; col++) {
+ if (*src & mask) {
+ PB_WRITE_PIXEL( PB, px+col, py+row, fragZ, fogCoord );
+ }
+ if (mask == 128U) {
+ src++;
+ mask = 1U;
+ }
+ else {
+ mask = mask << 1;
+ }
+ }
+
+ PB_CHECK_FLUSH( ctx, PB );
+
+ /* get ready for next row */
+ if (mask != 1)
+ src++;
+ }
+ else {
+ /* Msb first */
+ GLubyte mask = 128U >> (unpack->SkipPixels & 0x7);
+ for (col=0; col<width; col++) {
+ if (*src & mask) {
+ PB_WRITE_PIXEL( PB, px+col, py+row, fragZ, fogCoord );
+ }
+ if (mask == 1U) {
+ src++;
+ mask = 128U;
+ }
+ else {
+ mask = mask >> 1;
+ }
+ }
+
+ PB_CHECK_FLUSH( ctx, PB );
+
+ /* get ready for next row */
+ if (mask != 128)
+ src++;
+ }
+ }
+
+ gl_flush_pb(ctx);
+}
+
+
+
diff --git a/src/mesa/swrast/s_blend.c b/src/mesa/swrast/s_blend.c
new file mode 100644
index 0000000000..0e65229c4a
--- /dev/null
+++ b/src/mesa/swrast/s_blend.c
@@ -0,0 +1,667 @@
+/* $Id: s_blend.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.
+ */
+
+
+
+#include "glheader.h"
+#include "context.h"
+#include "macros.h"
+
+#include "s_alphabuf.h"
+#include "s_blend.h"
+#include "s_pb.h"
+#include "s_span.h"
+
+
+#ifdef USE_MMX_ASM
+#define _BLENDAPI _ASMAPI
+#else
+#define _BLENDAPI
+#endif
+
+/*
+ * Common transparency blending mode.
+ */
+static void _BLENDAPI
+blend_transparency( GLcontext *ctx, GLuint n, const GLubyte mask[],
+ GLchan rgba[][4], CONST GLchan dest[][4] )
+{
+ GLuint i;
+ ASSERT(ctx->Color.BlendEquation==GL_FUNC_ADD_EXT);
+ ASSERT(ctx->Color.BlendSrcRGB==GL_SRC_ALPHA);
+ ASSERT(ctx->Color.BlendDstRGB==GL_ONE_MINUS_SRC_ALPHA);
+ (void) ctx;
+
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ const GLint t = rgba[i][ACOMP]; /* t in [0, CHAN_MAX] */
+ if (t == 0) {
+ /* 0% alpha */
+ rgba[i][RCOMP] = dest[i][RCOMP];
+ rgba[i][GCOMP] = dest[i][GCOMP];
+ rgba[i][BCOMP] = dest[i][BCOMP];
+ rgba[i][ACOMP] = dest[i][ACOMP];
+ }
+ else if (t == CHAN_MAX) {
+ /* 100% alpha, no-op */
+ }
+ else {
+#if 0
+ /* This is pretty close, but Glean complains */
+ const GLint s = CHAN_MAX - t;
+ const GLint r = (rgba[i][RCOMP] * t + dest[i][RCOMP] * s + 1) >> 8;
+ const GLint g = (rgba[i][GCOMP] * t + dest[i][GCOMP] * s + 1) >> 8;
+ const GLint b = (rgba[i][BCOMP] * t + dest[i][BCOMP] * s + 1) >> 8;
+ const GLint a = (rgba[i][ACOMP] * t + dest[i][ACOMP] * s + 1) >> 8;
+#elif 0
+ /* This is slower but satisfies Glean */
+ const GLint s = CHAN_MAX - t;
+ const GLint r = (rgba[i][RCOMP] * t + dest[i][RCOMP] * s) / 255;
+ const GLint g = (rgba[i][GCOMP] * t + dest[i][GCOMP] * s) / 255;
+ const GLint b = (rgba[i][BCOMP] * t + dest[i][BCOMP] * s) / 255;
+ const GLint a = (rgba[i][ACOMP] * t + dest[i][ACOMP] * s) / 255;
+#else
+#if CHAN_BITS == 8
+ /* This satisfies Glean and should be reasonably fast */
+ /* Contributed by Nathan Hand */
+#define DIV255(X) (((X) << 8) + (X) + 256) >> 16
+ const GLint s = CHAN_MAX - t;
+ const GLint r = DIV255(rgba[i][RCOMP] * t + dest[i][RCOMP] * s);
+ const GLint g = DIV255(rgba[i][GCOMP] * t + dest[i][GCOMP] * s);
+ const GLint b = DIV255(rgba[i][BCOMP] * t + dest[i][BCOMP] * s);
+ const GLint a = DIV255(rgba[i][ACOMP] * t + dest[i][ACOMP] * s);
+#undef DIV255
+#else
+ const GLint s = CHAN_MAX - t;
+ const GLint r = (rgba[i][RCOMP] * t + dest[i][RCOMP] * s) / CHAN_MAX;
+ const GLint g = (rgba[i][GCOMP] * t + dest[i][GCOMP] * s) / CHAN_MAX;
+ const GLint b = (rgba[i][BCOMP] * t + dest[i][BCOMP] * s) / CHAN_MAX;
+ const GLint a = (rgba[i][ACOMP] * t + dest[i][ACOMP] * s) / CHAN_MAX;
+#endif
+#endif
+ ASSERT(r <= CHAN_MAX);
+ ASSERT(g <= CHAN_MAX);
+ ASSERT(b <= CHAN_MAX);
+ ASSERT(a <= CHAN_MAX);
+ rgba[i][RCOMP] = (GLchan) r;
+ rgba[i][GCOMP] = (GLchan) g;
+ rgba[i][BCOMP] = (GLchan) b;
+ rgba[i][ACOMP] = (GLchan) a;
+ }
+ }
+ }
+}
+
+
+
+/*
+ * Add src and dest.
+ */
+static void _BLENDAPI
+blend_add( GLcontext *ctx, GLuint n, const GLubyte mask[],
+ GLchan rgba[][4], CONST GLchan dest[][4] )
+{
+ GLuint i;
+ ASSERT(ctx->Color.BlendEquation==GL_FUNC_ADD_EXT);
+ ASSERT(ctx->Color.BlendSrcRGB==GL_ONE);
+ ASSERT(ctx->Color.BlendDstRGB==GL_ONE);
+ (void) ctx;
+
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLint r = rgba[i][RCOMP] + dest[i][RCOMP];
+ GLint g = rgba[i][GCOMP] + dest[i][GCOMP];
+ GLint b = rgba[i][BCOMP] + dest[i][BCOMP];
+ GLint a = rgba[i][ACOMP] + dest[i][ACOMP];
+ rgba[i][RCOMP] = (GLchan) MIN2( r, CHAN_MAX );
+ rgba[i][GCOMP] = (GLchan) MIN2( g, CHAN_MAX );
+ rgba[i][BCOMP] = (GLchan) MIN2( b, CHAN_MAX );
+ rgba[i][ACOMP] = (GLchan) MIN2( a, CHAN_MAX );
+ }
+ }
+}
+
+
+
+/*
+ * Blend min function (for GL_EXT_blend_minmax)
+ */
+static void _BLENDAPI
+blend_min( GLcontext *ctx, GLuint n, const GLubyte mask[],
+ GLchan rgba[][4], CONST GLchan dest[][4] )
+{
+ GLuint i;
+ ASSERT(ctx->Color.BlendEquation==GL_MIN_EXT);
+ (void) ctx;
+
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ rgba[i][RCOMP] = (GLchan) MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
+ rgba[i][GCOMP] = (GLchan) MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
+ rgba[i][BCOMP] = (GLchan) MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
+ rgba[i][ACOMP] = (GLchan) MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
+ }
+ }
+}
+
+
+
+/*
+ * Blend max function (for GL_EXT_blend_minmax)
+ */
+static void _BLENDAPI
+blend_max( GLcontext *ctx, GLuint n, const GLubyte mask[],
+ GLchan rgba[][4], CONST GLchan dest[][4] )
+{
+ GLuint i;
+ ASSERT(ctx->Color.BlendEquation==GL_MAX_EXT);
+ (void) ctx;
+
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ rgba[i][RCOMP] = (GLchan) MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
+ rgba[i][GCOMP] = (GLchan) MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
+ rgba[i][BCOMP] = (GLchan) MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
+ rgba[i][ACOMP] = (GLchan) MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
+ }
+ }
+}
+
+
+
+/*
+ * Modulate: result = src * dest
+ */
+static void _BLENDAPI
+blend_modulate( GLcontext *ctx, GLuint n, const GLubyte mask[],
+ GLchan rgba[][4], CONST GLchan dest[][4] )
+{
+ GLuint i;
+ (void) ctx;
+
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLint r = (rgba[i][RCOMP] * dest[i][RCOMP]) >> 8;
+ GLint g = (rgba[i][GCOMP] * dest[i][GCOMP]) >> 8;
+ GLint b = (rgba[i][BCOMP] * dest[i][BCOMP]) >> 8;
+ GLint a = (rgba[i][ACOMP] * dest[i][ACOMP]) >> 8;
+ rgba[i][RCOMP] = (GLchan) r;
+ rgba[i][GCOMP] = (GLchan) g;
+ rgba[i][BCOMP] = (GLchan) b;
+ rgba[i][ACOMP] = (GLchan) a;
+ }
+ }
+}
+
+
+
+/*
+ * General case blend pixels.
+ * Input: n - number of pixels
+ * mask - the usual write mask
+ * In/Out: rgba - the incoming and modified pixels
+ * Input: dest - the pixels from the dest color buffer
+ */
+static void _BLENDAPI
+blend_general( GLcontext *ctx, GLuint n, const GLubyte mask[],
+ GLchan rgba[][4], CONST GLchan dest[][4] )
+{
+ GLfloat rscale = 1.0F / CHAN_MAXF;
+ GLfloat gscale = 1.0F / CHAN_MAXF;
+ GLfloat bscale = 1.0F / CHAN_MAXF;
+ GLfloat ascale = 1.0F / CHAN_MAXF;
+ GLuint i;
+
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLint Rs, Gs, Bs, As; /* Source colors */
+ GLint Rd, Gd, Bd, Ad; /* Dest colors */
+ GLfloat sR, sG, sB, sA; /* Source scaling */
+ GLfloat dR, dG, dB, dA; /* Dest scaling */
+ GLfloat r, g, b, a;
+
+ /* Source Color */
+ Rs = rgba[i][RCOMP];
+ Gs = rgba[i][GCOMP];
+ Bs = rgba[i][BCOMP];
+ As = rgba[i][ACOMP];
+
+ /* Frame buffer color */
+ Rd = dest[i][RCOMP];
+ Gd = dest[i][GCOMP];
+ Bd = dest[i][BCOMP];
+ Ad = dest[i][ACOMP];
+
+ /* Source RGB factor */
+ switch (ctx->Color.BlendSrcRGB) {
+ case GL_ZERO:
+ sR = sG = sB = 0.0F;
+ break;
+ case GL_ONE:
+ sR = sG = sB = 1.0F;
+ break;
+ case GL_DST_COLOR:
+ sR = (GLfloat) Rd * rscale;
+ sG = (GLfloat) Gd * gscale;
+ sB = (GLfloat) Bd * bscale;
+ break;
+ case GL_ONE_MINUS_DST_COLOR:
+ sR = 1.0F - (GLfloat) Rd * rscale;
+ sG = 1.0F - (GLfloat) Gd * gscale;
+ sB = 1.0F - (GLfloat) Bd * bscale;
+ break;
+ case GL_SRC_ALPHA:
+ sR = sG = sB = (GLfloat) As * ascale;
+ break;
+ case GL_ONE_MINUS_SRC_ALPHA:
+ sR = sG = sB = (GLfloat) 1.0F - (GLfloat) As * ascale;
+ break;
+ case GL_DST_ALPHA:
+ sR = sG = sB = (GLfloat) Ad * ascale;
+ break;
+ case GL_ONE_MINUS_DST_ALPHA:
+ sR = sG = sB = 1.0F - (GLfloat) Ad * ascale;
+ break;
+ case GL_SRC_ALPHA_SATURATE:
+ if (As < CHAN_MAX - Ad) {
+ sR = sG = sB = (GLfloat) As * ascale;
+ }
+ else {
+ sR = sG = sB = 1.0F - (GLfloat) Ad * ascale;
+ }
+ break;
+ case GL_CONSTANT_COLOR:
+ sR = ctx->Color.BlendColor[0];
+ sG = ctx->Color.BlendColor[1];
+ sB = ctx->Color.BlendColor[2];
+ break;
+ case GL_ONE_MINUS_CONSTANT_COLOR:
+ sR = 1.0F - ctx->Color.BlendColor[0];
+ sG = 1.0F - ctx->Color.BlendColor[1];
+ sB = 1.0F - ctx->Color.BlendColor[2];
+ break;
+ case GL_CONSTANT_ALPHA:
+ sR = sG = sB = ctx->Color.BlendColor[3];
+ break;
+ case GL_ONE_MINUS_CONSTANT_ALPHA:
+ sR = sG = sB = 1.0F - ctx->Color.BlendColor[3];
+ break;
+ case GL_SRC_COLOR: /* GL_NV_blend_square */
+ sR = (GLfloat) Rs * rscale;
+ sG = (GLfloat) Gs * gscale;
+ sB = (GLfloat) Bs * bscale;
+ break;
+ case GL_ONE_MINUS_SRC_COLOR: /* GL_NV_blend_square */
+ sR = 1.0F - (GLfloat) Rs * rscale;
+ sG = 1.0F - (GLfloat) Gs * gscale;
+ sB = 1.0F - (GLfloat) Bs * bscale;
+ break;
+ default:
+ /* this should never happen */
+ gl_problem(ctx, "Bad blend source RGB factor in do_blend");
+ return;
+ }
+
+ /* Source Alpha factor */
+ switch (ctx->Color.BlendSrcA) {
+ case GL_ZERO:
+ sA = 0.0F;
+ break;
+ case GL_ONE:
+ sA = 1.0F;
+ break;
+ case GL_DST_COLOR:
+ sA = (GLfloat) Ad * ascale;
+ break;
+ case GL_ONE_MINUS_DST_COLOR:
+ sA = 1.0F - (GLfloat) Ad * ascale;
+ break;
+ case GL_SRC_ALPHA:
+ sA = (GLfloat) As * ascale;
+ break;
+ case GL_ONE_MINUS_SRC_ALPHA:
+ sA = (GLfloat) 1.0F - (GLfloat) As * ascale;
+ break;
+ case GL_DST_ALPHA:
+ sA =(GLfloat) Ad * ascale;
+ break;
+ case GL_ONE_MINUS_DST_ALPHA:
+ sA = 1.0F - (GLfloat) Ad * ascale;
+ break;
+ case GL_SRC_ALPHA_SATURATE:
+ sA = 1.0;
+ break;
+ case GL_CONSTANT_COLOR:
+ sA = ctx->Color.BlendColor[3];
+ break;
+ case GL_ONE_MINUS_CONSTANT_COLOR:
+ sA = 1.0F - ctx->Color.BlendColor[3];
+ break;
+ case GL_CONSTANT_ALPHA:
+ sA = ctx->Color.BlendColor[3];
+ break;
+ case GL_ONE_MINUS_CONSTANT_ALPHA:
+ sA = 1.0F - ctx->Color.BlendColor[3];
+ break;
+ case GL_SRC_COLOR: /* GL_NV_blend_square */
+ sA = (GLfloat) As * ascale;
+ break;
+ case GL_ONE_MINUS_SRC_COLOR: /* GL_NV_blend_square */
+ sA = 1.0F - (GLfloat) As * ascale;
+ break;
+ default:
+ /* this should never happen */
+ sA = 0.0F;
+ gl_problem(ctx, "Bad blend source A factor in do_blend");
+ }
+
+ /* Dest RGB factor */
+ switch (ctx->Color.BlendDstRGB) {
+ case GL_ZERO:
+ dR = dG = dB = 0.0F;
+ break;
+ case GL_ONE:
+ dR = dG = dB = 1.0F;
+ break;
+ case GL_SRC_COLOR:
+ dR = (GLfloat) Rs * rscale;
+ dG = (GLfloat) Gs * gscale;
+ dB = (GLfloat) Bs * bscale;
+ break;
+ case GL_ONE_MINUS_SRC_COLOR:
+ dR = 1.0F - (GLfloat) Rs * rscale;
+ dG = 1.0F - (GLfloat) Gs * gscale;
+ dB = 1.0F - (GLfloat) Bs * bscale;
+ break;
+ case GL_SRC_ALPHA:
+ dR = dG = dB = (GLfloat) As * ascale;
+ break;
+ case GL_ONE_MINUS_SRC_ALPHA:
+ dR = dG = dB = (GLfloat) 1.0F - (GLfloat) As * ascale;
+ break;
+ case GL_DST_ALPHA:
+ dR = dG = dB = (GLfloat) Ad * ascale;
+ break;
+ case GL_ONE_MINUS_DST_ALPHA:
+ dR = dG = dB = 1.0F - (GLfloat) Ad * ascale;
+ break;
+ case GL_CONSTANT_COLOR:
+ dR = ctx->Color.BlendColor[0];
+ dG = ctx->Color.BlendColor[1];
+ dB = ctx->Color.BlendColor[2];
+ break;
+ case GL_ONE_MINUS_CONSTANT_COLOR:
+ dR = 1.0F - ctx->Color.BlendColor[0];
+ dG = 1.0F - ctx->Color.BlendColor[1];
+ dB = 1.0F - ctx->Color.BlendColor[2];
+ break;
+ case GL_CONSTANT_ALPHA:
+ dR = dG = dB = ctx->Color.BlendColor[3];
+ break;
+ case GL_ONE_MINUS_CONSTANT_ALPHA:
+ dR = dG = dB = 1.0F - ctx->Color.BlendColor[3];
+ break;
+ case GL_DST_COLOR: /* GL_NV_blend_square */
+ dR = (GLfloat) Rd * rscale;
+ dG = (GLfloat) Gd * gscale;
+ dB = (GLfloat) Bd * bscale;
+ break;
+ case GL_ONE_MINUS_DST_COLOR: /* GL_NV_blend_square */
+ dR = 1.0F - (GLfloat) Rd * rscale;
+ dG = 1.0F - (GLfloat) Gd * gscale;
+ dB = 1.0F - (GLfloat) Bd * bscale;
+ break;
+ default:
+ /* this should never happen */
+ dR = dG = dB = 0.0F;
+ gl_problem(ctx, "Bad blend dest RGB factor in do_blend");
+ }
+
+ /* Dest Alpha factor */
+ switch (ctx->Color.BlendDstA) {
+ case GL_ZERO:
+ dA = 0.0F;
+ break;
+ case GL_ONE:
+ dA = 1.0F;
+ break;
+ case GL_SRC_COLOR:
+ dA = (GLfloat) As * ascale;
+ break;
+ case GL_ONE_MINUS_SRC_COLOR:
+ dA = 1.0F - (GLfloat) As * ascale;
+ break;
+ case GL_SRC_ALPHA:
+ dA = (GLfloat) As * ascale;
+ break;
+ case GL_ONE_MINUS_SRC_ALPHA:
+ dA = (GLfloat) 1.0F - (GLfloat) As * ascale;
+ break;
+ case GL_DST_ALPHA:
+ dA = (GLfloat) Ad * ascale;
+ break;
+ case GL_ONE_MINUS_DST_ALPHA:
+ dA = 1.0F - (GLfloat) Ad * ascale;
+ break;
+ case GL_CONSTANT_COLOR:
+ dA = ctx->Color.BlendColor[3];
+ break;
+ case GL_ONE_MINUS_CONSTANT_COLOR:
+ dA = 1.0F - ctx->Color.BlendColor[3];
+ break;
+ case GL_CONSTANT_ALPHA:
+ dA = ctx->Color.BlendColor[3];
+ break;
+ case GL_ONE_MINUS_CONSTANT_ALPHA:
+ dA = 1.0F - ctx->Color.BlendColor[3];
+ break;
+ case GL_DST_COLOR: /* GL_NV_blend_square */
+ dA = (GLfloat) Ad * ascale;
+ break;
+ case GL_ONE_MINUS_DST_COLOR: /* GL_NV_blend_square */
+ dA = 1.0F - (GLfloat) Ad * ascale;
+ break;
+ default:
+ /* this should never happen */
+ dA = 0.0F;
+ gl_problem(ctx, "Bad blend dest A factor in do_blend");
+ return;
+ }
+
+ /* Due to round-off problems we have to clamp against zero. */
+ /* Optimization: we don't have to do this for all src & dst factors */
+ if (dA < 0.0F) dA = 0.0F;
+ if (dR < 0.0F) dR = 0.0F;
+ if (dG < 0.0F) dG = 0.0F;
+ if (dB < 0.0F) dB = 0.0F;
+ if (sA < 0.0F) sA = 0.0F;
+ if (sR < 0.0F) sR = 0.0F;
+ if (sG < 0.0F) sG = 0.0F;
+ if (sB < 0.0F) sB = 0.0F;
+
+ ASSERT( sR <= 1.0 );
+ ASSERT( sG <= 1.0 );
+ ASSERT( sB <= 1.0 );
+ ASSERT( sA <= 1.0 );
+ ASSERT( dR <= 1.0 );
+ ASSERT( dG <= 1.0 );
+ ASSERT( dB <= 1.0 );
+ ASSERT( dA <= 1.0 );
+
+ /* compute blended color */
+ if (ctx->Color.BlendEquation==GL_FUNC_ADD_EXT) {
+ r = Rs * sR + Rd * dR + 0.5F;
+ g = Gs * sG + Gd * dG + 0.5F;
+ b = Bs * sB + Bd * dB + 0.5F;
+ a = As * sA + Ad * dA + 0.5F;
+ }
+ else if (ctx->Color.BlendEquation==GL_FUNC_SUBTRACT_EXT) {
+ r = Rs * sR - Rd * dR + 0.5F;
+ g = Gs * sG - Gd * dG + 0.5F;
+ b = Bs * sB - Bd * dB + 0.5F;
+ a = As * sA - Ad * dA + 0.5F;
+ }
+ else if (ctx->Color.BlendEquation==GL_FUNC_REVERSE_SUBTRACT_EXT) {
+ r = Rd * dR - Rs * sR + 0.5F;
+ g = Gd * dG - Gs * sG + 0.5F;
+ b = Bd * dB - Bs * sB + 0.5F;
+ a = Ad * dA - As * sA + 0.5F;
+ }
+ else {
+ /* should never get here */
+ r = g = b = a = 0.0F; /* silence uninitialized var warning */
+ gl_problem(ctx, "unexpected BlendEquation in blend_general()");
+ }
+
+ /* final clamping */
+ rgba[i][RCOMP] = (GLchan) (GLint) CLAMP( r, 0.0F, CHAN_MAXF );
+ rgba[i][GCOMP] = (GLchan) (GLint) CLAMP( g, 0.0F, CHAN_MAXF );
+ rgba[i][BCOMP] = (GLchan) (GLint) CLAMP( b, 0.0F, CHAN_MAXF );
+ rgba[i][ACOMP] = (GLchan) (GLint) CLAMP( a, 0.0F, CHAN_MAXF );
+ }
+ }
+}
+
+
+
+#if defined(USE_MMX_ASM)
+#include "X86/mmx.h"
+#include "X86/common_x86_asm.h"
+#endif
+
+
+/*
+ * Analyze current blending parameters to pick fastest blending function.
+ * Result: the ctx->Color.BlendFunc pointer is updated.
+ */
+static void set_blend_function( GLcontext *ctx )
+{
+ const GLenum eq = ctx->Color.BlendEquation;
+ const GLenum srcRGB = ctx->Color.BlendSrcRGB;
+ const GLenum dstRGB = ctx->Color.BlendDstRGB;
+ const GLenum srcA = ctx->Color.BlendSrcA;
+ const GLenum dstA = ctx->Color.BlendDstA;
+
+#if defined(USE_MMX_ASM)
+ /* Hmm. A table here would have 12^4 == way too many entries.
+ * Provide a hook for MMX instead.
+ */
+ if ( cpu_has_mmx ) {
+ gl_mmx_set_blend_function( ctx );
+ }
+ else
+#endif
+ if (srcRGB != srcA || dstRGB != dstA) {
+ ctx->Color.BlendFunc = blend_general;
+ }
+ else if (eq==GL_FUNC_ADD_EXT && srcRGB==GL_SRC_ALPHA
+ && dstRGB==GL_ONE_MINUS_SRC_ALPHA) {
+ ctx->Color.BlendFunc = blend_transparency;
+ }
+ else if (eq==GL_FUNC_ADD_EXT && srcRGB==GL_ONE && dstRGB==GL_ONE) {
+ ctx->Color.BlendFunc = blend_add;
+ }
+ else if (((eq==GL_FUNC_ADD_EXT || eq==GL_FUNC_REVERSE_SUBTRACT_EXT)
+ && (srcRGB==GL_ZERO && dstRGB==GL_SRC_COLOR))
+ ||
+ ((eq==GL_FUNC_ADD_EXT || eq==GL_FUNC_SUBTRACT_EXT)
+ && (srcRGB==GL_DST_COLOR && dstRGB==GL_ZERO))) {
+ ctx->Color.BlendFunc = blend_modulate;
+ }
+ else if (eq==GL_MIN_EXT) {
+ ctx->Color.BlendFunc = blend_min;
+ }
+ else if (eq==GL_MAX_EXT) {
+ ctx->Color.BlendFunc = blend_max;
+ }
+ else {
+ ctx->Color.BlendFunc = blend_general;
+ }
+}
+
+
+
+/*
+ * Apply the blending operator to a span of pixels.
+ * Input: n - number of pixels in span
+ * x, y - location of leftmost pixel in span in window coords.
+ * mask - boolean mask indicating which pixels to blend.
+ * In/Out: rgba - pixel values
+ */
+void
+_mesa_blend_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
+ GLchan rgba[][4], const GLubyte mask[] )
+{
+ GLchan dest[MAX_WIDTH][4];
+
+ /* Check if device driver can do the work */
+ if (ctx->Color.BlendEquation==GL_LOGIC_OP &&
+ !ctx->Color.ColorLogicOpEnabled) {
+ return;
+ }
+
+ /* Read span of current frame buffer pixels */
+ gl_read_rgba_span( ctx, ctx->DrawBuffer, n, x, y, dest );
+
+ if (!ctx->Color.BlendFunc)
+ set_blend_function(ctx);
+
+ (*ctx->Color.BlendFunc)( ctx, n, mask, rgba, (const GLchan (*)[4])dest );
+}
+
+
+
+/*
+ * Apply the blending operator to an array of pixels.
+ * Input: n - number of pixels in span
+ * x, y - array of pixel locations
+ * mask - boolean mask indicating which pixels to blend.
+ * In/Out: rgba - pixel values
+ */
+void
+_mesa_blend_pixels( GLcontext *ctx,
+ GLuint n, const GLint x[], const GLint y[],
+ GLchan rgba[][4], const GLubyte mask[] )
+{
+ GLchan dest[PB_SIZE][4];
+
+ /* Check if device driver can do the work */
+ if (ctx->Color.BlendEquation==GL_LOGIC_OP &&
+ !ctx->Color.ColorLogicOpEnabled) {
+ return;
+ }
+
+ /* Read pixels from current color buffer */
+ (*ctx->Driver.ReadRGBAPixels)( ctx, n, x, y, dest, mask );
+ if (ctx->RasterMask & ALPHABUF_BIT) {
+ _mesa_read_alpha_pixels( ctx, n, x, y, dest, mask );
+ }
+
+ if (!ctx->Color.BlendFunc)
+ set_blend_function(ctx);
+
+ (*ctx->Color.BlendFunc)( ctx, n, mask, rgba, (const GLchan (*)[4])dest );
+}
diff --git a/src/mesa/swrast/s_blend.h b/src/mesa/swrast/s_blend.h
new file mode 100644
index 0000000000..45c32f9088
--- /dev/null
+++ b/src/mesa/swrast/s_blend.h
@@ -0,0 +1,49 @@
+/* $Id: s_blend.h,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.
+ */
+
+
+#ifndef S_BLEND_H
+#define S_BLEND_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+
+extern void
+_mesa_blend_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
+ GLchan rgba[][4], const GLubyte mask[] );
+
+
+extern void
+_mesa_blend_pixels( GLcontext *ctx,
+ GLuint n, const GLint x[], const GLint y[],
+ GLchan rgba[][4], const GLubyte mask[] );
+
+
+
+#endif
diff --git a/src/mesa/swrast/s_buffers.c b/src/mesa/swrast/s_buffers.c
new file mode 100644
index 0000000000..b62198f091
--- /dev/null
+++ b/src/mesa/swrast/s_buffers.c
@@ -0,0 +1,257 @@
+/* $Id: s_buffers.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.
+ */
+
+
+#include "glheader.h"
+#include "macros.h"
+#include "mem.h"
+
+#include "s_accum.h"
+#include "s_alphabuf.h"
+#include "s_depth.h"
+#include "s_masking.h"
+#include "s_stencil.h"
+
+
+
+
+/*
+ * Clear the color buffer when glColorMask or glIndexMask is in effect.
+ */
+static void
+clear_color_buffer_with_masking( GLcontext *ctx )
+{
+ const GLint x = ctx->DrawBuffer->Xmin;
+ const GLint y = ctx->DrawBuffer->Ymin;
+ const GLint height = ctx->DrawBuffer->Ymax - ctx->DrawBuffer->Ymin;
+ const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin;
+
+ if (ctx->Visual.RGBAflag) {
+ /* RGBA mode */
+ const GLchan r = (GLint) (ctx->Color.ClearColor[0] * CHAN_MAXF);
+ const GLchan g = (GLint) (ctx->Color.ClearColor[1] * CHAN_MAXF);
+ const GLchan b = (GLint) (ctx->Color.ClearColor[2] * CHAN_MAXF);
+ const GLchan a = (GLint) (ctx->Color.ClearColor[3] * CHAN_MAXF);
+ GLint i;
+ for (i = 0; i < height; i++) {
+ GLchan rgba[MAX_WIDTH][4];
+ GLint j;
+ for (j=0; j<width; j++) {
+ rgba[j][RCOMP] = r;
+ rgba[j][GCOMP] = g;
+ rgba[j][BCOMP] = b;
+ rgba[j][ACOMP] = a;
+ }
+ _mesa_mask_rgba_span( ctx, width, x, y + i, rgba );
+ (*ctx->Driver.WriteRGBASpan)( ctx, width, x, y + i,
+ (CONST GLchan (*)[4]) rgba, NULL );
+ }
+ }
+ else {
+ /* Color index mode */
+ GLuint span[MAX_WIDTH];
+ GLubyte mask[MAX_WIDTH];
+ GLint i, j;
+ MEMSET( mask, 1, width );
+ for (i=0;i<height;i++) {
+ for (j=0;j<width;j++) {
+ span[j] = ctx->Color.ClearIndex;
+ }
+ _mesa_mask_index_span( ctx, width, x, y + i, span );
+ (*ctx->Driver.WriteCI32Span)( ctx, width, x, y + i, span, mask );
+ }
+ }
+}
+
+
+
+/*
+ * Clear a color buffer without index/channel masking.
+ */
+static void
+clear_color_buffer(GLcontext *ctx)
+{
+ const GLint x = ctx->DrawBuffer->Xmin;
+ const GLint y = ctx->DrawBuffer->Ymin;
+ const GLint height = ctx->DrawBuffer->Ymax - ctx->DrawBuffer->Ymin;
+ const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin;
+
+ if (ctx->Visual.RGBAflag) {
+ /* RGBA mode */
+ const GLchan r = (GLint) (ctx->Color.ClearColor[0] * CHAN_MAXF);
+ const GLchan g = (GLint) (ctx->Color.ClearColor[1] * CHAN_MAXF);
+ const GLchan b = (GLint) (ctx->Color.ClearColor[2] * CHAN_MAXF);
+ const GLchan a = (GLint) (ctx->Color.ClearColor[3] * CHAN_MAXF);
+ GLchan span[MAX_WIDTH][4];
+ GLint i;
+
+ ASSERT(*((GLuint *) &ctx->Color.ColorMask) == 0xffffffff);
+
+ for (i = 0; i < width; i++) {
+ span[i][RCOMP] = r;
+ span[i][GCOMP] = g;
+ span[i][BCOMP] = b;
+ span[i][ACOMP] = a;
+ }
+ for (i = 0; i < height; i++) {
+ (*ctx->Driver.WriteRGBASpan)( ctx, width, x, y + i,
+ (CONST GLchan (*)[4]) span, NULL );
+ }
+ }
+ else {
+ /* Color index mode */
+ ASSERT(ctx->Color.IndexMask == ~0);
+ if (ctx->Visual.IndexBits == 8) {
+ /* 8-bit clear */
+ GLubyte span[MAX_WIDTH];
+ GLint i;
+ MEMSET(span, ctx->Color.ClearIndex, width);
+ for (i = 0; i < height; i++) {
+ (*ctx->Driver.WriteCI8Span)( ctx, width, x, y + i, span, NULL );
+ }
+ }
+ else {
+ /* non 8-bit clear */
+ GLuint span[MAX_WIDTH];
+ GLint i;
+ for (i = 0; i < width; i++) {
+ span[i] = ctx->Color.ClearIndex;
+ }
+ for (i = 0; i < height; i++) {
+ (*ctx->Driver.WriteCI32Span)( ctx, width, x, y + i, span, NULL );
+ }
+ }
+ }
+}
+
+
+
+/*
+ * Clear the front/back/left/right color buffers.
+ * This function is usually only called if we need to clear the
+ * buffers with masking.
+ */
+static void
+clear_color_buffers(GLcontext *ctx)
+{
+ const GLuint colorMask = *((GLuint *) &ctx->Color.ColorMask);
+ GLuint bufferBit;
+
+ /* loop over four possible dest color buffers */
+ for (bufferBit = 1; bufferBit <= 8; bufferBit = bufferBit << 1) {
+ if (bufferBit & ctx->Color.DrawDestMask) {
+ if (bufferBit == FRONT_LEFT_BIT) {
+ (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_LEFT);
+ (void) (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer, GL_FRONT_LEFT);
+ }
+ else if (bufferBit == FRONT_RIGHT_BIT) {
+ (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_RIGHT);
+ (void) (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer, GL_FRONT_RIGHT);
+ }
+ else if (bufferBit == BACK_LEFT_BIT) {
+ (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_LEFT);
+ (void) (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer, GL_BACK_LEFT);
+ }
+ else {
+ (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_RIGHT);
+ (void) (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer, GL_BACK_RIGHT);
+ }
+
+ if (colorMask != 0xffffffff) {
+ clear_color_buffer_with_masking(ctx);
+ }
+ else {
+ clear_color_buffer(ctx);
+ }
+ }
+ }
+
+ /* restore default read/draw buffers */
+ (void) (*ctx->Driver.SetDrawBuffer)( ctx, ctx->Color.DriverDrawBuffer );
+ (void) (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer, ctx->Pixel.DriverReadBuffer );
+}
+
+
+
+void
+_swrast_Clear( GLcontext *ctx, GLbitfield mask,
+ GLboolean all,
+ GLint x, GLint y, GLint width, GLint height )
+{
+
+#ifdef DEBUG
+ {
+ GLbitfield legalBits = DD_FRONT_LEFT_BIT |
+ DD_FRONT_RIGHT_BIT |
+ DD_BACK_LEFT_BIT |
+ DD_BACK_RIGHT_BIT |
+ DD_DEPTH_BIT |
+ DD_STENCIL_BIT |
+ DD_ACCUM_BIT;
+ assert((mask & (~legalBits)) == 0);
+ }
+#endif
+
+ RENDER_START(ctx);
+
+ /* do software clearing here */
+ if (mask) {
+ if (mask & ctx->Color.DrawDestMask) clear_color_buffers(ctx);
+ if (mask & GL_DEPTH_BUFFER_BIT) _mesa_clear_depth_buffer(ctx);
+ if (mask & GL_ACCUM_BUFFER_BIT) _mesa_clear_accum_buffer(ctx);
+ if (mask & GL_STENCIL_BUFFER_BIT) _mesa_clear_stencil_buffer(ctx);
+ }
+
+ /* clear software-based alpha buffer(s) */
+ if ( (mask & GL_COLOR_BUFFER_BIT)
+ && ctx->DrawBuffer->UseSoftwareAlphaBuffers
+ && ctx->Color.ColorMask[ACOMP]) {
+ _mesa_clear_alpha_buffers( ctx );
+ }
+
+ RENDER_FINISH(ctx);
+}
+
+
+void
+_swrast_alloc_buffers( GLcontext *ctx )
+{
+ /* Reallocate other buffers if needed. */
+ if (ctx->DrawBuffer->UseSoftwareDepthBuffer) {
+ _mesa_alloc_depth_buffer( ctx );
+ }
+ if (ctx->DrawBuffer->UseSoftwareStencilBuffer) {
+ _mesa_alloc_stencil_buffer( ctx );
+ }
+ if (ctx->DrawBuffer->UseSoftwareAccumBuffer) {
+ _mesa_alloc_accum_buffer( ctx );
+ }
+ if (ctx->DrawBuffer->UseSoftwareAlphaBuffers) {
+ _mesa_alloc_alpha_buffers( ctx );
+ }
+}
+
+
diff --git a/src/mesa/swrast/s_context.c b/src/mesa/swrast/s_context.c
new file mode 100644
index 0000000000..87a2001849
--- /dev/null
+++ b/src/mesa/swrast/s_context.c
@@ -0,0 +1,49 @@
+/* $Id: s_context.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999 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.
+ */
+
+
+#include "glheader.h"
+
+#include "s_pb.h"
+
+
+GLboolean
+_swrast_create_context( GLcontext *ctx )
+{
+ ctx->PB = gl_alloc_pb();
+ if (!ctx->PB) return GL_FALSE;
+
+ return GL_TRUE;
+}
+
+void
+_swrast_destroy_context( GLcontext *ctx )
+{
+}
+
+
+
+
diff --git a/src/mesa/swrast/s_copypix.c b/src/mesa/swrast/s_copypix.c
new file mode 100644
index 0000000000..eddfe39037
--- /dev/null
+++ b/src/mesa/swrast/s_copypix.c
@@ -0,0 +1,821 @@
+/* $Id: s_copypix.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.
+ */
+
+
+#include "glheader.h"
+#include "colormac.h"
+#include "context.h"
+#include "convolve.h"
+#include "feedback.h"
+#include "macros.h"
+#include "mem.h"
+#include "mmath.h"
+#include "pixel.h"
+
+#include "s_depth.h"
+#include "s_imaging.h"
+#include "s_pixeltex.h"
+#include "s_span.h"
+#include "s_stencil.h"
+#include "s_texture.h"
+#include "s_zoom.h"
+
+
+
+/*
+ * Determine if there's overlap in an image copy
+ */
+static GLboolean
+regions_overlap(int srcx, int srcy, int dstx, int dsty, int width, int height,
+ float zoomX, float zoomY)
+{
+ if ((srcx > dstx + (width * zoomX) + 1) || (srcx + width + 1 < dstx)) {
+ return GL_FALSE;
+ }
+ else if ((srcy < dsty) && (srcy + height < dsty + (height * zoomY))) {
+ return GL_FALSE;
+ }
+ else if ((srcy > dsty) && (srcy + height > dsty + (height * zoomY))) {
+ return GL_FALSE;
+ }
+ else {
+ return GL_TRUE;
+ }
+}
+
+
+
+/*
+ * RGBA copypixels with convolution.
+ */
+static void
+copy_conv_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
+ GLint width, GLint height, GLint destx, GLint desty)
+{
+ GLdepth zspan[MAX_WIDTH];
+ GLboolean quick_draw;
+ GLint row;
+ GLboolean changeBuffer;
+ GLchan *saveReadAlpha;
+ const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
+ const GLuint transferOps = ctx->ImageTransferState;
+ GLfloat *dest, *tmpImage, *convImage;
+
+ if (ctx->Depth.Test || ctx->Fog.Enabled) {
+ /* fill in array of z values */
+ GLdepth z = (GLdepth)
+ (ctx->Current.RasterPos[2] * ctx->Visual.DepthMax);
+ GLint i;
+ for (i = 0; i < width; i++) {
+ zspan[i] = z;
+ }
+ }
+
+ if (ctx->RasterMask == 0
+ && !zoom
+ && destx >= 0
+ && destx + width <= ctx->DrawBuffer->Width) {
+ quick_draw = GL_TRUE;
+ }
+ else {
+ quick_draw = GL_FALSE;
+ }
+
+ /* If read and draw buffer are different we must do buffer switching */
+ saveReadAlpha = ctx->ReadBuffer->Alpha;
+ changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer
+ || ctx->DrawBuffer != ctx->ReadBuffer;
+
+
+ /* allocate space for GLfloat image */
+ tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
+ if (!tmpImage) {
+ gl_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
+ return;
+ }
+ convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
+ if (!convImage) {
+ FREE(tmpImage);
+ gl_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
+ return;
+ }
+
+ dest = tmpImage;
+
+ if (changeBuffer) {
+ (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
+ ctx->Pixel.DriverReadBuffer );
+ if (ctx->Pixel.DriverReadBuffer == GL_FRONT_LEFT)
+ ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontLeftAlpha;
+ else if (ctx->Pixel.DriverReadBuffer == GL_BACK_LEFT)
+ ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackLeftAlpha;
+ else if (ctx->Pixel.DriverReadBuffer == GL_FRONT_RIGHT)
+ ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontRightAlpha;
+ else
+ ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackRightAlpha;
+ }
+
+ /* read source image */
+ dest = tmpImage;
+ for (row = 0; row < height; row++) {
+ GLchan rgba[MAX_WIDTH][4];
+ GLint i;
+ gl_read_rgba_span(ctx, ctx->ReadBuffer, width, srcx, srcy + row, rgba);
+ /* convert GLchan to GLfloat */
+ for (i = 0; i < width; i++) {
+ *dest++ = (GLfloat) rgba[i][RCOMP] * (1.0F / CHAN_MAXF);
+ *dest++ = (GLfloat) rgba[i][GCOMP] * (1.0F / CHAN_MAXF);
+ *dest++ = (GLfloat) rgba[i][BCOMP] * (1.0F / CHAN_MAXF);
+ *dest++ = (GLfloat) rgba[i][ACOMP] * (1.0F / CHAN_MAXF);
+ }
+ }
+
+ /* read from the draw buffer again (in case of blending) */
+ if (changeBuffer) {
+ (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
+ ctx->Color.DriverDrawBuffer );
+ ctx->ReadBuffer->Alpha = saveReadAlpha;
+ }
+
+ /* do image transfer ops up until convolution */
+ for (row = 0; row < height; row++) {
+ GLfloat (*rgba)[4] = (GLfloat (*)[4]) tmpImage + row * width * 4;
+
+ /* scale & bias */
+ if (transferOps & IMAGE_SCALE_BIAS_BIT) {
+ _mesa_scale_and_bias_rgba(ctx, width, rgba);
+ }
+ /* color map lookup */
+ if (transferOps & IMAGE_MAP_COLOR_BIT) {
+ _mesa_map_rgba(ctx, width, rgba);
+ }
+ /* GL_COLOR_TABLE lookup */
+ if (transferOps & IMAGE_COLOR_TABLE_BIT) {
+ _mesa_lookup_rgba(&ctx->ColorTable, width, rgba);
+ }
+ }
+
+ /* do convolution */
+ if (ctx->Pixel.Convolution2DEnabled) {
+ _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
+ }
+ else {
+ ASSERT(ctx->Pixel.Separable2DEnabled);
+ _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
+ }
+ FREE(tmpImage);
+
+ /* do remaining image transfer ops */
+ for (row = 0; row < height; row++) {
+ GLfloat (*rgba)[4] = (GLfloat (*)[4]) convImage + row * width * 4;
+
+ /* GL_POST_CONVOLUTION_COLOR_TABLE lookup */
+ if (transferOps & IMAGE_POST_CONVOLUTION_COLOR_TABLE_BIT) {
+ _mesa_lookup_rgba(&ctx->PostConvolutionColorTable, width, rgba);
+ }
+ /* color matrix */
+ if (transferOps & IMAGE_COLOR_MATRIX_BIT) {
+ _mesa_transform_rgba(ctx, width, rgba);
+ }
+ /* GL_POST_COLOR_MATRIX_COLOR_TABLE lookup */
+ if (transferOps & IMAGE_POST_COLOR_MATRIX_COLOR_TABLE_BIT) {
+ _mesa_lookup_rgba(&ctx->PostColorMatrixColorTable, width, rgba);
+ }
+ /* update histogram count */
+ if (transferOps & IMAGE_HISTOGRAM_BIT) {
+ _mesa_update_histogram(ctx, width, (CONST GLfloat (*)[4]) rgba);
+ }
+ /* update min/max */
+ if (transferOps & IMAGE_MIN_MAX_BIT) {
+ _mesa_update_minmax(ctx, width, (CONST GLfloat (*)[4]) rgba);
+ }
+ }
+
+ for (row = 0; row < height; row++) {
+ const GLfloat *src = convImage + row * width * 4;
+ GLchan rgba[MAX_WIDTH][4];
+ GLint i, dy;
+
+ /* clamp to [0,1] and convert float back to chan */
+ for (i = 0; i < width; i++) {
+ GLint r = (GLint) (src[i * 4 + RCOMP] * CHAN_MAXF);
+ GLint g = (GLint) (src[i * 4 + GCOMP] * CHAN_MAXF);
+ GLint b = (GLint) (src[i * 4 + BCOMP] * CHAN_MAXF);
+ GLint a = (GLint) (src[i * 4 + ACOMP] * CHAN_MAXF);
+ rgba[i][RCOMP] = (GLchan) CLAMP(r, 0, CHAN_MAX);
+ rgba[i][GCOMP] = (GLchan) CLAMP(g, 0, CHAN_MAX);
+ rgba[i][BCOMP] = (GLchan) CLAMP(b, 0, CHAN_MAX);
+ rgba[i][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX);
+ }
+
+ if (ctx->Texture.ReallyEnabled && ctx->Pixel.PixelTextureEnabled) {
+ GLfloat s[MAX_WIDTH], t[MAX_WIDTH], r[MAX_WIDTH], q[MAX_WIDTH];
+ GLchan primary_rgba[MAX_WIDTH][4];
+ GLuint unit;
+ /* XXX not sure how multitexture is supposed to work here */
+
+ MEMCPY(primary_rgba, rgba, 4 * width * sizeof(GLchan));
+
+ for (unit = 0; unit < MAX_TEXTURE_UNITS; unit++) {
+ _mesa_pixeltexgen(ctx, width, (const GLchan (*)[4]) rgba,
+ s, t, r, q);
+ gl_texture_pixels(ctx, unit, width, s, t, r, NULL,
+ primary_rgba, rgba);
+ }
+ }
+
+ /* write row to framebuffer */
+
+ dy = desty + row;
+ if (quick_draw && dy >= 0 && dy < ctx->DrawBuffer->Height) {
+ (*ctx->Driver.WriteRGBASpan)( ctx, width, destx, dy,
+ (const GLchan (*)[4])rgba, NULL );
+ }
+ else if (zoom) {
+ gl_write_zoomed_rgba_span( ctx, width, destx, dy, zspan, 0,
+ (const GLchan (*)[4])rgba, desty);
+ }
+ else {
+ gl_write_rgba_span( ctx, width, destx, dy, zspan, 0, rgba, GL_BITMAP );
+ }
+ }
+
+ FREE(convImage);
+}
+
+
+/*
+ * RGBA copypixels
+ */
+static void
+copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
+ GLint width, GLint height, GLint destx, GLint desty)
+{
+ GLdepth zspan[MAX_WIDTH];
+ GLchan rgba[MAX_WIDTH][4];
+ GLchan *tmpImage,*p;
+ GLboolean quick_draw;
+ GLint sy, dy, stepy;
+ GLint i, j;
+ GLboolean changeBuffer;
+ GLchan *saveReadAlpha;
+ const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
+ GLint overlapping;
+ const GLuint transferOps = ctx->ImageTransferState;
+
+ if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
+ copy_conv_rgba_pixels(ctx, srcx, srcy, width, height, destx, desty);
+ return;
+ }
+
+ /* Determine if copy should be done bottom-to-top or top-to-bottom */
+ if (srcy < desty) {
+ /* top-down max-to-min */
+ sy = srcy + height - 1;
+ dy = desty + height - 1;
+ stepy = -1;
+ }
+ else {
+ /* bottom-up min-to-max */
+ sy = srcy;
+ dy = desty;
+ stepy = 1;
+ }
+
+ overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
+ ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
+
+ if (ctx->Depth.Test || ctx->Fog.Enabled) {
+ /* fill in array of z values */
+ GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual.DepthMax);
+ for (i=0;i<width;i++) {
+ zspan[i] = z;
+ }
+ }
+
+ if (ctx->RasterMask == 0
+ && !zoom
+ && destx >= 0
+ && destx + width <= ctx->DrawBuffer->Width) {
+ quick_draw = GL_TRUE;
+ }
+ else {
+ quick_draw = GL_FALSE;
+ }
+
+ /* If read and draw buffer are different we must do buffer switching */
+ saveReadAlpha = ctx->ReadBuffer->Alpha;
+ changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer
+ || ctx->DrawBuffer != ctx->ReadBuffer;
+
+ if (overlapping) {
+ GLint ssy = sy;
+ tmpImage = (GLchan *) MALLOC(width * height * sizeof(GLchan) * 4);
+ if (!tmpImage) {
+ gl_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
+ return;
+ }
+ p = tmpImage;
+ if (changeBuffer) {
+ (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
+ ctx->Pixel.DriverReadBuffer );
+ if (ctx->Pixel.DriverReadBuffer == GL_FRONT_LEFT)
+ ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontLeftAlpha;
+ else if (ctx->Pixel.DriverReadBuffer == GL_BACK_LEFT)
+ ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackLeftAlpha;
+ else if (ctx->Pixel.DriverReadBuffer == GL_FRONT_RIGHT)
+ ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontRightAlpha;
+ else
+ ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackRightAlpha;
+ }
+ for (j = 0; j < height; j++, ssy += stepy) {
+ gl_read_rgba_span( ctx, ctx->ReadBuffer, width, srcx, ssy,
+ (GLchan (*)[4]) p );
+ p += (width * sizeof(GLchan) * 4);
+ }
+ p = tmpImage;
+ }
+ else {
+ tmpImage = NULL; /* silence compiler warnings */
+ p = NULL;
+ }
+
+ for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
+ /* Get source pixels */
+ if (overlapping) {
+ /* get from buffered image */
+ MEMCPY(rgba, p, width * sizeof(GLchan) * 4);
+ p += (width * sizeof(GLchan) * 4);
+ }
+ else {
+ /* get from framebuffer */
+ if (changeBuffer) {
+ (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
+ ctx->Pixel.DriverReadBuffer );
+ if (ctx->Pixel.DriverReadBuffer == GL_FRONT_LEFT) {
+ ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontLeftAlpha;
+ }
+ else if (ctx->Pixel.DriverReadBuffer == GL_BACK_LEFT) {
+ ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackLeftAlpha;
+ }
+ else if (ctx->Pixel.DriverReadBuffer == GL_FRONT_RIGHT) {
+ ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontRightAlpha;
+ }
+ else {
+ ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackRightAlpha;
+ }
+ }
+ gl_read_rgba_span( ctx, ctx->ReadBuffer, width, srcx, sy, rgba );
+ }
+
+ if (changeBuffer) {
+ /* read from the draw buffer again (in case of blending) */
+ (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
+ ctx->Color.DriverDrawBuffer );
+ ctx->ReadBuffer->Alpha = saveReadAlpha;
+ }
+
+ if (transferOps) {
+ const GLfloat scale = (1.0F / CHAN_MAXF);
+ GLfloat rgbaFloat[MAX_WIDTH][4];
+ GLuint k;
+ /* convert chan to float */
+ for (k = 0; k < width; k++) {
+ rgbaFloat[k][RCOMP] = (GLfloat) rgba[k][RCOMP] * scale;
+ rgbaFloat[k][GCOMP] = (GLfloat) rgba[k][GCOMP] * scale;
+ rgbaFloat[k][BCOMP] = (GLfloat) rgba[k][BCOMP] * scale;
+ rgbaFloat[k][ACOMP] = (GLfloat) rgba[k][ACOMP] * scale;
+ }
+ /* scale & bias */
+ if (transferOps & IMAGE_SCALE_BIAS_BIT) {
+ _mesa_scale_and_bias_rgba(ctx, width, rgbaFloat);
+ }
+ /* color map lookup */
+ if (transferOps & IMAGE_MAP_COLOR_BIT) {
+ _mesa_map_rgba(ctx, width, rgbaFloat);
+ }
+ /* GL_COLOR_TABLE lookup */
+ if (transferOps & IMAGE_COLOR_TABLE_BIT) {
+ _mesa_lookup_rgba(&ctx->ColorTable, width, rgbaFloat);
+ }
+ /* convolution */
+ if (transferOps & IMAGE_CONVOLUTION_BIT) {
+ /* XXX to do */
+ }
+ /* GL_POST_CONVOLUTION_COLOR_TABLE lookup */
+ if (transferOps & IMAGE_POST_CONVOLUTION_COLOR_TABLE_BIT) {
+ _mesa_lookup_rgba(&ctx->PostConvolutionColorTable, width, rgbaFloat);
+ }
+ /* color matrix */
+ if (transferOps & IMAGE_COLOR_MATRIX_BIT) {
+ _mesa_transform_rgba(ctx, width, rgbaFloat);
+ }
+ /* GL_POST_COLOR_MATRIX_COLOR_TABLE lookup */
+ if (transferOps & IMAGE_POST_COLOR_MATRIX_COLOR_TABLE_BIT) {
+ _mesa_lookup_rgba(&ctx->PostColorMatrixColorTable, width, rgbaFloat);
+ }
+ /* update histogram count */
+ if (transferOps & IMAGE_HISTOGRAM_BIT) {
+ _mesa_update_histogram(ctx, width, (CONST GLfloat (*)[4]) rgbaFloat);
+ }
+ /* update min/max */
+ if (transferOps & IMAGE_MIN_MAX_BIT) {
+ _mesa_update_minmax(ctx, width, (CONST GLfloat (*)[4]) rgbaFloat);
+ }
+ /* clamp to [0,1] and convert float back to chan */
+ for (k = 0; k < width; k++) {
+ GLint r = (GLint) (rgbaFloat[k][RCOMP] * CHAN_MAXF);
+ GLint g = (GLint) (rgbaFloat[k][GCOMP] * CHAN_MAXF);
+ GLint b = (GLint) (rgbaFloat[k][BCOMP] * CHAN_MAXF);
+ GLint a = (GLint) (rgbaFloat[k][ACOMP] * CHAN_MAXF);
+ rgba[k][RCOMP] = (GLchan) CLAMP(r, 0, CHAN_MAX);
+ rgba[k][GCOMP] = (GLchan) CLAMP(g, 0, CHAN_MAX);
+ rgba[k][BCOMP] = (GLchan) CLAMP(b, 0, CHAN_MAX);
+ rgba[k][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX);
+ }
+ }
+
+ if (ctx->Texture.ReallyEnabled && ctx->Pixel.PixelTextureEnabled) {
+ GLfloat s[MAX_WIDTH], t[MAX_WIDTH], r[MAX_WIDTH], q[MAX_WIDTH];
+ GLchan primary_rgba[MAX_WIDTH][4];
+ GLuint unit;
+ /* XXX not sure how multitexture is supposed to work here */
+
+ MEMCPY(primary_rgba, rgba, 4 * width * sizeof(GLchan));
+
+ for (unit = 0; unit < MAX_TEXTURE_UNITS; unit++) {
+ _mesa_pixeltexgen(ctx, width, (const GLchan (*)[4]) rgba,
+ s, t, r, q);
+ gl_texture_pixels(ctx, unit, width, s, t, r, NULL,
+ primary_rgba, rgba);
+ }
+ }
+
+ if (quick_draw && dy >= 0 && dy < ctx->DrawBuffer->Height) {
+ (*ctx->Driver.WriteRGBASpan)( ctx, width, destx, dy,
+ (const GLchan (*)[4])rgba, NULL );
+ }
+ else if (zoom) {
+ gl_write_zoomed_rgba_span( ctx, width, destx, dy, zspan, 0,
+ (const GLchan (*)[4])rgba, desty);
+ }
+ else {
+ gl_write_rgba_span( ctx, width, destx, dy, zspan, 0, rgba, GL_BITMAP );
+ }
+ }
+
+ if (overlapping)
+ FREE(tmpImage);
+}
+
+
+static void copy_ci_pixels( GLcontext *ctx,
+ GLint srcx, GLint srcy, GLint width, GLint height,
+ GLint destx, GLint desty )
+{
+ GLdepth zspan[MAX_WIDTH];
+ GLuint *tmpImage,*p;
+ GLint sy, dy, stepy;
+ GLint i, j;
+ GLboolean changeBuffer;
+ const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
+ const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset;
+ GLint overlapping;
+
+ /* Determine if copy should be bottom-to-top or top-to-bottom */
+ if (srcy<desty) {
+ /* top-down max-to-min */
+ sy = srcy + height - 1;
+ dy = desty + height - 1;
+ stepy = -1;
+ }
+ else {
+ /* bottom-up min-to-max */
+ sy = srcy;
+ dy = desty;
+ stepy = 1;
+ }
+
+ overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
+ ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
+
+ if (ctx->Depth.Test || ctx->Fog.Enabled) {
+ /* fill in array of z values */
+ GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual.DepthMax);
+ for (i=0;i<width;i++) {
+ zspan[i] = z;
+ }
+ }
+
+ /* If read and draw buffer are different we must do buffer switching */
+ changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer
+ || ctx->DrawBuffer != ctx->ReadBuffer;
+
+ if (overlapping) {
+ GLint ssy = sy;
+ tmpImage = (GLuint *) MALLOC(width * height * sizeof(GLuint));
+ if (!tmpImage) {
+ gl_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
+ return;
+ }
+ p = tmpImage;
+ if (changeBuffer) {
+ (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
+ ctx->Pixel.DriverReadBuffer );
+ }
+ for (j = 0; j < height; j++, ssy += stepy) {
+ gl_read_index_span( ctx, ctx->ReadBuffer, width, srcx, ssy, p );
+ p += width;
+ }
+ p = tmpImage;
+ }
+ else {
+ tmpImage = NULL; /* silence compiler warning */
+ p = NULL;
+ }
+
+ for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
+ GLuint indexes[MAX_WIDTH];
+ if (overlapping) {
+ MEMCPY(indexes, p, width * sizeof(GLuint));
+ p += width;
+ }
+ else {
+ if (changeBuffer) {
+ (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
+ ctx->Pixel.DriverReadBuffer );
+ }
+ gl_read_index_span( ctx, ctx->ReadBuffer, width, srcx, sy, indexes );
+ }
+
+ if (changeBuffer) {
+ /* set read buffer back to draw buffer (in case of logicops) */
+ (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
+ ctx->Color.DriverDrawBuffer );
+ }
+
+ if (shift_or_offset) {
+ _mesa_shift_and_offset_ci( ctx, width, indexes );
+ }
+ if (ctx->Pixel.MapColorFlag) {
+ _mesa_map_ci( ctx, width, indexes );
+ }
+
+ if (zoom) {
+ gl_write_zoomed_index_span( ctx, width, destx, dy, zspan, 0, indexes, desty );
+ }
+ else {
+ gl_write_index_span(ctx, width, destx, dy, zspan, 0, indexes, GL_BITMAP);
+ }
+ }
+
+ if (overlapping)
+ FREE(tmpImage);
+}
+
+
+
+/*
+ * TODO: Optimize!!!!
+ */
+static void copy_depth_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
+ GLint width, GLint height,
+ GLint destx, GLint desty )
+{
+ GLfloat depth[MAX_WIDTH];
+ GLdepth zspan[MAX_WIDTH];
+ GLfloat *p, *tmpImage;
+ GLuint indexes[MAX_WIDTH];
+ GLchan rgba[MAX_WIDTH][4];
+ GLint sy, dy, stepy;
+ GLint i, j;
+ const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
+ GLint overlapping;
+
+ if (!ctx->ReadBuffer->DepthBuffer || !ctx->DrawBuffer->DepthBuffer) {
+ gl_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" );
+ return;
+ }
+
+ /* Determine if copy should be bottom-to-top or top-to-bottom */
+ if (srcy<desty) {
+ /* top-down max-to-min */
+ sy = srcy + height - 1;
+ dy = desty + height - 1;
+ stepy = -1;
+ }
+ else {
+ /* bottom-up min-to-max */
+ sy = srcy;
+ dy = desty;
+ stepy = 1;
+ }
+
+ overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
+ ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
+
+ /* setup colors or indexes */
+ if (ctx->Visual.RGBAflag) {
+ GLuint *rgba32 = (GLuint *) rgba;
+ GLuint color = *(GLuint*)( ctx->Current.Color );
+ for (i = 0; i < width; i++) {
+ rgba32[i] = color;
+ }
+ }
+ else {
+ for (i = 0; i < width; i++) {
+ indexes[i] = ctx->Current.Index;
+ }
+ }
+
+ if (overlapping) {
+ GLint ssy = sy;
+ tmpImage = (GLfloat *) MALLOC(width * height * sizeof(GLfloat));
+ if (!tmpImage) {
+ gl_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
+ return;
+ }
+ p = tmpImage;
+ for (j = 0; j < height; j++, ssy += stepy) {
+ _mesa_read_depth_span_float(ctx, width, srcx, ssy, p);
+ p += width;
+ }
+ p = tmpImage;
+ }
+ else {
+ tmpImage = NULL; /* silence compiler warning */
+ p = NULL;
+ }
+
+ for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
+ if (overlapping) {
+ MEMCPY(depth, p, width * sizeof(GLfloat));
+ p += width;
+ }
+ else {
+ _mesa_read_depth_span_float(ctx, width, srcx, sy, depth);
+ }
+
+ for (i = 0; i < width; i++) {
+ GLfloat d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias;
+ zspan[i] = (GLdepth) (CLAMP(d, 0.0F, 1.0F) * ctx->Visual.DepthMax);
+ }
+
+ if (ctx->Visual.RGBAflag) {
+ if (zoom) {
+ gl_write_zoomed_rgba_span( ctx, width, destx, dy, zspan, 0,
+ (const GLchan (*)[4])rgba, desty );
+ }
+ else {
+ gl_write_rgba_span( ctx, width, destx, dy, zspan, 0,
+ rgba, GL_BITMAP);
+ }
+ }
+ else {
+ if (zoom) {
+ gl_write_zoomed_index_span( ctx, width, destx, dy,
+ zspan, 0, indexes, desty );
+ }
+ else {
+ gl_write_index_span( ctx, width, destx, dy,
+ zspan, 0, indexes, GL_BITMAP );
+ }
+ }
+ }
+
+ if (overlapping)
+ FREE(tmpImage);
+}
+
+
+
+static void copy_stencil_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
+ GLint width, GLint height,
+ GLint destx, GLint desty )
+{
+ GLint sy, dy, stepy;
+ GLint j;
+ GLstencil *p, *tmpImage;
+ const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
+ const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset;
+ GLint overlapping;
+
+ if (!ctx->DrawBuffer->Stencil || !ctx->ReadBuffer->Stencil) {
+ gl_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" );
+ return;
+ }
+
+ /* Determine if copy should be bottom-to-top or top-to-bottom */
+ if (srcy < desty) {
+ /* top-down max-to-min */
+ sy = srcy + height - 1;
+ dy = desty + height - 1;
+ stepy = -1;
+ }
+ else {
+ /* bottom-up min-to-max */
+ sy = srcy;
+ dy = desty;
+ stepy = 1;
+ }
+
+ overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
+ ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
+
+ if (overlapping) {
+ GLint ssy = sy;
+ tmpImage = (GLstencil *) MALLOC(width * height * sizeof(GLstencil));
+ if (!tmpImage) {
+ gl_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
+ return;
+ }
+ p = tmpImage;
+ for (j = 0; j < height; j++, ssy += stepy) {
+ _mesa_read_stencil_span( ctx, width, srcx, ssy, p );
+ p += width;
+ }
+ p = tmpImage;
+ }
+ else {
+ tmpImage = NULL; /* silence compiler warning */
+ p = NULL;
+ }
+
+ for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
+ GLstencil stencil[MAX_WIDTH];
+
+ if (overlapping) {
+ MEMCPY(stencil, p, width * sizeof(GLstencil));
+ p += width;
+ }
+ else {
+ _mesa_read_stencil_span( ctx, width, srcx, sy, stencil );
+ }
+
+ if (shift_or_offset) {
+ _mesa_shift_and_offset_stencil( ctx, width, stencil );
+ }
+ if (ctx->Pixel.MapStencilFlag) {
+ _mesa_map_stencil( ctx, width, stencil );
+ }
+
+ if (zoom) {
+ gl_write_zoomed_stencil_span( ctx, width, destx, dy, stencil, desty );
+ }
+ else {
+ _mesa_write_stencil_span( ctx, width, destx, dy, stencil );
+ }
+ }
+
+ if (overlapping)
+ FREE(tmpImage);
+}
+
+
+
+
+void
+_swrast_CopyPixels( GLcontext *ctx,
+ GLint srcx, GLint srcy, GLsizei width, GLsizei height,
+ GLint destx, GLint desty,
+ GLenum type )
+{
+ if (type == GL_COLOR && ctx->Visual.RGBAflag) {
+ copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty );
+ }
+ else if (type == GL_COLOR && !ctx->Visual.RGBAflag) {
+ copy_ci_pixels( ctx, srcx, srcy, width, height, destx, desty );
+ }
+ else if (type == GL_DEPTH) {
+ copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty );
+ }
+ else if (type == GL_STENCIL) {
+ copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty );
+ }
+ else {
+ gl_error( ctx, GL_INVALID_ENUM, "glCopyPixels" );
+ }
+}
diff --git a/src/mesa/swrast/s_depth.c b/src/mesa/swrast/s_depth.c
new file mode 100644
index 0000000000..e9dd63093c
--- /dev/null
+++ b/src/mesa/swrast/s_depth.c
@@ -0,0 +1,1632 @@
+/* $Id: s_depth.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ *
+ * 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.
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "macros.h"
+#include "mem.h"
+
+#include "s_depth.h"
+#include "s_pb.h"
+
+
+
+
+/*
+ * Return address of depth buffer value for given window coord.
+ */
+GLvoid *
+_mesa_zbuffer_address(GLcontext *ctx, GLint x, GLint y)
+{
+ if (ctx->Visual.DepthBits <= 16)
+ return (GLushort *) ctx->DrawBuffer->DepthBuffer + ctx->DrawBuffer->Width * y + x;
+ else
+ return (GLuint *) ctx->DrawBuffer->DepthBuffer + ctx->DrawBuffer->Width * y + x;
+}
+
+
+#define Z_ADDRESS16( CTX, X, Y ) \
+ ( ((GLushort *) (CTX)->DrawBuffer->DepthBuffer) \
+ + (CTX)->DrawBuffer->Width * (Y) + (X) )
+
+#define Z_ADDRESS32( CTX, X, Y ) \
+ ( ((GLuint *) (CTX)->DrawBuffer->DepthBuffer) \
+ + (CTX)->DrawBuffer->Width * (Y) + (X) )
+
+
+
+/**********************************************************************/
+/***** Depth Testing Functions *****/
+/**********************************************************************/
+
+
+/*
+ * Do depth test for an array of fragments. This is used both for
+ * software and hardware Z buffers.
+ * Input: zbuffer - array of z values in the zbuffer
+ * z - array of fragment z values
+ * Return: number of fragments which pass the test.
+ */
+static GLuint
+depth_test_span16( GLcontext *ctx, GLuint n, GLint x, GLint y,
+ GLushort zbuffer[], const GLdepth z[], GLubyte mask[] )
+{
+ GLuint passed = 0;
+
+ /* switch cases ordered from most frequent to less frequent */
+ switch (ctx->Depth.Func) {
+ case GL_LESS:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ if (z[i] < zbuffer[i]) {
+ /* pass */
+ zbuffer[i] = z[i];
+ passed++;
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ if (z[i] < zbuffer[i]) {
+ /* pass */
+ passed++;
+ }
+ else {
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_LEQUAL:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ if (z[i] <= zbuffer[i]) {
+ zbuffer[i] = z[i];
+ passed++;
+ }
+ else {
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ if (z[i] <= zbuffer[i]) {
+ /* pass */
+ passed++;
+ }
+ else {
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_GEQUAL:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ if (z[i] >= zbuffer[i]) {
+ zbuffer[i] = z[i];
+ passed++;
+ }
+ else {
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ if (z[i] >= zbuffer[i]) {
+ /* pass */
+ passed++;
+ }
+ else {
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_GREATER:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ if (z[i] > zbuffer[i]) {
+ zbuffer[i] = z[i];
+ passed++;
+ }
+ else {
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ if (z[i] > zbuffer[i]) {
+ /* pass */
+ passed++;
+ }
+ else {
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_NOTEQUAL:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ if (z[i] != zbuffer[i]) {
+ zbuffer[i] = z[i];
+ passed++;
+ }
+ else {
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ if (z[i] != zbuffer[i]) {
+ /* pass */
+ passed++;
+ }
+ else {
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_EQUAL:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ if (z[i] == zbuffer[i]) {
+ zbuffer[i] = z[i];
+ passed++;
+ }
+ else {
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ if (z[i] == zbuffer[i]) {
+ /* pass */
+ passed++;
+ }
+ else {
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_ALWAYS:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ zbuffer[i] = z[i];
+ passed++;
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer or mask */
+ passed = n;
+ }
+ break;
+ case GL_NEVER:
+ BZERO(mask, n * sizeof(GLubyte));
+ break;
+ default:
+ gl_problem(ctx, "Bad depth func in depth_test_span16");
+ }
+
+ return passed;
+}
+
+
+static GLuint
+depth_test_span32( GLcontext *ctx, GLuint n, GLint x, GLint y,
+ GLuint zbuffer[], const GLdepth z[], GLubyte mask[] )
+{
+ GLuint passed = 0;
+
+ /* switch cases ordered from most frequent to less frequent */
+ switch (ctx->Depth.Func) {
+ case GL_LESS:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ if (z[i] < zbuffer[i]) {
+ /* pass */
+ zbuffer[i] = z[i];
+ passed++;
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ if (z[i] < zbuffer[i]) {
+ /* pass */
+ passed++;
+ }
+ else {
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_LEQUAL:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ if (z[i] <= zbuffer[i]) {
+ zbuffer[i] = z[i];
+ passed++;
+ }
+ else {
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ if (z[i] <= zbuffer[i]) {
+ /* pass */
+ passed++;
+ }
+ else {
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_GEQUAL:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ if (z[i] >= zbuffer[i]) {
+ zbuffer[i] = z[i];
+ passed++;
+ }
+ else {
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ if (z[i] >= zbuffer[i]) {
+ /* pass */
+ passed++;
+ }
+ else {
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_GREATER:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ if (z[i] > zbuffer[i]) {
+ zbuffer[i] = z[i];
+ passed++;
+ }
+ else {
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ if (z[i] > zbuffer[i]) {
+ /* pass */
+ passed++;
+ }
+ else {
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_NOTEQUAL:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ if (z[i] != zbuffer[i]) {
+ zbuffer[i] = z[i];
+ passed++;
+ }
+ else {
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ if (z[i] != zbuffer[i]) {
+ /* pass */
+ passed++;
+ }
+ else {
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_EQUAL:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ if (z[i] == zbuffer[i]) {
+ zbuffer[i] = z[i];
+ passed++;
+ }
+ else {
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ if (z[i] == zbuffer[i]) {
+ /* pass */
+ passed++;
+ }
+ else {
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_ALWAYS:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ zbuffer[i] = z[i];
+ passed++;
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer or mask */
+ passed = n;
+ }
+ break;
+ case GL_NEVER:
+ BZERO(mask, n * sizeof(GLubyte));
+ break;
+ default:
+ gl_problem(ctx, "Bad depth func in depth_test_span32");
+ }
+
+ return passed;
+}
+
+
+
+/*
+ * Apply depth test to span of fragments. Hardware or software z buffer.
+ */
+GLuint
+_mesa_depth_test_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
+ const GLdepth z[], GLubyte mask[] )
+{
+ if (ctx->Driver.ReadDepthSpan) {
+ /* hardware-based depth buffer */
+ GLdepth zbuffer[MAX_WIDTH];
+ GLuint passed;
+ (*ctx->Driver.ReadDepthSpan)(ctx, n, x, y, zbuffer);
+ passed = depth_test_span32(ctx, n, x, y, zbuffer, z, mask);
+ assert(ctx->Driver.WriteDepthSpan);
+ (*ctx->Driver.WriteDepthSpan)(ctx, n, x, y, zbuffer, mask);
+ return passed;
+ }
+ else {
+ /* software depth buffer */
+ if (ctx->Visual.DepthBits <= 16) {
+ GLushort *zptr = (GLushort *) Z_ADDRESS16(ctx, x, y);
+ GLuint passed = depth_test_span16(ctx, n, x, y, zptr, z, mask);
+ return passed;
+ }
+ else {
+ GLuint *zptr = (GLuint *) Z_ADDRESS32(ctx, x, y);
+ GLuint passed = depth_test_span32(ctx, n, x, y, zptr, z, mask);
+ return passed;
+ }
+ }
+}
+
+
+
+
+/*
+ * Do depth testing for an array of fragments using software Z buffer.
+ */
+static void
+software_depth_test_pixels16( GLcontext *ctx, GLuint n,
+ const GLint x[], const GLint y[],
+ const GLdepth z[], GLubyte mask[] )
+{
+ /* switch cases ordered from most frequent to less frequent */
+ switch (ctx->Depth.Func) {
+ case GL_LESS:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ GLushort *zptr = Z_ADDRESS16(ctx,x[i],y[i]);
+ if (z[i] < *zptr) {
+ /* pass */
+ *zptr = z[i];
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ GLushort *zptr = Z_ADDRESS16(ctx,x[i],y[i]);
+ if (z[i] < *zptr) {
+ /* pass */
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_LEQUAL:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ GLushort *zptr = Z_ADDRESS16(ctx,x[i],y[i]);
+ if (z[i] <= *zptr) {
+ /* pass */
+ *zptr = z[i];
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ GLushort *zptr = Z_ADDRESS16(ctx,x[i],y[i]);
+ if (z[i] <= *zptr) {
+ /* pass */
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_GEQUAL:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ GLushort *zptr = Z_ADDRESS16(ctx,x[i],y[i]);
+ if (z[i] >= *zptr) {
+ /* pass */
+ *zptr = z[i];
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ GLushort *zptr = Z_ADDRESS16(ctx,x[i],y[i]);
+ if (z[i] >= *zptr) {
+ /* pass */
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_GREATER:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ GLushort *zptr = Z_ADDRESS16(ctx,x[i],y[i]);
+ if (z[i] > *zptr) {
+ /* pass */
+ *zptr = z[i];
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ GLushort *zptr = Z_ADDRESS16(ctx,x[i],y[i]);
+ if (z[i] > *zptr) {
+ /* pass */
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_NOTEQUAL:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ GLushort *zptr = Z_ADDRESS16(ctx,x[i],y[i]);
+ if (z[i] != *zptr) {
+ /* pass */
+ *zptr = z[i];
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ GLushort *zptr = Z_ADDRESS16(ctx,x[i],y[i]);
+ if (z[i] != *zptr) {
+ /* pass */
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_EQUAL:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ GLushort *zptr = Z_ADDRESS16(ctx,x[i],y[i]);
+ if (z[i] == *zptr) {
+ /* pass */
+ *zptr = z[i];
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ GLushort *zptr = Z_ADDRESS16(ctx,x[i],y[i]);
+ if (z[i] == *zptr) {
+ /* pass */
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_ALWAYS:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ GLushort *zptr = Z_ADDRESS16(ctx,x[i],y[i]);
+ *zptr = z[i];
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer or mask */
+ }
+ break;
+ case GL_NEVER:
+ /* depth test never passes */
+ BZERO(mask, n * sizeof(GLubyte));
+ break;
+ default:
+ gl_problem(ctx, "Bad depth func in software_depth_test_pixels");
+ }
+}
+
+
+
+/*
+ * Do depth testing for an array of fragments using software Z buffer.
+ */
+static void
+software_depth_test_pixels32( GLcontext *ctx, GLuint n,
+ const GLint x[], const GLint y[],
+ const GLdepth z[], GLubyte mask[] )
+{
+ /* switch cases ordered from most frequent to less frequent */
+ switch (ctx->Depth.Func) {
+ case GL_LESS:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ GLuint *zptr = Z_ADDRESS32(ctx,x[i],y[i]);
+ if (z[i] < *zptr) {
+ /* pass */
+ *zptr = z[i];
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ GLuint *zptr = Z_ADDRESS32(ctx,x[i],y[i]);
+ if (z[i] < *zptr) {
+ /* pass */
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_LEQUAL:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ GLuint *zptr = Z_ADDRESS32(ctx,x[i],y[i]);
+ if (z[i] <= *zptr) {
+ /* pass */
+ *zptr = z[i];
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ GLuint *zptr = Z_ADDRESS32(ctx,x[i],y[i]);
+ if (z[i] <= *zptr) {
+ /* pass */
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_GEQUAL:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ GLuint *zptr = Z_ADDRESS32(ctx,x[i],y[i]);
+ if (z[i] >= *zptr) {
+ /* pass */
+ *zptr = z[i];
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ GLuint *zptr = Z_ADDRESS32(ctx,x[i],y[i]);
+ if (z[i] >= *zptr) {
+ /* pass */
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_GREATER:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ GLuint *zptr = Z_ADDRESS32(ctx,x[i],y[i]);
+ if (z[i] > *zptr) {
+ /* pass */
+ *zptr = z[i];
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ GLuint *zptr = Z_ADDRESS32(ctx,x[i],y[i]);
+ if (z[i] > *zptr) {
+ /* pass */
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_NOTEQUAL:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ GLuint *zptr = Z_ADDRESS32(ctx,x[i],y[i]);
+ if (z[i] != *zptr) {
+ /* pass */
+ *zptr = z[i];
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ GLuint *zptr = Z_ADDRESS32(ctx,x[i],y[i]);
+ if (z[i] != *zptr) {
+ /* pass */
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_EQUAL:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ GLuint *zptr = Z_ADDRESS32(ctx,x[i],y[i]);
+ if (z[i] == *zptr) {
+ /* pass */
+ *zptr = z[i];
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ GLuint *zptr = Z_ADDRESS32(ctx,x[i],y[i]);
+ if (z[i] == *zptr) {
+ /* pass */
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_ALWAYS:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ GLuint *zptr = Z_ADDRESS32(ctx,x[i],y[i]);
+ *zptr = z[i];
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer or mask */
+ }
+ break;
+ case GL_NEVER:
+ /* depth test never passes */
+ BZERO(mask, n * sizeof(GLubyte));
+ break;
+ default:
+ gl_problem(ctx, "Bad depth func in software_depth_test_pixels");
+ }
+}
+
+
+
+/*
+ * Do depth testing for an array of pixels using hardware Z buffer.
+ * Input/output: zbuffer - array of depth values from Z buffer
+ * Input: z - array of fragment z values.
+ */
+static void
+hardware_depth_test_pixels( GLcontext *ctx, GLuint n, GLdepth zbuffer[],
+ const GLdepth z[], GLubyte mask[] )
+{
+ /* switch cases ordered from most frequent to less frequent */
+ switch (ctx->Depth.Func) {
+ case GL_LESS:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ if (z[i] < zbuffer[i]) {
+ /* pass */
+ zbuffer[i] = z[i];
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ if (z[i] < zbuffer[i]) {
+ /* pass */
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_LEQUAL:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ if (z[i] <= zbuffer[i]) {
+ /* pass */
+ zbuffer[i] = z[i];
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ if (z[i] <= zbuffer[i]) {
+ /* pass */
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_GEQUAL:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ if (z[i] >= zbuffer[i]) {
+ /* pass */
+ zbuffer[i] = z[i];
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ if (z[i] >= zbuffer[i]) {
+ /* pass */
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_GREATER:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ if (z[i] > zbuffer[i]) {
+ /* pass */
+ zbuffer[i] = z[i];
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ if (z[i] > zbuffer[i]) {
+ /* pass */
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_NOTEQUAL:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ if (z[i] != zbuffer[i]) {
+ /* pass */
+ zbuffer[i] = z[i];
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ if (z[i] != zbuffer[i]) {
+ /* pass */
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_EQUAL:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ if (z[i] == zbuffer[i]) {
+ /* pass */
+ zbuffer[i] = z[i];
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ if (z[i] == zbuffer[i]) {
+ /* pass */
+ }
+ else {
+ /* fail */
+ mask[i] = 0;
+ }
+ }
+ }
+ }
+ break;
+ case GL_ALWAYS:
+ if (ctx->Depth.Mask) {
+ /* Update Z buffer */
+ GLuint i;
+ for (i=0; i<n; i++) {
+ if (mask[i]) {
+ zbuffer[i] = z[i];
+ }
+ }
+ }
+ else {
+ /* Don't update Z buffer or mask */
+ }
+ break;
+ case GL_NEVER:
+ /* depth test never passes */
+ BZERO(mask, n * sizeof(GLubyte));
+ break;
+ default:
+ gl_problem(ctx, "Bad depth func in hardware_depth_test_pixels");
+ }
+}
+
+
+
+void
+_mesa_depth_test_pixels( GLcontext *ctx,
+ GLuint n, const GLint x[], const GLint y[],
+ const GLdepth z[], GLubyte mask[] )
+{
+ if (ctx->Driver.ReadDepthPixels) {
+ /* read depth values from hardware Z buffer */
+ GLdepth zbuffer[PB_SIZE];
+ (*ctx->Driver.ReadDepthPixels)(ctx, n, x, y, zbuffer);
+
+ hardware_depth_test_pixels( ctx, n, zbuffer, z, mask );
+
+ /* update hardware Z buffer with new values */
+ assert(ctx->Driver.WriteDepthPixels);
+ (*ctx->Driver.WriteDepthPixels)(ctx, n, x, y, zbuffer, mask );
+ }
+ else {
+ /* software depth testing */
+ if (ctx->Visual.DepthBits <= 16)
+ software_depth_test_pixels16(ctx, n, x, y, z, mask);
+ else
+ software_depth_test_pixels32(ctx, n, x, y, z, mask);
+ }
+}
+
+
+
+
+
+/**********************************************************************/
+/***** Read Depth Buffer *****/
+/**********************************************************************/
+
+
+/*
+ * Read a span of depth values from the depth buffer.
+ * This function does clipping before calling the device driver function.
+ */
+void
+_mesa_read_depth_span( GLcontext *ctx,
+ GLint n, GLint x, GLint y, GLdepth depth[] )
+{
+ if (y < 0 || y >= ctx->DrawBuffer->Height ||
+ x + (GLint) n <= 0 || x >= ctx->DrawBuffer->Width) {
+ /* span is completely outside framebuffer */
+ GLint i;
+ for (i = 0; i < n; i++)
+ depth[i] = 0;
+ return;
+ }
+
+ if (x < 0) {
+ GLint dx = -x;
+ GLint i;
+ for (i = 0; i < dx; i++)
+ depth[i] = 0;
+ x = 0;
+ n -= dx;
+ depth += dx;
+ }
+ if (x + n > ctx->DrawBuffer->Width) {
+ GLint dx = x + n - ctx->DrawBuffer->Width;
+ GLint i;
+ for (i = 0; i < dx; i++)
+ depth[n - i - 1] = 0;
+ n -= dx;
+ }
+ if (n <= 0) {
+ return;
+ }
+
+ if (ctx->DrawBuffer->DepthBuffer) {
+ /* read from software depth buffer */
+ if (ctx->Visual.DepthBits <= 16) {
+ const GLushort *zptr = Z_ADDRESS16( ctx, x, y );
+ GLuint i;
+ for (i = 0; i < n; i++) {
+ depth[i] = zptr[i];
+ }
+ }
+ else {
+ const GLuint *zptr = Z_ADDRESS32( ctx, x, y );
+ GLuint i;
+ for (i = 0; i < n; i++) {
+ depth[i] = zptr[i];
+ }
+ }
+ }
+ else if (ctx->Driver.ReadDepthSpan) {
+ /* read from hardware depth buffer */
+ (*ctx->Driver.ReadDepthSpan)( ctx, n, x, y, depth );
+ }
+ else {
+ /* no depth buffer */
+ BZERO(depth, n * sizeof(GLfloat));
+ }
+
+}
+
+
+
+
+/*
+ * Return a span of depth values from the depth buffer as floats in [0,1].
+ * This is used for both hardware and software depth buffers.
+ * Input: n - how many pixels
+ * x,y - location of first pixel
+ * Output: depth - the array of depth values
+ */
+void
+_mesa_read_depth_span_float( GLcontext *ctx,
+ GLint n, GLint x, GLint y, GLfloat depth[] )
+{
+ const GLfloat scale = 1.0F / ctx->Visual.DepthMaxF;
+
+ if (y < 0 || y >= ctx->DrawBuffer->Height ||
+ x + (GLint) n <= 0 || x >= ctx->DrawBuffer->Width) {
+ /* span is completely outside framebuffer */
+ GLint i;
+ for (i = 0; i < n; i++)
+ depth[i] = 0.0F;
+ return;
+ }
+
+ if (x < 0) {
+ GLint dx = -x;
+ GLint i;
+ for (i = 0; i < dx; i++)
+ depth[i] = 0.0F;
+ n -= dx;
+ x = 0;
+ }
+ if (x + n > ctx->DrawBuffer->Width) {
+ GLint dx = x + n - ctx->DrawBuffer->Width;
+ GLint i;
+ for (i = 0; i < dx; i++)
+ depth[n - i - 1] = 0.0F;
+ n -= dx;
+ }
+ if (n <= 0) {
+ return;
+ }
+
+ if (ctx->DrawBuffer->DepthBuffer) {
+ /* read from software depth buffer */
+ if (ctx->Visual.DepthBits <= 16) {
+ const GLushort *zptr = Z_ADDRESS16( ctx, x, y );
+ GLuint i;
+ for (i = 0; i < n; i++) {
+ depth[i] = (GLfloat) zptr[i] * scale;
+ }
+ }
+ else {
+ const GLuint *zptr = Z_ADDRESS32( ctx, x, y );
+ GLuint i;
+ for (i = 0; i < n; i++) {
+ depth[i] = (GLfloat) zptr[i] * scale;
+ }
+ }
+ }
+ else if (ctx->Driver.ReadDepthSpan) {
+ /* read from hardware depth buffer */
+ GLdepth d[MAX_WIDTH];
+ GLuint i;
+ assert(n <= MAX_WIDTH);
+ (*ctx->Driver.ReadDepthSpan)( ctx, n, x, y, d );
+ for (i = 0; i < n; i++) {
+ depth[i] = d[i] * scale;
+ }
+ }
+ else {
+ /* no depth buffer */
+ BZERO(depth, n * sizeof(GLfloat));
+ }
+}
+
+
+
+/**********************************************************************/
+/***** Allocate and Clear Depth Buffer *****/
+/**********************************************************************/
+
+
+
+/*
+ * Allocate a new depth buffer. If there's already a depth buffer allocated
+ * it will be free()'d. The new depth buffer will be uniniitalized.
+ * This function is only called through Driver.alloc_depth_buffer.
+ */
+void
+_mesa_alloc_depth_buffer( GLcontext *ctx )
+{
+ /* deallocate current depth buffer if present */
+ if (ctx->DrawBuffer->UseSoftwareDepthBuffer) {
+ GLint bytesPerValue;
+
+ if (ctx->DrawBuffer->DepthBuffer) {
+ FREE(ctx->DrawBuffer->DepthBuffer);
+ ctx->DrawBuffer->DepthBuffer = NULL;
+ }
+
+ /* allocate new depth buffer, but don't initialize it */
+ if (ctx->Visual.DepthBits <= 16)
+ bytesPerValue = sizeof(GLushort);
+ else
+ bytesPerValue = sizeof(GLuint);
+
+ ctx->DrawBuffer->DepthBuffer = MALLOC( ctx->DrawBuffer->Width
+ * ctx->DrawBuffer->Height
+ * bytesPerValue );
+
+ if (!ctx->DrawBuffer->DepthBuffer) {
+ /* out of memory */
+ ctx->Depth.Test = GL_FALSE;
+ ctx->NewState |= _NEW_DEPTH;
+ gl_error( ctx, GL_OUT_OF_MEMORY, "Couldn't allocate depth buffer" );
+ }
+ }
+}
+
+
+
+
+/*
+ * Clear the depth buffer. If the depth buffer doesn't exist yet we'll
+ * allocate it now.
+ * This function is only called through Driver.clear_depth_buffer.
+ */
+void
+_mesa_clear_depth_buffer( GLcontext *ctx )
+{
+ if (ctx->Visual.DepthBits == 0
+ || !ctx->DrawBuffer->DepthBuffer
+ || !ctx->Depth.Mask) {
+ /* no depth buffer, or writing to it is disabled */
+ return;
+ }
+
+ /* The loops in this function have been written so the IRIX 5.3
+ * C compiler can unroll them. Hopefully other compilers can too!
+ */
+
+ if (ctx->Scissor.Enabled) {
+ /* only clear scissor region */
+ if (ctx->Visual.DepthBits <= 16) {
+ const GLushort clearValue = (GLushort) (ctx->Depth.Clear * ctx->Visual.DepthMax);
+ const GLint rows = ctx->DrawBuffer->Ymax - ctx->DrawBuffer->Ymin;
+ const GLint width = ctx->DrawBuffer->Width;
+ GLushort *dRow = (GLushort *) ctx->DrawBuffer->DepthBuffer
+ + ctx->DrawBuffer->Ymin * width + ctx->DrawBuffer->Xmin;
+ GLint i, j;
+ for (i = 0; i < rows; i++) {
+ for (j = 0; j < width; j++) {
+ dRow[j] = clearValue;
+ }
+ dRow += width;
+ }
+ }
+ else {
+ const GLuint clearValue = (GLuint) (ctx->Depth.Clear * ctx->Visual.DepthMax);
+ const GLint rows = ctx->DrawBuffer->Ymax - ctx->DrawBuffer->Ymin;
+ const GLint width = ctx->DrawBuffer->Width;
+ GLuint *dRow = (GLuint *) ctx->DrawBuffer->DepthBuffer
+ + ctx->DrawBuffer->Ymin * width + ctx->DrawBuffer->Xmin;
+ GLint i, j;
+ for (i = 0; i < rows; i++) {
+ for (j = 0; j < width; j++) {
+ dRow[j] = clearValue;
+ }
+ dRow += width;
+ }
+ }
+ }
+ else {
+ /* clear whole buffer */
+ if (ctx->Visual.DepthBits <= 16) {
+ const GLushort clearValue = (GLushort) (ctx->Depth.Clear * ctx->Visual.DepthMax);
+ if ((clearValue & 0xff) == (clearValue >> 8)) {
+ if (clearValue == 0) {
+ BZERO(ctx->DrawBuffer->DepthBuffer,
+ 2*ctx->DrawBuffer->Width*ctx->DrawBuffer->Height);
+ }
+ else {
+ /* lower and upper bytes of clear_value are same, use MEMSET */
+ MEMSET( ctx->DrawBuffer->DepthBuffer, clearValue & 0xff,
+ 2 * ctx->DrawBuffer->Width * ctx->DrawBuffer->Height);
+ }
+ }
+ else {
+ GLushort *d = (GLushort *) ctx->DrawBuffer->DepthBuffer;
+ GLint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
+ while (n >= 16) {
+ d[0] = clearValue; d[1] = clearValue;
+ d[2] = clearValue; d[3] = clearValue;
+ d[4] = clearValue; d[5] = clearValue;
+ d[6] = clearValue; d[7] = clearValue;
+ d[8] = clearValue; d[9] = clearValue;
+ d[10] = clearValue; d[11] = clearValue;
+ d[12] = clearValue; d[13] = clearValue;
+ d[14] = clearValue; d[15] = clearValue;
+ d += 16;
+ n -= 16;
+ }
+ while (n > 0) {
+ *d++ = clearValue;
+ n--;
+ }
+ }
+ }
+ else {
+ /* >16 bit depth buffer */
+ const GLuint clearValue = (GLuint) (ctx->Depth.Clear * ctx->Visual.DepthMax);
+ if (clearValue == 0) {
+ BZERO(ctx->DrawBuffer->DepthBuffer,
+ ctx->DrawBuffer->Width*ctx->DrawBuffer->Height*sizeof(GLuint));
+ }
+ else {
+ GLint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
+ GLuint *d = (GLuint *) ctx->DrawBuffer->DepthBuffer;
+ while (n >= 16) {
+ d[0] = clearValue; d[1] = clearValue;
+ d[2] = clearValue; d[3] = clearValue;
+ d[4] = clearValue; d[5] = clearValue;
+ d[6] = clearValue; d[7] = clearValue;
+ d[8] = clearValue; d[9] = clearValue;
+ d[10] = clearValue; d[11] = clearValue;
+ d[12] = clearValue; d[13] = clearValue;
+ d[14] = clearValue; d[15] = clearValue;
+ d += 16;
+ n -= 16;
+ }
+ while (n > 0) {
+ *d++ = clearValue;
+ n--;
+ }
+ }
+ }
+ }
+}
diff --git a/src/mesa/swrast/s_depth.h b/src/mesa/swrast/s_depth.h
new file mode 100644
index 0000000000..e5de2189b7
--- /dev/null
+++ b/src/mesa/swrast/s_depth.h
@@ -0,0 +1,69 @@
+/* $Id: s_depth.h,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ *
+ * 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.
+ */
+
+
+#ifndef S_DEPTH_H
+#define S_DEPTH_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+extern GLvoid *
+_mesa_zbuffer_address(GLcontext *ctx, GLint x, GLint y);
+
+
+extern GLuint
+_mesa_depth_test_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
+ const GLdepth z[], GLubyte mask[] );
+
+extern void
+_mesa_depth_test_pixels( GLcontext *ctx,
+ GLuint n, const GLint x[], const GLint y[],
+ const GLdepth z[], GLubyte mask[] );
+
+
+extern void
+_mesa_read_depth_span( GLcontext *ctx,
+ GLint n, GLint x, GLint y, GLdepth depth[] );
+
+
+extern void
+_mesa_read_depth_span_float( GLcontext *ctx, GLint n, GLint x, GLint y,
+ GLfloat depth[] );
+
+
+extern void
+_mesa_alloc_depth_buffer( GLcontext* ctx );
+
+
+extern void
+_mesa_clear_depth_buffer( GLcontext* ctx );
+
+
+
+#endif
diff --git a/src/mesa/swrast/s_drawpix.c b/src/mesa/swrast/s_drawpix.c
new file mode 100644
index 0000000000..ba6ea07e54
--- /dev/null
+++ b/src/mesa/swrast/s_drawpix.c
@@ -0,0 +1,885 @@
+/* $Id: s_drawpix.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.
+ */
+
+
+#include "glheader.h"
+#include "colormac.h"
+#include "context.h"
+#include "convolve.h"
+#include "image.h"
+#include "macros.h"
+#include "mem.h"
+#include "mmath.h"
+#include "pixel.h"
+
+#include "s_pixeltex.h"
+#include "s_span.h"
+#include "s_stencil.h"
+#include "s_texture.h"
+#include "s_zoom.h"
+
+
+
+/*
+ * Given the dest position, size and skipPixels and skipRows values
+ * for a glDrawPixels command, perform clipping of the image bounds
+ * so the result lies withing the context's buffer bounds.
+ * Return: GL_TRUE if image is ready for drawing
+ * GL_FALSE if image was completely clipped away (draw nothing)
+ */
+GLboolean
+_mesa_clip_pixelrect(const GLcontext *ctx,
+ GLint *destX, GLint *destY,
+ GLsizei *width, GLsizei *height,
+ GLint *skipPixels, GLint *skipRows)
+{
+ const GLframebuffer *buffer = ctx->DrawBuffer;
+
+ /* left clipping */
+ if (*destX < buffer->Xmin) {
+ *skipPixels += (buffer->Xmin - *destX);
+ *width -= (buffer->Xmin - *destX);
+ *destX = buffer->Xmin;
+ }
+ /* right clipping */
+ if (*destX + *width > buffer->Xmax)
+ *width -= (*destX + *width - buffer->Xmax);
+
+ if (*width <= 0)
+ return GL_FALSE;
+
+ /* bottom clipping */
+ if (*destY < buffer->Ymin) {
+ *skipRows += (buffer->Ymin - *destY);
+ *height -= (buffer->Ymin - *destY);
+ *destY = buffer->Ymin;
+ }
+ /* top clipping */
+ if (*destY + *height > buffer->Ymax)
+ *height -= (*destY + *height - buffer->Ymax);
+
+ if (*height <= 0)
+ return GL_TRUE;
+
+ return GL_TRUE;
+}
+
+
+
+/*
+ * Try to do a fast and simple RGB(a) glDrawPixels.
+ * Return: GL_TRUE if success, GL_FALSE if slow path must be used instead
+ */
+static GLboolean
+fast_draw_pixels(GLcontext *ctx, GLint x, GLint y,
+ GLsizei width, GLsizei height,
+ GLenum format, GLenum type, const GLvoid *pixels)
+{
+ const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
+ GLchan rgb[MAX_WIDTH][3];
+ GLchan rgba[MAX_WIDTH][4];
+
+ ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx, "glDrawPixels",
+ GL_FALSE);
+
+
+ if (!ctx->Current.RasterPosValid) {
+ return GL_TRUE; /* no-op */
+ }
+
+ if ((ctx->RasterMask&(~(SCISSOR_BIT|WINCLIP_BIT)))==0
+ && ctx->Texture.ReallyEnabled == 0
+ && unpack->Alignment == 1
+ && !unpack->SwapBytes
+ && !unpack->LsbFirst) {
+
+ GLint destX = x;
+ GLint destY = y;
+ GLint drawWidth = width; /* actual width drawn */
+ GLint drawHeight = height; /* actual height drawn */
+ GLint skipPixels = unpack->SkipPixels;
+ GLint skipRows = unpack->SkipRows;
+ GLint rowLength;
+ GLdepth zSpan[MAX_WIDTH]; /* only used when zooming */
+ GLint zoomY0 = 0;
+
+ if (unpack->RowLength > 0)
+ rowLength = unpack->RowLength;
+ else
+ rowLength = width;
+
+ /* If we're not using pixel zoom then do all clipping calculations
+ * now. Otherwise, we'll let the gl_write_zoomed_*_span() functions
+ * handle the clipping.
+ */
+ if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
+ /* horizontal clipping */
+ if (destX < ctx->DrawBuffer->Xmin) {
+ skipPixels += (ctx->DrawBuffer->Xmin - destX);
+ drawWidth -= (ctx->DrawBuffer->Xmin - destX);
+ destX = ctx->DrawBuffer->Xmin;
+ }
+ if (destX + drawWidth > ctx->DrawBuffer->Xmax)
+ drawWidth -= (destX + drawWidth - ctx->DrawBuffer->Xmax);
+ if (drawWidth <= 0)
+ return GL_TRUE;
+
+ /* vertical clipping */
+ if (destY < ctx->DrawBuffer->Ymin) {
+ skipRows += (ctx->DrawBuffer->Ymin - destY);
+ drawHeight -= (ctx->DrawBuffer->Ymin - destY);
+ destY = ctx->DrawBuffer->Ymin;
+ }
+ if (destY + drawHeight > ctx->DrawBuffer->Ymax)
+ drawHeight -= (destY + drawHeight - ctx->DrawBuffer->Ymax);
+ if (drawHeight <= 0)
+ return GL_TRUE;
+ }
+ else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
+ /* upside-down image */
+ /* horizontal clipping */
+ if (destX < ctx->DrawBuffer->Xmin) {
+ skipPixels += (ctx->DrawBuffer->Xmin - destX);
+ drawWidth -= (ctx->DrawBuffer->Xmin - destX);
+ destX = ctx->DrawBuffer->Xmin;
+ }
+ if (destX + drawWidth > ctx->DrawBuffer->Xmax)
+ drawWidth -= (destX + drawWidth - ctx->DrawBuffer->Xmax);
+ if (drawWidth <= 0)
+ return GL_TRUE;
+
+ /* vertical clipping */
+ if (destY > ctx->DrawBuffer->Ymax) {
+ skipRows += (destY - ctx->DrawBuffer->Ymax);
+ drawHeight -= (destY - ctx->DrawBuffer->Ymax);
+ destY = ctx->DrawBuffer->Ymax;
+ }
+ if (destY - drawHeight < ctx->DrawBuffer->Ymin)
+ drawHeight -= (ctx->DrawBuffer->Ymin - (destY - drawHeight));
+ if (drawHeight <= 0)
+ return GL_TRUE;
+ }
+ else {
+ /* setup array of fragment Z value to pass to zoom function */
+ GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual.DepthMaxF);
+ GLint i;
+ ASSERT(drawWidth < MAX_WIDTH);
+ for (i=0; i<drawWidth; i++)
+ zSpan[i] = z;
+
+ /* save Y value of first row */
+ zoomY0 = (GLint) (ctx->Current.RasterPos[1] + 0.5F);
+ }
+
+
+ /*
+ * Ready to draw!
+ * The window region at (destX, destY) of size (drawWidth, drawHeight)
+ * will be written to.
+ * We'll take pixel data from buffer pointed to by "pixels" but we'll
+ * skip "skipRows" rows and skip "skipPixels" pixels/row.
+ */
+
+ if (format == GL_RGBA && type == CHAN_TYPE
+ && ctx->ImageTransferState==0) {
+ if (ctx->Visual.RGBAflag) {
+ GLchan *src = (GLchan *) pixels
+ + (skipRows * rowLength + skipPixels) * 4;
+ if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
+ /* no zooming */
+ GLint row;
+ for (row=0; row<drawHeight; row++) {
+ (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
+ (void *) src, NULL);
+ src += rowLength * 4;
+ destY++;
+ }
+ }
+ else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
+ /* upside-down */
+ GLint row;
+ for (row=0; row<drawHeight; row++) {
+ destY--;
+ (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
+ (void *) src, NULL);
+ src += rowLength * 4;
+ }
+ }
+ else {
+ /* with zooming */
+ GLint row;
+ for (row=0; row<drawHeight; row++) {
+ gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
+ zSpan, 0, (void *) src, zoomY0);
+ src += rowLength * 4;
+ destY++;
+ }
+ }
+ }
+ return GL_TRUE;
+ }
+ else if (format == GL_RGB && type == CHAN_TYPE
+ && ctx->ImageTransferState == 0) {
+ if (ctx->Visual.RGBAflag) {
+ GLchan *src = (GLchan *) pixels
+ + (skipRows * rowLength + skipPixels) * 3;
+ if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
+ GLint row;
+ for (row=0; row<drawHeight; row++) {
+ (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
+ (void *) src, NULL);
+ src += rowLength * 3;
+ destY++;
+ }
+ }
+ else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
+ /* upside-down */
+ GLint row;
+ for (row=0; row<drawHeight; row++) {
+ destY--;
+ (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
+ (void *) src, NULL);
+ src += rowLength * 3;
+ }
+ }
+ else {
+ /* with zooming */
+ GLint row;
+ for (row=0; row<drawHeight; row++) {
+ gl_write_zoomed_rgb_span(ctx, drawWidth, destX, destY,
+ zSpan, 0, (void *) src, zoomY0);
+ src += rowLength * 3;
+ destY++;
+ }
+ }
+ }
+ return GL_TRUE;
+ }
+ else if (format == GL_LUMINANCE && type == CHAN_TYPE
+ && ctx->ImageTransferState==0) {
+ if (ctx->Visual.RGBAflag) {
+ GLchan *src = (GLchan *) pixels
+ + (skipRows * rowLength + skipPixels);
+ if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
+ /* no zooming */
+ GLint row;
+ ASSERT(drawWidth < MAX_WIDTH);
+ for (row=0; row<drawHeight; row++) {
+ GLint i;
+ for (i=0;i<drawWidth;i++) {
+ rgb[i][0] = src[i];
+ rgb[i][1] = src[i];
+ rgb[i][2] = src[i];
+ }
+ (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
+ (void *) rgb, NULL);
+ src += rowLength;
+ destY++;
+ }
+ }
+ else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
+ /* upside-down */
+ GLint row;
+ ASSERT(drawWidth < MAX_WIDTH);
+ for (row=0; row<drawHeight; row++) {
+ GLint i;
+ for (i=0;i<drawWidth;i++) {
+ rgb[i][0] = src[i];
+ rgb[i][1] = src[i];
+ rgb[i][2] = src[i];
+ }
+ destY--;
+ (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
+ (void *) rgb, NULL);
+ src += rowLength;
+ }
+ }
+ else {
+ /* with zooming */
+ GLint row;
+ ASSERT(drawWidth < MAX_WIDTH);
+ for (row=0; row<drawHeight; row++) {
+ GLint i;
+ for (i=0;i<drawWidth;i++) {
+ rgb[i][0] = src[i];
+ rgb[i][1] = src[i];
+ rgb[i][2] = src[i];
+ }
+ gl_write_zoomed_rgb_span(ctx, drawWidth, destX, destY,
+ zSpan, 0, (void *) rgb, zoomY0);
+ src += rowLength;
+ destY++;
+ }
+ }
+ }
+ return GL_TRUE;
+ }
+ else if (format == GL_LUMINANCE_ALPHA && type == CHAN_TYPE
+ && ctx->ImageTransferState == 0) {
+ if (ctx->Visual.RGBAflag) {
+ GLchan *src = (GLchan *) pixels
+ + (skipRows * rowLength + skipPixels)*2;
+ if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
+ /* no zooming */
+ GLint row;
+ ASSERT(drawWidth < MAX_WIDTH);
+ for (row=0; row<drawHeight; row++) {
+ GLint i;
+ GLchan *ptr = src;
+ for (i=0;i<drawWidth;i++) {
+ rgba[i][0] = *ptr;
+ rgba[i][1] = *ptr;
+ rgba[i][2] = *ptr++;
+ rgba[i][3] = *ptr++;
+ }
+ (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
+ (void *) rgba, NULL);
+ src += rowLength*2;
+ destY++;
+ }
+ }
+ else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
+ /* upside-down */
+ GLint row;
+ ASSERT(drawWidth < MAX_WIDTH);
+ for (row=0; row<drawHeight; row++) {
+ GLint i;
+ GLchan *ptr = src;
+ for (i=0;i<drawWidth;i++) {
+ rgba[i][0] = *ptr;
+ rgba[i][1] = *ptr;
+ rgba[i][2] = *ptr++;
+ rgba[i][3] = *ptr++;
+ }
+ destY--;
+ (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
+ (void *) rgba, NULL);
+ src += rowLength*2;
+ }
+ }
+ else {
+ /* with zooming */
+ GLint row;
+ ASSERT(drawWidth < MAX_WIDTH);
+ for (row=0; row<drawHeight; row++) {
+ GLchan *ptr = src;
+ GLint i;
+ for (i=0;i<drawWidth;i++) {
+ rgba[i][0] = *ptr;
+ rgba[i][1] = *ptr;
+ rgba[i][2] = *ptr++;
+ rgba[i][3] = *ptr++;
+ }
+ gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
+ zSpan, 0, (void *) rgba, zoomY0);
+ src += rowLength*2;
+ destY++;
+ }
+ }
+ }
+ return GL_TRUE;
+ }
+ else if (format==GL_COLOR_INDEX && type==GL_UNSIGNED_BYTE) {
+ GLubyte *src = (GLubyte *) pixels + skipRows * rowLength + skipPixels;
+ if (ctx->Visual.RGBAflag) {
+ /* convert CI data to RGBA */
+ if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
+ /* no zooming */
+ GLint row;
+ for (row=0; row<drawHeight; row++) {
+ ASSERT(drawWidth < MAX_WIDTH);
+ _mesa_map_ci8_to_rgba(ctx, drawWidth, src, rgba);
+ (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
+ (const GLchan (*)[4]) rgba,
+ NULL);
+ src += rowLength;
+ destY++;
+ }
+ return GL_TRUE;
+ }
+ else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
+ /* upside-down */
+ GLint row;
+ for (row=0; row<drawHeight; row++) {
+ ASSERT(drawWidth < MAX_WIDTH);
+ _mesa_map_ci8_to_rgba(ctx, drawWidth, src, rgba);
+ destY--;
+ (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
+ (const GLchan (*)[4]) rgba,
+ NULL);
+ src += rowLength;
+ }
+ return GL_TRUE;
+ }
+ else {
+ /* with zooming */
+ GLint row;
+ for (row=0; row<drawHeight; row++) {
+ ASSERT(drawWidth < MAX_WIDTH);
+ _mesa_map_ci8_to_rgba(ctx, drawWidth, src, rgba);
+ gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
+ zSpan, 0, (void *) rgba, zoomY0);
+ src += rowLength;
+ destY++;
+ }
+ return GL_TRUE;
+ }
+ }
+ else if (ctx->ImageTransferState==0) {
+ /* write CI data to CI frame buffer */
+ GLint row;
+ if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
+ /* no zooming */
+ for (row=0; row<drawHeight; row++) {
+ (*ctx->Driver.WriteCI8Span)(ctx, drawWidth, destX, destY,
+ src, NULL);
+ src += rowLength;
+ destY++;
+ }
+ return GL_TRUE;
+ }
+ else {
+ /* with zooming */
+ return GL_FALSE;
+ }
+ }
+ }
+ else {
+ /* can't handle this pixel format and/or data type here */
+ return GL_FALSE;
+ }
+ }
+
+ /* can't do a simple draw, have to use slow path */
+ return GL_FALSE;
+}
+
+
+
+/*
+ * Do glDrawPixels of index pixels.
+ */
+static void
+draw_index_pixels( GLcontext *ctx, GLint x, GLint y,
+ GLsizei width, GLsizei height,
+ GLenum type, const GLvoid *pixels )
+{
+ const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
+ const GLint desty = y;
+ GLint row, drawWidth;
+ GLdepth zspan[MAX_WIDTH];
+
+ drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
+
+ /* Fragment depth values */
+ if (ctx->Depth.Test || ctx->Fog.Enabled) {
+ GLdepth zval = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual.DepthMaxF);
+ GLint i;
+ for (i = 0; i < drawWidth; i++) {
+ zspan[i] = zval;
+ }
+ }
+
+ /*
+ * General solution
+ */
+ for (row = 0; row < height; row++, y++) {
+ GLuint indexes[MAX_WIDTH];
+ const GLvoid *source = _mesa_image_address(&ctx->Unpack,
+ pixels, width, height, GL_COLOR_INDEX, type, 0, row, 0);
+ _mesa_unpack_index_span(ctx, drawWidth, GL_UNSIGNED_INT, indexes,
+ type, source, &ctx->Unpack,
+ ctx->ImageTransferState);
+ if (zoom) {
+ gl_write_zoomed_index_span(ctx, drawWidth, x, y, zspan, 0, indexes, desty);
+ }
+ else {
+ gl_write_index_span(ctx, drawWidth, x, y, zspan, 0, indexes, GL_BITMAP);
+ }
+ }
+}
+
+
+
+/*
+ * Do glDrawPixels of stencil image. The image datatype may either
+ * be GLubyte or GLbitmap.
+ */
+static void
+draw_stencil_pixels( GLcontext *ctx, GLint x, GLint y,
+ GLsizei width, GLsizei height,
+ GLenum type, const GLvoid *pixels )
+{
+ const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
+ const GLint desty = y;
+ GLint row, drawWidth;
+
+ if (type != GL_BYTE &&
+ type != GL_UNSIGNED_BYTE &&
+ type != GL_SHORT &&
+ type != GL_UNSIGNED_SHORT &&
+ type != GL_INT &&
+ type != GL_UNSIGNED_INT &&
+ type != GL_FLOAT &&
+ type != GL_BITMAP) {
+ gl_error( ctx, GL_INVALID_ENUM, "glDrawPixels(stencil type)");
+ return;
+ }
+
+ drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
+
+ for (row = 0; row < height; row++, y++) {
+ GLstencil values[MAX_WIDTH];
+ GLenum destType = (sizeof(GLstencil) == sizeof(GLubyte))
+ ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT;
+ const GLvoid *source = _mesa_image_address(&ctx->Unpack,
+ pixels, width, height, GL_COLOR_INDEX, type, 0, row, 0);
+ _mesa_unpack_index_span(ctx, drawWidth, destType, values,
+ type, source, &ctx->Unpack,
+ ctx->ImageTransferState);
+ if (ctx->ImageTransferState & IMAGE_SHIFT_OFFSET_BIT) {
+ _mesa_shift_and_offset_stencil( ctx, drawWidth, values );
+ }
+ if (ctx->Pixel.MapStencilFlag) {
+ _mesa_map_stencil( ctx, drawWidth, values );
+ }
+
+ if (zoom) {
+ gl_write_zoomed_stencil_span( ctx, (GLuint) drawWidth, x, y,
+ values, desty );
+ }
+ else {
+ _mesa_write_stencil_span( ctx, (GLuint) drawWidth, x, y, values );
+ }
+ }
+}
+
+
+
+/*
+ * Do a glDrawPixels of depth values.
+ */
+static void
+draw_depth_pixels( GLcontext *ctx, GLint x, GLint y,
+ GLsizei width, GLsizei height,
+ GLenum type, const GLvoid *pixels )
+{
+ const GLboolean bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0;
+ const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
+ const GLint desty = y;
+ GLchan rgba[MAX_WIDTH][4];
+ GLuint ispan[MAX_WIDTH];
+ GLint drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
+
+ if (type != GL_BYTE
+ && type != GL_UNSIGNED_BYTE
+ && type != GL_SHORT
+ && type != GL_UNSIGNED_SHORT
+ && type != GL_INT
+ && type != GL_UNSIGNED_INT
+ && type != GL_FLOAT) {
+ gl_error(ctx, GL_INVALID_ENUM, "glDrawPixels(type)");
+ return;
+ }
+
+ /* Colors or indexes */
+ if (ctx->Visual.RGBAflag) {
+ GLint r = FLOAT_TO_CHAN(ctx->Current.RasterColor[0]);
+ GLint g = FLOAT_TO_CHAN(ctx->Current.RasterColor[1]);
+ GLint b = FLOAT_TO_CHAN(ctx->Current.RasterColor[2]);
+ GLint a = FLOAT_TO_CHAN(ctx->Current.RasterColor[3]);
+ GLint i;
+ for (i = 0; i < drawWidth; i++) {
+ rgba[i][RCOMP] = r;
+ rgba[i][GCOMP] = g;
+ rgba[i][BCOMP] = b;
+ rgba[i][ACOMP] = a;
+ }
+ }
+ else {
+ GLint i;
+ for (i = 0; i < drawWidth; i++) {
+ ispan[i] = ctx->Current.RasterIndex;
+ }
+ }
+
+ if (type==GL_UNSIGNED_SHORT && sizeof(GLdepth)==sizeof(GLushort)
+ && !bias_or_scale && !zoom && ctx->Visual.RGBAflag) {
+ /* Special case: directly write 16-bit depth values */
+ GLint row;
+ for (row = 0; row < height; row++, y++) {
+ GLdepth zspan[MAX_WIDTH];
+ const GLushort *zptr = _mesa_image_address(&ctx->Unpack,
+ pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0);
+ GLint i;
+ for (i = 0; i < width; i++)
+ zspan[i] = zptr[i];
+ gl_write_rgba_span( ctx, width, x, y, zspan, 0, rgba, GL_BITMAP );
+ }
+ }
+ else if (type==GL_UNSIGNED_INT && ctx->Visual.DepthBits == 32
+ && !bias_or_scale && !zoom && ctx->Visual.RGBAflag) {
+ /* Special case: directly write 32-bit depth values */
+ GLint row;
+ for (row = 0; row < height; row++, y++) {
+ const GLuint *zptr = _mesa_image_address(&ctx->Unpack,
+ pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0);
+ gl_write_rgba_span( ctx, width, x, y, zptr, 0, rgba, GL_BITMAP );
+ }
+ }
+ else {
+ /* General case */
+ GLint row;
+ for (row = 0; row < height; row++, y++) {
+ GLdepth zspan[MAX_WIDTH];
+ const GLvoid *src = _mesa_image_address(&ctx->Unpack,
+ pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0);
+ _mesa_unpack_depth_span( ctx, drawWidth, zspan, type, src,
+ &ctx->Unpack, ctx->ImageTransferState );
+ if (ctx->Visual.RGBAflag) {
+ if (zoom) {
+ gl_write_zoomed_rgba_span(ctx, width, x, y, zspan, 0,
+ (const GLchan (*)[4]) rgba, desty);
+ }
+ else {
+ gl_write_rgba_span(ctx, width, x, y, zspan, 0, rgba, GL_BITMAP);
+ }
+ }
+ else {
+ if (zoom) {
+ gl_write_zoomed_index_span(ctx, width, x, y, zspan, 0,
+ ispan, GL_BITMAP);
+ }
+ else {
+ gl_write_index_span(ctx, width, x, y, zspan, 0,
+ ispan, GL_BITMAP);
+ }
+ }
+
+ }
+ }
+}
+
+
+/*
+ * Do glDrawPixels of RGBA pixels.
+ */
+static void
+draw_rgba_pixels( GLcontext *ctx, GLint x, GLint y,
+ GLsizei width, GLsizei height,
+ GLenum format, GLenum type, const GLvoid *pixels )
+{
+ const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
+ const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
+ const GLint desty = y;
+ GLdepth zspan[MAX_WIDTH];
+ GLboolean quickDraw;
+ GLfloat *convImage = NULL;
+ GLuint transferOps = ctx->ImageTransferState;
+
+ if (!_mesa_is_legal_format_and_type(format, type)) {
+ gl_error(ctx, GL_INVALID_ENUM, "glDrawPixels(format or type)");
+ return;
+ }
+
+ /* Try an optimized glDrawPixels first */
+ if (fast_draw_pixels(ctx, x, y, width, height, format, type, pixels))
+ return;
+
+ /* Fragment depth values */
+ if (ctx->Depth.Test || ctx->Fog.Enabled) {
+ /* fill in array of z values */
+ GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual.DepthMaxF);
+ GLint i;
+ for (i=0;i<width;i++) {
+ zspan[i] = z;
+ }
+ }
+
+
+ if (ctx->RasterMask == 0 && !zoom && x >= 0 && y >= 0
+ && x + width <= ctx->DrawBuffer->Width
+ && y + height <= ctx->DrawBuffer->Height) {
+ quickDraw = GL_TRUE;
+ }
+ else {
+ quickDraw = GL_FALSE;
+ }
+
+ if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
+ /* Convolution has to be handled specially. We'll create an
+ * intermediate image, applying all pixel transfer operations
+ * up to convolution. Then we'll convolve the image. Then
+ * we'll proceed with the rest of the transfer operations and
+ * rasterize the image.
+ */
+ GLint row;
+ GLfloat *dest, *tmpImage;
+
+ tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
+ if (!tmpImage) {
+ gl_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
+ return;
+ }
+ convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
+ if (!convImage) {
+ FREE(tmpImage);
+ gl_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
+ return;
+ }
+
+ /* Unpack the image and apply transfer ops up to convolution */
+ dest = tmpImage;
+ for (row = 0; row < height; row++) {
+ const GLvoid *source = _mesa_image_address(unpack,
+ pixels, width, height, format, type, 0, row, 0);
+ _mesa_unpack_float_color_span(ctx, width, GL_RGBA, (void *) dest,
+ format, type, source, unpack,
+ transferOps & IMAGE_PRE_CONVOLUTION_BITS,
+ GL_FALSE);
+ dest += width * 4;
+ }
+
+ /* do convolution */
+ if (ctx->Pixel.Convolution2DEnabled) {
+ _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
+ }
+ else {
+ ASSERT(ctx->Pixel.Separable2DEnabled);
+ _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
+ }
+ FREE(tmpImage);
+
+ /* continue transfer ops and draw the convolved image */
+ unpack = &_mesa_native_packing;
+ pixels = convImage;
+ format = GL_RGBA;
+ type = GL_FLOAT;
+ transferOps &= IMAGE_POST_CONVOLUTION_BITS;
+ }
+
+ /*
+ * General solution
+ */
+ {
+ GLchan rgba[MAX_WIDTH][4];
+ GLint row;
+ if (width > MAX_WIDTH)
+ width = MAX_WIDTH;
+ for (row = 0; row < height; row++, y++) {
+ const GLvoid *source = _mesa_image_address(unpack,
+ pixels, width, height, format, type, 0, row, 0);
+ _mesa_unpack_chan_color_span(ctx, width, GL_RGBA, (void*) rgba,
+ format, type, source, unpack,
+ transferOps);
+ if ((ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink) ||
+ (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink))
+ continue;
+
+ if (ctx->Texture.ReallyEnabled && ctx->Pixel.PixelTextureEnabled) {
+ GLfloat s[MAX_WIDTH], t[MAX_WIDTH], r[MAX_WIDTH], q[MAX_WIDTH];
+ GLchan primary_rgba[MAX_WIDTH][4];
+ GLuint unit;
+ /* XXX not sure how multitexture is supposed to work here */
+
+ MEMCPY(primary_rgba, rgba, 4 * width * sizeof(GLchan));
+
+ for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
+ if (ctx->Texture.Unit[unit].ReallyEnabled) {
+ _mesa_pixeltexgen(ctx, width, (const GLchan (*)[4]) rgba,
+ s, t, r, q);
+ gl_texture_pixels(ctx, unit, width, s, t, r, NULL,
+ primary_rgba, rgba);
+ }
+ }
+ }
+
+ if (quickDraw) {
+ (*ctx->Driver.WriteRGBASpan)( ctx, width, x, y,
+ (CONST GLchan (*)[]) rgba, NULL);
+ }
+ else if (zoom) {
+ gl_write_zoomed_rgba_span( ctx, width, x, y, zspan, 0,
+ (CONST GLchan (*)[]) rgba, desty );
+ }
+ else {
+ gl_write_rgba_span( ctx, (GLuint) width, x, y, zspan, 0,
+ rgba, GL_BITMAP);
+ }
+ }
+ }
+
+ if (convImage) {
+ FREE(convImage);
+ }
+}
+
+
+
+/*
+ * Execute glDrawPixels
+ */
+void
+_swrast_DrawPixels( GLcontext *ctx,
+ GLint x, GLint y,
+ GLsizei width, GLsizei height,
+ GLenum format, GLenum type,
+ const struct gl_pixelstore_attrib *unpack,
+ const GLvoid *pixels )
+{
+ (void) unpack;
+
+ switch (format) {
+ case GL_STENCIL_INDEX:
+ draw_stencil_pixels( ctx, x, y, width, height, type, pixels );
+ break;
+ case GL_DEPTH_COMPONENT:
+ draw_depth_pixels( ctx, x, y, width, height, type, pixels );
+ break;
+ case GL_COLOR_INDEX:
+ if (ctx->Visual.RGBAflag)
+ draw_rgba_pixels(ctx, x,y, width, height, format, type, pixels);
+ else
+ draw_index_pixels(ctx, x, y, width, height, type, pixels);
+ break;
+ case GL_RED:
+ case GL_GREEN:
+ case GL_BLUE:
+ case GL_ALPHA:
+ case GL_LUMINANCE:
+ case GL_LUMINANCE_ALPHA:
+ case GL_RGB:
+ case GL_BGR:
+ case GL_RGBA:
+ case GL_BGRA:
+ case GL_ABGR_EXT:
+ draw_rgba_pixels(ctx, x, y, width, height, format, type, pixels);
+ break;
+ default:
+ gl_error( ctx, GL_INVALID_ENUM, "glDrawPixels(format)" );
+ }
+}
+
diff --git a/src/mesa/swrast/s_drawpix.h b/src/mesa/swrast/s_drawpix.h
new file mode 100644
index 0000000000..1edac14097
--- /dev/null
+++ b/src/mesa/swrast/s_drawpix.h
@@ -0,0 +1,42 @@
+/* $Id: s_drawpix.h,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ *
+ * Copyright (C) 1999 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.
+ */
+
+
+#ifndef S_DRAWPIXELS_H
+#define S_DRAWPIXELS_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+extern GLboolean
+_mesa_clip_pixelrect(const GLcontext *ctx,
+ GLint *destX, GLint *destY,
+ GLsizei *width, GLsizei *height,
+ GLint *skipPixels, GLint *skipRows);
+
+#endif
diff --git a/src/mesa/swrast/s_fog.c b/src/mesa/swrast/s_fog.c
new file mode 100644
index 0000000000..32fafe617c
--- /dev/null
+++ b/src/mesa/swrast/s_fog.c
@@ -0,0 +1,188 @@
+/* $Id: s_fog.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.
+ */
+
+
+#include "glheader.h"
+#include "colormac.h"
+#include "context.h"
+#include "macros.h"
+#include "mmath.h"
+
+#include "s_fog.h"
+
+
+/*
+ * Apply fog to an array of RGBA pixels.
+ * Input: n - number of pixels
+ * fog - array of interpolated screen-space fog coordinates in [0..1]
+ * red, green, blue, alpha - pixel colors
+ * Output: red, green, blue, alpha - fogged pixel colors
+ */
+void
+_mesa_fog_rgba_pixels( const GLcontext *ctx,
+ GLuint n,
+ const GLfixed fog[],
+ GLchan rgba[][4] )
+{
+ GLfixed rFog = ctx->Fog.Color[0] * CHAN_MAXF;
+ GLfixed gFog = ctx->Fog.Color[1] * CHAN_MAXF;
+ GLfixed bFog = ctx->Fog.Color[2] * CHAN_MAXF;
+ GLuint i;
+
+ for (i=0;i<n;i++) {
+ GLfixed f = CLAMP(fog[i], 0, FIXED_ONE);
+ GLfixed g = FIXED_ONE - f;
+ rgba[i][0] = (f*rgba[i][0] + g*rFog) >> FIXED_SHIFT;
+ rgba[i][1] = (f*rgba[i][1] + g*gFog) >> FIXED_SHIFT;
+ rgba[i][2] = (f*rgba[i][2] + g*bFog) >> FIXED_SHIFT;
+ }
+}
+
+
+
+
+/*
+ * Apply fog to an array of color index pixels.
+ * Input: n - number of pixels
+ * z - array of integer depth values
+ * index - pixel color indexes
+ * Output: index - fogged pixel color indexes
+ */
+void
+_mesa_fog_ci_pixels( const GLcontext *ctx,
+ GLuint n, const GLfixed fog[], GLuint index[] )
+{
+ GLuint idx = ctx->Fog.Index;
+ GLuint i;
+
+ for (i=0;i<n;i++) {
+ GLfixed f = FixedToFloat(CLAMP(fog[i], 0, FIXED_ONE));
+ index[i] = (GLuint) ((GLfloat) index[i] + (1.0F-f) * idx);
+ }
+}
+
+
+
+/*
+ * Calculate fog coords from window z values
+ * Input: n - number of pixels
+ * z - array of integer depth values
+ * red, green, blue, alpha - pixel colors
+ * Output: red, green, blue, alpha - fogged pixel colors
+ *
+ * Use lookup table & interpolation?
+ */
+void
+_mesa_win_fog_coords_from_z( const GLcontext *ctx,
+ GLuint n,
+ const GLdepth z[],
+ GLfixed fogcoord[] )
+{
+ GLfloat c = ctx->ProjectionMatrix.m[10];
+ GLfloat d = ctx->ProjectionMatrix.m[14];
+ GLuint i;
+
+ GLfloat tz = ctx->Viewport.WindowMap.m[MAT_TZ];
+ GLfloat szInv = 1.0F / ctx->Viewport.WindowMap.m[MAT_SZ];
+
+ switch (ctx->Fog.Mode) {
+ case GL_LINEAR:
+ {
+ GLfloat fogEnd = ctx->Fog.End;
+ GLfloat fogScale = (GLfloat) FIXED_ONE / (ctx->Fog.End -
+ ctx->Fog.Start);
+ for (i=0;i<n;i++) {
+ GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
+ GLfloat eyez = -d / (c+ndcz);
+ if (eyez < 0.0) eyez = -eyez;
+ fogcoord[i] = (GLint)(fogEnd - eyez) * fogScale;
+ }
+ }
+ break;
+ case GL_EXP:
+ for (i=0;i<n;i++) {
+ GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
+ GLfloat eyez = d / (c+ndcz);
+ if (eyez < 0.0) eyez = -eyez;
+ fogcoord[i] = FloatToFixed(exp( -ctx->Fog.Density * eyez ));
+ }
+ break;
+ case GL_EXP2:
+ {
+ GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density;
+ for (i=0;i<n;i++) {
+ GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
+ GLfloat eyez = d / (c+ndcz);
+ GLfloat tmp = negDensitySquared * eyez * eyez;
+#if defined(__alpha__) || defined(__alpha)
+ /* XXX this underflow check may be needed for other systems */
+ if (tmp < FLT_MIN_10_EXP)
+ tmp = FLT_MIN_10_EXP;
+#endif
+ fogcoord[i] = FloatToFixed(exp( tmp ));
+ }
+ }
+ break;
+ default:
+ gl_problem(ctx, "Bad fog mode in _mesa_win_fog_coords_from_z");
+ return;
+ }
+}
+
+
+/*
+ * Apply fog to an array of RGBA pixels.
+ * Input: n - number of pixels
+ * z - array of integer depth values
+ * red, green, blue, alpha - pixel colors
+ * Output: red, green, blue, alpha - fogged pixel colors
+ */
+void
+_mesa_depth_fog_rgba_pixels( const GLcontext *ctx,
+ GLuint n, const GLdepth z[], GLchan rgba[][4] )
+{
+ GLfixed fog[MAX_WIDTH];
+ _mesa_win_fog_coords_from_z( ctx, n, z, fog );
+ _mesa_fog_rgba_pixels( ctx, n, fog, rgba );
+}
+
+
+/*
+ * Apply fog to an array of color index pixels.
+ * Input: n - number of pixels
+ * z - array of integer depth values
+ * index - pixel color indexes
+ * Output: index - fogged pixel color indexes
+ */
+void
+_mesa_depth_fog_ci_pixels( const GLcontext *ctx,
+ GLuint n, const GLdepth z[], GLuint index[] )
+{
+ GLfixed fog[MAX_WIDTH];
+ _mesa_win_fog_coords_from_z( ctx, n, z, fog );
+ _mesa_fog_ci_pixels( ctx, n, fog, index );
+}
+
diff --git a/src/mesa/swrast/s_fog.h b/src/mesa/swrast/s_fog.h
new file mode 100644
index 0000000000..e550412ece
--- /dev/null
+++ b/src/mesa/swrast/s_fog.h
@@ -0,0 +1,63 @@
+/* $Id: s_fog.h,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.
+ */
+
+
+#ifndef S_FOG_H
+#define S_FOG_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+
+
+extern void
+_mesa_fog_rgba_pixels( const GLcontext *ctx,
+ GLuint n, const GLfixed fog[],
+ GLchan rgba[][4] );
+
+extern void
+_mesa_fog_ci_pixels( const GLcontext *ctx,
+ GLuint n, const GLfixed fog[], GLuint indx[] );
+
+extern void
+_mesa_win_fog_coords_from_z( const GLcontext *ctx,
+ GLuint n,
+ const GLdepth z[],
+ GLfixed fogcoord[] );
+
+extern void
+_mesa_depth_fog_rgba_pixels( const GLcontext *ctx,
+ GLuint n, const GLdepth z[], GLchan rgba[][4] );
+
+extern void
+_mesa_depth_fog_ci_pixels( const GLcontext *ctx,
+ GLuint n, const GLdepth z[], GLuint index[] );
+
+
+
+#endif
diff --git a/src/mesa/swrast/s_imaging.c b/src/mesa/swrast/s_imaging.c
new file mode 100644
index 0000000000..672d163d8c
--- /dev/null
+++ b/src/mesa/swrast/s_imaging.c
@@ -0,0 +1,105 @@
+/* $Id: s_imaging.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.4
+ *
+ * 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.
+ */
+
+
+/*
+ * Histogram, Min/max and convolution for GL_ARB_imaging subset
+ *
+ */
+
+
+#include "glheader.h"
+#include "colormac.h"
+#include "image.h"
+#include "mmath.h"
+
+#include "s_imaging.h"
+#include "s_span.h"
+
+
+
+/*
+ * Update the min/max values from an array of fragment colors.
+ */
+void
+_mesa_update_minmax(GLcontext *ctx, GLuint n, const GLfloat rgba[][4])
+{
+ GLuint i;
+ for (i = 0; i < n; i++) {
+ /* update mins */
+ if (rgba[i][RCOMP] < ctx->MinMax.Min[RCOMP])
+ ctx->MinMax.Min[RCOMP] = rgba[i][RCOMP];
+ if (rgba[i][GCOMP] < ctx->MinMax.Min[GCOMP])
+ ctx->MinMax.Min[GCOMP] = rgba[i][GCOMP];
+ if (rgba[i][BCOMP] < ctx->MinMax.Min[BCOMP])
+ ctx->MinMax.Min[BCOMP] = rgba[i][BCOMP];
+ if (rgba[i][ACOMP] < ctx->MinMax.Min[ACOMP])
+ ctx->MinMax.Min[ACOMP] = rgba[i][ACOMP];
+
+ /* update maxs */
+ if (rgba[i][RCOMP] > ctx->MinMax.Max[RCOMP])
+ ctx->MinMax.Max[RCOMP] = rgba[i][RCOMP];
+ if (rgba[i][GCOMP] > ctx->MinMax.Max[GCOMP])
+ ctx->MinMax.Max[GCOMP] = rgba[i][GCOMP];
+ if (rgba[i][BCOMP] > ctx->MinMax.Max[BCOMP])
+ ctx->MinMax.Max[BCOMP] = rgba[i][BCOMP];
+ if (rgba[i][ACOMP] > ctx->MinMax.Max[ACOMP])
+ ctx->MinMax.Max[ACOMP] = rgba[i][ACOMP];
+ }
+}
+
+
+/*
+ * Update the histogram values from an array of fragment colors.
+ */
+void
+_mesa_update_histogram(GLcontext *ctx, GLuint n, const GLfloat rgba[][4])
+{
+ const GLint max = ctx->Histogram.Width - 1;
+ GLfloat w = (GLfloat) max;
+ GLuint i;
+
+ if (ctx->Histogram.Width == 0)
+ return;
+
+ for (i = 0; i < n; i++) {
+ GLint ri = (GLint) (rgba[i][RCOMP] * w + 0.5F);
+ GLint gi = (GLint) (rgba[i][GCOMP] * w + 0.5F);
+ GLint bi = (GLint) (rgba[i][BCOMP] * w + 0.5F);
+ GLint ai = (GLint) (rgba[i][ACOMP] * w + 0.5F);
+ ri = CLAMP(ri, 0, max);
+ gi = CLAMP(gi, 0, max);
+ bi = CLAMP(bi, 0, max);
+ ai = CLAMP(ai, 0, max);
+ ctx->Histogram.Count[ri][RCOMP]++;
+ ctx->Histogram.Count[gi][GCOMP]++;
+ ctx->Histogram.Count[bi][BCOMP]++;
+ ctx->Histogram.Count[ai][ACOMP]++;
+ }
+}
+
+
+
diff --git a/src/mesa/swrast/s_lines.c b/src/mesa/swrast/s_lines.c
new file mode 100644
index 0000000000..75a01cf12e
--- /dev/null
+++ b/src/mesa/swrast/s_lines.c
@@ -0,0 +1,1173 @@
+/* $Id: s_lines.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.
+ */
+
+
+#include "glheader.h"
+#include "feedback.h"
+#include "macros.h"
+#include "mmath.h"
+#include "vb.h"
+
+#include "s_pb.h"
+#include "s_depth.h"
+
+
+
+/**********************************************************************/
+/***** Rasterization *****/
+/**********************************************************************/
+
+
+/*
+ * There are 4 pairs (RGBA, CI) of line drawing functions:
+ * 1. simple: width=1 and no special rasterization functions (fastest)
+ * 2. flat: width=1, non-stippled, flat-shaded, any raster operations
+ * 3. smooth: width=1, non-stippled, smooth-shaded, any raster operations
+ * 4. general: any other kind of line (slowest)
+ */
+
+
+/*
+ * All line drawing functions have the same arguments:
+ * v1, v2 - indexes of first and second endpoints into vertex buffer arrays
+ * pv - provoking vertex: which vertex color/index to use for flat shading.
+ */
+
+
+
+
+
+
+#if MAX_WIDTH > MAX_HEIGHT
+# define MAXPOINTS MAX_WIDTH
+#else
+# define MAXPOINTS MAX_HEIGHT
+#endif
+
+
+/* Flat, color index line */
+static void flat_ci_line( GLcontext *ctx,
+ GLuint vert0, GLuint vert1, GLuint pvert )
+{
+ PB_SET_INDEX( ctx->PB, ctx->VB->IndexPtr->data[pvert] );
+
+#define INTERP_XY 1
+#define PLOT(X,Y) PB_WRITE_PIXEL(ctx->PB, X, Y, 0, 0);
+
+#include "s_linetemp.h"
+
+ gl_flush_pb(ctx);
+}
+
+
+
+/* Flat, color index line with Z interpolation/testing */
+static void flat_ci_z_line( GLcontext *ctx,
+ GLuint vert0, GLuint vert1, GLuint pvert )
+{
+ PB_SET_INDEX( ctx->PB, ctx->VB->IndexPtr->data[pvert] );
+
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define PLOT(X,Y) PB_WRITE_PIXEL(ctx->PB, X, Y, Z, fog0);
+
+#include "s_linetemp.h"
+
+ gl_flush_pb(ctx);
+}
+
+
+
+/* Flat-shaded, RGBA line */
+static void flat_rgba_line( GLcontext *ctx,
+ GLuint vert0, GLuint vert1, GLuint pvert )
+{
+ const GLchan *color = ctx->VB->ColorPtr->data[pvert];
+ PB_SET_COLOR( ctx->PB, color[0], color[1], color[2], color[3] );
+
+#define INTERP_XY 1
+#define PLOT(X,Y) PB_WRITE_PIXEL(ctx->PB, X, Y, 0, 0);
+
+#include "s_linetemp.h"
+
+ gl_flush_pb(ctx);
+}
+
+
+
+/* Flat-shaded, RGBA line with Z interpolation/testing */
+static void flat_rgba_z_line( GLcontext *ctx,
+ GLuint vert0, GLuint vert1, GLuint pvert )
+{
+ const GLchan *color = ctx->VB->ColorPtr->data[pvert];
+ PB_SET_COLOR( ctx->PB, color[0], color[1], color[2], color[3] );
+
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define PLOT(X,Y) PB_WRITE_PIXEL(ctx->PB, X, Y, Z, fog0);
+
+#include "s_linetemp.h"
+
+ gl_flush_pb(ctx);
+}
+
+
+
+/* Smooth shaded, color index line */
+static void smooth_ci_line( GLcontext *ctx,
+ GLuint vert0, GLuint vert1, GLuint pvert )
+{
+ GLint count = ctx->PB->count;
+ GLint *pbx = ctx->PB->x;
+ GLint *pby = ctx->PB->y;
+ GLuint *pbi = ctx->PB->index;
+ (void) pvert;
+
+ ctx->PB->mono = GL_FALSE;
+
+#define INTERP_XY 1
+#define INTERP_INDEX 1
+
+#define PLOT(X,Y) \
+ pbx[count] = X; \
+ pby[count] = Y; \
+ pbi[count] = I; \
+ count++;
+
+#include "s_linetemp.h"
+
+ ctx->PB->count = count;
+ gl_flush_pb(ctx);
+}
+
+
+
+/* Smooth shaded, color index line with Z interpolation/testing */
+static void smooth_ci_z_line( GLcontext *ctx,
+ GLuint vert0, GLuint vert1, GLuint pvert )
+{
+ GLint count = ctx->PB->count;
+ GLint *pbx = ctx->PB->x;
+ GLint *pby = ctx->PB->y;
+ GLdepth *pbz = ctx->PB->z;
+ GLuint *pbi = ctx->PB->index;
+ (void) pvert;
+
+ ctx->PB->mono = GL_FALSE;
+
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_INDEX 1
+
+#define PLOT(X,Y) \
+ pbx[count] = X; \
+ pby[count] = Y; \
+ pbz[count] = Z; \
+ pbi[count] = I; \
+ count++;
+
+#include "s_linetemp.h"
+
+ ctx->PB->count = count;
+ gl_flush_pb(ctx);
+}
+
+
+
+/* Smooth-shaded, RGBA line */
+static void smooth_rgba_line( GLcontext *ctx,
+ GLuint vert0, GLuint vert1, GLuint pvert )
+{
+ GLint count = ctx->PB->count;
+ GLint *pbx = ctx->PB->x;
+ GLint *pby = ctx->PB->y;
+ GLchan (*pbrgba)[4] = ctx->PB->rgba;
+ (void) pvert;
+
+ ctx->PB->mono = GL_FALSE;
+
+#define INTERP_XY 1
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+
+#define PLOT(X,Y) \
+ pbx[count] = X; \
+ pby[count] = Y; \
+ pbrgba[count][RCOMP] = FixedToInt(r0); \
+ pbrgba[count][GCOMP] = FixedToInt(g0); \
+ pbrgba[count][BCOMP] = FixedToInt(b0); \
+ pbrgba[count][ACOMP] = FixedToInt(a0); \
+ count++;
+
+#include "s_linetemp.h"
+
+ ctx->PB->count = count;
+ gl_flush_pb(ctx);
+}
+
+
+
+/* Smooth-shaded, RGBA line with Z interpolation/testing */
+static void smooth_rgba_z_line( GLcontext *ctx,
+ GLuint vert0, GLuint vert1, GLuint pvert )
+{
+ GLint count = ctx->PB->count;
+ GLint *pbx = ctx->PB->x;
+ GLint *pby = ctx->PB->y;
+ GLdepth *pbz = ctx->PB->z;
+ GLfixed *pbfog = ctx->PB->fog;
+ GLchan (*pbrgba)[4] = ctx->PB->rgba;
+
+ (void) pvert;
+
+ ctx->PB->mono = GL_FALSE;
+
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+
+#define PLOT(X,Y) \
+ pbx[count] = X; \
+ pby[count] = Y; \
+ pbz[count] = Z; \
+ pbfog[count] = fog0; \
+ pbrgba[count][RCOMP] = FixedToInt(r0); \
+ pbrgba[count][GCOMP] = FixedToInt(g0); \
+ pbrgba[count][BCOMP] = FixedToInt(b0); \
+ pbrgba[count][ACOMP] = FixedToInt(a0); \
+ count++;
+
+#include "s_linetemp.h"
+
+ ctx->PB->count = count;
+ gl_flush_pb(ctx);
+}
+
+
+#define CHECK_FULL(count) \
+ if (count >= PB_SIZE-MAX_WIDTH) { \
+ ctx->PB->count = count; \
+ gl_flush_pb(ctx); \
+ count = ctx->PB->count; \
+ }
+
+
+
+/* Smooth shaded, color index, any width, maybe stippled */
+static void general_smooth_ci_line( GLcontext *ctx,
+ GLuint vert0, GLuint vert1, GLuint pvert )
+{
+ GLint count = ctx->PB->count;
+ GLint *pbx = ctx->PB->x;
+ GLint *pby = ctx->PB->y;
+ GLdepth *pbz = ctx->PB->z;
+ GLfixed *pbfog = ctx->PB->fog;
+ GLuint *pbi = ctx->PB->index;
+ (void) pvert;
+
+ ctx->PB->mono = GL_FALSE;
+
+ if (ctx->Line.StippleFlag) {
+ /* stippled */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_INDEX 1
+#define WIDE 1
+#define STIPPLE 1
+#define PLOT(X,Y) \
+ pbx[count] = X; \
+ pby[count] = Y; \
+ pbz[count] = Z; \
+ pbfog[count] = fog0; \
+ pbi[count] = I; \
+ count++; \
+ CHECK_FULL(count);
+#include "s_linetemp.h"
+ }
+ else {
+ /* unstippled */
+ if (ctx->Line.Width==2.0F) {
+ /* special case: unstippled and width=2 */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_INDEX 1
+#define XMAJOR_PLOT(X,Y) \
+ pbx[count] = X; pbx[count+1] = X; \
+ pby[count] = Y; pby[count+1] = Y+1; \
+ pbz[count] = Z; pbz[count+1] = Z; \
+ pbfog[count] = fog0; pbfog[count+1] = fog0; \
+ pbi[count] = I; pbi[count+1] = I; \
+ count += 2; \
+ CHECK_FULL(count);
+#define YMAJOR_PLOT(X,Y) \
+ pbx[count] = X; pbx[count+1] = X+1; \
+ pby[count] = Y; pby[count+1] = Y; \
+ pbz[count] = Z; pbz[count+1] = Z; \
+ pbfog[count] = fog0; pbfog[count+1] = fog0; \
+ pbi[count] = I; pbi[count+1] = I; \
+ count += 2; \
+ CHECK_FULL(count);
+#include "s_linetemp.h"
+ }
+ else {
+ /* unstippled, any width */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_INDEX 1
+#define WIDE 1
+#define PLOT(X,Y) \
+ pbx[count] = X; \
+ pby[count] = Y; \
+ pbz[count] = Z; \
+ pbi[count] = I; \
+ pbfog[count] = fog0; \
+ count++; \
+ CHECK_FULL(count);
+#include "s_linetemp.h"
+ }
+ }
+
+ ctx->PB->count = count;
+ gl_flush_pb(ctx);
+}
+
+
+/* Flat shaded, color index, any width, maybe stippled */
+static void general_flat_ci_line( GLcontext *ctx,
+ GLuint vert0, GLuint vert1, GLuint pvert )
+{
+ GLint count;
+ GLint *pbx = ctx->PB->x;
+ GLint *pby = ctx->PB->y;
+ GLdepth *pbz = ctx->PB->z;
+ GLfixed *pbfog = ctx->PB->fog;
+ PB_SET_INDEX( ctx->PB, ctx->VB->IndexPtr->data[pvert] );
+ count = ctx->PB->count;
+
+ if (ctx->Line.StippleFlag) {
+ /* stippled, any width */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define WIDE 1
+#define STIPPLE 1
+#define PLOT(X,Y) \
+ pbx[count] = X; \
+ pby[count] = Y; \
+ pbz[count] = Z; \
+ pbfog[count] = fog0; \
+ count++; \
+ CHECK_FULL(count);
+#include "s_linetemp.h"
+ }
+ else {
+ /* unstippled */
+ if (ctx->Line.Width==2.0F) {
+ /* special case: unstippled and width=2 */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define XMAJOR_PLOT(X,Y) \
+ pbx[count] = X; pbx[count+1] = X; \
+ pby[count] = Y; pby[count+1] = Y+1; \
+ pbz[count] = Z; pbz[count+1] = Z; \
+ pbfog[count] = fog0; pbfog[count+1] = fog0; \
+ count += 2; \
+ CHECK_FULL(count);
+#define YMAJOR_PLOT(X,Y) \
+ pbx[count] = X; pbx[count+1] = X+1; \
+ pby[count] = Y; pby[count+1] = Y; \
+ pbz[count] = Z; pbz[count+1] = Z; \
+ pbfog[count] = fog0; pbfog[count+1] = fog0; \
+ count += 2; \
+ CHECK_FULL(count);
+#include "s_linetemp.h"
+ }
+ else {
+ /* unstippled, any width */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define WIDE 1
+#define PLOT(X,Y) \
+ pbx[count] = X; \
+ pby[count] = Y; \
+ pbz[count] = Z; \
+ pbfog[count] = fog0; \
+ count++; \
+ CHECK_FULL(count);
+#include "s_linetemp.h"
+ }
+ }
+
+ ctx->PB->count = count;
+ gl_flush_pb(ctx);
+}
+
+
+
+static void general_smooth_rgba_line( GLcontext *ctx,
+ GLuint vert0, GLuint vert1, GLuint pvert)
+{
+ GLint count = ctx->PB->count;
+ GLint *pbx = ctx->PB->x;
+ GLint *pby = ctx->PB->y;
+ GLdepth *pbz = ctx->PB->z;
+ GLfixed *pbfog = ctx->PB->fog;
+ GLchan (*pbrgba)[4] = ctx->PB->rgba;
+
+ (void) pvert;
+
+ ctx->PB->mono = GL_FALSE;
+
+ if (ctx->Line.StippleFlag) {
+ /* stippled */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+#define WIDE 1
+#define STIPPLE 1
+#define PLOT(X,Y) \
+ pbx[count] = X; \
+ pby[count] = Y; \
+ pbz[count] = Z; \
+ pbfog[count] = fog0; \
+ pbrgba[count][RCOMP] = FixedToInt(r0); \
+ pbrgba[count][GCOMP] = FixedToInt(g0); \
+ pbrgba[count][BCOMP] = FixedToInt(b0); \
+ pbrgba[count][ACOMP] = FixedToInt(a0); \
+ count++; \
+ CHECK_FULL(count);
+#include "s_linetemp.h"
+ }
+ else {
+ /* unstippled */
+ if (ctx->Line.Width==2.0F) {
+ /* special case: unstippled and width=2 */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+#define XMAJOR_PLOT(X,Y) \
+ pbx[count] = X; pbx[count+1] = X; \
+ pby[count] = Y; pby[count+1] = Y+1; \
+ pbz[count] = Z; pbz[count+1] = Z; \
+ pbfog[count] = fog0; pbfog[count+1] = fog0; \
+ pbrgba[count][RCOMP] = FixedToInt(r0); \
+ pbrgba[count][GCOMP] = FixedToInt(g0); \
+ pbrgba[count][BCOMP] = FixedToInt(b0); \
+ pbrgba[count][ACOMP] = FixedToInt(a0); \
+ pbrgba[count+1][RCOMP] = FixedToInt(r0); \
+ pbrgba[count+1][GCOMP] = FixedToInt(g0); \
+ pbrgba[count+1][BCOMP] = FixedToInt(b0); \
+ pbrgba[count+1][ACOMP] = FixedToInt(a0); \
+ count += 2; \
+ CHECK_FULL(count);
+#define YMAJOR_PLOT(X,Y) \
+ pbx[count] = X; pbx[count+1] = X+1; \
+ pby[count] = Y; pby[count+1] = Y; \
+ pbz[count] = Z; pbz[count+1] = Z; \
+ pbfog[count] = fog0; pbfog[count+1] = fog0; \
+ pbrgba[count][RCOMP] = FixedToInt(r0); \
+ pbrgba[count][GCOMP] = FixedToInt(g0); \
+ pbrgba[count][BCOMP] = FixedToInt(b0); \
+ pbrgba[count][ACOMP] = FixedToInt(a0); \
+ pbrgba[count+1][RCOMP] = FixedToInt(r0); \
+ pbrgba[count+1][GCOMP] = FixedToInt(g0); \
+ pbrgba[count+1][BCOMP] = FixedToInt(b0); \
+ pbrgba[count+1][ACOMP] = FixedToInt(a0); \
+ count += 2; \
+ CHECK_FULL(count);
+#include "s_linetemp.h"
+ }
+ else {
+ /* unstippled, any width */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+#define WIDE 1
+#define PLOT(X,Y) \
+ pbx[count] = X; \
+ pby[count] = Y; \
+ pbz[count] = Z; \
+ pbfog[count] = fog0; \
+ pbrgba[count][RCOMP] = FixedToInt(r0); \
+ pbrgba[count][GCOMP] = FixedToInt(g0); \
+ pbrgba[count][BCOMP] = FixedToInt(b0); \
+ pbrgba[count][ACOMP] = FixedToInt(a0); \
+ count++; \
+ CHECK_FULL(count);
+#include "s_linetemp.h"
+ }
+ }
+
+ ctx->PB->count = count;
+ gl_flush_pb(ctx);
+}
+
+
+static void general_flat_rgba_line( GLcontext *ctx,
+ GLuint vert0, GLuint vert1, GLuint pvert )
+{
+ const GLchan *color = ctx->VB->ColorPtr->data[pvert];
+ PB_SET_COLOR( ctx->PB, color[0], color[1], color[2], color[3] );
+
+ if (ctx->Line.StippleFlag) {
+ /* stippled */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define WIDE 1
+#define STIPPLE 1
+#define PLOT(X,Y) PB_WRITE_PIXEL(ctx->PB, X, Y, Z, fog0);
+#include "s_linetemp.h"
+ }
+ else {
+ /* unstippled */
+ if (ctx->Line.Width==2.0F) {
+ /* special case: unstippled and width=2 */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define XMAJOR_PLOT(X,Y) PB_WRITE_PIXEL(ctx->PB, X, Y, Z, fog0); \
+ PB_WRITE_PIXEL(ctx->PB, X, Y+1, Z, fog0);
+#define YMAJOR_PLOT(X,Y) PB_WRITE_PIXEL(ctx->PB, X, Y, Z, fog0); \
+ PB_WRITE_PIXEL(ctx->PB, X+1, Y, Z, fog0);
+#include "s_linetemp.h"
+ }
+ else {
+ /* unstippled, any width */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define WIDE 1
+#define PLOT(X,Y) PB_WRITE_PIXEL(ctx->PB, X, Y, Z, fog0);
+#include "s_linetemp.h"
+ }
+ }
+
+ gl_flush_pb(ctx);
+}
+
+
+/* Flat-shaded, textured, any width, maybe stippled */
+static void flat_textured_line( GLcontext *ctx,
+ GLuint vert0, GLuint vert1, GLuint pv )
+{
+ GLint count;
+ GLint *pbx = ctx->PB->x;
+ GLint *pby = ctx->PB->y;
+ GLdepth *pbz = ctx->PB->z;
+ GLfixed *pbfog = ctx->PB->fog;
+ GLfloat *pbs = ctx->PB->s[0];
+ GLfloat *pbt = ctx->PB->t[0];
+ GLfloat *pbu = ctx->PB->u[0];
+ GLchan *color = ctx->VB->ColorPtr->data[pv];
+ PB_SET_COLOR( ctx->PB, color[0], color[1], color[2], color[3] );
+ count = ctx->PB->count;
+
+ if (ctx->Line.StippleFlag) {
+ /* stippled */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_TEX 1
+#define WIDE 1
+#define STIPPLE 1
+#define PLOT(X,Y) \
+ { \
+ pbx[count] = X; \
+ pby[count] = Y; \
+ pbz[count] = Z; \
+ pbfog[count] = fog0; \
+ pbs[count] = fragTexcoord[0];\
+ pbt[count] = fragTexcoord[1];\
+ pbu[count] = fragTexcoord[2];\
+ count++; \
+ CHECK_FULL(count); \
+ }
+#include "s_linetemp.h"
+ }
+ else {
+ /* unstippled */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_TEX 1
+#define WIDE 1
+#define PLOT(X,Y) \
+ { \
+ pbx[count] = X; \
+ pby[count] = Y; \
+ pbz[count] = Z; \
+ pbfog[count] = fog0; \
+ pbs[count] = fragTexcoord[0];\
+ pbt[count] = fragTexcoord[1];\
+ pbu[count] = fragTexcoord[2];\
+ count++; \
+ CHECK_FULL(count); \
+ }
+#include "s_linetemp.h"
+ }
+
+ ctx->PB->count = count;
+ gl_flush_pb(ctx);
+}
+
+
+
+/* Smooth-shaded, textured, any width, maybe stippled */
+static void smooth_textured_line( GLcontext *ctx,
+ GLuint vert0, GLuint vert1, GLuint pvert )
+{
+ GLint count = ctx->PB->count;
+ GLint *pbx = ctx->PB->x;
+ GLint *pby = ctx->PB->y;
+ GLdepth *pbz = ctx->PB->z;
+ GLfixed *pbfog = ctx->PB->fog;
+ GLfloat *pbs = ctx->PB->s[0];
+ GLfloat *pbt = ctx->PB->t[0];
+ GLfloat *pbu = ctx->PB->u[0];
+ GLchan (*pbrgba)[4] = ctx->PB->rgba;
+ (void) pvert;
+
+ ctx->PB->mono = GL_FALSE;
+
+ if (ctx->Line.StippleFlag) {
+ /* stippled */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+#define INTERP_TEX 1
+#define WIDE 1
+#define STIPPLE 1
+#define PLOT(X,Y) \
+ { \
+ pbx[count] = X; \
+ pby[count] = Y; \
+ pbz[count] = Z; \
+ pbfog[count] = fog0; \
+ pbs[count] = fragTexcoord[0]; \
+ pbt[count] = fragTexcoord[1]; \
+ pbu[count] = fragTexcoord[2]; \
+ pbrgba[count][RCOMP] = FixedToInt(r0); \
+ pbrgba[count][GCOMP] = FixedToInt(g0); \
+ pbrgba[count][BCOMP] = FixedToInt(b0); \
+ pbrgba[count][ACOMP] = FixedToInt(a0); \
+ count++; \
+ CHECK_FULL(count); \
+ }
+#include "s_linetemp.h"
+ }
+ else {
+ /* unstippled */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+#define INTERP_TEX 1
+#define WIDE 1
+#define PLOT(X,Y) \
+ { \
+ pbx[count] = X; \
+ pby[count] = Y; \
+ pbz[count] = Z; \
+ pbfog[count] = fog0; \
+ pbs[count] = fragTexcoord[0]; \
+ pbt[count] = fragTexcoord[1]; \
+ pbu[count] = fragTexcoord[2]; \
+ pbrgba[count][RCOMP] = FixedToInt(r0); \
+ pbrgba[count][GCOMP] = FixedToInt(g0); \
+ pbrgba[count][BCOMP] = FixedToInt(b0); \
+ pbrgba[count][ACOMP] = FixedToInt(a0); \
+ count++; \
+ CHECK_FULL(count); \
+ }
+#include "s_linetemp.h"
+ }
+
+ ctx->PB->count = count;
+ gl_flush_pb(ctx);
+}
+
+
+/* Smooth-shaded, multitextured, any width, maybe stippled, separate specular
+ * color interpolation.
+ */
+static void smooth_multitextured_line( GLcontext *ctx,
+ GLuint vert0, GLuint vert1, GLuint pvert )
+{
+ GLint count = ctx->PB->count;
+ GLint *pbx = ctx->PB->x;
+ GLint *pby = ctx->PB->y;
+ GLdepth *pbz = ctx->PB->z;
+ GLfixed *pbfog = ctx->PB->fog;
+ GLchan (*pbrgba)[4] = ctx->PB->rgba;
+ GLchan (*pbspec)[3] = ctx->PB->spec;
+
+ (void) pvert;
+
+ ctx->PB->mono = GL_FALSE;
+
+ if (ctx->Line.StippleFlag) {
+ /* stippled */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_RGB 1
+#define INTERP_SPEC 1
+#define INTERP_ALPHA 1
+#define INTERP_MULTITEX 1
+#define WIDE 1
+#define STIPPLE 1
+#define PLOT(X,Y) \
+ { \
+ GLuint u; \
+ pbx[count] = X; \
+ pby[count] = Y; \
+ pbz[count] = Z; \
+ pbfog[count] = fog0; \
+ pbrgba[count][RCOMP] = FixedToInt(r0); \
+ pbrgba[count][GCOMP] = FixedToInt(g0); \
+ pbrgba[count][BCOMP] = FixedToInt(b0); \
+ pbrgba[count][ACOMP] = FixedToInt(a0); \
+ pbspec[count][RCOMP] = FixedToInt(sr0); \
+ pbspec[count][GCOMP] = FixedToInt(sg0); \
+ pbspec[count][BCOMP] = FixedToInt(sb0); \
+ for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { \
+ if (ctx->Texture.Unit[u].ReallyEnabled) { \
+ ctx->PB->s[u][0] = fragTexcoord[u][0]; \
+ ctx->PB->s[u][1] = fragTexcoord[u][1]; \
+ ctx->PB->s[u][2] = fragTexcoord[u][2]; \
+ ctx->PB->s[u][3] = fragTexcoord[u][3]; \
+ } \
+ } \
+ count++; \
+ CHECK_FULL(count); \
+ }
+#include "s_linetemp.h"
+ }
+ else {
+ /* unstippled */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_RGB 1
+#define INTERP_SPEC 1
+#define INTERP_ALPHA 1
+#define INTERP_MULTITEX 1
+#define WIDE 1
+#define PLOT(X,Y) \
+ { \
+ GLuint u; \
+ pbx[count] = X; \
+ pby[count] = Y; \
+ pbz[count] = Z; \
+ pbfog[count] = fog0; \
+ pbrgba[count][RCOMP] = FixedToInt(r0); \
+ pbrgba[count][GCOMP] = FixedToInt(g0); \
+ pbrgba[count][BCOMP] = FixedToInt(b0); \
+ pbrgba[count][ACOMP] = FixedToInt(a0); \
+ pbspec[count][RCOMP] = FixedToInt(sr0); \
+ pbspec[count][GCOMP] = FixedToInt(sg0); \
+ pbspec[count][BCOMP] = FixedToInt(sb0); \
+ for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { \
+ if (ctx->Texture.Unit[u].ReallyEnabled) { \
+ ctx->PB->s[u][0] = fragTexcoord[u][0]; \
+ ctx->PB->s[u][1] = fragTexcoord[u][1]; \
+ ctx->PB->s[u][2] = fragTexcoord[u][2]; \
+ ctx->PB->s[u][3] = fragTexcoord[u][3]; \
+ } \
+ } \
+ count++; \
+ CHECK_FULL(count); \
+ }
+#include "s_linetemp.h"
+ }
+
+ ctx->PB->count = count;
+ gl_flush_pb(ctx);
+}
+
+
+/* Flat-shaded, multitextured, any width, maybe stippled, separate specular
+ * color interpolation.
+ */
+static void flat_multitextured_line( GLcontext *ctx,
+ GLuint vert0, GLuint vert1, GLuint pvert )
+{
+ GLint count = ctx->PB->count;
+ GLint *pbx = ctx->PB->x;
+ GLint *pby = ctx->PB->y;
+ GLdepth *pbz = ctx->PB->z;
+ GLfixed *pbfog = ctx->PB->fog;
+ GLchan (*pbrgba)[4] = ctx->PB->rgba;
+ GLchan (*pbspec)[3] = ctx->PB->spec;
+ GLchan *color = ctx->VB->ColorPtr->data[pvert];
+ GLchan sRed = ctx->VB->SecondaryColorPtr->data ? ctx->VB->SecondaryColorPtr->data[pvert][0] : 0;
+ GLchan sGreen = ctx->VB->SecondaryColorPtr->data ? ctx->VB->SecondaryColorPtr->data[pvert][1] : 0;
+ GLchan sBlue = ctx->VB->SecondaryColorPtr->data ? ctx->VB->SecondaryColorPtr->data[pvert][2] : 0;
+
+ (void) pvert;
+
+ ctx->PB->mono = GL_FALSE;
+
+ if (ctx->Line.StippleFlag) {
+ /* stippled */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_ALPHA 1
+#define INTERP_MULTITEX 1
+#define WIDE 1
+#define STIPPLE 1
+#define PLOT(X,Y) \
+ { \
+ GLuint u; \
+ pbx[count] = X; \
+ pby[count] = Y; \
+ pbz[count] = Z; \
+ pbfog[count] = fog0; \
+ pbrgba[count][RCOMP] = color[0]; \
+ pbrgba[count][GCOMP] = color[1]; \
+ pbrgba[count][BCOMP] = color[2]; \
+ pbrgba[count][ACOMP] = color[3]; \
+ pbspec[count][RCOMP] = sRed; \
+ pbspec[count][GCOMP] = sGreen; \
+ pbspec[count][BCOMP] = sBlue; \
+ for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { \
+ if (ctx->Texture.Unit[u].ReallyEnabled) { \
+ ctx->PB->s[u][0] = fragTexcoord[u][0]; \
+ ctx->PB->s[u][1] = fragTexcoord[u][1]; \
+ ctx->PB->s[u][2] = fragTexcoord[u][2]; \
+ ctx->PB->s[u][3] = fragTexcoord[u][3]; \
+ } \
+ } \
+ count++; \
+ CHECK_FULL(count); \
+ }
+#include "s_linetemp.h"
+ }
+ else {
+ /* unstippled */
+#define INTERP_XY 1
+#define INTERP_Z 1
+#define INTERP_ALPHA 1
+#define INTERP_MULTITEX 1
+#define WIDE 1
+#define PLOT(X,Y) \
+ { \
+ GLuint u; \
+ pbx[count] = X; \
+ pby[count] = Y; \
+ pbz[count] = Z; \
+ pbfog[count] = fog0; \
+ pbrgba[count][RCOMP] = color[0]; \
+ pbrgba[count][GCOMP] = color[1]; \
+ pbrgba[count][BCOMP] = color[2]; \
+ pbrgba[count][ACOMP] = color[3]; \
+ pbspec[count][RCOMP] = sRed; \
+ pbspec[count][GCOMP] = sGreen; \
+ pbspec[count][BCOMP] = sBlue; \
+ for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { \
+ if (ctx->Texture.Unit[u].ReallyEnabled) { \
+ ctx->PB->s[u][0] = fragTexcoord[u][0]; \
+ ctx->PB->s[u][1] = fragTexcoord[u][1]; \
+ ctx->PB->s[u][2] = fragTexcoord[u][2]; \
+ ctx->PB->s[u][3] = fragTexcoord[u][3]; \
+ } \
+ } \
+ count++; \
+ CHECK_FULL(count); \
+ }
+#include "s_linetemp.h"
+ }
+
+ ctx->PB->count = count;
+ gl_flush_pb(ctx);
+}
+
+
+
+
+/*
+ * Antialiased RGBA line
+ *
+ * This AA line function isn't terribly efficient but it's pretty
+ * straight-forward to understand. Also, it doesn't exactly conform
+ * to the specification.
+ */
+static void aa_rgba_line( GLcontext *ctx,
+ GLuint vert0, GLuint vert1, GLuint pvert )
+{
+#define INTERP_RGBA 1
+#define PLOT(x, y) \
+ { \
+ PB_WRITE_RGBA_PIXEL( pb, (x), (y), z, fog0, \
+ red, green, blue, coverage ); \
+ }
+#include "s_lnaatemp.h"
+}
+
+/*
+ * Antialiased Textured RGBA line
+ *
+ * This AA line function isn't terribly efficient but it's pretty
+ * straight-forward to understand. Also, it doesn't exactly conform
+ * to the specification.
+ */
+static void aa_tex_rgba_line( GLcontext *ctx,
+ GLuint vert0, GLuint vert1, GLuint pvert )
+{
+#define INTERP_RGBA 1
+#define INTERP_TEX 1
+#define PLOT(x, y) \
+ { \
+ PB_WRITE_TEX_PIXEL( pb, (x), (y), z, fog0, \
+ red, green, blue, coverage, \
+ fragTexcoord[0], fragTexcoord[1], fragTexcoord[2] ); \
+ }
+#include "s_lnaatemp.h"
+}
+
+
+/*
+ * Antialiased Multitextured RGBA line
+ *
+ * This AA line function isn't terribly efficient but it's pretty
+ * straight-forward to understand. Also, it doesn't exactly conform
+ * to the specification.
+ */
+static void aa_multitex_rgba_line( GLcontext *ctx,
+ GLuint vert0, GLuint vert1, GLuint pvert )
+{
+#define INTERP_RGBA 1
+#define INTERP_SPEC 1
+#define INTERP_MULTITEX 1
+#define PLOT(x, y) \
+ { \
+ PB_WRITE_MULTITEX_SPEC_PIXEL( pb, (x), (y), z, fog0, \
+ red, green, blue, coverage, specRed, specGreen, specBlue, \
+ fragTexcoord ); \
+ }
+#include "s_lnaatemp.h"
+}
+
+
+/*
+ * Antialiased CI line. Same comments for RGBA antialiased lines apply.
+ */
+static void aa_ci_line( GLcontext *ctx,
+ GLuint vert0, GLuint vert1, GLuint pvert )
+{
+#define INTERP_INDEX 1
+#define PLOT(x, y) \
+ { \
+ PB_WRITE_CI_PIXEL( pb, (x), (y), z, fog0, index + coverage ); \
+ }
+#include "s_lnaatemp.h"
+}
+
+
+/*
+ * Null rasterizer for measuring transformation speed.
+ */
+static void null_line( GLcontext *ctx, GLuint v1, GLuint v2, GLuint pv )
+{
+ (void) ctx;
+ (void) v1;
+ (void) v2;
+ (void) pv;
+}
+
+
+
+#ifdef DEBUG
+void
+_mesa_print_line_function(GLcontext *ctx)
+{
+ printf("Line Func == ");
+ if (ctx->Driver.LineFunc == flat_ci_line)
+ printf("flat_ci_line\n");
+ else if (ctx->Driver.LineFunc == flat_ci_z_line)
+ printf("flat_ci_z_line\n");
+ else if (ctx->Driver.LineFunc == flat_rgba_line)
+ printf("flat_rgba_line\n");
+ else if (ctx->Driver.LineFunc == flat_rgba_z_line)
+ printf("flat_rgba_z_line\n");
+ else if (ctx->Driver.LineFunc == smooth_ci_line)
+ printf("smooth_ci_line\n");
+ else if (ctx->Driver.LineFunc == smooth_ci_z_line)
+ printf("smooth_ci_z_line\n");
+ else if (ctx->Driver.LineFunc == smooth_rgba_line)
+ printf("smooth_rgba_line\n");
+ else if (ctx->Driver.LineFunc == smooth_rgba_z_line)
+ printf("smooth_rgba_z_line\n");
+ else if (ctx->Driver.LineFunc == general_smooth_ci_line)
+ printf("general_smooth_ci_line\n");
+ else if (ctx->Driver.LineFunc == general_flat_ci_line)
+ printf("general_flat_ci_line\n");
+ else if (ctx->Driver.LineFunc == general_smooth_rgba_line)
+ printf("general_smooth_rgba_line\n");
+ else if (ctx->Driver.LineFunc == general_flat_rgba_line)
+ printf("general_flat_rgba_line\n");
+ else if (ctx->Driver.LineFunc == flat_textured_line)
+ printf("flat_textured_line\n");
+ else if (ctx->Driver.LineFunc == smooth_textured_line)
+ printf("smooth_textured_line\n");
+ else if (ctx->Driver.LineFunc == smooth_multitextured_line)
+ printf("smooth_multitextured_line\n");
+ else if (ctx->Driver.LineFunc == flat_multitextured_line)
+ printf("flat_multitextured_line\n");
+ else if (ctx->Driver.LineFunc == aa_rgba_line)
+ printf("aa_rgba_line\n");
+ else if (ctx->Driver.LineFunc == aa_tex_rgba_line)
+ printf("aa_tex_rgba_line\n");
+ else if (ctx->Driver.LineFunc == aa_multitex_rgba_line)
+ printf("aa_multitex_rgba_line\n");
+ else if (ctx->Driver.LineFunc == aa_ci_line)
+ printf("aa_ci_line\n");
+ else if (ctx->Driver.LineFunc == null_line)
+ printf("null_line\n");
+ else
+ printf("Driver func %p\n", ctx->Driver.LineFunc);
+}
+#endif
+
+
+
+/*
+ * Determine which line drawing function to use given the current
+ * rendering context.
+ *
+ * Please update the summary flag _SWRAST_NEW_LINE if you add or remove
+ * tests to this code.
+ */
+void
+_swrast_set_line_function( GLcontext *ctx )
+{
+ GLboolean rgbmode = ctx->Visual.RGBAflag;
+ /* TODO: antialiased lines */
+
+ if (ctx->RenderMode==GL_RENDER) {
+ if (ctx->NoRaster) {
+ ctx->Driver.LineFunc = null_line;
+ return;
+ }
+ if (ctx->Driver.LineFunc) {
+ /* Device driver will draw lines. */
+ return;
+ }
+
+ if (ctx->Line.SmoothFlag) {
+ /* antialiased lines */
+ if (rgbmode) {
+ if (ctx->Texture.ReallyEnabled) {
+ if (ctx->Texture.MultiTextureEnabled
+ || ctx->Light.Model.ColorControl==GL_SEPARATE_SPECULAR_COLOR
+ || ctx->Fog.ColorSumEnabled)
+ /* Multitextured! */
+ ctx->Driver.LineFunc = aa_multitex_rgba_line;
+ else
+ ctx->Driver.LineFunc = aa_tex_rgba_line;
+ } else {
+ ctx->Driver.LineFunc = aa_rgba_line;
+ }
+ }
+ else {
+ ctx->Driver.LineFunc = aa_ci_line;
+ }
+ }
+ else if (ctx->Texture.ReallyEnabled) {
+ if (ctx->Texture.MultiTextureEnabled
+ || ctx->Light.Model.ColorControl==GL_SEPARATE_SPECULAR_COLOR
+ || ctx->Fog.ColorSumEnabled) {
+ /* multi-texture and/or separate specular color */
+ if (ctx->Light.ShadeModel==GL_SMOOTH)
+ ctx->Driver.LineFunc = smooth_multitextured_line;
+ else
+ ctx->Driver.LineFunc = flat_multitextured_line;
+ }
+ else {
+ if (ctx->Light.ShadeModel==GL_SMOOTH) {
+ ctx->Driver.LineFunc = smooth_textured_line;
+ }
+ else {
+ ctx->Driver.LineFunc = flat_textured_line;
+ }
+ }
+ }
+ else if (ctx->Line.Width!=1.0 || ctx->Line.StippleFlag
+ || ctx->Line.SmoothFlag) {
+ if (ctx->Light.ShadeModel==GL_SMOOTH) {
+ if (rgbmode)
+ ctx->Driver.LineFunc = general_smooth_rgba_line;
+ else
+ ctx->Driver.LineFunc = general_smooth_ci_line;
+ }
+ else {
+ if (rgbmode)
+ ctx->Driver.LineFunc = general_flat_rgba_line;
+ else
+ ctx->Driver.LineFunc = general_flat_ci_line;
+ }
+ }
+ else {
+ if (ctx->Light.ShadeModel==GL_SMOOTH) {
+ /* Width==1, non-stippled, smooth-shaded */
+ if (ctx->Depth.Test || ctx->Fog.Enabled) {
+ if (rgbmode)
+ ctx->Driver.LineFunc = smooth_rgba_z_line;
+ else
+ ctx->Driver.LineFunc = smooth_ci_z_line;
+ }
+ else {
+ if (rgbmode)
+ ctx->Driver.LineFunc = smooth_rgba_line;
+ else
+ ctx->Driver.LineFunc = smooth_ci_line;
+ }
+ }
+ else {
+ /* Width==1, non-stippled, flat-shaded */
+ if (ctx->Depth.Test || ctx->Fog.Enabled) {
+ if (rgbmode)
+ ctx->Driver.LineFunc = flat_rgba_z_line;
+ else
+ ctx->Driver.LineFunc = flat_ci_z_line;
+ }
+ else {
+ if (rgbmode)
+ ctx->Driver.LineFunc = flat_rgba_line;
+ else
+ ctx->Driver.LineFunc = flat_ci_line;
+ }
+ }
+ }
+ }
+ else if (ctx->RenderMode==GL_FEEDBACK) {
+ ctx->Driver.LineFunc = gl_feedback_line;
+ }
+ else {
+ /* GL_SELECT mode */
+ ctx->Driver.LineFunc = gl_select_line;
+ }
+
+ /*_mesa_print_line_function(ctx);*/
+}
diff --git a/src/mesa/swrast/s_linetemp.h b/src/mesa/swrast/s_linetemp.h
new file mode 100644
index 0000000000..a79badbff1
--- /dev/null
+++ b/src/mesa/swrast/s_linetemp.h
@@ -0,0 +1,682 @@
+/* $Id: s_linetemp.h,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.
+ */
+
+
+/*
+ * Line Rasterizer Template
+ *
+ * This file is #include'd to generate custom line rasterizers.
+ *
+ * The following macros may be defined to indicate what auxillary information
+ * must be interplated along the line:
+ * INTERP_Z - if defined, interpolate Z and FOG values
+ * INTERP_RGB - if defined, interpolate RGB values
+ * INTERP_SPEC - if defined, interpolate specular RGB values
+ * INTERP_ALPHA - if defined, interpolate Alpha values
+ * INTERP_INDEX - if defined, interpolate color index values
+ * INTERP_TEX - if defined, interpolate unit 0 texcoords
+ * INTERP_MULTITEX - if defined, interpolate multi-texcoords
+ *
+ * When one can directly address pixels in the color buffer the following
+ * macros can be defined and used to directly compute pixel addresses during
+ * rasterization (see pixelPtr):
+ * PIXEL_TYPE - the datatype of a pixel (GLubyte, GLushort, GLuint)
+ * BYTES_PER_ROW - number of bytes per row in the color buffer
+ * PIXEL_ADDRESS(X,Y) - returns the address of pixel at (X,Y) where
+ * Y==0 at bottom of screen and increases upward.
+ *
+ * Similarly, for direct depth buffer access, this type is used for depth
+ * buffer addressing:
+ * DEPTH_TYPE - either GLushort or GLuint
+ *
+ * Optionally, one may provide one-time setup code
+ * SETUP_CODE - code which is to be executed once per line
+ *
+ * To enable line stippling define STIPPLE = 1
+ * To enable wide lines define WIDE = 1
+ *
+ * To actually "plot" each pixel either the PLOT macro or
+ * (XMAJOR_PLOT and YMAJOR_PLOT macros) must be defined...
+ * PLOT(X,Y) - code to plot a pixel. Example:
+ * if (Z < *zPtr) {
+ * *zPtr = Z;
+ * color = pack_rgb( FixedToInt(r0), FixedToInt(g0),
+ * FixedToInt(b0) );
+ * put_pixel( X, Y, color );
+ * }
+ *
+ * This code was designed for the origin to be in the lower-left corner.
+ *
+ */
+
+
+/*void line( GLcontext *ctx, GLuint vert0, GLuint vert1, GLuint pvert )*/
+{
+ const struct vertex_buffer *VB = ctx->VB;
+ GLint x0 = (GLint) VB->Win.data[vert0][0];
+ GLint x1 = (GLint) VB->Win.data[vert1][0];
+ GLint y0 = (GLint) VB->Win.data[vert0][1];
+ GLint y1 = (GLint) VB->Win.data[vert1][1];
+ GLint dx, dy;
+#ifdef INTERP_XY
+ GLint xstep, ystep;
+#endif
+#ifdef INTERP_Z
+ GLint z0, z1, dz;
+ const GLint depthBits = ctx->Visual.DepthBits;
+ const GLint fixedToDepthShift = depthBits <= 16 ? FIXED_SHIFT : 0;
+# define FixedToDepth(F) ((F) >> fixedToDepthShift)
+# ifdef DEPTH_TYPE
+ GLint zPtrXstep, zPtrYstep;
+ DEPTH_TYPE *zPtr;
+# endif
+ GLfixed fog0 = FloatToFixed(VB->FogCoordPtr->data[vert0]);
+ GLfixed dfog = FloatToFixed(VB->FogCoordPtr->data[vert1]) - fog0;
+#endif
+#ifdef INTERP_RGB
+ GLfixed r0 = IntToFixed(VB->ColorPtr->data[vert0][0]);
+ GLfixed dr = IntToFixed(VB->ColorPtr->data[vert1][0]) - r0;
+ GLfixed g0 = IntToFixed(VB->ColorPtr->data[vert0][1]);
+ GLfixed dg = IntToFixed(VB->ColorPtr->data[vert1][1]) - g0;
+ GLfixed b0 = IntToFixed(VB->ColorPtr->data[vert0][2]);
+ GLfixed db = IntToFixed(VB->ColorPtr->data[vert1][2]) - b0;
+#endif
+#ifdef INTERP_SPEC
+ GLfixed sr0 = VB->SecondaryColorPtr->data ? IntToFixed(VB->SecondaryColorPtr->data[vert0][0]) : 0;
+ GLfixed dsr = VB->SecondaryColorPtr->data ? IntToFixed(VB->SecondaryColorPtr->data[vert1][0]) - sr0 : 0;
+ GLfixed sg0 = VB->SecondaryColorPtr->data ? IntToFixed(VB->SecondaryColorPtr->data[vert0][1]) : 0;
+ GLfixed dsg = VB->SecondaryColorPtr->data ? IntToFixed(VB->SecondaryColorPtr->data[vert1][1]) - sg0 : 0;
+ GLfixed sb0 = VB->SecondaryColorPtr->data ? IntToFixed(VB->SecondaryColorPtr->data[vert0][2]) : 0;
+ GLfixed dsb = VB->SecondaryColorPtr->data ? IntToFixed(VB->SecondaryColorPtr->data[vert1][2]) - sb0 : 0;
+#endif
+#ifdef INTERP_ALPHA
+ GLfixed a0 = IntToFixed(VB->ColorPtr->data[vert0][3]);
+ GLfixed da = IntToFixed(VB->ColorPtr->data[vert1][3]) - a0;
+#endif
+#ifdef INTERP_INDEX
+ GLint i0 = VB->IndexPtr->data[vert0] << 8;
+ GLint di = (GLint) (VB->IndexPtr->data[vert1] << 8) - i0;
+#endif
+#ifdef INTERP_TEX
+ const GLfloat invw0 = VB->Win.data[vert0][3];
+ const GLfloat invw1 = VB->Win.data[vert1][3];
+ GLfloat tex[4];
+ GLfloat dtex[4];
+ GLfloat fragTexcoord[4];
+#endif
+#ifdef INTERP_MULTITEX
+ const GLfloat invw0 = VB->Win.data[vert0][3];
+ const GLfloat invw1 = VB->Win.data[vert1][3];
+ GLfloat tex[MAX_TEXTURE_UNITS][4];
+ GLfloat dtex[MAX_TEXTURE_UNITS][4];
+ GLfloat fragTexcoord[MAX_TEXTURE_UNITS][4];
+#endif
+#ifdef PIXEL_ADDRESS
+ PIXEL_TYPE *pixelPtr;
+ GLint pixelXstep, pixelYstep;
+#endif
+#ifdef WIDE
+ /* for wide lines, draw all X in [x+min, x+max] or Y in [y+min, y+max] */
+ GLint width, min, max;
+ width = (GLint) CLAMP( ctx->Line.Width, MIN_LINE_WIDTH, MAX_LINE_WIDTH );
+ min = (width-1) / -2;
+ max = min + width - 1;
+#endif
+#ifdef INTERP_TEX
+ {
+ tex[0] = invw0 * VB->TexCoordPtr[0]->data[vert0][0];
+ dtex[0] = invw1 * VB->TexCoordPtr[0]->data[vert1][0] - tex[0];
+ if (VB->TexCoordPtr[0]->size > 1) {
+ tex[1] = invw0 * VB->TexCoordPtr[0]->data[vert0][1];
+ dtex[1] = invw1 * VB->TexCoordPtr[0]->data[vert1][1] - tex[1];
+ }
+ else {
+ tex[1] = 0.0;
+ dtex[1] = 0.0;
+ }
+ if (VB->TexCoordPtr[0]->size > 2) {
+ tex[2] = invw0 * VB->TexCoordPtr[0]->data[vert0][2];
+ dtex[2] = invw1 * VB->TexCoordPtr[0]->data[vert1][2] - tex[2];
+ }
+ else {
+ tex[2] = 0.0;
+ dtex[2] = 0.0;
+ }
+ if (VB->TexCoordPtr[0]->size > 3) {
+ tex[3] = invw0 * VB->TexCoordPtr[0]->data[vert0][3];
+ dtex[3] = invw1 * VB->TexCoordPtr[0]->data[vert1][3] - tex[3];
+ }
+ else {
+ tex[3] = invw0;
+ dtex[3] = invw1 - invw0;
+ }
+ }
+#endif
+#ifdef INTERP_MULTITEX
+ {
+ GLuint u;
+ for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+ if (ctx->Texture.Unit[u].ReallyEnabled) {
+ tex[u][0] = invw0 * VB->TexCoordPtr[u]->data[vert0][0];
+ dtex[u][0] = invw1 * VB->TexCoordPtr[u]->data[vert1][0] - tex[u][0];
+ if (VB->TexCoordPtr[u]->size > 1) {
+ tex[u][1] = invw0 * VB->TexCoordPtr[u]->data[vert0][1];
+ dtex[u][1] = invw1 * VB->TexCoordPtr[u]->data[vert1][1] - tex[u][1];
+ }
+ else {
+ tex[u][1] = 0.0;
+ dtex[u][1] = 0.0;
+ }
+ if (VB->TexCoordPtr[u]->size > 2) {
+ tex[u][2] = invw0 * VB->TexCoordPtr[u]->data[vert0][2];
+ dtex[u][2] = invw1 * VB->TexCoordPtr[u]->data[vert1][2] - tex[u][2];
+ }
+ else {
+ tex[u][2] = 0.0;
+ dtex[u][2] = 0.0;
+ }
+ if (VB->TexCoordPtr[u]->size > 3) {
+ tex[u][3] = invw0 * VB->TexCoordPtr[u]->data[vert0][3];
+ dtex[u][3] = invw1 * VB->TexCoordPtr[u]->data[vert1][3] - tex[u][3];
+ }
+ else {
+ tex[u][3] = invw0;
+ dtex[u][3] = invw1 - invw0;
+ }
+ }
+ }
+ }
+#endif
+
+
+/*
+ * Despite being clipped to the view volume, the line's window coordinates
+ * may just lie outside the window bounds. That is, if the legal window
+ * coordinates are [0,W-1][0,H-1], it's possible for x==W and/or y==H.
+ * This quick and dirty code nudges the endpoints inside the window if
+ * necessary.
+ */
+#ifdef CLIP_HACK
+ {
+ GLint w = ctx->DrawBuffer->Width;
+ GLint h = ctx->DrawBuffer->Height;
+ if ((x0==w) | (x1==w)) {
+ if ((x0==w) & (x1==w))
+ return;
+ x0 -= x0==w;
+ x1 -= x1==w;
+ }
+ if ((y0==h) | (y1==h)) {
+ if ((y0==h) & (y1==h))
+ return;
+ y0 -= y0==h;
+ y1 -= y1==h;
+ }
+ }
+#endif
+ dx = x1 - x0;
+ dy = y1 - y0;
+ if (dx==0 && dy==0) {
+ return;
+ }
+
+ /*
+ * Setup
+ */
+#ifdef SETUP_CODE
+ SETUP_CODE
+#endif
+
+#ifdef INTERP_Z
+# ifdef DEPTH_TYPE
+ zPtr = (DEPTH_TYPE *) _mesa_zbuffer_address(ctx, x0, y0);
+# endif
+ if (depthBits <= 16) {
+ z0 = FloatToFixed(VB->Win.data[vert0][2] + ctx->LineZoffset);
+ z1 = FloatToFixed(VB->Win.data[vert1][2] + ctx->LineZoffset);
+ }
+ else {
+ z0 = (int) VB->Win.data[vert0][2] + ctx->LineZoffset;
+ z1 = (int) VB->Win.data[vert1][2] + ctx->LineZoffset;
+ }
+#endif
+#ifdef PIXEL_ADDRESS
+ pixelPtr = (PIXEL_TYPE *) PIXEL_ADDRESS(x0,y0);
+#endif
+
+ if (dx<0) {
+ dx = -dx; /* make positive */
+#ifdef INTERP_XY
+ xstep = -1;
+#endif
+#if defined(INTERP_Z) && defined(DEPTH_TYPE)
+ zPtrXstep = -((GLint)sizeof(DEPTH_TYPE));
+#endif
+#ifdef PIXEL_ADDRESS
+ pixelXstep = -((GLint)sizeof(PIXEL_TYPE));
+#endif
+ }
+ else {
+#ifdef INTERP_XY
+ xstep = 1;
+#endif
+#if defined(INTERP_Z) && defined(DEPTH_TYPE)
+ zPtrXstep = ((GLint)sizeof(DEPTH_TYPE));
+#endif
+#ifdef PIXEL_ADDRESS
+ pixelXstep = ((GLint)sizeof(PIXEL_TYPE));
+#endif
+ }
+
+ if (dy<0) {
+ dy = -dy; /* make positive */
+#ifdef INTERP_XY
+ ystep = -1;
+#endif
+#if defined(INTERP_Z) && defined(DEPTH_TYPE)
+ zPtrYstep = -ctx->DrawBuffer->Width * ((GLint)sizeof(DEPTH_TYPE));
+#endif
+#ifdef PIXEL_ADDRESS
+ pixelYstep = BYTES_PER_ROW;
+#endif
+ }
+ else {
+#ifdef INTERP_XY
+ ystep = 1;
+#endif
+#if defined(INTERP_Z) && defined(DEPTH_TYPE)
+ zPtrYstep = ctx->DrawBuffer->Width * ((GLint)sizeof(DEPTH_TYPE));
+#endif
+#ifdef PIXEL_ADDRESS
+ pixelYstep = -(BYTES_PER_ROW);
+#endif
+ }
+
+ /*
+ * Draw
+ */
+
+ if (dx>dy) {
+ /*** X-major line ***/
+ GLint i;
+ GLint errorInc = dy+dy;
+ GLint error = errorInc-dx;
+ GLint errorDec = error-dx;
+#ifdef INTERP_Z
+ dz = (z1-z0) / dx;
+ dfog /= dx;
+#endif
+#ifdef INTERP_RGB
+ dr /= dx; /* convert from whole line delta to per-pixel delta */
+ dg /= dx;
+ db /= dx;
+#endif
+#ifdef INTERP_SPEC
+ dsr /= dx; /* convert from whole line delta to per-pixel delta */
+ dsg /= dx;
+ dsb /= dx;
+#endif
+#ifdef INTERP_ALPHA
+ da /= dx;
+#endif
+#ifdef INTERP_INDEX
+ di /= dx;
+#endif
+#ifdef INTERP_TEX
+ {
+ const GLfloat invDx = 1.0F / (GLfloat) dx;
+ dtex[0] *= invDx;
+ dtex[1] *= invDx;
+ dtex[2] *= invDx;
+ dtex[3] *= invDx;
+ }
+#endif
+#ifdef INTERP_MULTITEX
+ {
+ const GLfloat invDx = 1.0F / (GLfloat) dx;
+ GLuint u;
+ for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+ if (ctx->Texture.Unit[u].ReallyEnabled) {
+ dtex[u][0] *= invDx;
+ dtex[u][1] *= invDx;
+ dtex[u][2] *= invDx;
+ dtex[u][3] *= invDx;
+ }
+ }
+ }
+#endif
+
+ for (i=0;i<dx;i++) {
+#ifdef STIPPLE
+ GLushort m;
+ m = 1 << ((ctx->StippleCounter/ctx->Line.StippleFactor) & 0xf);
+ if (ctx->Line.StipplePattern & m) {
+#endif
+#ifdef INTERP_Z
+ GLdepth Z = FixedToDepth(z0);
+#endif
+#ifdef INTERP_INDEX
+ GLint I = i0 >> 8;
+#endif
+#ifdef INTERP_TEX
+ {
+ const GLfloat invQ = 1.0F / tex[3];
+ fragTexcoord[0] = tex[0] * invQ;
+ fragTexcoord[1] = tex[1] * invQ;
+ fragTexcoord[2] = tex[2] * invQ;
+ }
+#endif
+#ifdef INTERP_MULTITEX
+ {
+ GLuint u;
+ for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+ if (ctx->Texture.Unit[u].ReallyEnabled) {
+ const GLfloat invQ = 1.0F / tex[u][3];
+ fragTexcoord[u][0] = tex[u][0] * invQ;
+ fragTexcoord[u][1] = tex[u][1] * invQ;
+ fragTexcoord[u][2] = tex[u][2] * invQ;
+ }
+ }
+ }
+#endif
+#ifdef WIDE
+ {
+ GLint yy;
+ GLint ymin = y0 + min;
+ GLint ymax = y0 + max;
+ for (yy=ymin;yy<=ymax;yy++) {
+ PLOT( x0, yy );
+ }
+ }
+#else
+# ifdef XMAJOR_PLOT
+ XMAJOR_PLOT( x0, y0 );
+# else
+ PLOT( x0, y0 );
+# endif
+#endif /*WIDE*/
+#ifdef STIPPLE
+ }
+ ctx->StippleCounter++;
+#endif
+#ifdef INTERP_XY
+ x0 += xstep;
+#endif
+#ifdef INTERP_Z
+# ifdef DEPTH_TYPE
+ zPtr = (DEPTH_TYPE *) ((GLubyte*) zPtr + zPtrXstep);
+# endif
+ z0 += dz;
+ fog0 += dfog;
+#endif
+#ifdef INTERP_RGB
+ r0 += dr;
+ g0 += dg;
+ b0 += db;
+#endif
+#ifdef INTERP_SPEC
+ sr0 += dsr;
+ sg0 += dsg;
+ sb0 += dsb;
+#endif
+#ifdef INTERP_ALPHA
+ a0 += da;
+#endif
+#ifdef INTERP_INDEX
+ i0 += di;
+#endif
+#ifdef INTERP_TEX
+ tex[0] += dtex[0];
+ tex[1] += dtex[1];
+ tex[2] += dtex[2];
+ tex[3] += dtex[3];
+#endif
+#ifdef INTERP_MULTITEX
+ {
+ GLuint u;
+ for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+ if (ctx->Texture.Unit[u].ReallyEnabled) {
+ tex[u][0] += dtex[u][0];
+ tex[u][1] += dtex[u][1];
+ tex[u][2] += dtex[u][2];
+ tex[u][3] += dtex[u][3];
+ }
+ }
+ }
+#endif
+
+#ifdef PIXEL_ADDRESS
+ pixelPtr = (PIXEL_TYPE*) ((GLubyte*) pixelPtr + pixelXstep);
+#endif
+ if (error<0) {
+ error += errorInc;
+ }
+ else {
+ error += errorDec;
+#ifdef INTERP_XY
+ y0 += ystep;
+#endif
+#if defined(INTERP_Z) && defined(DEPTH_TYPE)
+ zPtr = (DEPTH_TYPE *) ((GLubyte*) zPtr + zPtrYstep);
+#endif
+#ifdef PIXEL_ADDRESS
+ pixelPtr = (PIXEL_TYPE*) ((GLubyte*) pixelPtr + pixelYstep);
+#endif
+ }
+ }
+ }
+ else {
+ /*** Y-major line ***/
+ GLint i;
+ GLint errorInc = dx+dx;
+ GLint error = errorInc-dy;
+ GLint errorDec = error-dy;
+#ifdef INTERP_Z
+ dz = (z1-z0) / dy;
+ dfog /= dy;
+#endif
+#ifdef INTERP_RGB
+ dr /= dy; /* convert from whole line delta to per-pixel delta */
+ dg /= dy;
+ db /= dy;
+#endif
+#ifdef INTERP_SPEC
+ dsr /= dy; /* convert from whole line delta to per-pixel delta */
+ dsg /= dy;
+ dsb /= dy;
+#endif
+#ifdef INTERP_ALPHA
+ da /= dy;
+#endif
+#ifdef INTERP_INDEX
+ di /= dy;
+#endif
+#ifdef INTERP_TEX
+ {
+ const GLfloat invDy = 1.0F / (GLfloat) dy;
+ dtex[0] *= invDy;
+ dtex[1] *= invDy;
+ dtex[2] *= invDy;
+ dtex[3] *= invDy;
+ }
+#endif
+#ifdef INTERP_MULTITEX
+ {
+ const GLfloat invDy = 1.0F / (GLfloat) dy;
+ GLuint u;
+ for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+ if (ctx->Texture.Unit[u].ReallyEnabled) {
+ dtex[u][0] *= invDy;
+ dtex[u][1] *= invDy;
+ dtex[u][2] *= invDy;
+ dtex[u][3] *= invDy;
+ }
+ }
+ }
+#endif
+
+ for (i=0;i<dy;i++) {
+#ifdef STIPPLE
+ GLushort m;
+ m = 1 << ((ctx->StippleCounter/ctx->Line.StippleFactor) & 0xf);
+ if (ctx->Line.StipplePattern & m) {
+#endif
+#ifdef INTERP_Z
+ GLdepth Z = FixedToDepth(z0);
+#endif
+#ifdef INTERP_INDEX
+ GLint I = i0 >> 8;
+#endif
+#ifdef INTERP_TEX
+ {
+ const GLfloat invQ = 1.0F / tex[3];
+ fragTexcoord[0] = tex[0] * invQ;
+ fragTexcoord[1] = tex[1] * invQ;
+ fragTexcoord[2] = tex[2] * invQ;
+ }
+#endif
+#ifdef INTERP_MULTITEX
+ {
+ GLuint u;
+ for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+ if (ctx->Texture.Unit[u].ReallyEnabled) {
+ const GLfloat invQ = 1.0F / tex[u][3];
+ fragTexcoord[u][0] = tex[u][0] * invQ;
+ fragTexcoord[u][1] = tex[u][1] * invQ;
+ fragTexcoord[u][2] = tex[u][2] * invQ;
+ }
+ }
+ }
+#endif
+#ifdef WIDE
+ {
+ GLint xx;
+ GLint xmin = x0 + min;
+ GLint xmax = x0 + max;
+ for (xx=xmin;xx<=xmax;xx++) {
+ PLOT( xx, y0 );
+ }
+ }
+#else
+# ifdef YMAJOR_PLOT
+ YMAJOR_PLOT( x0, y0 );
+# else
+ PLOT( x0, y0 );
+# endif
+#endif /*WIDE*/
+#ifdef STIPPLE
+ }
+ ctx->StippleCounter++;
+#endif
+#ifdef INTERP_XY
+ y0 += ystep;
+#endif
+#ifdef INTERP_Z
+# ifdef DEPTH_TYPE
+ zPtr = (DEPTH_TYPE *) ((GLubyte*) zPtr + zPtrYstep);
+# endif
+ z0 += dz;
+ fog0 += dfog;
+#endif
+#ifdef INTERP_RGB
+ r0 += dr;
+ g0 += dg;
+ b0 += db;
+#endif
+#ifdef INTERP_SPEC
+ sr0 += dsr;
+ sg0 += dsg;
+ sb0 += dsb;
+#endif
+#ifdef INTERP_ALPHA
+ a0 += da;
+#endif
+#ifdef INTERP_INDEX
+ i0 += di;
+#endif
+#ifdef INTERP_TEX
+ tex[0] += dtex[0];
+ tex[1] += dtex[1];
+ tex[2] += dtex[2];
+ tex[3] += dtex[3];
+#endif
+#ifdef INTERP_MULTITEX
+ {
+ GLuint u;
+ for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+ if (ctx->Texture.Unit[u].ReallyEnabled) {
+ tex[u][0] += dtex[u][0];
+ tex[u][1] += dtex[u][1];
+ tex[u][2] += dtex[u][2];
+ tex[u][3] += dtex[u][3];
+ }
+ }
+ }
+#endif
+#ifdef PIXEL_ADDRESS
+ pixelPtr = (PIXEL_TYPE*) ((GLubyte*) pixelPtr + pixelYstep);
+#endif
+ if (error<0) {
+ error += errorInc;
+ }
+ else {
+ error += errorDec;
+#ifdef INTERP_XY
+ x0 += xstep;
+#endif
+#if defined(INTERP_Z) && defined(DEPTH_TYPE)
+ zPtr = (DEPTH_TYPE *) ((GLubyte*) zPtr + zPtrXstep);
+#endif
+#ifdef PIXEL_ADDRESS
+ pixelPtr = (PIXEL_TYPE*) ((GLubyte*) pixelPtr + pixelXstep);
+#endif
+ }
+ }
+ }
+
+}
+
+
+#undef INTERP_XY
+#undef INTERP_Z
+#undef INTERP_RGB
+#undef INTERP_SPEC
+#undef INTERP_ALPHA
+#undef INTERP_TEX
+#undef INTERP_MULTITEX
+#undef INTERP_INDEX
+#undef PIXEL_ADDRESS
+#undef PIXEL_TYPE
+#undef DEPTH_TYPE
+#undef BYTES_PER_ROW
+#undef SETUP_CODE
+#undef PLOT
+#undef XMAJOR_PLOT
+#undef YMAJOR_PLOT
+#undef CLIP_HACK
+#undef STIPPLE
+#undef WIDE
+#undef FixedToDepth
diff --git a/src/mesa/swrast/s_logic.c b/src/mesa/swrast/s_logic.c
new file mode 100644
index 0000000000..760d7e7065
--- /dev/null
+++ b/src/mesa/swrast/s_logic.c
@@ -0,0 +1,360 @@
+/* $Id: s_logic.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.
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "macros.h"
+
+#include "s_alphabuf.h"
+#include "s_logic.h"
+#include "s_pb.h"
+#include "s_span.h"
+
+
+
+/*
+ * Apply logic op to array of CI pixels.
+ */
+static void index_logicop( GLcontext *ctx, GLuint n,
+ GLuint index[], const GLuint dest[],
+ const GLubyte mask[] )
+{
+ GLuint i;
+ switch (ctx->Color.LogicOp) {
+ case GL_CLEAR:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ index[i] = 0;
+ }
+ }
+ break;
+ case GL_SET:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ index[i] = 1;
+ }
+ }
+ break;
+ case GL_COPY:
+ /* do nothing */
+ break;
+ case GL_COPY_INVERTED:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ index[i] = ~index[i];
+ }
+ }
+ break;
+ case GL_NOOP:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ index[i] = dest[i];
+ }
+ }
+ break;
+ case GL_INVERT:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ index[i] = ~dest[i];
+ }
+ }
+ break;
+ case GL_AND:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ index[i] &= dest[i];
+ }
+ }
+ break;
+ case GL_NAND:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ index[i] = ~(index[i] & dest[i]);
+ }
+ }
+ break;
+ case GL_OR:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ index[i] |= dest[i];
+ }
+ }
+ break;
+ case GL_NOR:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ index[i] = ~(index[i] | dest[i]);
+ }
+ }
+ break;
+ case GL_XOR:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ index[i] ^= dest[i];
+ }
+ }
+ break;
+ case GL_EQUIV:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ index[i] = ~(index[i] ^ dest[i]);
+ }
+ }
+ break;
+ case GL_AND_REVERSE:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ index[i] = index[i] & ~dest[i];
+ }
+ }
+ break;
+ case GL_AND_INVERTED:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ index[i] = ~index[i] & dest[i];
+ }
+ }
+ break;
+ case GL_OR_REVERSE:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ index[i] = index[i] | ~dest[i];
+ }
+ }
+ break;
+ case GL_OR_INVERTED:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ index[i] = ~index[i] | dest[i];
+ }
+ }
+ break;
+ default:
+ gl_error( ctx, GL_INVALID_ENUM, "gl_logic error" );
+ }
+}
+
+
+
+/*
+ * Apply the current logic operator to a span of CI pixels. This is only
+ * used if the device driver can't do logic ops.
+ */
+void
+_mesa_logicop_ci_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
+ GLuint index[], const GLubyte mask[] )
+{
+ GLuint dest[MAX_WIDTH];
+ /* Read dest values from frame buffer */
+ (*ctx->Driver.ReadCI32Span)( ctx, n, x, y, dest );
+ index_logicop( ctx, n, index, dest, mask );
+}
+
+
+
+/*
+ * Apply the current logic operator to an array of CI pixels. This is only
+ * used if the device driver can't do logic ops.
+ */
+void
+_mesa_logicop_ci_pixels( GLcontext *ctx,
+ GLuint n, const GLint x[], const GLint y[],
+ GLuint index[], const GLubyte mask[] )
+{
+ GLuint dest[PB_SIZE];
+ /* Read dest values from frame buffer */
+ (*ctx->Driver.ReadCI32Pixels)( ctx, n, x, y, dest, mask );
+ index_logicop( ctx, n, index, dest, mask );
+}
+
+
+
+/*
+ * Apply logic operator to rgba pixels.
+ * Input: ctx - the context
+ * n - number of pixels
+ * mask - pixel mask array
+ * In/Out: src - incoming pixels which will be modified
+ * Input: dest - frame buffer values
+ *
+ * Note: Since the R, G, B, and A channels are all treated the same we
+ * process them as 4-byte GLuints instead of four GLubytes.
+ */
+static void rgba_logicop( const GLcontext *ctx, GLuint n,
+ const GLubyte mask[],
+ GLuint src[], const GLuint dest[] )
+{
+ GLuint i;
+ switch (ctx->Color.LogicOp) {
+ case GL_CLEAR:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ src[i] = 0;
+ }
+ }
+ break;
+ case GL_SET:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ src[i] = 0xffffffff;
+ }
+ }
+ break;
+ case GL_COPY:
+ /* do nothing */
+ break;
+ case GL_COPY_INVERTED:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ src[i] = ~src[i];
+ }
+ }
+ break;
+ case GL_NOOP:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ src[i] = dest[i];
+ }
+ }
+ break;
+ case GL_INVERT:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ src[i] = ~dest[i];
+ }
+ }
+ break;
+ case GL_AND:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ src[i] &= dest[i];
+ }
+ }
+ break;
+ case GL_NAND:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ src[i] = ~(src[i] & src[i]);
+ }
+ }
+ break;
+ case GL_OR:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ src[i]|= dest[i];
+ }
+ }
+ break;
+ case GL_NOR:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ src[i] = ~(src[i] | dest[i]);
+ }
+ }
+ break;
+ case GL_XOR:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ src[i] ^= dest[i];
+ }
+ }
+ break;
+ case GL_EQUIV:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ src[i] = ~(src[i] ^ dest[i]);
+ }
+ }
+ break;
+ case GL_AND_REVERSE:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ src[i] = src[i] & ~dest[i];
+ }
+ }
+ break;
+ case GL_AND_INVERTED:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ src[i] = ~src[i] & dest[i];
+ }
+ }
+ break;
+ case GL_OR_REVERSE:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ src[i] = src[i] | ~dest[i];
+ }
+ }
+ break;
+ case GL_OR_INVERTED:
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ src[i] = ~src[i] | dest[i];
+ }
+ }
+ break;
+ default:
+ /* should never happen */
+ gl_problem(ctx, "Bad function in rgba_logicop");
+ }
+}
+
+
+
+/*
+ * Apply the current logic operator to a span of RGBA pixels.
+ * This is only used if the device driver can't do logic ops.
+ */
+void
+_mesa_logicop_rgba_span( GLcontext *ctx,
+ GLuint n, GLint x, GLint y,
+ GLchan rgba[][4], const GLubyte mask[] )
+{
+ GLchan dest[MAX_WIDTH][4];
+ gl_read_rgba_span( ctx, ctx->DrawBuffer, n, x, y, dest );
+ rgba_logicop( ctx, n, mask, (GLuint *) rgba, (const GLuint *) dest );
+}
+
+
+
+/*
+ * Apply the current logic operator to an array of RGBA pixels.
+ * This is only used if the device driver can't do logic ops.
+ */
+void
+_mesa_logicop_rgba_pixels( GLcontext *ctx,
+ GLuint n, const GLint x[], const GLint y[],
+ GLchan rgba[][4], const GLubyte mask[] )
+{
+ GLchan dest[PB_SIZE][4];
+ (*ctx->Driver.ReadRGBAPixels)( ctx, n, x, y, dest, mask );
+ if (ctx->RasterMask & ALPHABUF_BIT) {
+ _mesa_read_alpha_pixels( ctx, n, x, y, dest, mask );
+ }
+ rgba_logicop( ctx, n, mask, (GLuint *) rgba, (const GLuint *) dest );
+}
diff --git a/src/mesa/swrast/s_logic.h b/src/mesa/swrast/s_logic.h
new file mode 100644
index 0000000000..d1b8739cbb
--- /dev/null
+++ b/src/mesa/swrast/s_logic.h
@@ -0,0 +1,59 @@
+/* $Id: s_logic.h,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.
+ */
+
+
+#ifndef S_LOGIC_H
+#define S_LOGIC_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+extern void
+_mesa_logicop_ci_span( GLcontext *ctx,
+ GLuint n, GLint x, GLint y, GLuint index[],
+ const GLubyte mask[] );
+
+
+extern void
+_mesa_logicop_ci_pixels( GLcontext *ctx,
+ GLuint n, const GLint x[], const GLint y[],
+ GLuint index[], const GLubyte mask[] );
+
+
+extern void
+_mesa_logicop_rgba_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
+ GLchan rgba[][4], const GLubyte mask[] );
+
+
+extern void
+_mesa_logicop_rgba_pixels( GLcontext *ctx,
+ GLuint n, const GLint x[], const GLint y[],
+ GLchan rgba[][4], const GLubyte mask[] );
+
+
+#endif
diff --git a/src/mesa/swrast/s_masking.c b/src/mesa/swrast/s_masking.c
new file mode 100644
index 0000000000..5831edf9c0
--- /dev/null
+++ b/src/mesa/swrast/s_masking.c
@@ -0,0 +1,180 @@
+/* $Id: s_masking.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.
+ */
+
+
+/*
+ * Implement the effect of glColorMask and glIndexMask in software.
+ */
+
+
+#include "glheader.h"
+#include "enums.h"
+#include "macros.h"
+
+#include "s_alphabuf.h"
+#include "s_masking.h"
+#include "s_pb.h"
+#include "s_span.h"
+
+
+/*
+ * Apply glColorMask to a span of RGBA pixels.
+ */
+void
+_mesa_mask_rgba_span( GLcontext *ctx,
+ GLuint n, GLint x, GLint y, GLchan rgba[][4] )
+{
+ GLchan dest[MAX_WIDTH][4];
+ GLuint i;
+
+#if CHAN_BITS == 8
+
+ GLuint srcMask = *((GLuint*)ctx->Color.ColorMask);
+ GLuint dstMask = ~srcMask;
+ GLuint *rgba32 = (GLuint *) rgba;
+ GLuint *dest32 = (GLuint *) dest;
+
+ gl_read_rgba_span( ctx, ctx->DrawBuffer, n, x, y, dest );
+ for (i = 0; i < n; i++) {
+ rgba32[i] = (rgba32[i] & srcMask) | (dest32[i] & dstMask);
+ }
+
+#else
+
+ const GLint rMask = ctx->Color.ColorMask[RCOMP];
+ const GLint gMask = ctx->Color.ColorMask[GCOMP];
+ const GLint bMask = ctx->Color.ColorMask[BCOMP];
+ const GLint aMask = ctx->Color.ColorMask[ACOMP];
+
+ gl_read_rgba_span( ctx, ctx->DrawBuffer, n, x, y, dest );
+ for (i = 0; i < n; i++) {
+ if (!rMask) rgba[i][RCOMP] = dest[i][RCOMP];
+ if (!gMask) rgba[i][GCOMP] = dest[i][GCOMP];
+ if (!bMask) rgba[i][BCOMP] = dest[i][BCOMP];
+ if (!aMask) rgba[i][ACOMP] = dest[i][ACOMP];
+ }
+
+#endif
+}
+
+
+
+/*
+ * Apply glColorMask to an array of RGBA pixels.
+ */
+void
+_mesa_mask_rgba_pixels( GLcontext *ctx,
+ GLuint n, const GLint x[], const GLint y[],
+ GLchan rgba[][4], const GLubyte mask[] )
+{
+ GLchan dest[PB_SIZE][4];
+ GLuint i;
+
+#if CHAN_BITS == 8
+
+ GLuint srcMask = *((GLuint*)ctx->Color.ColorMask);
+ GLuint dstMask = ~srcMask;
+ GLuint *rgba32 = (GLuint *) rgba;
+ GLuint *dest32 = (GLuint *) dest;
+
+ (*ctx->Driver.ReadRGBAPixels)( ctx, n, x, y, dest, mask );
+ if (ctx->RasterMask & ALPHABUF_BIT) {
+ _mesa_read_alpha_pixels( ctx, n, x, y, dest, mask );
+ }
+
+ for (i=0; i<n; i++) {
+ rgba32[i] = (rgba32[i] & srcMask) | (dest32[i] & dstMask);
+ }
+
+#else
+
+ const GLint rMask = ctx->Color.ColorMask[RCOMP];
+ const GLint gMask = ctx->Color.ColorMask[GCOMP];
+ const GLint bMask = ctx->Color.ColorMask[BCOMP];
+ const GLint aMask = ctx->Color.ColorMask[ACOMP];
+
+ (*ctx->Driver.ReadRGBAPixels)( ctx, n, x, y, dest, mask );
+ if (ctx->RasterMask & ALPHABUF_BIT) {
+ _mesa_read_alpha_pixels( ctx, n, x, y, dest, mask );
+ }
+
+ for (i = 0; i < n; i++) {
+ if (!rMask) rgba[i][RCOMP] = dest[i][RCOMP];
+ if (!gMask) rgba[i][GCOMP] = dest[i][GCOMP];
+ if (!bMask) rgba[i][BCOMP] = dest[i][BCOMP];
+ if (!aMask) rgba[i][ACOMP] = dest[i][ACOMP];
+ }
+
+#endif
+}
+
+
+
+/*
+ * Apply glIndexMask to a span of CI pixels.
+ */
+void
+_mesa_mask_index_span( GLcontext *ctx,
+ GLuint n, GLint x, GLint y, GLuint index[] )
+{
+ GLuint i;
+ GLuint fbindexes[MAX_WIDTH];
+ GLuint msrc, mdest;
+
+ gl_read_index_span( ctx, ctx->DrawBuffer, n, x, y, fbindexes );
+
+ msrc = ctx->Color.IndexMask;
+ mdest = ~msrc;
+
+ for (i=0;i<n;i++) {
+ index[i] = (index[i] & msrc) | (fbindexes[i] & mdest);
+ }
+}
+
+
+
+/*
+ * Apply glIndexMask to an array of CI pixels.
+ */
+void
+_mesa_mask_index_pixels( GLcontext *ctx,
+ GLuint n, const GLint x[], const GLint y[],
+ GLuint index[], const GLubyte mask[] )
+{
+ GLuint i;
+ GLuint fbindexes[PB_SIZE];
+ GLuint msrc, mdest;
+
+ (*ctx->Driver.ReadCI32Pixels)( ctx, n, x, y, fbindexes, mask );
+
+ msrc = ctx->Color.IndexMask;
+ mdest = ~msrc;
+
+ for (i=0;i<n;i++) {
+ index[i] = (index[i] & msrc) | (fbindexes[i] & mdest);
+ }
+}
+
diff --git a/src/mesa/swrast/s_masking.h b/src/mesa/swrast/s_masking.h
new file mode 100644
index 0000000000..3f25461ddc
--- /dev/null
+++ b/src/mesa/swrast/s_masking.h
@@ -0,0 +1,76 @@
+/* $Id: s_masking.h,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.
+ */
+
+
+#ifndef S_MASKING_H
+#define S_MASKING_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+/*
+ * Implement glColorMask for a span of RGBA pixels.
+ */
+extern void
+_mesa_mask_rgba_span( GLcontext *ctx,
+ GLuint n, GLint x, GLint y,
+ GLchan rgba[][4] );
+
+
+
+/*
+ * Implement glColorMask for an array of RGBA pixels.
+ */
+extern void
+_mesa_mask_rgba_pixels( GLcontext *ctx,
+ GLuint n, const GLint x[], const GLint y[],
+ GLchan rgba[][4], const GLubyte mask[] );
+
+
+
+/*
+ * Implement glIndexMask for a span of CI pixels.
+ */
+extern void
+_mesa_mask_index_span( GLcontext *ctx,
+ GLuint n, GLint x, GLint y, GLuint index[] );
+
+
+
+/*
+ * Implement glIndexMask for an array of CI pixels.
+ */
+extern void
+_mesa_mask_index_pixels( GLcontext *ctx,
+ GLuint n, const GLint x[], const GLint y[],
+ GLuint index[], const GLubyte mask[] );
+
+
+
+#endif
+
diff --git a/src/mesa/swrast/s_pixeltex.c b/src/mesa/swrast/s_pixeltex.c
new file mode 100644
index 0000000000..854482a251
--- /dev/null
+++ b/src/mesa/swrast/s_pixeltex.c
@@ -0,0 +1,80 @@
+/* $Id: s_pixeltex.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.
+ */
+
+
+/*
+ * This file implements both the GL_SGIX_pixel_texture and
+ * GL_SIGS_pixel_texture extensions. Luckily, they pretty much
+ * overlap in functionality so we use the same state variables
+ * and execution code for both.
+ */
+
+
+#include "glheader.h"
+#include "colormac.h"
+
+#include "s_pixeltex.h"
+
+
+/*
+ * Convert RGBA values into strq texture coordinates.
+ */
+void
+_mesa_pixeltexgen(GLcontext *ctx, GLuint n, const GLchan rgba[][4],
+ GLfloat s[], GLfloat t[], GLfloat r[], GLfloat q[])
+{
+ if (ctx->Pixel.FragmentRgbSource == GL_CURRENT_RASTER_COLOR) {
+ GLuint i;
+ for (i = 0; i < n; i++) {
+ s[i] = ctx->Current.RasterColor[RCOMP];
+ t[i] = ctx->Current.RasterColor[GCOMP];
+ r[i] = ctx->Current.RasterColor[BCOMP];
+ }
+ }
+ else {
+ GLuint i;
+ ASSERT(ctx->Pixel.FragmentRgbSource == GL_PIXEL_GROUP_COLOR_SGIS);
+ for (i = 0; i < n; i++) {
+ s[i] = CHAN_TO_FLOAT(rgba[i][RCOMP]);
+ t[i] = CHAN_TO_FLOAT(rgba[i][GCOMP]);
+ r[i] = CHAN_TO_FLOAT(rgba[i][BCOMP]);
+ }
+ }
+
+ if (ctx->Pixel.FragmentAlphaSource == GL_CURRENT_RASTER_COLOR) {
+ GLuint i;
+ for (i = 0; i < n; i++) {
+ q[i] = ctx->Current.RasterColor[ACOMP];
+ }
+ }
+ else {
+ GLuint i;
+ ASSERT(ctx->Pixel.FragmentAlphaSource == GL_PIXEL_GROUP_COLOR_SGIS);
+ for (i = 0; i < n; i++) {
+ q[i] = CHAN_TO_FLOAT(rgba[i][ACOMP]);
+ }
+ }
+}
diff --git a/src/mesa/swrast/s_pixeltex.h b/src/mesa/swrast/s_pixeltex.h
new file mode 100644
index 0000000000..50946423e2
--- /dev/null
+++ b/src/mesa/swrast/s_pixeltex.h
@@ -0,0 +1,39 @@
+/* $Id: s_pixeltex.h,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 noti_mesa_PixelTexGenParameterfvce 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.
+ */
+
+
+#ifndef S_PIXELTEX_H
+#define S_PIXELTEX_H
+
+#include "types.h"
+#include "swrast.h"
+
+extern void
+_mesa_pixeltexgen(GLcontext *ctx, GLuint n, const GLchan rgba[][4],
+ GLfloat s[], GLfloat t[], GLfloat r[], GLfloat q[]);
+
+
+#endif
diff --git a/src/mesa/swrast/s_points.c b/src/mesa/swrast/s_points.c
new file mode 100644
index 0000000000..b24fc642ac
--- /dev/null
+++ b/src/mesa/swrast/s_points.c
@@ -0,0 +1,1193 @@
+/* $Id: s_points.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.4
+ *
+ * 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.
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "feedback.h"
+#include "macros.h"
+#include "mmath.h"
+#include "texstate.h"
+#include "vb.h"
+
+#include "s_pb.h"
+#include "s_span.h"
+
+
+/**********************************************************************/
+/***** Rasterization *****/
+/**********************************************************************/
+
+
+/*
+ * There are 3 pairs (RGBA, CI) of point rendering functions:
+ * 1. simple: size=1 and no special rasterization functions (fastest)
+ * 2. size1: size=1 and any rasterization functions
+ * 3. general: any size and rasterization functions (slowest)
+ *
+ * All point rendering functions take the same two arguments: first and
+ * last which specify that the points specified by VB[first] through
+ * VB[last] are to be rendered.
+ */
+
+
+
+
+
+/*
+ * CI points with size == 1.0
+ */
+static void
+size1_ci_points( GLcontext *ctx, GLuint first, GLuint last )
+{
+ struct vertex_buffer *VB = ctx->VB;
+ struct pixel_buffer *PB = ctx->PB;
+ GLfloat *win, *fog;
+ GLint *pbx = PB->x, *pby = PB->y;
+ GLdepth *pbz = PB->z;
+ GLfixed *pbfog = PB->fog;
+ GLuint *pbi = PB->index;
+ GLuint pbcount = PB->count;
+ GLuint i;
+
+ win = &VB->Win.data[first][0];
+ fog = &VB->FogCoordPtr->data[first];
+
+ for (i = first; i <= last; i++) {
+ if (VB->ClipMask[i] == 0) {
+ pbx[pbcount] = (GLint) win[0];
+ pby[pbcount] = (GLint) win[1];
+ pbz[pbcount] = (GLint) (win[2] + ctx->PointZoffset);
+ pbfog[pbcount] = FloatToFixed(fog[i]);
+ pbi[pbcount] = VB->IndexPtr->data[i];
+ pbcount++;
+ }
+ win += 3;
+ }
+ PB->count = pbcount;
+ PB_CHECK_FLUSH(ctx, PB);
+}
+
+
+
+/*
+ * RGBA points with size == 1.0
+ */
+static void
+size1_rgba_points( GLcontext *ctx, GLuint first, GLuint last )
+{
+ struct vertex_buffer *VB = ctx->VB;
+ struct pixel_buffer *PB = ctx->PB;
+ GLuint i;
+
+ for (i = first; i <= last; i++) {
+ if (VB->ClipMask[i] == 0) {
+ GLint x, y, z;
+ GLint fog;
+ GLint red, green, blue, alpha;
+
+ x = (GLint) VB->Win.data[i][0];
+ y = (GLint) VB->Win.data[i][1];
+ z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
+
+ fog = FloatToFixed( VB->FogCoordPtr->data[i] );
+
+ red = VB->ColorPtr->data[i][0];
+ green = VB->ColorPtr->data[i][1];
+ blue = VB->ColorPtr->data[i][2];
+ alpha = VB->ColorPtr->data[i][3];
+
+ PB_WRITE_RGBA_PIXEL( PB, x, y, z, fog, red, green, blue, alpha );
+ }
+ }
+ PB_CHECK_FLUSH(ctx, PB);
+}
+
+
+
+/*
+ * General CI points.
+ */
+static void
+general_ci_points( GLcontext *ctx, GLuint first, GLuint last )
+{
+ struct vertex_buffer *VB = ctx->VB;
+ struct pixel_buffer *PB = ctx->PB;
+ const GLint isize = (GLint) (ctx->Point.Size + 0.5F);
+ GLint radius = isize >> 1;
+ GLuint i;
+
+ for (i = first; i <= last; i++) {
+ if (VB->ClipMask[i] == 0) {
+ GLint x0, x1, y0, y1;
+ GLint ix, iy;
+
+ GLint x = (GLint) VB->Win.data[i][0];
+ GLint y = (GLint) VB->Win.data[i][1];
+ GLint z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
+
+ GLfixed fog = FloatToFixed( VB->FogCoordPtr->data[i] );
+
+ if (isize & 1) {
+ /* odd size */
+ x0 = x - radius;
+ x1 = x + radius;
+ y0 = y - radius;
+ y1 = y + radius;
+ }
+ else {
+ /* even size */
+ x0 = (GLint) (x + 1.5F) - radius;
+ x1 = x0 + isize - 1;
+ y0 = (GLint) (y + 1.5F) - radius;
+ y1 = y0 + isize - 1;
+ }
+
+ PB_SET_INDEX( PB, VB->IndexPtr->data[i] );
+
+ for (iy = y0; iy <= y1; iy++) {
+ for (ix = x0; ix <= x1; ix++) {
+ PB_WRITE_PIXEL( PB, ix, iy, z, fog );
+ }
+ }
+ PB_CHECK_FLUSH(ctx,PB);
+ }
+ }
+}
+
+
+/*
+ * General RGBA points.
+ */
+static void
+general_rgba_points( GLcontext *ctx, GLuint first, GLuint last )
+{
+ struct vertex_buffer *VB = ctx->VB;
+ struct pixel_buffer *PB = ctx->PB;
+ GLint isize = (GLint) (ctx->Point.Size + 0.5F);
+ GLint radius = isize >> 1;
+ GLuint i;
+
+ for (i = first; i <= last; i++) {
+ if (VB->ClipMask[i] == 0) {
+ GLint x0, x1, y0, y1;
+ GLint ix, iy;
+
+ GLint x = (GLint) VB->Win.data[i][0];
+ GLint y = (GLint) VB->Win.data[i][1];
+ GLint z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
+
+ GLfixed fog = FloatToFixed( VB->FogCoordPtr->data[i] );
+
+ if (isize & 1) {
+ /* odd size */
+ x0 = x - radius;
+ x1 = x + radius;
+ y0 = y - radius;
+ y1 = y + radius;
+ }
+ else {
+ /* even size */
+ x0 = (GLint) (x + 1.5F) - radius;
+ x1 = x0 + isize - 1;
+ y0 = (GLint) (y + 1.5F) - radius;
+ y1 = y0 + isize - 1;
+ }
+
+ PB_SET_COLOR( PB,
+ VB->ColorPtr->data[i][0],
+ VB->ColorPtr->data[i][1],
+ VB->ColorPtr->data[i][2],
+ VB->ColorPtr->data[i][3] );
+
+ for (iy = y0; iy <= y1; iy++) {
+ for (ix = x0; ix <= x1; ix++) {
+ PB_WRITE_PIXEL( PB, ix, iy, z, fog );
+ }
+ }
+ PB_CHECK_FLUSH(ctx,PB);
+ }
+ }
+}
+
+
+
+
+/*
+ * Textured RGBA points.
+ */
+static void
+textured_rgba_points( GLcontext *ctx, GLuint first, GLuint last )
+{
+ struct vertex_buffer *VB = ctx->VB;
+ struct pixel_buffer *PB = ctx->PB;
+ GLuint i;
+
+ for (i = first; i <= last; i++) {
+ if (VB->ClipMask[i] == 0) {
+ GLint x0, x1, y0, y1;
+ GLint ix, iy, radius;
+ GLint red, green, blue, alpha;
+ GLfloat s, t, u;
+
+ GLint x = (GLint) VB->Win.data[i][0];
+ GLint y = (GLint) VB->Win.data[i][1];
+ GLint z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
+ GLint isize = (GLint) (ctx->Point.Size + 0.5F);
+
+ GLfixed fog = FloatToFixed( VB->FogCoordPtr->data[i] );
+
+ if (isize < 1) {
+ isize = 1;
+ }
+ radius = isize >> 1;
+
+ if (isize & 1) {
+ /* odd size */
+ x0 = x - radius;
+ x1 = x + radius;
+ y0 = y - radius;
+ y1 = y + radius;
+ }
+ else {
+ /* even size */
+ x0 = (GLint) (x + 1.5F) - radius;
+ x1 = x0 + isize - 1;
+ y0 = (GLint) (y + 1.5F) - radius;
+ y1 = y0 + isize - 1;
+ }
+
+ red = VB->ColorPtr->data[i][0];
+ green = VB->ColorPtr->data[i][1];
+ blue = VB->ColorPtr->data[i][2];
+ alpha = VB->ColorPtr->data[i][3];
+
+ switch (VB->TexCoordPtr[0]->size) {
+ case 4:
+ s = VB->TexCoordPtr[0]->data[i][0]/VB->TexCoordPtr[0]->data[i][3];
+ t = VB->TexCoordPtr[0]->data[i][1]/VB->TexCoordPtr[0]->data[i][3];
+ u = VB->TexCoordPtr[0]->data[i][2]/VB->TexCoordPtr[0]->data[i][3];
+ break;
+ case 3:
+ s = VB->TexCoordPtr[0]->data[i][0];
+ t = VB->TexCoordPtr[0]->data[i][1];
+ u = VB->TexCoordPtr[0]->data[i][2];
+ break;
+ case 2:
+ s = VB->TexCoordPtr[0]->data[i][0];
+ t = VB->TexCoordPtr[0]->data[i][1];
+ u = 0.0;
+ break;
+ case 1:
+ s = VB->TexCoordPtr[0]->data[i][0];
+ t = 0.0;
+ u = 0.0;
+ break;
+ default:
+ /* should never get here */
+ s = t = u = 0.0;
+ gl_problem(ctx, "unexpected texcoord size in textured_rgba_points()");
+ }
+
+ for (iy = y0; iy <= y1; iy++) {
+ for (ix = x0; ix <= x1; ix++) {
+ PB_WRITE_TEX_PIXEL( PB, ix, iy, z, fog, red, green, blue, alpha,
+ s, t, u );
+ }
+ }
+
+ PB_CHECK_FLUSH(ctx, PB);
+ }
+ }
+}
+
+
+/*
+ * Multitextured RGBA points.
+ */
+static void
+multitextured_rgba_points( GLcontext *ctx, GLuint first, GLuint last )
+{
+ struct vertex_buffer *VB = ctx->VB;
+ struct pixel_buffer *PB = ctx->PB;
+ GLuint i;
+
+ for (i = first; i <= last; i++) {
+ if (VB->ClipMask[i] == 0) {
+ const GLint red = VB->ColorPtr->data[i][0];
+ const GLint green = VB->ColorPtr->data[i][1];
+ const GLint blue = VB->ColorPtr->data[i][2];
+ const GLint alpha = VB->ColorPtr->data[i][3];
+ const GLint sRed = VB->SecondaryColorPtr->data ? VB->SecondaryColorPtr->data[i][0] : 0;
+ const GLint sGreen = VB->SecondaryColorPtr->data ? VB->SecondaryColorPtr->data[i][1] : 0;
+ const GLint sBlue = VB->SecondaryColorPtr->data ? VB->SecondaryColorPtr->data[i][2] : 0;
+ const GLint x = (GLint) VB->Win.data[i][0];
+ const GLint y = (GLint) VB->Win.data[i][1];
+ const GLint z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
+ GLint x0, x1, y0, y1;
+ GLint ix, iy;
+ GLfloat texcoord[MAX_TEXTURE_UNITS][4];
+ GLint radius, u;
+ GLint isize = (GLint) (ctx->Point.Size + 0.5F);
+
+ GLfixed fog = FloatToFixed( VB->FogCoordPtr->data[i] );
+
+ if (isize < 1) {
+ isize = 1;
+ }
+ radius = isize >> 1;
+
+ if (isize & 1) {
+ /* odd size */
+ x0 = x - radius;
+ x1 = x + radius;
+ y0 = y - radius;
+ y1 = y + radius;
+ }
+ else {
+ /* even size */
+ x0 = (GLint) (x + 1.5F) - radius;
+ x1 = x0 + isize - 1;
+ y0 = (GLint) (y + 1.5F) - radius;
+ y1 = y0 + isize - 1;
+ }
+
+ for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+ if (ctx->Texture.Unit[u].ReallyEnabled) {
+ switch (VB->TexCoordPtr[0]->size) {
+ case 4:
+ texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0] /
+ VB->TexCoordPtr[u]->data[i][3];
+ texcoord[u][1] = VB->TexCoordPtr[u]->data[i][1] /
+ VB->TexCoordPtr[u]->data[i][3];
+ texcoord[u][2] = VB->TexCoordPtr[u]->data[i][2] /
+ VB->TexCoordPtr[u]->data[i][3];
+ break;
+ case 3:
+ texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0];
+ texcoord[u][1] = VB->TexCoordPtr[u]->data[i][1];
+ texcoord[u][2] = VB->TexCoordPtr[u]->data[i][2];
+ break;
+ case 2:
+ texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0];
+ texcoord[u][1] = VB->TexCoordPtr[u]->data[i][1];
+ texcoord[u][2] = 0.0;
+ break;
+ case 1:
+ texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0];
+ texcoord[u][1] = 0.0;
+ texcoord[u][2] = 0.0;
+ break;
+ default:
+ /* should never get here */
+ gl_problem(ctx, "unexpected texcoord size");
+ }
+ }
+ }
+
+ for (iy = y0; iy <= y1; iy++) {
+ for (ix = x0; ix <= x1; ix++) {
+ PB_WRITE_MULTITEX_SPEC_PIXEL( PB, ix, iy, z, fog,
+ red, green, blue, alpha,
+ sRed, sGreen, sBlue,
+ texcoord );
+ }
+ }
+ PB_CHECK_FLUSH(ctx, PB);
+ }
+ }
+}
+
+
+/*
+ * NOTES on aa point rasterization:
+ *
+ * Let d = distance of fragment center from vertex.
+ * if d < rmin2 then
+ * fragment has 100% coverage
+ * else if d > rmax2 then
+ * fragment has 0% coverage
+ * else
+ * fragement has % coverage = (d - rmin2) / (rmax2 - rmin2)
+ */
+
+
+/*
+ * Antialiased points with or without texture mapping.
+ */
+static void
+antialiased_rgba_points( GLcontext *ctx, GLuint first, GLuint last )
+{
+ struct vertex_buffer *VB = ctx->VB;
+ struct pixel_buffer *PB = ctx->PB;
+ const GLfloat radius = ctx->Point.Size * 0.5F;
+ const GLfloat rmin = radius - 0.7071F; /* 0.7071 = sqrt(2)/2 */
+ const GLfloat rmax = radius + 0.7071F;
+ const GLfloat rmin2 = MAX2(0.0, rmin * rmin);
+ const GLfloat rmax2 = rmax * rmax;
+ const GLfloat cscale = 256.0F / (rmax2 - rmin2);
+ GLuint i;
+
+ if (ctx->Texture.ReallyEnabled) {
+ for (i = first; i <= last; i++) {
+ if (VB->ClipMask[i] == 0) {
+ GLint x, y;
+ GLfloat vx = VB->Win.data[i][0];
+ GLfloat vy = VB->Win.data[i][1];
+ const GLint xmin = (GLint) (vx - radius);
+ const GLint xmax = (GLint) (vx + radius);
+ const GLint ymin = (GLint) (vy - radius);
+ const GLint ymax = (GLint) (vy + radius);
+ const GLint z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
+ const GLint red = VB->ColorPtr->data[i][0];
+ const GLint green = VB->ColorPtr->data[i][1];
+ const GLint blue = VB->ColorPtr->data[i][2];
+ GLfloat texcoord[MAX_TEXTURE_UNITS][4];
+ GLint u, alpha;
+
+ GLfixed fog = FloatToFixed( VB->FogCoordPtr->data[i] );
+
+ for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+ if (ctx->Texture.Unit[u].ReallyEnabled) {
+ switch (VB->TexCoordPtr[0]->size) {
+ case 4:
+ texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0] /
+ VB->TexCoordPtr[u]->data[i][3];
+ texcoord[u][1] = VB->TexCoordPtr[u]->data[i][1] /
+ VB->TexCoordPtr[u]->data[i][3];
+ texcoord[u][2] = VB->TexCoordPtr[u]->data[i][2] /
+ VB->TexCoordPtr[u]->data[i][3];
+ break;
+ case 3:
+ texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0];
+ texcoord[u][1] = VB->TexCoordPtr[u]->data[i][1];
+ texcoord[u][2] = VB->TexCoordPtr[u]->data[i][2];
+ break;
+ case 2:
+ texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0];
+ texcoord[u][1] = VB->TexCoordPtr[u]->data[i][1];
+ texcoord[u][2] = 0.0;
+ break;
+ case 1:
+ texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0];
+ texcoord[u][1] = 0.0;
+ texcoord[u][2] = 0.0;
+ break;
+ default:
+ /* should never get here */
+ gl_problem(ctx, "unexpected texcoord size in antialiased_rgba_points()");
+ }
+ }
+ }
+
+ /* translate by a half pixel to simplify math below */
+ vx -= 0.5F;
+ vx -= 0.5F;
+
+ for (y = ymin; y <= ymax; y++) {
+ for (x = xmin; x <= xmax; x++) {
+ const GLfloat dx = x - vx;
+ const GLfloat dy = y - vy;
+ const GLfloat dist2 = dx*dx + dy*dy;
+ if (dist2 < rmax2) {
+ alpha = VB->ColorPtr->data[i][3];
+ if (dist2 >= rmin2) {
+ GLint coverage = (GLint) (256.0F - (dist2 - rmin2) * cscale);
+ /* coverage is in [0,256] */
+ alpha = (alpha * coverage) >> 8;
+ }
+ if (ctx->Texture.MultiTextureEnabled) {
+ PB_WRITE_MULTITEX_PIXEL( PB, x,y,z, fog,
+ red, green, blue,
+ alpha, texcoord );
+ }
+ else {
+ PB_WRITE_TEX_PIXEL( PB, x,y,z, fog,
+ red, green, blue, alpha,
+ texcoord[0][0],
+ texcoord[0][1],
+ texcoord[0][2] );
+ }
+ }
+ }
+ }
+
+ PB_CHECK_FLUSH(ctx,PB);
+ }
+ }
+ }
+ else {
+ /* Not texture mapped */
+ for (i=first;i<=last;i++) {
+ if (VB->ClipMask[i]==0) {
+ const GLint xmin = (GLint) (VB->Win.data[i][0] - 0.0 - radius);
+ const GLint xmax = (GLint) (VB->Win.data[i][0] - 0.0 + radius);
+ const GLint ymin = (GLint) (VB->Win.data[i][1] - 0.0 - radius);
+ const GLint ymax = (GLint) (VB->Win.data[i][1] - 0.0 + radius);
+ const GLint red = VB->ColorPtr->data[i][0];
+ const GLint green = VB->ColorPtr->data[i][1];
+ const GLint blue = VB->ColorPtr->data[i][2];
+ const GLint z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
+ GLint x, y;
+
+ GLfixed fog = FloatToFixed( VB->FogCoordPtr->data[i] );
+
+ /*
+ printf("point %g, %g\n", VB->Win.data[i][0], VB->Win.data[i][1]);
+ printf("%d..%d X %d..%d\n", xmin, xmax, ymin, ymax);
+ */
+ for (y = ymin; y <= ymax; y++) {
+ for (x = xmin; x <= xmax; x++) {
+ const GLfloat dx = x + 0.5F - VB->Win.data[i][0];
+ const GLfloat dy = y + 0.5F - VB->Win.data[i][1];
+ const GLfloat dist2 = dx*dx + dy*dy;
+ if (dist2 < rmax2) {
+ GLint alpha = VB->ColorPtr->data[i][3];
+ if (dist2 >= rmin2) {
+ GLint coverage = (GLint) (256.0F - (dist2 - rmin2) * cscale);
+ /* coverage is in [0,256] */
+ alpha = (alpha * coverage) >> 8;
+ }
+ PB_WRITE_RGBA_PIXEL(PB, x, y, z, fog,
+ red, green, blue, alpha);
+ }
+ }
+ }
+ PB_CHECK_FLUSH(ctx,PB);
+ }
+ }
+ }
+}
+
+
+
+/*
+ * Null rasterizer for measuring transformation speed.
+ */
+static void
+null_points( GLcontext *ctx, GLuint first, GLuint last )
+{
+ (void) ctx;
+ (void) first;
+ (void) last;
+}
+
+
+
+/* Definition of the functions for GL_EXT_point_parameters */
+
+/* Calculates the distance attenuation formula of a vector of points in
+ * eye space coordinates
+ */
+static void
+dist3(GLfloat *out, GLuint first, GLuint last,
+ const GLcontext *ctx, const GLvector4f *v)
+{
+ GLuint stride = v->stride;
+ const GLfloat *p = VEC_ELT(v, GLfloat, first);
+ GLuint i;
+
+ for (i = first ; i <= last ; i++, STRIDE_F(p, stride) ) {
+ GLfloat dist = GL_SQRT(p[0]*p[0]+p[1]*p[1]+p[2]*p[2]);
+ out[i] = 1.0F / (ctx->Point.Params[0] +
+ dist * (ctx->Point.Params[1] +
+ dist * ctx->Point.Params[2]));
+ }
+}
+
+
+static void
+dist2(GLfloat *out, GLuint first, GLuint last,
+ const GLcontext *ctx, const GLvector4f *v)
+{
+ GLuint stride = v->stride;
+ const GLfloat *p = VEC_ELT(v, GLfloat, first);
+ GLuint i;
+
+ for (i = first ; i <= last ; i++, STRIDE_F(p, stride) ) {
+ GLfloat dist = GL_SQRT(p[0]*p[0]+p[1]*p[1]);
+ out[i] = 1.0F / (ctx->Point.Params[0] +
+ dist * (ctx->Point.Params[1] +
+ dist * ctx->Point.Params[2]));
+ }
+}
+
+
+typedef void (*dist_func)(GLfloat *out, GLuint first, GLuint last,
+ const GLcontext *ctx, const GLvector4f *v);
+
+
+static dist_func eye_dist_tab[5] = {
+ 0,
+ 0,
+ dist2,
+ dist3,
+ dist3
+};
+
+
+
+/*
+ * Distance Attenuated General CI points.
+ */
+static void
+dist_atten_general_ci_points( GLcontext *ctx, GLuint first, GLuint last )
+{
+ struct vertex_buffer *VB = ctx->VB;
+ struct pixel_buffer *PB = ctx->PB;
+ GLfloat dist[VB_SIZE];
+ const GLfloat psize = ctx->Point.Size;
+ GLuint i;
+
+ ASSERT(ctx->NeedEyeCoords);
+ (eye_dist_tab[VB->EyePtr->size])( dist, first, last, ctx, VB->EyePtr );
+
+
+ for (i=first;i<=last;i++) {
+ if (VB->ClipMask[i]==0) {
+ GLint x0, x1, y0, y1;
+ GLint ix, iy;
+ GLint isize, radius;
+ GLint x = (GLint) VB->Win.data[i][0];
+ GLint y = (GLint) VB->Win.data[i][1];
+ GLint z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
+ GLfloat dsize = psize * dist[i];
+
+ GLfixed fog = FloatToFixed( VB->FogCoordPtr->data[i] );
+
+ if (dsize >= ctx->Point.Threshold) {
+ isize = (GLint) (MIN2(dsize, ctx->Point.MaxSize) + 0.5F);
+ }
+ else {
+ isize = (GLint) (MAX2(ctx->Point.Threshold, ctx->Point.MinSize) + 0.5F);
+ }
+ radius = isize >> 1;
+
+ if (isize & 1) {
+ /* odd size */
+ x0 = x - radius;
+ x1 = x + radius;
+ y0 = y - radius;
+ y1 = y + radius;
+ }
+ else {
+ /* even size */
+ x0 = (GLint) (x + 1.5F) - radius;
+ x1 = x0 + isize - 1;
+ y0 = (GLint) (y + 1.5F) - radius;
+ y1 = y0 + isize - 1;
+ }
+
+ PB_SET_INDEX( PB, VB->IndexPtr->data[i] );
+
+ for (iy=y0;iy<=y1;iy++) {
+ for (ix=x0;ix<=x1;ix++) {
+ PB_WRITE_PIXEL( PB, ix, iy, z, fog );
+ }
+ }
+ PB_CHECK_FLUSH(ctx,PB);
+ }
+ }
+}
+
+/*
+ * Distance Attenuated General RGBA points.
+ */
+static void
+dist_atten_general_rgba_points( GLcontext *ctx, GLuint first, GLuint last )
+{
+ struct vertex_buffer *VB = ctx->VB;
+ struct pixel_buffer *PB = ctx->PB;
+ GLfloat dist[VB_SIZE];
+ const GLfloat psize = ctx->Point.Size;
+ GLuint i;
+
+ ASSERT (ctx->NeedEyeCoords);
+ (eye_dist_tab[VB->EyePtr->size])( dist, first, last, ctx, VB->EyePtr );
+
+ for (i=first;i<=last;i++) {
+ if (VB->ClipMask[i]==0) {
+ GLint x0, x1, y0, y1;
+ GLint ix, iy;
+ GLint isize, radius;
+ GLint x = (GLint) VB->Win.data[i][0];
+ GLint y = (GLint) VB->Win.data[i][1];
+ GLint z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
+ GLfloat dsize=psize*dist[i];
+ GLchan alpha;
+ GLfixed fog = FloatToFixed( VB->FogCoordPtr->data[i] );
+
+ if (dsize >= ctx->Point.Threshold) {
+ isize = (GLint) (MIN2(dsize,ctx->Point.MaxSize)+0.5F);
+ alpha = VB->ColorPtr->data[i][3];
+ }
+ else {
+ isize = (GLint) (MAX2(ctx->Point.Threshold,ctx->Point.MinSize)+0.5F);
+ dsize /= ctx->Point.Threshold;
+ alpha = (GLint) (VB->ColorPtr->data[i][3]* (dsize*dsize));
+ }
+ radius = isize >> 1;
+
+ if (isize & 1) {
+ /* odd size */
+ x0 = x - radius;
+ x1 = x + radius;
+ y0 = y - radius;
+ y1 = y + radius;
+ }
+ else {
+ /* even size */
+ x0 = (GLint) (x + 1.5F) - radius;
+ x1 = x0 + isize - 1;
+ y0 = (GLint) (y + 1.5F) - radius;
+ y1 = y0 + isize - 1;
+ }
+
+ PB_SET_COLOR( PB,
+ VB->ColorPtr->data[i][0],
+ VB->ColorPtr->data[i][1],
+ VB->ColorPtr->data[i][2],
+ alpha );
+
+ for (iy = y0; iy <= y1; iy++) {
+ for (ix = x0; ix <= x1; ix++) {
+ PB_WRITE_PIXEL( PB, ix, iy, z, fog );
+ }
+ }
+ PB_CHECK_FLUSH(ctx,PB);
+ }
+ }
+}
+
+/*
+ * Distance Attenuated Textured RGBA points.
+ */
+static void
+dist_atten_textured_rgba_points( GLcontext *ctx, GLuint first, GLuint last )
+{
+ struct vertex_buffer *VB = ctx->VB;
+ struct pixel_buffer *PB = ctx->PB;
+ GLfloat dist[VB_SIZE];
+ const GLfloat psize = ctx->Point.Size;
+ GLuint i;
+
+ ASSERT(ctx->NeedEyeCoords);
+ (eye_dist_tab[VB->EyePtr->size])( dist, first, last, ctx, VB->EyePtr );
+
+ for (i=first;i<=last;i++) {
+ if (VB->ClipMask[i]==0) {
+ const GLint x = (GLint) VB->Win.data[i][0];
+ const GLint y = (GLint) VB->Win.data[i][1];
+ const GLint z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
+ const GLint red = VB->ColorPtr->data[i][0];
+ const GLint green = VB->ColorPtr->data[i][1];
+ const GLint blue = VB->ColorPtr->data[i][2];
+ GLfloat texcoord[MAX_TEXTURE_UNITS][4];
+ GLint x0, x1, y0, y1;
+ GLint ix, iy, alpha, u;
+ GLint isize, radius;
+ GLfloat dsize = psize*dist[i];
+
+ GLfixed fog = FloatToFixed( VB->FogCoordPtr->data[i] );
+
+ /* compute point size and alpha */
+ if (dsize >= ctx->Point.Threshold) {
+ isize = (GLint) (MIN2(dsize, ctx->Point.MaxSize) + 0.5F);
+ alpha = VB->ColorPtr->data[i][3];
+ }
+ else {
+ isize = (GLint) (MAX2(ctx->Point.Threshold, ctx->Point.MinSize) + 0.5F);
+ dsize /= ctx->Point.Threshold;
+ alpha = (GLint) (VB->ColorPtr->data[i][3] * (dsize * dsize));
+ }
+ if (isize < 1) {
+ isize = 1;
+ }
+ radius = isize >> 1;
+
+ if (isize & 1) {
+ /* odd size */
+ x0 = x - radius;
+ x1 = x + radius;
+ y0 = y - radius;
+ y1 = y + radius;
+ }
+ else {
+ /* even size */
+ x0 = (GLint) (x + 1.5F) - radius;
+ x1 = x0 + isize - 1;
+ y0 = (GLint) (y + 1.5F) - radius;
+ y1 = y0 + isize - 1;
+ }
+
+ /* get texture coordinates */
+ for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+ if (ctx->Texture.Unit[u].ReallyEnabled) {
+ switch (VB->TexCoordPtr[0]->size) {
+ case 4:
+ texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0] /
+ VB->TexCoordPtr[u]->data[i][3];
+ texcoord[u][1] = VB->TexCoordPtr[u]->data[i][1] /
+ VB->TexCoordPtr[u]->data[i][3];
+ texcoord[u][2] = VB->TexCoordPtr[u]->data[i][2] /
+ VB->TexCoordPtr[u]->data[i][3];
+ break;
+ case 3:
+ texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0];
+ texcoord[u][1] = VB->TexCoordPtr[u]->data[i][1];
+ texcoord[u][2] = VB->TexCoordPtr[u]->data[i][2];
+ break;
+ case 2:
+ texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0];
+ texcoord[u][1] = VB->TexCoordPtr[u]->data[i][1];
+ texcoord[u][2] = 0.0;
+ break;
+ case 1:
+ texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0];
+ texcoord[u][1] = 0.0;
+ texcoord[u][2] = 0.0;
+ break;
+ default:
+ /* should never get here */
+ gl_problem(ctx, "unexpected texcoord size");
+ }
+ }
+ }
+
+ for (iy = y0; iy <= y1; iy++) {
+ for (ix = x0; ix <= x1; ix++) {
+ if (ctx->Texture.MultiTextureEnabled) {
+ PB_WRITE_MULTITEX_PIXEL( PB, ix, iy, z, fog,
+ red, green, blue, alpha,
+ texcoord );
+ }
+ else {
+ PB_WRITE_TEX_PIXEL( PB, ix, iy, z, fog,
+ red, green, blue, alpha,
+ texcoord[0][0],
+ texcoord[0][1],
+ texcoord[0][2] );
+ }
+ }
+ }
+ PB_CHECK_FLUSH(ctx,PB);
+ }
+ }
+}
+
+/*
+ * Distance Attenuated Antialiased points with or without texture mapping.
+ */
+static void
+dist_atten_antialiased_rgba_points( GLcontext *ctx, GLuint first, GLuint last )
+{
+ struct vertex_buffer *VB = ctx->VB;
+ struct pixel_buffer *PB = ctx->PB;
+ GLfloat dist[VB_SIZE];
+ const GLfloat psize = ctx->Point.Size;
+ GLuint i;
+
+ ASSERT(ctx->NeedEyeCoords);
+ (eye_dist_tab[VB->EyePtr->size])( dist, first, last, ctx, VB->EyePtr );
+
+ if (ctx->Texture.ReallyEnabled) {
+ for (i=first;i<=last;i++) {
+ if (VB->ClipMask[i]==0) {
+ GLfloat radius, rmin, rmax, rmin2, rmax2, cscale, alphaf;
+ GLint xmin, ymin, xmax, ymax;
+ GLint x, y, z;
+ GLint red, green, blue, alpha;
+ GLfloat texcoord[MAX_TEXTURE_UNITS][4];
+ GLfloat dsize = psize * dist[i];
+ GLint u;
+
+ GLfixed fog = FloatToFixed( VB->FogCoordPtr->data[i] );
+
+ if (dsize >= ctx->Point.Threshold) {
+ radius = MIN2(dsize, ctx->Point.MaxSize) * 0.5F;
+ alphaf = 1.0F;
+ }
+ else {
+ radius = (MAX2(ctx->Point.Threshold, ctx->Point.MinSize) * 0.5F);
+ dsize /= ctx->Point.Threshold;
+ alphaf = (dsize*dsize);
+ }
+ rmin = radius - 0.7071F; /* 0.7071 = sqrt(2)/2 */
+ rmax = radius + 0.7071F;
+ rmin2 = MAX2(0.0, rmin * rmin);
+ rmax2 = rmax * rmax;
+ cscale = 256.0F / (rmax2 - rmin2);
+
+ xmin = (GLint) (VB->Win.data[i][0] - radius);
+ xmax = (GLint) (VB->Win.data[i][0] + radius);
+ ymin = (GLint) (VB->Win.data[i][1] - radius);
+ ymax = (GLint) (VB->Win.data[i][1] + radius);
+ z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
+
+ red = VB->ColorPtr->data[i][0];
+ green = VB->ColorPtr->data[i][1];
+ blue = VB->ColorPtr->data[i][2];
+
+ /* get texture coordinates */
+ for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+ if (ctx->Texture.Unit[u].ReallyEnabled) {
+ switch (VB->TexCoordPtr[0]->size) {
+ case 4:
+ texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0] /
+ VB->TexCoordPtr[u]->data[i][3];
+ texcoord[u][1] = VB->TexCoordPtr[u]->data[i][1] /
+ VB->TexCoordPtr[u]->data[i][3];
+ texcoord[u][2] = VB->TexCoordPtr[u]->data[i][2] /
+ VB->TexCoordPtr[u]->data[i][3];
+ break;
+ case 3:
+ texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0];
+ texcoord[u][1] = VB->TexCoordPtr[u]->data[i][1];
+ texcoord[u][2] = VB->TexCoordPtr[u]->data[i][2];
+ break;
+ case 2:
+ texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0];
+ texcoord[u][1] = VB->TexCoordPtr[u]->data[i][1];
+ texcoord[u][2] = 0.0;
+ break;
+ case 1:
+ texcoord[u][0] = VB->TexCoordPtr[u]->data[i][0];
+ texcoord[u][1] = 0.0;
+ texcoord[u][2] = 0.0;
+ break;
+ default:
+ /* should never get here */
+ gl_problem(ctx, "unexpected texcoord size");
+ }
+ }
+ }
+
+ for (y = ymin; y <= ymax; y++) {
+ for (x = xmin; x <= xmax; x++) {
+ const GLfloat dx = x + 0.5F - VB->Win.data[i][0];
+ const GLfloat dy = y + 0.5F - VB->Win.data[i][1];
+ const GLfloat dist2 = dx*dx + dy*dy;
+ if (dist2 < rmax2) {
+ alpha = VB->ColorPtr->data[i][3];
+ if (dist2 >= rmin2) {
+ GLint coverage = (GLint) (256.0F - (dist2 - rmin2) * cscale);
+ /* coverage is in [0,256] */
+ alpha = (alpha * coverage) >> 8;
+ }
+ alpha = (GLint) (alpha * alphaf);
+ if (ctx->Texture.MultiTextureEnabled) {
+ PB_WRITE_MULTITEX_PIXEL( PB, x, y, z, fog,
+ red, green, blue, alpha,
+ texcoord );
+ }
+ else {
+ PB_WRITE_TEX_PIXEL( PB, x,y,z, fog,
+ red, green, blue, alpha,
+ texcoord[0][0],
+ texcoord[0][1],
+ texcoord[0][2] );
+ }
+ }
+ }
+ }
+ PB_CHECK_FLUSH(ctx,PB);
+ }
+ }
+ }
+ else {
+ /* Not texture mapped */
+ for (i = first; i <= last; i++) {
+ if (VB->ClipMask[i] == 0) {
+ GLfloat radius, rmin, rmax, rmin2, rmax2, cscale, alphaf;
+ GLint xmin, ymin, xmax, ymax;
+ GLint x, y, z;
+ GLfixed fog;
+ GLint red, green, blue, alpha;
+ GLfloat dsize = psize * dist[i];
+
+ if (dsize >= ctx->Point.Threshold) {
+ radius = MIN2(dsize, ctx->Point.MaxSize) * 0.5F;
+ alphaf = 1.0F;
+ }
+ else {
+ radius = (MAX2(ctx->Point.Threshold, ctx->Point.MinSize) * 0.5F);
+ dsize /= ctx->Point.Threshold;
+ alphaf = dsize * dsize;
+ }
+ rmin = radius - 0.7071F; /* 0.7071 = sqrt(2)/2 */
+ rmax = radius + 0.7071F;
+ rmin2 = MAX2(0.0, rmin * rmin);
+ rmax2 = rmax * rmax;
+ cscale = 256.0F / (rmax2 - rmin2);
+
+ xmin = (GLint) (VB->Win.data[i][0] - radius);
+ xmax = (GLint) (VB->Win.data[i][0] + radius);
+ ymin = (GLint) (VB->Win.data[i][1] - radius);
+ ymax = (GLint) (VB->Win.data[i][1] + radius);
+ z = (GLint) (VB->Win.data[i][2] + ctx->PointZoffset);
+
+ fog = FloatToFixed( VB->FogCoordPtr->data[i] );
+
+ red = VB->ColorPtr->data[i][0];
+ green = VB->ColorPtr->data[i][1];
+ blue = VB->ColorPtr->data[i][2];
+
+ for (y = ymin; y <= ymax; y++) {
+ for (x = xmin; x <= xmax; x++) {
+ const GLfloat dx = x + 0.5F - VB->Win.data[i][0];
+ const GLfloat dy = y + 0.5F - VB->Win.data[i][1];
+ const GLfloat dist2 = dx * dx + dy * dy;
+ if (dist2 < rmax2) {
+ alpha = VB->ColorPtr->data[i][3];
+ if (dist2 >= rmin2) {
+ GLint coverage = (GLint) (256.0F - (dist2 - rmin2) * cscale);
+ /* coverage is in [0,256] */
+ alpha = (alpha * coverage) >> 8;
+ }
+ alpha = (GLint) (alpha * alphaf);
+ PB_WRITE_RGBA_PIXEL(PB, x, y, z, fog,
+ red, green, blue, alpha);
+ }
+ }
+ }
+ PB_CHECK_FLUSH(ctx,PB);
+ }
+ }
+ }
+}
+
+
+#ifdef DEBUG
+void
+_mesa_print_points_function(GLcontext *ctx)
+{
+ printf("Point Func == ");
+ if (ctx->Driver.PointsFunc == size1_ci_points)
+ printf("size1_ci_points\n");
+ else if (ctx->Driver.PointsFunc == size1_rgba_points)
+ printf("size1_rgba_points\n");
+ else if (ctx->Driver.PointsFunc == general_ci_points)
+ printf("general_ci_points\n");
+ else if (ctx->Driver.PointsFunc == general_rgba_points)
+ printf("general_rgba_points\n");
+ else if (ctx->Driver.PointsFunc == textured_rgba_points)
+ printf("textured_rgba_points\n");
+ else if (ctx->Driver.PointsFunc == multitextured_rgba_points)
+ printf("multitextured_rgba_points\n");
+ else if (ctx->Driver.PointsFunc == antialiased_rgba_points)
+ printf("antialiased_rgba_points\n");
+ else if (ctx->Driver.PointsFunc == null_points)
+ printf("null_points\n");
+ else if (ctx->Driver.PointsFunc == dist_atten_general_ci_points)
+ printf("dist_atten_general_ci_points\n");
+ else if (ctx->Driver.PointsFunc == dist_atten_general_rgba_points)
+ printf("dist_atten_general_rgba_points\n");
+ else if (ctx->Driver.PointsFunc == dist_atten_textured_rgba_points)
+ printf("dist_atten_textured_rgba_points\n");
+ else if (ctx->Driver.PointsFunc == dist_atten_antialiased_rgba_points)
+ printf("dist_atten_antialiased_rgba_points\n");
+ else if (!ctx->Driver.PointsFunc)
+ printf("NULL\n");
+ else
+ printf("Driver func %p\n", ctx->Driver.PointsFunc);
+}
+#endif
+
+
+/*
+ * Examine the current context to determine which point drawing function
+ * should be used.
+ */
+void
+_swrast_set_point_function( GLcontext *ctx )
+{
+ GLboolean rgbmode = ctx->Visual.RGBAflag;
+
+ if (ctx->RenderMode==GL_RENDER) {
+ if (ctx->NoRaster) {
+ ctx->Driver.PointsFunc = null_points;
+ return;
+ }
+ if (ctx->Driver.PointsFunc) {
+ /* Device driver will draw points. */
+ ctx->IndirectTriangles &= ~DD_POINT_SW_RASTERIZE;
+ return;
+ }
+
+ if (!ctx->Point.Attenuated) {
+ if (ctx->Point.SmoothFlag && rgbmode) {
+ ctx->Driver.PointsFunc = antialiased_rgba_points;
+ }
+ else if (ctx->Texture.ReallyEnabled) {
+ if (ctx->Texture.MultiTextureEnabled ||
+ ctx->Light.Model.ColorControl==GL_SEPARATE_SPECULAR_COLOR ||
+ ctx->Fog.ColorSumEnabled) {
+ ctx->Driver.PointsFunc = multitextured_rgba_points;
+ }
+ else {
+ ctx->Driver.PointsFunc = textured_rgba_points;
+ }
+ }
+ else if (ctx->Point.Size==1.0) {
+ /* size=1, any raster ops */
+ if (rgbmode)
+ ctx->Driver.PointsFunc = size1_rgba_points;
+ else
+ ctx->Driver.PointsFunc = size1_ci_points;
+ }
+ else {
+ /* every other kind of point rendering */
+ if (rgbmode)
+ ctx->Driver.PointsFunc = general_rgba_points;
+ else
+ ctx->Driver.PointsFunc = general_ci_points;
+ }
+ }
+ else if(ctx->Point.SmoothFlag && rgbmode) {
+ ctx->Driver.PointsFunc = dist_atten_antialiased_rgba_points;
+ }
+ else if (ctx->Texture.ReallyEnabled) {
+ ctx->Driver.PointsFunc = dist_atten_textured_rgba_points;
+ }
+ else {
+ /* every other kind of point rendering */
+ if (rgbmode)
+ ctx->Driver.PointsFunc = dist_atten_general_rgba_points;
+ else
+ ctx->Driver.PointsFunc = dist_atten_general_ci_points;
+ }
+ }
+ else if (ctx->RenderMode==GL_FEEDBACK) {
+ ctx->Driver.PointsFunc = gl_feedback_points;
+ }
+ else {
+ /* GL_SELECT mode */
+ ctx->Driver.PointsFunc = gl_select_points;
+ }
+
+ /*_mesa_print_points_function(ctx);*/
+}
+
diff --git a/src/mesa/swrast/s_readpix.c b/src/mesa/swrast/s_readpix.c
new file mode 100644
index 0000000000..74a4d68266
--- /dev/null
+++ b/src/mesa/swrast/s_readpix.c
@@ -0,0 +1,765 @@
+/* $Id: s_readpix.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.
+ */
+
+
+#include "glheader.h"
+#include "colormac.h"
+#include "convolve.h"
+#include "context.h"
+#include "feedback.h"
+#include "image.h"
+#include "macros.h"
+#include "mem.h"
+#include "pixel.h"
+
+#include "s_alphabuf.h"
+#include "s_depth.h"
+#include "s_span.h"
+#include "s_stencil.h"
+
+
+
+/*
+ * Read a block of color index pixels.
+ */
+static void read_index_pixels( GLcontext *ctx,
+ GLint x, GLint y,
+ GLsizei width, GLsizei height,
+ GLenum type, GLvoid *pixels,
+ const struct gl_pixelstore_attrib *packing )
+{
+ GLint i, j, readWidth;
+
+ /* error checking */
+ if (ctx->Visual.RGBAflag) {
+ gl_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
+ return;
+ }
+
+ ASSERT(ctx->Driver.SetReadBuffer);
+ (*ctx->Driver.SetReadBuffer)(ctx, ctx->ReadBuffer, ctx->Pixel.DriverReadBuffer);
+
+ readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
+
+ /* process image row by row */
+ for (j=0;j<height;j++,y++) {
+ GLuint index[MAX_WIDTH];
+ GLvoid *dest;
+
+ (*ctx->Driver.ReadCI32Span)( ctx, readWidth, x, y, index );
+
+ if (ctx->Pixel.IndexShift!=0 || ctx->Pixel.IndexOffset!=0) {
+ _mesa_shift_and_offset_ci( ctx, readWidth, index);
+ }
+
+ if (ctx->Pixel.MapColorFlag) {
+ _mesa_map_ci(ctx, readWidth, index);
+ }
+
+ dest = _mesa_image_address(packing, pixels,
+ width, height, GL_COLOR_INDEX, type, 0, j, 0);
+
+ switch (type) {
+ case GL_UNSIGNED_BYTE:
+ {
+ GLubyte *dst = (GLubyte *) dest;
+ for (i=0;i<readWidth;i++) {
+ *dst++ = (GLubyte) index[i];
+ }
+ }
+ break;
+ case GL_BYTE:
+ {
+ GLbyte *dst = (GLbyte *) dest;
+ for (i=0;i<readWidth;i++) {
+ dst[i] = (GLbyte) index[i];
+ }
+ }
+ break;
+ case GL_UNSIGNED_SHORT:
+ {
+ GLushort *dst = (GLushort *) dest;
+ for (i=0;i<readWidth;i++) {
+ dst[i] = (GLushort) index[i];
+ }
+ if (packing->SwapBytes) {
+ _mesa_swap2( (GLushort *) dst, readWidth );
+ }
+ }
+ break;
+ case GL_SHORT:
+ {
+ GLshort *dst = (GLshort *) dest;
+ for (i=0;i<readWidth;i++) {
+ dst[i] = (GLshort) index[i];
+ }
+ if (packing->SwapBytes) {
+ _mesa_swap2( (GLushort *) dst, readWidth );
+ }
+ }
+ break;
+ case GL_UNSIGNED_INT:
+ {
+ GLuint *dst = (GLuint *) dest;
+ for (i=0;i<readWidth;i++) {
+ dst[i] = (GLuint) index[i];
+ }
+ if (packing->SwapBytes) {
+ _mesa_swap4( (GLuint *) dst, readWidth );
+ }
+ }
+ break;
+ case GL_INT:
+ {
+ GLint *dst = (GLint *) dest;
+ for (i=0;i<readWidth;i++) {
+ dst[i] = (GLint) index[i];
+ }
+ if (packing->SwapBytes) {
+ _mesa_swap4( (GLuint *) dst, readWidth );
+ }
+ }
+ break;
+ case GL_FLOAT:
+ {
+ GLfloat *dst = (GLfloat *) dest;
+ for (i=0;i<readWidth;i++) {
+ dst[i] = (GLfloat) index[i];
+ }
+ if (packing->SwapBytes) {
+ _mesa_swap4( (GLuint *) dst, readWidth );
+ }
+ }
+ break;
+ default:
+ gl_error( ctx, GL_INVALID_ENUM, "glReadPixels(type)" );
+ j = height + 1; /* exit loop */
+ }
+ }
+
+ (*ctx->Driver.SetReadBuffer)(ctx, ctx->DrawBuffer, ctx->Color.DriverDrawBuffer);
+}
+
+
+
+static void read_depth_pixels( GLcontext *ctx,
+ GLint x, GLint y,
+ GLsizei width, GLsizei height,
+ GLenum type, GLvoid *pixels,
+ const struct gl_pixelstore_attrib *packing )
+{
+ GLint i, j, readWidth;
+ GLboolean bias_or_scale;
+
+ /* Error checking */
+ if (ctx->Visual.DepthBits <= 0) {
+ /* No depth buffer */
+ gl_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
+ return;
+ }
+
+ readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
+
+ if (type != GL_BYTE &&
+ type != GL_UNSIGNED_BYTE &&
+ type != GL_SHORT &&
+ type != GL_UNSIGNED_SHORT &&
+ type != GL_INT &&
+ type != GL_UNSIGNED_INT &&
+ type != GL_FLOAT) {
+ gl_error( ctx, GL_INVALID_OPERATION, "glReadPixels(depth type)");
+ return;
+ }
+
+ bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0;
+
+ if (type==GL_UNSIGNED_SHORT && ctx->Visual.DepthBits == 16
+ && !bias_or_scale && !packing->SwapBytes) {
+ /* Special case: directly read 16-bit unsigned depth values. */
+ for (j=0;j<height;j++,y++) {
+ GLdepth depth[MAX_WIDTH];
+ GLushort *dst = (GLushort*) _mesa_image_address( packing, pixels,
+ width, height, GL_DEPTH_COMPONENT, type, 0, j, 0 );
+ GLint i;
+ _mesa_read_depth_span(ctx, width, x, y, depth);
+ for (i = 0; i < width; i++)
+ dst[i] = depth[i];
+ }
+ }
+ else if (type==GL_UNSIGNED_INT && ctx->Visual.DepthBits == 32
+ && !bias_or_scale && !packing->SwapBytes) {
+ /* Special case: directly read 32-bit unsigned depth values. */
+ for (j=0;j<height;j++,y++) {
+ GLdepth *dst = (GLdepth *) _mesa_image_address( packing, pixels,
+ width, height, GL_DEPTH_COMPONENT, type, 0, j, 0 );
+ _mesa_read_depth_span(ctx, width, x, y, dst);
+ }
+ }
+ else {
+ /* General case (slower) */
+ for (j=0;j<height;j++,y++) {
+ GLfloat depth[MAX_WIDTH];
+ GLvoid *dest;
+
+ _mesa_read_depth_span_float(ctx, readWidth, x, y, depth);
+
+ if (bias_or_scale) {
+ for (i=0;i<readWidth;i++) {
+ GLfloat d;
+ d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias;
+ depth[i] = CLAMP( d, 0.0F, 1.0F );
+ }
+ }
+
+ dest = _mesa_image_address(packing, pixels,
+ width, height, GL_DEPTH_COMPONENT, type, 0, j, 0);
+
+ switch (type) {
+ case GL_UNSIGNED_BYTE:
+ {
+ GLubyte *dst = (GLubyte *) dest;
+ for (i=0;i<readWidth;i++) {
+ dst[i] = FLOAT_TO_UBYTE( depth[i] );
+ }
+ }
+ break;
+ case GL_BYTE:
+ {
+ GLbyte *dst = (GLbyte *) dest;
+ for (i=0;i<readWidth;i++) {
+ dst[i] = FLOAT_TO_BYTE( depth[i] );
+ }
+ }
+ break;
+ case GL_UNSIGNED_SHORT:
+ {
+ GLushort *dst = (GLushort *) dest;
+ for (i=0;i<readWidth;i++) {
+ dst[i] = FLOAT_TO_USHORT( depth[i] );
+ }
+ if (packing->SwapBytes) {
+ _mesa_swap2( (GLushort *) dst, readWidth );
+ }
+ }
+ break;
+ case GL_SHORT:
+ {
+ GLshort *dst = (GLshort *) dest;
+ for (i=0;i<readWidth;i++) {
+ dst[i] = FLOAT_TO_SHORT( depth[i] );
+ }
+ if (packing->SwapBytes) {
+ _mesa_swap2( (GLushort *) dst, readWidth );
+ }
+ }
+ break;
+ case GL_UNSIGNED_INT:
+ {
+ GLuint *dst = (GLuint *) dest;
+ for (i=0;i<readWidth;i++) {
+ dst[i] = FLOAT_TO_UINT( depth[i] );
+ }
+ if (packing->SwapBytes) {
+ _mesa_swap4( (GLuint *) dst, readWidth );
+ }
+ }
+ break;
+ case GL_INT:
+ {
+ GLint *dst = (GLint *) dest;
+ for (i=0;i<readWidth;i++) {
+ dst[i] = FLOAT_TO_INT( depth[i] );
+ }
+ if (packing->SwapBytes) {
+ _mesa_swap4( (GLuint *) dst, readWidth );
+ }
+ }
+ break;
+ case GL_FLOAT:
+ {
+ GLfloat *dst = (GLfloat *) dest;
+ for (i=0;i<readWidth;i++) {
+ dst[i] = depth[i];
+ }
+ if (packing->SwapBytes) {
+ _mesa_swap4( (GLuint *) dst, readWidth );
+ }
+ }
+ break;
+ default:
+ gl_error( ctx, GL_INVALID_ENUM, "glReadPixels(type)" );
+ }
+ }
+ }
+}
+
+
+
+static void read_stencil_pixels( GLcontext *ctx,
+ GLint x, GLint y,
+ GLsizei width, GLsizei height,
+ GLenum type, GLvoid *pixels,
+ const struct gl_pixelstore_attrib *packing )
+{
+ GLboolean shift_or_offset;
+ GLint i, j, readWidth;
+
+ if (type != GL_BYTE &&
+ type != GL_UNSIGNED_BYTE &&
+ type != GL_SHORT &&
+ type != GL_UNSIGNED_SHORT &&
+ type != GL_INT &&
+ type != GL_UNSIGNED_INT &&
+ type != GL_FLOAT &&
+ type != GL_BITMAP) {
+ gl_error( ctx, GL_INVALID_OPERATION, "glReadPixels(stencil type)");
+ return;
+ }
+
+ readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
+
+ if (ctx->Visual.StencilBits<=0) {
+ /* No stencil buffer */
+ gl_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
+ return;
+ }
+
+ shift_or_offset = ctx->Pixel.IndexShift!=0 || ctx->Pixel.IndexOffset!=0;
+
+ /* process image row by row */
+ for (j=0;j<height;j++,y++) {
+ GLvoid *dest;
+ GLstencil stencil[MAX_WIDTH];
+
+ _mesa_read_stencil_span( ctx, readWidth, x, y, stencil );
+
+ if (shift_or_offset) {
+ _mesa_shift_and_offset_stencil( ctx, readWidth, stencil );
+ }
+
+ if (ctx->Pixel.MapStencilFlag) {
+ _mesa_map_stencil( ctx, readWidth, stencil );
+ }
+
+ dest = _mesa_image_address( packing, pixels,
+ width, height, GL_STENCIL_INDEX, type, 0, j, 0 );
+
+ switch (type) {
+ case GL_UNSIGNED_BYTE:
+ if (sizeof(GLstencil) == 8) {
+ MEMCPY( dest, stencil, readWidth );
+ }
+ else {
+ GLubyte *dst = (GLubyte *) dest;
+ for (i=0;i<readWidth;i++) {
+ dst[i] = (GLubyte) stencil[i];
+ }
+ }
+ break;
+ case GL_BYTE:
+ if (sizeof(GLstencil) == 8) {
+ MEMCPY( dest, stencil, readWidth );
+ }
+ else {
+ GLbyte *dst = (GLbyte *) dest;
+ for (i=0;i<readWidth;i++) {
+ dst[i] = (GLbyte) stencil[i];
+ }
+ }
+ break;
+ case GL_UNSIGNED_SHORT:
+ {
+ GLushort *dst = (GLushort *) dest;
+ for (i=0;i<readWidth;i++) {
+ dst[i] = (GLushort) stencil[i];
+ }
+ if (packing->SwapBytes) {
+ _mesa_swap2( (GLushort *) dst, readWidth );
+ }
+ }
+ break;
+ case GL_SHORT:
+ {
+ GLshort *dst = (GLshort *) dest;
+ for (i=0;i<readWidth;i++) {
+ dst[i] = (GLshort) stencil[i];
+ }
+ if (packing->SwapBytes) {
+ _mesa_swap2( (GLushort *) dst, readWidth );
+ }
+ }
+ break;
+ case GL_UNSIGNED_INT:
+ {
+ GLuint *dst = (GLuint *) dest;
+ for (i=0;i<readWidth;i++) {
+ dst[i] = (GLuint) stencil[i];
+ }
+ if (packing->SwapBytes) {
+ _mesa_swap4( (GLuint *) dst, readWidth );
+ }
+ }
+ break;
+ case GL_INT:
+ {
+ GLint *dst = (GLint *) dest;
+ for (i=0;i<readWidth;i++) {
+ *dst++ = (GLint) stencil[i];
+ }
+ if (packing->SwapBytes) {
+ _mesa_swap4( (GLuint *) dst, readWidth );
+ }
+ }
+ break;
+ case GL_FLOAT:
+ {
+ GLfloat *dst = (GLfloat *) dest;
+ for (i=0;i<readWidth;i++) {
+ dst[i] = (GLfloat) stencil[i];
+ }
+ if (packing->SwapBytes) {
+ _mesa_swap4( (GLuint *) dst, readWidth );
+ }
+ }
+ break;
+ case GL_BITMAP:
+ if (packing->LsbFirst) {
+ GLubyte *dst = (GLubyte*) dest;
+ GLint shift = 0;
+ for (i = 0; i < readWidth; i++) {
+ if (shift == 0)
+ *dst = 0;
+ *dst |= ((stencil != 0) << shift);
+ shift++;
+ if (shift == 8) {
+ shift = 0;
+ dst++;
+ }
+ }
+ }
+ else {
+ GLubyte *dst = (GLubyte*) dest;
+ GLint shift = 7;
+ for (i = 0; i < readWidth; i++) {
+ if (shift == 7)
+ *dst = 0;
+ *dst |= ((stencil != 0) << shift);
+ shift--;
+ if (shift < 0) {
+ shift = 7;
+ dst++;
+ }
+ }
+ }
+ break;
+ default:
+ gl_error( ctx, GL_INVALID_ENUM, "glReadPixels(type)" );
+ }
+ }
+}
+
+
+
+/*
+ * Optimized glReadPixels for particular pixel formats:
+ * GL_UNSIGNED_BYTE, GL_RGBA
+ * when pixel scaling, biasing and mapping are disabled.
+ */
+static GLboolean
+read_fast_rgba_pixels( GLcontext *ctx,
+ GLint x, GLint y,
+ GLsizei width, GLsizei height,
+ GLenum format, GLenum type,
+ GLvoid *pixels,
+ const struct gl_pixelstore_attrib *packing )
+{
+ /* can't do scale, bias, mapping, etc */
+ if (ctx->ImageTransferState)
+ return GL_FALSE;
+
+ /* can't do fancy pixel packing */
+ if (packing->Alignment != 1 || packing->SwapBytes || packing->LsbFirst)
+ return GL_FALSE;
+
+ {
+ GLint srcX = x;
+ GLint srcY = y;
+ GLint readWidth = width; /* actual width read */
+ GLint readHeight = height; /* actual height read */
+ GLint skipPixels = packing->SkipPixels;
+ GLint skipRows = packing->SkipRows;
+ GLint rowLength;
+
+ if (packing->RowLength > 0)
+ rowLength = packing->RowLength;
+ else
+ rowLength = width;
+
+ /* horizontal clipping */
+ if (srcX < ctx->ReadBuffer->Xmin) {
+ skipPixels += (ctx->ReadBuffer->Xmin - srcX);
+ readWidth -= (ctx->ReadBuffer->Xmin - srcX);
+ srcX = ctx->ReadBuffer->Xmin;
+ }
+ if (srcX + readWidth > ctx->ReadBuffer->Xmax)
+ readWidth -= (srcX + readWidth - ctx->ReadBuffer->Xmax);
+ if (readWidth <= 0)
+ return GL_TRUE;
+
+ /* vertical clipping */
+ if (srcY < ctx->ReadBuffer->Ymin) {
+ skipRows += (ctx->ReadBuffer->Ymin - srcY);
+ readHeight -= (ctx->ReadBuffer->Ymin - srcY);
+ srcY = ctx->ReadBuffer->Ymin;
+ }
+ if (srcY + readHeight > ctx->ReadBuffer->Ymax)
+ readHeight -= (srcY + readHeight - ctx->ReadBuffer->Ymax);
+ if (readHeight <= 0)
+ return GL_TRUE;
+
+ /*
+ * Ready to read!
+ * The window region at (destX, destY) of size (readWidth, readHeight)
+ * will be read back.
+ * We'll write pixel data to buffer pointed to by "pixels" but we'll
+ * skip "skipRows" rows and skip "skipPixels" pixels/row.
+ */
+#if CHAN_BITS == 8
+ if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
+#elif CHAN_BITS == 16
+ if (format == GL_RGBA && type == GL_UNSIGNED_SHORT) {
+#else
+ if (0) {
+#endif
+ GLchan *dest = (GLchan *) pixels
+ + (skipRows * rowLength + skipPixels) * 4;
+ GLint row;
+ for (row=0; row<readHeight; row++) {
+ (*ctx->Driver.ReadRGBASpan)(ctx, readWidth, srcX, srcY,
+ (GLchan (*)[4]) dest);
+ if (ctx->DrawBuffer->UseSoftwareAlphaBuffers) {
+ _mesa_read_alpha_span(ctx, readWidth, srcX, srcY,
+ (GLchan (*)[4]) dest);
+ }
+ dest += rowLength * 4;
+ srcY++;
+ }
+ return GL_TRUE;
+ }
+ else {
+ /* can't do this format/type combination */
+ return GL_FALSE;
+ }
+ }
+}
+
+
+
+/*
+ * Read R, G, B, A, RGB, L, or LA pixels.
+ */
+static void read_rgba_pixels( GLcontext *ctx,
+ GLint x, GLint y,
+ GLsizei width, GLsizei height,
+ GLenum format, GLenum type, GLvoid *pixels,
+ const struct gl_pixelstore_attrib *packing )
+{
+ GLint readWidth;
+
+ (*ctx->Driver.SetReadBuffer)(ctx, ctx->ReadBuffer, ctx->Pixel.DriverReadBuffer);
+
+ /* Try optimized path first */
+ if (read_fast_rgba_pixels( ctx, x, y, width, height,
+ format, type, pixels, packing )) {
+
+ (*ctx->Driver.SetReadBuffer)(ctx, ctx->DrawBuffer, ctx->Color.DriverDrawBuffer);
+ return; /* done! */
+ }
+
+ readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
+
+ /* do error checking on pixel type, format was already checked by caller */
+ switch (type) {
+ case GL_UNSIGNED_BYTE:
+ case GL_BYTE:
+ case GL_UNSIGNED_SHORT:
+ case GL_SHORT:
+ case GL_UNSIGNED_INT:
+ case GL_INT:
+ case GL_FLOAT:
+ case GL_UNSIGNED_BYTE_3_3_2:
+ case GL_UNSIGNED_BYTE_2_3_3_REV:
+ case GL_UNSIGNED_SHORT_5_6_5:
+ case GL_UNSIGNED_SHORT_5_6_5_REV:
+ case GL_UNSIGNED_SHORT_4_4_4_4:
+ case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+ case GL_UNSIGNED_SHORT_5_5_5_1:
+ case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+ case GL_UNSIGNED_INT_8_8_8_8:
+ case GL_UNSIGNED_INT_8_8_8_8_REV:
+ case GL_UNSIGNED_INT_10_10_10_2:
+ case GL_UNSIGNED_INT_2_10_10_10_REV:
+ /* valid pixel type */
+ break;
+ default:
+ gl_error( ctx, GL_INVALID_ENUM, "glReadPixels(type)" );
+ return;
+ }
+
+ if (!_mesa_is_legal_format_and_type(format, type) ||
+ format == GL_INTENSITY) {
+ gl_error(ctx, GL_INVALID_OPERATION, "glReadPixels(format or type)");
+ return;
+ }
+
+ if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
+ const GLuint transferOps = ctx->ImageTransferState;
+ GLfloat *dest, *src, *tmpImage, *convImage;
+ GLint row;
+
+ tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
+ if (!tmpImage) {
+ gl_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
+ return;
+ }
+ convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
+ if (!convImage) {
+ FREE(tmpImage);
+ gl_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
+ return;
+ }
+
+ /* read full RGBA, FLOAT image */
+ dest = tmpImage;
+ for (row = 0; row < height; row++, y++) {
+ GLchan rgba[MAX_WIDTH][4];
+ if (ctx->Visual.RGBAflag) {
+ gl_read_rgba_span(ctx, ctx->ReadBuffer, readWidth, x, y, rgba);
+ }
+ else {
+ GLuint index[MAX_WIDTH];
+ (*ctx->Driver.ReadCI32Span)(ctx, readWidth, x, y, index);
+ if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset !=0 ) {
+ _mesa_map_ci(ctx, readWidth, index);
+ }
+ _mesa_map_ci_to_rgba_chan(ctx, readWidth, index, rgba);
+ }
+ _mesa_pack_rgba_span(ctx, readWidth, (const GLchan (*)[4]) rgba,
+ GL_RGBA, GL_FLOAT, dest, &_mesa_native_packing,
+ transferOps & IMAGE_PRE_CONVOLUTION_BITS);
+ dest += width * 4;
+ }
+
+ /* do convolution */
+ if (ctx->Pixel.Convolution2DEnabled) {
+ _mesa_convolve_2d_image(ctx, &readWidth, &height, tmpImage, convImage);
+ }
+ else {
+ ASSERT(ctx->Pixel.Separable2DEnabled);
+ _mesa_convolve_sep_image(ctx, &readWidth, &height, tmpImage, convImage);
+ }
+ FREE(tmpImage);
+
+ /* finish transfer ops and pack the resulting image */
+ src = convImage;
+ for (row = 0; row < height; row++) {
+ GLvoid *dest;
+ dest = _mesa_image_address(packing, pixels, width, height,
+ format, type, 0, row, 0);
+ _mesa_pack_float_rgba_span(ctx, readWidth,
+ (const GLfloat (*)[4]) src,
+ format, type, dest, packing,
+ transferOps & IMAGE_POST_CONVOLUTION_BITS);
+ src += readWidth * 4;
+ }
+ }
+ else {
+ /* no convolution */
+ GLint row;
+ for (row = 0; row < height; row++, y++) {
+ GLchan rgba[MAX_WIDTH][4];
+ GLvoid *dst;
+ if (ctx->Visual.RGBAflag) {
+ gl_read_rgba_span(ctx, ctx->ReadBuffer, readWidth, x, y, rgba);
+ }
+ else {
+ GLuint index[MAX_WIDTH];
+ (*ctx->Driver.ReadCI32Span)(ctx, readWidth, x, y, index);
+ if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset != 0) {
+ _mesa_map_ci(ctx, readWidth, index);
+ }
+ _mesa_map_ci_to_rgba_chan(ctx, readWidth, index, rgba);
+ }
+ dst = _mesa_image_address(packing, pixels, width, height,
+ format, type, 0, row, 0);
+ _mesa_pack_rgba_span(ctx, readWidth, (const GLchan (*)[4]) rgba,
+ format, type, dst, packing,
+ ctx->ImageTransferState);
+ }
+ }
+
+ (*ctx->Driver.SetReadBuffer)(ctx, ctx->DrawBuffer, ctx->Color.DriverDrawBuffer);
+}
+
+
+
+void
+_swrast_ReadPixels( GLcontext *ctx,
+ GLint x, GLint y, GLsizei width, GLsizei height,
+ GLenum format, GLenum type,
+ const struct gl_pixelstore_attrib *pack,
+ GLvoid *pixels )
+{
+ (void) pack;
+
+ switch (format) {
+ case GL_COLOR_INDEX:
+ read_index_pixels(ctx, x, y, width, height, type, pixels, &ctx->Pack);
+ break;
+ case GL_STENCIL_INDEX:
+ read_stencil_pixels(ctx, x,y, width,height, type, pixels, &ctx->Pack);
+ break;
+ case GL_DEPTH_COMPONENT:
+ read_depth_pixels(ctx, x, y, width, height, type, pixels, &ctx->Pack);
+ break;
+ case GL_RED:
+ case GL_GREEN:
+ case GL_BLUE:
+ case GL_ALPHA:
+ case GL_RGB:
+ case GL_LUMINANCE:
+ case GL_LUMINANCE_ALPHA:
+ case GL_RGBA:
+ case GL_BGR:
+ case GL_BGRA:
+ case GL_ABGR_EXT:
+ read_rgba_pixels(ctx, x, y, width, height,
+ format, type, pixels, &ctx->Pack);
+ break;
+ default:
+ gl_error( ctx, GL_INVALID_ENUM, "glReadPixels(format)" );
+ }
+}
diff --git a/src/mesa/swrast/s_span.c b/src/mesa/swrast/s_span.c
new file mode 100644
index 0000000000..ca02802ceb
--- /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 );
+ }
+}
diff --git a/src/mesa/swrast/s_span.h b/src/mesa/swrast/s_span.h
new file mode 100644
index 0000000000..61411b9f98
--- /dev/null
+++ b/src/mesa/swrast/s_span.h
@@ -0,0 +1,99 @@
+/* $Id: s_span.h,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.
+ */
+
+
+
+
+
+#ifndef S_SPAN_H
+#define S_SPAN_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+extern void gl_write_index_span( GLcontext *ctx,
+ GLuint n, GLint x, GLint y, const GLdepth z[],
+ const GLfixed fog[],
+ GLuint index[], GLenum primitive );
+
+
+extern void gl_write_monoindex_span( GLcontext *ctx,
+ GLuint n, GLint x, GLint y,
+ const GLdepth z[],
+ const GLfixed fog[],
+ GLuint index, GLenum primitive );
+
+
+extern void gl_write_rgba_span( GLcontext *ctx,
+ GLuint n, GLint x, GLint y, const GLdepth z[],
+ const GLfixed fog[],
+ GLchan rgba[][4], GLenum primitive );
+
+
+extern 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 );
+
+
+extern 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 rgba[][4], CONST GLchan spec[][4],
+ GLenum primitive );
+
+
+extern 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_TEXTURE_UNITS][MAX_WIDTH],
+ GLchan rgba[][4],
+ CONST GLchan spec[][4],
+ GLenum primitive );
+
+
+extern void gl_read_rgba_span( GLcontext *ctx, GLframebuffer *buffer,
+ GLuint n, GLint x, GLint y,
+ GLchan rgba[][4] );
+
+
+extern void gl_read_index_span( GLcontext *ctx, GLframebuffer *buffer,
+ GLuint n, GLint x, GLint y, GLuint indx[] );
+
+
+#endif
diff --git a/src/mesa/swrast/s_stencil.c b/src/mesa/swrast/s_stencil.c
new file mode 100644
index 0000000000..c957a683a1
--- /dev/null
+++ b/src/mesa/swrast/s_stencil.c
@@ -0,0 +1,1303 @@
+/* $Id: s_stencil.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.
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "macros.h"
+#include "mem.h"
+
+#include "s_depth.h"
+#include "s_pb.h"
+#include "s_stencil.h"
+
+
+
+
+
+/* Stencil Logic:
+
+IF stencil test fails THEN
+ Apply fail-op to stencil value
+ Don't write the pixel (RGBA,Z)
+ELSE
+ IF doing depth test && depth test fails THEN
+ Apply zfail-op to stencil value
+ Write RGBA and Z to appropriate buffers
+ ELSE
+ Apply zpass-op to stencil value
+ENDIF
+
+*/
+
+
+
+
+/*
+ * Return the address of a stencil buffer value given the window coords:
+ */
+#define STENCIL_ADDRESS(X,Y) \
+ (ctx->DrawBuffer->Stencil + ctx->DrawBuffer->Width * (Y) + (X))
+
+
+
+/*
+ * Apply the given stencil operator to the array of stencil values.
+ * Don't touch stencil[i] if mask[i] is zero.
+ * Input: n - size of stencil array
+ * oper - the stencil buffer operator
+ * stencil - array of stencil values
+ * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
+ * Output: stencil - modified values
+ */
+static void apply_stencil_op( const GLcontext *ctx, GLenum oper,
+ GLuint n, GLstencil stencil[],
+ const GLubyte mask[] )
+{
+ const GLstencil ref = ctx->Stencil.Ref;
+ const GLstencil wrtmask = ctx->Stencil.WriteMask;
+ const GLstencil invmask = (GLstencil) (~ctx->Stencil.WriteMask);
+ GLuint i;
+
+ switch (oper) {
+ case GL_KEEP:
+ /* do nothing */
+ break;
+ case GL_ZERO:
+ if (invmask==0) {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ stencil[i] = 0;
+ }
+ }
+ }
+ else {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ stencil[i] = (GLstencil) (stencil[i] & invmask);
+ }
+ }
+ }
+ break;
+ case GL_REPLACE:
+ if (invmask==0) {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ stencil[i] = ref;
+ }
+ }
+ }
+ else {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLstencil s = stencil[i];
+ stencil[i] = (GLstencil) ((invmask & s ) | (wrtmask & ref));
+ }
+ }
+ }
+ break;
+ case GL_INCR:
+ if (invmask==0) {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLstencil s = stencil[i];
+ if (s < STENCIL_MAX) {
+ stencil[i] = (GLstencil) (s+1);
+ }
+ }
+ }
+ }
+ else {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ /* VERIFY logic of adding 1 to a write-masked value */
+ GLstencil s = stencil[i];
+ if (s < STENCIL_MAX) {
+ stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s+1)));
+ }
+ }
+ }
+ }
+ break;
+ case GL_DECR:
+ if (invmask==0) {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLstencil s = stencil[i];
+ if (s>0) {
+ stencil[i] = (GLstencil) (s-1);
+ }
+ }
+ }
+ }
+ else {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ /* VERIFY logic of subtracting 1 to a write-masked value */
+ GLstencil s = stencil[i];
+ if (s>0) {
+ stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s-1)));
+ }
+ }
+ }
+ }
+ break;
+ case GL_INCR_WRAP_EXT:
+ if (invmask==0) {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ stencil[i]++;
+ }
+ }
+ }
+ else {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLstencil s = stencil[i];
+ stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s+1)));
+ }
+ }
+ }
+ break;
+ case GL_DECR_WRAP_EXT:
+ if (invmask==0) {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ stencil[i]--;
+ }
+ }
+ }
+ else {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLstencil s = stencil[i];
+ stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s-1)));
+ }
+ }
+ }
+ break;
+ case GL_INVERT:
+ if (invmask==0) {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLstencil s = stencil[i];
+ stencil[i] = (GLstencil) ~s;
+ }
+ }
+ }
+ else {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLstencil s = stencil[i];
+ stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & ~s));
+ }
+ }
+ }
+ break;
+ default:
+ gl_problem(ctx, "Bad stencil op in apply_stencil_op");
+ }
+}
+
+
+
+
+/*
+ * Apply stencil test to an array of stencil values (before depth buffering).
+ * Input: n - number of pixels in the array
+ * stencil - array of [n] stencil values
+ * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
+ * Output: mask - pixels which fail the stencil test will have their
+ * mask flag set to 0.
+ * stencil - updated stencil values (where the test passed)
+ * Return: GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
+ */
+static GLboolean
+do_stencil_test( GLcontext *ctx, GLuint n, GLstencil stencil[],
+ GLubyte mask[] )
+{
+ GLubyte fail[PB_SIZE];
+ GLboolean allfail = GL_FALSE;
+ GLuint i;
+ GLstencil r, s;
+
+ ASSERT(n <= PB_SIZE);
+
+ /*
+ * Perform stencil test. The results of this operation are stored
+ * in the fail[] array:
+ * IF fail[i] is non-zero THEN
+ * the stencil fail operator is to be applied
+ * ELSE
+ * the stencil fail operator is not to be applied
+ * ENDIF
+ */
+ switch (ctx->Stencil.Function) {
+ case GL_NEVER:
+ /* always fail */
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ mask[i] = 0;
+ fail[i] = 1;
+ }
+ else {
+ fail[i] = 0;
+ }
+ }
+ allfail = GL_TRUE;
+ break;
+ case GL_LESS:
+ r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
+ if (r < s) {
+ /* passed */
+ fail[i] = 0;
+ }
+ else {
+ fail[i] = 1;
+ mask[i] = 0;
+ }
+ }
+ else {
+ fail[i] = 0;
+ }
+ }
+ break;
+ case GL_LEQUAL:
+ r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
+ if (r <= s) {
+ /* pass */
+ fail[i] = 0;
+ }
+ else {
+ fail[i] = 1;
+ mask[i] = 0;
+ }
+ }
+ else {
+ fail[i] = 0;
+ }
+ }
+ break;
+ case GL_GREATER:
+ r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
+ if (r > s) {
+ /* passed */
+ fail[i] = 0;
+ }
+ else {
+ fail[i] = 1;
+ mask[i] = 0;
+ }
+ }
+ else {
+ fail[i] = 0;
+ }
+ }
+ break;
+ case GL_GEQUAL:
+ r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
+ if (r >= s) {
+ /* passed */
+ fail[i] = 0;
+ }
+ else {
+ fail[i] = 1;
+ mask[i] = 0;
+ }
+ }
+ else {
+ fail[i] = 0;
+ }
+ }
+ break;
+ case GL_EQUAL:
+ r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
+ if (r == s) {
+ /* passed */
+ fail[i] = 0;
+ }
+ else {
+ fail[i] = 1;
+ mask[i] = 0;
+ }
+ }
+ else {
+ fail[i] = 0;
+ }
+ }
+ break;
+ case GL_NOTEQUAL:
+ r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
+ if (r != s) {
+ /* passed */
+ fail[i] = 0;
+ }
+ else {
+ fail[i] = 1;
+ mask[i] = 0;
+ }
+ }
+ else {
+ fail[i] = 0;
+ }
+ }
+ break;
+ case GL_ALWAYS:
+ /* always pass */
+ for (i=0;i<n;i++) {
+ fail[i] = 0;
+ }
+ break;
+ default:
+ gl_problem(ctx, "Bad stencil func in gl_stencil_span");
+ return 0;
+ }
+
+ if (ctx->Stencil.FailFunc != GL_KEEP) {
+ apply_stencil_op( ctx, ctx->Stencil.FailFunc, n, stencil, fail );
+ }
+
+ return !allfail;
+}
+
+
+
+
+/*
+ * Apply stencil and depth testing to an array of pixels.
+ * Hardware or software stencil buffer acceptable.
+ * Input: n - number of pixels in the span
+ * z - array [n] of z values
+ * stencil - array [n] of stencil values
+ * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
+ * Output: stencil - modified stencil values
+ * mask - array [n] of flags (1=stencil and depth test passed)
+ * Return: GL_TRUE - all fragments failed the testing
+ * GL_FALSE - one or more fragments passed the testing
+ *
+ */
+static GLboolean
+stencil_and_ztest_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
+ const GLdepth z[], GLstencil stencil[],
+ GLubyte mask[] )
+{
+ ASSERT(ctx->Stencil.Enabled);
+ ASSERT(n <= PB_SIZE);
+
+ /*
+ * Apply the stencil test to the fragments.
+ * failMask[i] is 1 if the stencil test failed.
+ */
+ if (do_stencil_test( ctx, n, stencil, mask ) == GL_FALSE) {
+ /* all fragments failed the stencil test, we're done. */
+ return GL_FALSE;
+ }
+
+
+ /*
+ * Some fragments passed the stencil test, apply depth test to them
+ * and apply Zpass and Zfail stencil ops.
+ */
+ if (ctx->Depth.Test==GL_FALSE) {
+ /*
+ * No depth buffer, just apply zpass stencil function to active pixels.
+ */
+ apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, mask );
+ }
+ else {
+ /*
+ * Perform depth buffering, then apply zpass or zfail stencil function.
+ */
+ GLubyte passmask[MAX_WIDTH], failmask[MAX_WIDTH], oldmask[MAX_WIDTH];
+ GLuint i;
+
+ /* save the current mask bits */
+ MEMCPY(oldmask, mask, n * sizeof(GLubyte));
+
+ /* apply the depth test */
+ _mesa_depth_test_span(ctx, n, x, y, z, mask);
+
+ /* Set the stencil pass/fail flags according to result of depth testing.
+ * if oldmask[i] == 0 then
+ * Don't touch the stencil value
+ * else if oldmask[i] and newmask[i] then
+ * Depth test passed
+ * else
+ * assert(oldmask[i] && !newmask[i])
+ * Depth test failed
+ * endif
+ */
+ for (i=0;i<n;i++) {
+ ASSERT(mask[i] == 0 || mask[i] == 1);
+ passmask[i] = oldmask[i] & mask[i];
+ failmask[i] = oldmask[i] & (mask[i] ^ 1);
+ }
+
+ /* apply the pass and fail operations */
+ if (ctx->Stencil.ZFailFunc != GL_KEEP) {
+ apply_stencil_op( ctx, ctx->Stencil.ZFailFunc, n, stencil, failmask );
+ }
+ if (ctx->Stencil.ZPassFunc != GL_KEEP) {
+ apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, passmask );
+ }
+ }
+
+ return GL_TRUE; /* one or more fragments passed both tests */
+}
+
+
+
+/*
+ * Apply stencil and depth testing to the span of pixels.
+ * Both software and hardware stencil buffers are acceptable.
+ * Input: n - number of pixels in the span
+ * x, y - location of leftmost pixel in span
+ * z - array [n] of z values
+ * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
+ * Output: mask - array [n] of flags (1=stencil and depth test passed)
+ * Return: GL_TRUE - all fragments failed the testing
+ * GL_FALSE - one or more fragments passed the testing
+ *
+ */
+GLboolean
+_mesa_stencil_and_ztest_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
+ const GLdepth z[], GLubyte mask[] )
+{
+ GLstencil stencilRow[MAX_WIDTH];
+ GLstencil *stencil;
+ GLboolean result;
+
+ ASSERT(ctx->Stencil.Enabled);
+ ASSERT(n <= MAX_WIDTH);
+
+ /* Get initial stencil values */
+ if (ctx->Driver.WriteStencilSpan) {
+ ASSERT(ctx->Driver.ReadStencilSpan);
+ /* Get stencil values from the hardware stencil buffer */
+ (*ctx->Driver.ReadStencilSpan)(ctx, n, x, y, stencilRow);
+ stencil = stencilRow;
+ }
+ else {
+ /* software stencil buffer */
+ stencil = STENCIL_ADDRESS(x, y);
+ }
+
+ /* do all the stencil/depth testing/updating */
+ result = stencil_and_ztest_span( ctx, n, x, y, z, stencil, mask );
+
+ if (ctx->Driver.WriteStencilSpan) {
+ /* Write updated stencil values into hardware stencil buffer */
+ (ctx->Driver.WriteStencilSpan)(ctx, n, x, y, stencil, mask );
+ }
+
+ return result;
+}
+
+
+
+
+/*
+ * Apply the given stencil operator for each pixel in the array whose
+ * mask flag is set. This is for software stencil buffers only.
+ * Input: n - number of pixels in the span
+ * x, y - array of [n] pixels
+ * operator - the stencil buffer operator
+ * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
+ */
+static void
+apply_stencil_op_to_pixels( const GLcontext *ctx,
+ GLuint n, const GLint x[], const GLint y[],
+ GLenum oper, const GLubyte mask[] )
+{
+ const GLstencil ref = ctx->Stencil.Ref;
+ const GLstencil wrtmask = ctx->Stencil.WriteMask;
+ const GLstencil invmask = (GLstencil) (~ctx->Stencil.WriteMask);
+ GLuint i;
+
+ ASSERT(!ctx->Driver.WriteStencilSpan); /* software stencil buffer only! */
+
+ switch (oper) {
+ case GL_KEEP:
+ /* do nothing */
+ break;
+ case GL_ZERO:
+ if (invmask==0) {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+ *sptr = 0;
+ }
+ }
+ }
+ else {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+ *sptr = (GLstencil) (invmask & *sptr);
+ }
+ }
+ }
+ break;
+ case GL_REPLACE:
+ if (invmask==0) {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+ *sptr = ref;
+ }
+ }
+ }
+ else {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+ *sptr = (GLstencil) ((invmask & *sptr ) | (wrtmask & ref));
+ }
+ }
+ }
+ break;
+ case GL_INCR:
+ if (invmask==0) {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+ if (*sptr < STENCIL_MAX) {
+ *sptr = (GLstencil) (*sptr + 1);
+ }
+ }
+ }
+ }
+ else {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+ if (*sptr < STENCIL_MAX) {
+ *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr+1)));
+ }
+ }
+ }
+ }
+ break;
+ case GL_DECR:
+ if (invmask==0) {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+ if (*sptr>0) {
+ *sptr = (GLstencil) (*sptr - 1);
+ }
+ }
+ }
+ }
+ else {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+ if (*sptr>0) {
+ *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr-1)));
+ }
+ }
+ }
+ }
+ break;
+ case GL_INCR_WRAP_EXT:
+ if (invmask==0) {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+ *sptr = (GLstencil) (*sptr + 1);
+ }
+ }
+ }
+ else {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+ *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr+1)));
+ }
+ }
+ }
+ break;
+ case GL_DECR_WRAP_EXT:
+ if (invmask==0) {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+ *sptr = (GLstencil) (*sptr - 1);
+ }
+ }
+ }
+ else {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+ *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr-1)));
+ }
+ }
+ }
+ break;
+ case GL_INVERT:
+ if (invmask==0) {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+ *sptr = (GLstencil) (~*sptr);
+ }
+ }
+ }
+ else {
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
+ *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & ~*sptr));
+ }
+ }
+ }
+ break;
+ default:
+ gl_problem(ctx, "Bad stencilop in apply_stencil_op_to_pixels");
+ }
+}
+
+
+
+/*
+ * Apply stencil test to an array of pixels before depth buffering.
+ * Used for software stencil buffer only.
+ * Input: n - number of pixels in the span
+ * x, y - array of [n] pixels to stencil
+ * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
+ * Output: mask - pixels which fail the stencil test will have their
+ * mask flag set to 0.
+ * Return: 0 = all pixels failed, 1 = zero or more pixels passed.
+ */
+static GLboolean
+stencil_test_pixels( GLcontext *ctx, GLuint n,
+ const GLint x[], const GLint y[], GLubyte mask[] )
+{
+ GLubyte fail[PB_SIZE];
+ GLstencil r, s;
+ GLuint i;
+ GLboolean allfail = GL_FALSE;
+
+ ASSERT(!ctx->Driver.WriteStencilSpan); /* software stencil buffer only! */
+
+ /*
+ * Perform stencil test. The results of this operation are stored
+ * in the fail[] array:
+ * IF fail[i] is non-zero THEN
+ * the stencil fail operator is to be applied
+ * ELSE
+ * the stencil fail operator is not to be applied
+ * ENDIF
+ */
+
+ switch (ctx->Stencil.Function) {
+ case GL_NEVER:
+ /* always fail */
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ mask[i] = 0;
+ fail[i] = 1;
+ }
+ else {
+ fail[i] = 0;
+ }
+ }
+ allfail = GL_TRUE;
+ break;
+ case GL_LESS:
+ r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
+ s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
+ if (r < s) {
+ /* passed */
+ fail[i] = 0;
+ }
+ else {
+ fail[i] = 1;
+ mask[i] = 0;
+ }
+ }
+ else {
+ fail[i] = 0;
+ }
+ }
+ break;
+ case GL_LEQUAL:
+ r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
+ s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
+ if (r <= s) {
+ /* pass */
+ fail[i] = 0;
+ }
+ else {
+ fail[i] = 1;
+ mask[i] = 0;
+ }
+ }
+ else {
+ fail[i] = 0;
+ }
+ }
+ break;
+ case GL_GREATER:
+ r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
+ s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
+ if (r > s) {
+ /* passed */
+ fail[i] = 0;
+ }
+ else {
+ fail[i] = 1;
+ mask[i] = 0;
+ }
+ }
+ else {
+ fail[i] = 0;
+ }
+ }
+ break;
+ case GL_GEQUAL:
+ r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
+ s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
+ if (r >= s) {
+ /* passed */
+ fail[i] = 0;
+ }
+ else {
+ fail[i] = 1;
+ mask[i] = 0;
+ }
+ }
+ else {
+ fail[i] = 0;
+ }
+ }
+ break;
+ case GL_EQUAL:
+ r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
+ s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
+ if (r == s) {
+ /* passed */
+ fail[i] = 0;
+ }
+ else {
+ fail[i] = 1;
+ mask[i] = 0;
+ }
+ }
+ else {
+ fail[i] = 0;
+ }
+ }
+ break;
+ case GL_NOTEQUAL:
+ r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
+ for (i=0;i<n;i++) {
+ if (mask[i]) {
+ GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
+ s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
+ if (r != s) {
+ /* passed */
+ fail[i] = 0;
+ }
+ else {
+ fail[i] = 1;
+ mask[i] = 0;
+ }
+ }
+ else {
+ fail[i] = 0;
+ }
+ }
+ break;
+ case GL_ALWAYS:
+ /* always pass */
+ for (i=0;i<n;i++) {
+ fail[i] = 0;
+ }
+ break;
+ default:
+ gl_problem(ctx, "Bad stencil func in gl_stencil_pixels");
+ return 0;
+ }
+
+ if (ctx->Stencil.FailFunc != GL_KEEP) {
+ apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.FailFunc, fail );
+ }
+
+ return !allfail;
+}
+
+
+
+
+/*
+ * Apply stencil and depth testing to an array of pixels.
+ * This is used both for software and hardware stencil buffers.
+ *
+ * The comments in this function are a bit sparse but the code is
+ * almost identical to stencil_and_ztest_span(), which is well
+ * commented.
+ *
+ * Input: n - number of pixels in the array
+ * x, y - array of [n] pixel positions
+ * z - array [n] of z values
+ * mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
+ * Output: mask - array [n] of flags (1=stencil and depth test passed)
+ * Return: GL_TRUE - all fragments failed the testing
+ * GL_FALSE - one or more fragments passed the testing
+ */
+GLboolean
+_mesa_stencil_and_ztest_pixels( GLcontext *ctx,
+ GLuint n, const GLint x[], const GLint y[],
+ const GLdepth z[], GLubyte mask[] )
+{
+ ASSERT(ctx->Stencil.Enabled);
+ ASSERT(n <= PB_SIZE);
+
+ if (ctx->Driver.WriteStencilPixels) {
+ /*** Hardware stencil buffer ***/
+ GLstencil stencil[PB_SIZE];
+ GLubyte mask[PB_SIZE];
+
+ ASSERT(ctx->Driver.ReadStencilPixels);
+ (*ctx->Driver.ReadStencilPixels)(ctx, n, x, y, stencil);
+
+
+ if (do_stencil_test( ctx, n, stencil, mask ) == GL_FALSE) {
+ /* all fragments failed the stencil test, we're done. */
+ return GL_FALSE;
+ }
+
+ if (ctx->Depth.Test == GL_FALSE) {
+ apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, mask );
+ }
+ else {
+ GLubyte passmask[PB_SIZE], failmask[PB_SIZE], oldmask[PB_SIZE];
+ GLuint i;
+
+ MEMCPY(oldmask, mask, n * sizeof(GLubyte));
+
+ _mesa_depth_test_pixels(ctx, n, x, y, z, mask);
+
+ for (i=0;i<n;i++) {
+ ASSERT(mask[i] == 0 || mask[i] == 1);
+ passmask[i] = oldmask[i] & mask[i];
+ failmask[i] = oldmask[i] & (mask[i] ^ 1);
+ }
+
+ if (ctx->Stencil.ZFailFunc != GL_KEEP) {
+ apply_stencil_op( ctx, ctx->Stencil.ZFailFunc, n, stencil, failmask );
+ }
+ if (ctx->Stencil.ZPassFunc != GL_KEEP) {
+ apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, passmask );
+ }
+ }
+
+ /* Write updated stencil values into hardware stencil buffer */
+ (ctx->Driver.WriteStencilPixels)(ctx, n, x, y, stencil, mask );
+
+ return GL_TRUE;
+
+ }
+ else {
+ /*** Software stencil buffer ***/
+
+ if (stencil_test_pixels(ctx, n, x, y, mask) == GL_FALSE) {
+ /* all fragments failed the stencil test, we're done. */
+ return GL_FALSE;
+ }
+
+
+ if (ctx->Depth.Test==GL_FALSE) {
+ apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.ZPassFunc, mask );
+ }
+ else {
+ GLubyte passmask[PB_SIZE], failmask[PB_SIZE], oldmask[PB_SIZE];
+ GLuint i;
+
+ MEMCPY(oldmask, mask, n * sizeof(GLubyte));
+
+ _mesa_depth_test_pixels(ctx, n, x, y, z, mask);
+
+ for (i=0;i<n;i++) {
+ ASSERT(mask[i] == 0 || mask[i] == 1);
+ passmask[i] = oldmask[i] & mask[i];
+ failmask[i] = oldmask[i] & (mask[i] ^ 1);
+ }
+
+ if (ctx->Stencil.ZFailFunc != GL_KEEP) {
+ apply_stencil_op_to_pixels( ctx, n, x, y,
+ ctx->Stencil.ZFailFunc, failmask );
+ }
+ if (ctx->Stencil.ZPassFunc != GL_KEEP) {
+ apply_stencil_op_to_pixels( ctx, n, x, y,
+ ctx->Stencil.ZPassFunc, passmask );
+ }
+ }
+
+ return GL_TRUE; /* one or more fragments passed both tests */
+ }
+}
+
+
+
+/*
+ * Return a span of stencil values from the stencil buffer.
+ * Used for glRead/CopyPixels
+ * Input: n - how many pixels
+ * x,y - location of first pixel
+ * Output: stencil - the array of stencil values
+ */
+void
+_mesa_read_stencil_span( GLcontext *ctx,
+ GLint n, GLint x, GLint y, GLstencil stencil[] )
+{
+ if (y < 0 || y >= ctx->DrawBuffer->Height ||
+ x + n <= 0 || x >= ctx->DrawBuffer->Width) {
+ /* span is completely outside framebuffer */
+ return; /* undefined values OK */
+ }
+
+ if (x < 0) {
+ GLint dx = -x;
+ x = 0;
+ n -= dx;
+ stencil += dx;
+ }
+ if (x + n > ctx->DrawBuffer->Width) {
+ GLint dx = x + n - ctx->DrawBuffer->Width;
+ n -= dx;
+ }
+ if (n <= 0) {
+ return;
+ }
+
+
+ ASSERT(n >= 0);
+ if (ctx->Driver.ReadStencilSpan) {
+ (*ctx->Driver.ReadStencilSpan)( ctx, (GLuint) n, x, y, stencil );
+ }
+ else if (ctx->DrawBuffer->Stencil) {
+ const GLstencil *s = STENCIL_ADDRESS( x, y );
+#if STENCIL_BITS == 8
+ MEMCPY( stencil, s, n * sizeof(GLstencil) );
+#else
+ GLuint i;
+ for (i=0;i<n;i++)
+ stencil[i] = s[i];
+#endif
+ }
+}
+
+
+
+/*
+ * Write a span of stencil values to the stencil buffer.
+ * Used for glDraw/CopyPixels
+ * Input: n - how many pixels
+ * x, y - location of first pixel
+ * stencil - the array of stencil values
+ */
+void
+_mesa_write_stencil_span( GLcontext *ctx, GLint n, GLint x, GLint y,
+ const GLstencil stencil[] )
+{
+ if (y < 0 || y >= ctx->DrawBuffer->Height ||
+ x + n <= 0 || x >= ctx->DrawBuffer->Width) {
+ /* span is completely outside framebuffer */
+ return; /* undefined values OK */
+ }
+
+ if (x < 0) {
+ GLint dx = -x;
+ x = 0;
+ n -= dx;
+ stencil += dx;
+ }
+ if (x + n > ctx->DrawBuffer->Width) {
+ GLint dx = x + n - ctx->DrawBuffer->Width;
+ n -= dx;
+ }
+ if (n <= 0) {
+ return;
+ }
+
+ if (ctx->Driver.WriteStencilSpan) {
+ (*ctx->Driver.WriteStencilSpan)( ctx, n, x, y, stencil, NULL );
+ }
+ else if (ctx->DrawBuffer->Stencil) {
+ GLstencil *s = STENCIL_ADDRESS( x, y );
+#if STENCIL_BITS == 8
+ MEMCPY( s, stencil, n * sizeof(GLstencil) );
+#else
+ GLuint i;
+ for (i=0;i<n;i++)
+ s[i] = stencil[i];
+#endif
+ }
+}
+
+
+
+/*
+ * Allocate a new stencil buffer. If there's an old one it will be
+ * deallocated first. The new stencil buffer will be uninitialized.
+ */
+void
+_mesa_alloc_stencil_buffer( GLcontext *ctx )
+{
+ GLuint buffersize = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
+
+ /* deallocate current stencil buffer if present */
+ if (ctx->DrawBuffer->Stencil) {
+ FREE(ctx->DrawBuffer->Stencil);
+ ctx->DrawBuffer->Stencil = NULL;
+ }
+
+ /* allocate new stencil buffer */
+ ctx->DrawBuffer->Stencil = (GLstencil *) MALLOC(buffersize * sizeof(GLstencil));
+ if (!ctx->DrawBuffer->Stencil) {
+ /* out of memory */
+/* _mesa_set_enable( ctx, GL_STENCIL_TEST, GL_FALSE ); */
+ gl_error( ctx, GL_OUT_OF_MEMORY, "_mesa_alloc_stencil_buffer" );
+ }
+}
+
+
+
+/*
+ * Clear the software (malloc'd) stencil buffer.
+ */
+static void
+clear_software_stencil_buffer( GLcontext *ctx )
+{
+ if (ctx->Visual.StencilBits==0 || !ctx->DrawBuffer->Stencil) {
+ /* no stencil buffer */
+ return;
+ }
+
+ if (ctx->Scissor.Enabled) {
+ /* clear scissor region only */
+ const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin;
+ if (ctx->Stencil.WriteMask != STENCIL_MAX) {
+ /* must apply mask to the clear */
+ GLint y;
+ for (y = ctx->DrawBuffer->Ymin; y < ctx->DrawBuffer->Ymax; y++) {
+ const GLstencil mask = ctx->Stencil.WriteMask;
+ const GLstencil invMask = ~mask;
+ const GLstencil clearVal = (ctx->Stencil.Clear & mask);
+ GLstencil *stencil = STENCIL_ADDRESS( ctx->DrawBuffer->Xmin, y );
+ GLint i;
+ for (i = 0; i < width; i++) {
+ stencil[i] = (stencil[i] & invMask) | clearVal;
+ }
+ }
+ }
+ else {
+ /* no masking */
+ GLint y;
+ for (y = ctx->DrawBuffer->Ymin; y < ctx->DrawBuffer->Ymax; y++) {
+ GLstencil *stencil = STENCIL_ADDRESS( ctx->DrawBuffer->Xmin, y );
+#if STENCIL_BITS==8
+ MEMSET( stencil, ctx->Stencil.Clear, width * sizeof(GLstencil) );
+#else
+ GLint i;
+ for (i = 0; i < width; i++)
+ stencil[x] = ctx->Stencil.Clear;
+#endif
+ }
+ }
+ }
+ else {
+ /* clear whole stencil buffer */
+ if (ctx->Stencil.WriteMask != STENCIL_MAX) {
+ /* must apply mask to the clear */
+ const GLuint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
+ GLstencil *stencil = ctx->DrawBuffer->Stencil;
+ const GLstencil mask = ctx->Stencil.WriteMask;
+ const GLstencil invMask = ~mask;
+ const GLstencil clearVal = (ctx->Stencil.Clear & mask);
+ GLuint i;
+ for (i = 0; i < n; i++) {
+ stencil[i] = (stencil[i] & invMask) | clearVal;
+ }
+ }
+ else {
+ /* clear whole buffer without masking */
+ const GLuint n = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
+ GLstencil *stencil = ctx->DrawBuffer->Stencil;
+
+#if STENCIL_BITS==8
+ MEMSET(stencil, ctx->Stencil.Clear, n * sizeof(GLstencil) );
+#else
+ GLuint i;
+ for (i = 0; i < n; i++) {
+ stencil[i] = ctx->Stencil.Clear;
+ }
+#endif
+ }
+ }
+}
+
+
+
+/*
+ * Clear the hardware (in graphics card) stencil buffer.
+ * This is done with the Driver.WriteStencilSpan() and Driver.ReadStencilSpan()
+ * functions.
+ * Actually, if there is a hardware stencil buffer it really should have
+ * been cleared in Driver.Clear()! However, if the hardware does not
+ * support scissored clears or masked clears (i.e. glStencilMask) then
+ * we have to use the span-based functions.
+ */
+static void
+clear_hardware_stencil_buffer( GLcontext *ctx )
+{
+ ASSERT(ctx->Driver.WriteStencilSpan);
+ ASSERT(ctx->Driver.ReadStencilSpan);
+
+ if (ctx->Scissor.Enabled) {
+ /* clear scissor region only */
+ const GLint x = ctx->DrawBuffer->Xmin;
+ const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin;
+ if (ctx->Stencil.WriteMask != STENCIL_MAX) {
+ /* must apply mask to the clear */
+ GLint y;
+ for (y = ctx->DrawBuffer->Ymin; y < ctx->DrawBuffer->Ymax; y++) {
+ const GLstencil mask = ctx->Stencil.WriteMask;
+ const GLstencil invMask = ~mask;
+ const GLstencil clearVal = (ctx->Stencil.Clear & mask);
+ GLstencil stencil[MAX_WIDTH];
+ GLint i;
+ (*ctx->Driver.ReadStencilSpan)(ctx, x, y, width, stencil);
+ for (i = 0; i < width; i++) {
+ stencil[i] = (stencil[i] & invMask) | clearVal;
+ }
+ (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL);
+ }
+ }
+ else {
+ /* no masking */
+ GLstencil stencil[MAX_WIDTH];
+ GLint y, i;
+ for (i = 0; i < width; i++) {
+ stencil[i] = ctx->Stencil.Clear;
+ }
+ for (y = ctx->DrawBuffer->Ymin; y < ctx->DrawBuffer->Ymax; y++) {
+ (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL);
+ }
+ }
+ }
+ else {
+ /* clear whole stencil buffer */
+ if (ctx->Stencil.WriteMask != STENCIL_MAX) {
+ /* must apply mask to the clear */
+ const GLstencil mask = ctx->Stencil.WriteMask;
+ const GLstencil invMask = ~mask;
+ const GLstencil clearVal = (ctx->Stencil.Clear & mask);
+ const GLint width = ctx->DrawBuffer->Width;
+ const GLint height = ctx->DrawBuffer->Height;
+ const GLint x = ctx->DrawBuffer->Xmin;
+ GLint y;
+ for (y = 0; y < height; y++) {
+ GLstencil stencil[MAX_WIDTH];
+ GLuint i;
+ (*ctx->Driver.ReadStencilSpan)(ctx, x, y, width, stencil);
+ for (i = 0; i < width; i++) {
+ stencil[i] = (stencil[i] & invMask) | clearVal;
+ }
+ (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL);
+ }
+ }
+ else {
+ /* clear whole buffer without masking */
+ const GLint width = ctx->DrawBuffer->Width;
+ const GLint height = ctx->DrawBuffer->Width;
+ const GLint x = ctx->DrawBuffer->Xmin;
+ GLstencil stencil[MAX_WIDTH];
+ GLint y, i;
+ for (i = 0; i < width; i++) {
+ stencil[i] = ctx->Stencil.Clear;
+ }
+ for (y = 0; y < height; y++) {
+ (*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL);
+ }
+ }
+ }
+}
+
+
+
+/*
+ * Clear the stencil buffer.
+ */
+void
+_mesa_clear_stencil_buffer( GLcontext *ctx )
+{
+ if (ctx->Driver.WriteStencilSpan) {
+ ASSERT(ctx->Driver.ReadStencilSpan);
+ clear_hardware_stencil_buffer(ctx);
+ }
+ else {
+ clear_software_stencil_buffer(ctx);
+ }
+}
+
diff --git a/src/mesa/swrast/s_stencil.h b/src/mesa/swrast/s_stencil.h
new file mode 100644
index 0000000000..80e6a67213
--- /dev/null
+++ b/src/mesa/swrast/s_stencil.h
@@ -0,0 +1,64 @@
+/* $Id: s_stencil.h,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ *
+ * 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.
+ */
+
+
+#ifndef S_STENCIL_H
+#define S_STENCIL_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+extern GLboolean
+_mesa_stencil_and_ztest_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
+ const GLdepth z[], GLubyte mask[] );
+
+extern GLboolean
+_mesa_stencil_and_ztest_pixels( GLcontext *ctx, GLuint n,
+ const GLint x[], const GLint y[],
+ const GLdepth z[], GLubyte mask[] );
+
+
+extern void
+_mesa_read_stencil_span( GLcontext *ctx, GLint n, GLint x, GLint y,
+ GLstencil stencil[] );
+
+
+extern void
+_mesa_write_stencil_span( GLcontext *ctx, GLint n, GLint x, GLint y,
+ const GLstencil stencil[] );
+
+
+extern void
+_mesa_alloc_stencil_buffer( GLcontext *ctx );
+
+
+extern void
+_mesa_clear_stencil_buffer( GLcontext *ctx );
+
+
+#endif
diff --git a/src/mesa/swrast/s_texture.c b/src/mesa/swrast/s_texture.c
new file mode 100644
index 0000000000..04f8645b97
--- /dev/null
+++ b/src/mesa/swrast/s_texture.c
@@ -0,0 +1,2539 @@
+/* $Id: s_texture.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.
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "colormac.h"
+#include "macros.h"
+#include "mmath.h"
+#include "mem.h"
+#include "teximage.h"
+
+#include "s_pb.h"
+#include "s_texture.h"
+
+
+
+
+/*
+ * Paletted texture sampling.
+ * Input: tObj - the texture object
+ * index - the palette index (8-bit only)
+ * Output: red, green, blue, alpha - the texel color
+ */
+static void palette_sample(const struct gl_texture_object *tObj,
+ GLint index, GLchan rgba[4] )
+{
+ GLcontext *ctx = _mesa_get_current_context(); /* THIS IS A HACK */
+ const GLchan *palette;
+ GLenum format;
+
+ if (ctx->Texture.SharedPalette) {
+ ASSERT(!ctx->Texture.Palette.FloatTable);
+ palette = (const GLchan *) ctx->Texture.Palette.Table;
+ format = ctx->Texture.Palette.Format;
+ }
+ else {
+ ASSERT(!tObj->Palette.FloatTable);
+ palette = (const GLchan *) tObj->Palette.Table;
+ format = tObj->Palette.Format;
+ }
+
+ switch (format) {
+ case GL_ALPHA:
+ rgba[ACOMP] = palette[index];
+ return;
+ case GL_LUMINANCE:
+ case GL_INTENSITY:
+ rgba[RCOMP] = palette[index];
+ return;
+ case GL_LUMINANCE_ALPHA:
+ rgba[RCOMP] = palette[(index << 1) + 0];
+ rgba[ACOMP] = palette[(index << 1) + 1];
+ return;
+ case GL_RGB:
+ rgba[RCOMP] = palette[index * 3 + 0];
+ rgba[GCOMP] = palette[index * 3 + 1];
+ rgba[BCOMP] = palette[index * 3 + 2];
+ return;
+ case GL_RGBA:
+ rgba[RCOMP] = palette[(index << 2) + 0];
+ rgba[GCOMP] = palette[(index << 2) + 1];
+ rgba[BCOMP] = palette[(index << 2) + 2];
+ rgba[ACOMP] = palette[(index << 2) + 3];
+ return;
+ default:
+ gl_problem(NULL, "Bad palette format in palette_sample");
+ }
+}
+
+
+
+/*
+ * These values are used in the fixed-point arithmetic used
+ * for linear filtering.
+ */
+#define WEIGHT_SCALE 65536.0F
+#define WEIGHT_SHIFT 16
+
+
+/*
+ * Used to compute texel locations for linear sampling.
+ */
+#define COMPUTE_LINEAR_TEXEL_LOCATIONS(wrapMode, S, U, SIZE, I0, I1) \
+{ \
+ if (wrapMode == GL_REPEAT) { \
+ U = S * SIZE - 0.5F; \
+ I0 = ((GLint) myFloor(U)) & (SIZE - 1); \
+ I1 = (I0 + 1) & (SIZE - 1); \
+ } \
+ else { \
+ U = S * SIZE; \
+ if (U < 0.0F) \
+ U = 0.0F; \
+ else if (U >= SIZE) \
+ U = SIZE; \
+ U -= 0.5F; \
+ I0 = (GLint) myFloor(U); \
+ I1 = I0 + 1; \
+ if (wrapMode == GL_CLAMP_TO_EDGE) { \
+ if (I0 < 0) \
+ I0 = 0; \
+ if (I1 >= SIZE) \
+ I1 = SIZE - 1; \
+ } \
+ } \
+}
+
+
+/*
+ * Used to compute texel location for nearest sampling.
+ */
+#define COMPUTE_NEAREST_TEXEL_LOCATION(wrapMode, S, SIZE, I) \
+{ \
+ if (wrapMode == GL_REPEAT) { \
+ /* s limited to [0,1) */ \
+ /* i limited to [0,width-1] */ \
+ I = (GLint) (S * SIZE); \
+ if (S < 0.0F) \
+ I -= 1; \
+ I &= (SIZE - 1); \
+ } \
+ else if (wrapMode == GL_CLAMP_TO_EDGE) { \
+ const GLfloat min = 1.0F / (2.0F * SIZE); \
+ const GLfloat max = 1.0F - min; \
+ if (S < min) \
+ I = 0; \
+ else if (S > max) \
+ I = SIZE - 1; \
+ else \
+ I = (GLint) (S * SIZE); \
+ } \
+ else { \
+ ASSERT(wrapMode == GL_CLAMP); \
+ /* s limited to [0,1] */ \
+ /* i limited to [0,width-1] */ \
+ if (S <= 0.0F) \
+ I = 0; \
+ else if (S >= 1.0F) \
+ I = SIZE - 1; \
+ else \
+ I = (GLint) (S * SIZE); \
+ } \
+}
+
+
+/*
+ * Compute linear mipmap levels for given lambda.
+ */
+#define COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level) \
+{ \
+ if (lambda < 0.0F) \
+ lambda = 0.0F; \
+ else if (lambda > tObj->M) \
+ lambda = tObj->M; \
+ level = (GLint) (tObj->BaseLevel + lambda); \
+}
+
+
+/*
+ * Compute nearest mipmap level for given lambda.
+ */
+#define COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level) \
+{ \
+ if (lambda <= 0.5F) \
+ lambda = 0.0F; \
+ else if (lambda > tObj->M + 0.4999F) \
+ lambda = tObj->M + 0.4999F; \
+ level = (GLint) (tObj->BaseLevel + lambda + 0.5F); \
+ if (level > tObj->P) \
+ level = tObj->P; \
+}
+
+
+
+
+/*
+ * Bitflags for texture border color sampling.
+ */
+#define I0BIT 1
+#define I1BIT 2
+#define J0BIT 4
+#define J1BIT 8
+#define K0BIT 16
+#define K1BIT 32
+
+
+
+/**********************************************************************/
+/* 1-D Texture Sampling Functions */
+/**********************************************************************/
+
+
+/*
+ * Return floor of x, being careful of negative values.
+ */
+static GLfloat myFloor(GLfloat x)
+{
+ if (x < 0.0F)
+ return (GLfloat) ((GLint) x - 1);
+ else
+ return (GLfloat) (GLint) x;
+}
+
+
+/*
+ * Return the fractional part of x.
+ */
+#define myFrac(x) ( (x) - myFloor(x) )
+
+
+
+
+/*
+ * Given 1-D texture image and an (i) texel column coordinate, return the
+ * texel color.
+ */
+static void get_1d_texel( const struct gl_texture_object *tObj,
+ const struct gl_texture_image *img, GLint i,
+ GLchan rgba[4] )
+{
+ const GLchan *texel;
+
+#ifdef DEBUG
+ GLint width = img->Width;
+ assert(i >= 0);
+ assert(i < width);
+#endif
+
+ switch (img->Format) {
+ case GL_COLOR_INDEX:
+ {
+ GLint index = img->Data[i];
+ palette_sample(tObj, index, rgba);
+ return;
+ }
+ case GL_ALPHA:
+ rgba[ACOMP] = img->Data[ i ];
+ return;
+ case GL_LUMINANCE:
+ case GL_INTENSITY:
+ rgba[RCOMP] = img->Data[ i ];
+ return;
+ case GL_LUMINANCE_ALPHA:
+ texel = img->Data + i * 2;
+ rgba[RCOMP] = texel[0];
+ rgba[ACOMP] = texel[1];
+ return;
+ case GL_RGB:
+ texel = img->Data + i * 3;
+ rgba[RCOMP] = texel[0];
+ rgba[GCOMP] = texel[1];
+ rgba[BCOMP] = texel[2];
+ return;
+ case GL_RGBA:
+ texel = img->Data + i * 4;
+ rgba[RCOMP] = texel[0];
+ rgba[GCOMP] = texel[1];
+ rgba[BCOMP] = texel[2];
+ rgba[ACOMP] = texel[3];
+ return;
+ default:
+ gl_problem(NULL, "Bad format in get_1d_texel");
+ return;
+ }
+}
+
+
+
+/*
+ * Return the texture sample for coordinate (s) using GL_NEAREST filter.
+ */
+static void sample_1d_nearest( const struct gl_texture_object *tObj,
+ const struct gl_texture_image *img,
+ GLfloat s, GLchan rgba[4] )
+{
+ const GLint width = img->Width2; /* without border, power of two */
+ const GLchan *texel;
+ GLint i;
+
+ COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, s, width, i);
+
+ /* skip over the border, if any */
+ i += img->Border;
+
+ /* Get the texel */
+ switch (img->Format) {
+ case GL_COLOR_INDEX:
+ {
+ GLint index = img->Data[i];
+ palette_sample(tObj, index, rgba );
+ return;
+ }
+ case GL_ALPHA:
+ rgba[ACOMP] = img->Data[i];
+ return;
+ case GL_LUMINANCE:
+ case GL_INTENSITY:
+ rgba[RCOMP] = img->Data[i];
+ return;
+ case GL_LUMINANCE_ALPHA:
+ texel = img->Data + i * 2;
+ rgba[RCOMP] = texel[0];
+ rgba[ACOMP] = texel[1];
+ return;
+ case GL_RGB:
+ texel = img->Data + i * 3;
+ rgba[RCOMP] = texel[0];
+ rgba[GCOMP] = texel[1];
+ rgba[BCOMP] = texel[2];
+ return;
+ case GL_RGBA:
+ texel = img->Data + i * 4;
+ rgba[RCOMP] = texel[0];
+ rgba[GCOMP] = texel[1];
+ rgba[BCOMP] = texel[2];
+ rgba[ACOMP] = texel[3];
+ return;
+ default:
+ gl_problem(NULL, "Bad format in sample_1d_nearest");
+ }
+}
+
+
+
+/*
+ * Return the texture sample for coordinate (s) using GL_LINEAR filter.
+ */
+static void sample_1d_linear( const struct gl_texture_object *tObj,
+ const struct gl_texture_image *img,
+ GLfloat s,
+ GLchan rgba[4] )
+{
+ const GLint width = img->Width2;
+ GLint i0, i1;
+ GLfloat u;
+ GLuint useBorderColor;
+
+ COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, s, u, width, i0, i1);
+
+ useBorderColor = 0;
+ if (img->Border) {
+ i0 += img->Border;
+ i1 += img->Border;
+ }
+ else {
+ if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
+ if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
+ }
+
+ {
+ const GLfloat a = myFrac(u);
+ /* compute sample weights in fixed point in [0,WEIGHT_SCALE] */
+ const GLint w0 = (GLint) ((1.0F-a) * WEIGHT_SCALE + 0.5F);
+ const GLint w1 = (GLint) ( a * WEIGHT_SCALE + 0.5F);
+
+ GLchan t0[4], t1[4]; /* texels */
+
+ if (useBorderColor & I0BIT) {
+ COPY_CHAN4(t0, tObj->BorderColor);
+ }
+ else {
+ get_1d_texel( tObj, img, i0, t0 );
+ }
+ if (useBorderColor & I1BIT) {
+ COPY_CHAN4(t1, tObj->BorderColor);
+ }
+ else {
+ get_1d_texel( tObj, img, i1, t1 );
+ }
+
+ rgba[0] = (GLchan) ((w0 * t0[0] + w1 * t1[0]) >> WEIGHT_SHIFT);
+ rgba[1] = (GLchan) ((w0 * t0[1] + w1 * t1[1]) >> WEIGHT_SHIFT);
+ rgba[2] = (GLchan) ((w0 * t0[2] + w1 * t1[2]) >> WEIGHT_SHIFT);
+ rgba[3] = (GLchan) ((w0 * t0[3] + w1 * t1[3]) >> WEIGHT_SHIFT);
+ }
+}
+
+
+static void
+sample_1d_nearest_mipmap_nearest( const struct gl_texture_object *tObj,
+ GLfloat s, GLfloat lambda,
+ GLchan rgba[4] )
+{
+ GLint level;
+ COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
+ sample_1d_nearest( tObj, tObj->Image[level], s, rgba );
+}
+
+
+static void
+sample_1d_linear_mipmap_nearest( const struct gl_texture_object *tObj,
+ GLfloat s, GLfloat lambda,
+ GLchan rgba[4] )
+{
+ GLint level;
+ COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
+ sample_1d_linear( tObj, tObj->Image[level], s, rgba );
+}
+
+
+
+static void
+sample_1d_nearest_mipmap_linear( const struct gl_texture_object *tObj,
+ GLfloat s, GLfloat lambda,
+ GLchan rgba[4] )
+{
+ GLint level;
+
+ COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
+
+ if (level >= tObj->P) {
+ sample_1d_nearest( tObj, tObj->Image[tObj->P], s, rgba );
+ }
+ else {
+ GLchan t0[4], t1[4];
+ const GLfloat f = myFrac(lambda);
+ sample_1d_nearest( tObj, tObj->Image[level ], s, t0 );
+ sample_1d_nearest( tObj, tObj->Image[level+1], s, t1 );
+ rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
+ rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
+ rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
+ rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
+ }
+}
+
+
+
+static void
+sample_1d_linear_mipmap_linear( const struct gl_texture_object *tObj,
+ GLfloat s, GLfloat lambda,
+ GLchan rgba[4] )
+{
+ GLint level;
+
+ COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
+
+ if (level >= tObj->P) {
+ sample_1d_linear( tObj, tObj->Image[tObj->P], s, rgba );
+ }
+ else {
+ GLchan t0[4], t1[4];
+ const GLfloat f = myFrac(lambda);
+ sample_1d_linear( tObj, tObj->Image[level ], s, t0 );
+ sample_1d_linear( tObj, tObj->Image[level+1], s, t1 );
+ rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
+ rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
+ rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
+ rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
+ }
+}
+
+
+
+static void sample_nearest_1d( const struct gl_texture_object *tObj, GLuint n,
+ const GLfloat s[], const GLfloat t[],
+ const GLfloat u[], const GLfloat lambda[],
+ GLchan rgba[][4] )
+{
+ GLuint i;
+ struct gl_texture_image *image = tObj->Image[tObj->BaseLevel];
+ (void) t;
+ (void) u;
+ (void) lambda;
+ for (i=0;i<n;i++) {
+ sample_1d_nearest( tObj, image, s[i], rgba[i] );
+ }
+}
+
+
+
+static void sample_linear_1d( const struct gl_texture_object *tObj, GLuint n,
+ const GLfloat s[], const GLfloat t[],
+ const GLfloat u[], const GLfloat lambda[],
+ GLchan rgba[][4] )
+{
+ GLuint i;
+ struct gl_texture_image *image = tObj->Image[tObj->BaseLevel];
+ (void) t;
+ (void) u;
+ (void) lambda;
+ for (i=0;i<n;i++) {
+ sample_1d_linear( tObj, image, s[i], rgba[i] );
+ }
+}
+
+
+/*
+ * Given an (s) texture coordinate and lambda (level of detail) value,
+ * return a texture sample.
+ *
+ */
+static void sample_lambda_1d( const struct gl_texture_object *tObj, GLuint n,
+ const GLfloat s[], const GLfloat t[],
+ const GLfloat u[], const GLfloat lambda[],
+ GLchan rgba[][4] )
+{
+ GLuint i;
+
+ (void) t;
+ (void) u;
+
+ for (i=0;i<n;i++) {
+ if (lambda[i] > tObj->MinMagThresh) {
+ /* minification */
+ switch (tObj->MinFilter) {
+ case GL_NEAREST:
+ sample_1d_nearest( tObj, tObj->Image[tObj->BaseLevel], s[i], rgba[i] );
+ break;
+ case GL_LINEAR:
+ sample_1d_linear( tObj, tObj->Image[tObj->BaseLevel], s[i], rgba[i] );
+ break;
+ case GL_NEAREST_MIPMAP_NEAREST:
+ sample_1d_nearest_mipmap_nearest( tObj, lambda[i], s[i], rgba[i] );
+ break;
+ case GL_LINEAR_MIPMAP_NEAREST:
+ sample_1d_linear_mipmap_nearest( tObj, s[i], lambda[i], rgba[i] );
+ break;
+ case GL_NEAREST_MIPMAP_LINEAR:
+ sample_1d_nearest_mipmap_linear( tObj, s[i], lambda[i], rgba[i] );
+ break;
+ case GL_LINEAR_MIPMAP_LINEAR:
+ sample_1d_linear_mipmap_linear( tObj, s[i], lambda[i], rgba[i] );
+ break;
+ default:
+ gl_problem(NULL, "Bad min filter in sample_1d_texture");
+ return;
+ }
+ }
+ else {
+ /* magnification */
+ switch (tObj->MagFilter) {
+ case GL_NEAREST:
+ sample_1d_nearest( tObj, tObj->Image[tObj->BaseLevel], s[i], rgba[i] );
+ break;
+ case GL_LINEAR:
+ sample_1d_linear( tObj, tObj->Image[tObj->BaseLevel], s[i], rgba[i] );
+ break;
+ default:
+ gl_problem(NULL, "Bad mag filter in sample_1d_texture");
+ return;
+ }
+ }
+ }
+}
+
+
+
+
+/**********************************************************************/
+/* 2-D Texture Sampling Functions */
+/**********************************************************************/
+
+
+/*
+ * Given a texture image and an (i,j) integer texel coordinate, return the
+ * texel color.
+ */
+static void get_2d_texel( const struct gl_texture_object *tObj,
+ const struct gl_texture_image *img, GLint i, GLint j,
+ GLchan rgba[4] )
+{
+ const GLint width = img->Width; /* includes border */
+ const GLchan *texel;
+
+#ifdef DEBUG
+ const GLint height = img->Height; /* includes border */
+ assert(i >= 0);
+ assert(i < width);
+ assert(j >= 0);
+ assert(j < height);
+#endif
+
+ switch (img->Format) {
+ case GL_COLOR_INDEX:
+ {
+ GLint index = img->Data[ width *j + i ];
+ palette_sample(tObj, index, rgba );
+ return;
+ }
+ case GL_ALPHA:
+ rgba[ACOMP] = img->Data[ width * j + i ];
+ return;
+ case GL_LUMINANCE:
+ case GL_INTENSITY:
+ rgba[RCOMP] = img->Data[ width * j + i ];
+ return;
+ case GL_LUMINANCE_ALPHA:
+ texel = img->Data + (width * j + i) * 2;
+ rgba[RCOMP] = texel[0];
+ rgba[ACOMP] = texel[1];
+ return;
+ case GL_RGB:
+ texel = img->Data + (width * j + i) * 3;
+ rgba[RCOMP] = texel[0];
+ rgba[GCOMP] = texel[1];
+ rgba[BCOMP] = texel[2];
+ return;
+ case GL_RGBA:
+ texel = img->Data + (width * j + i) * 4;
+ rgba[RCOMP] = texel[0];
+ rgba[GCOMP] = texel[1];
+ rgba[BCOMP] = texel[2];
+ rgba[ACOMP] = texel[3];
+ return;
+ default:
+ gl_problem(NULL, "Bad format in get_2d_texel");
+ }
+}
+
+
+
+/*
+ * Return the texture sample for coordinate (s,t) using GL_NEAREST filter.
+ */
+static void sample_2d_nearest( const struct gl_texture_object *tObj,
+ const struct gl_texture_image *img,
+ GLfloat s, GLfloat t,
+ GLchan rgba[] )
+{
+ const GLint imgWidth = img->Width; /* includes border */
+ const GLint width = img->Width2; /* without border, power of two */
+ const GLint height = img->Height2; /* without border, power of two */
+ const GLchan *texel;
+ GLint i, j;
+
+ COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, s, width, i);
+ COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapT, t, height, j);
+
+ /* skip over the border, if any */
+ i += img->Border;
+ j += img->Border;
+
+ switch (img->Format) {
+ case GL_COLOR_INDEX:
+ {
+ GLint index = img->Data[ j * imgWidth + i ];
+ palette_sample(tObj, index, rgba);
+ return;
+ }
+ case GL_ALPHA:
+ rgba[ACOMP] = img->Data[ j * imgWidth + i ];
+ return;
+ case GL_LUMINANCE:
+ case GL_INTENSITY:
+ rgba[RCOMP] = img->Data[ j * imgWidth + i ];
+ return;
+ case GL_LUMINANCE_ALPHA:
+ texel = img->Data + ((j * imgWidth + i) << 1);
+ rgba[RCOMP] = texel[0];
+ rgba[ACOMP] = texel[1];
+ return;
+ case GL_RGB:
+ texel = img->Data + (j * imgWidth + i) * 3;
+ rgba[RCOMP] = texel[0];
+ rgba[GCOMP] = texel[1];
+ rgba[BCOMP] = texel[2];
+ return;
+ case GL_RGBA:
+ texel = img->Data + ((j * imgWidth + i) << 2);
+ rgba[RCOMP] = texel[0];
+ rgba[GCOMP] = texel[1];
+ rgba[BCOMP] = texel[2];
+ rgba[ACOMP] = texel[3];
+ return;
+ default:
+ gl_problem(NULL, "Bad format in sample_2d_nearest");
+ }
+}
+
+
+
+/*
+ * Return the texture sample for coordinate (s,t) using GL_LINEAR filter.
+ * New sampling code contributed by Lynn Quam <quam@ai.sri.com>.
+ */
+static void sample_2d_linear( const struct gl_texture_object *tObj,
+ const struct gl_texture_image *img,
+ GLfloat s, GLfloat t,
+ GLchan rgba[] )
+{
+ const GLint width = img->Width2;
+ const GLint height = img->Height2;
+ GLint i0, j0, i1, j1;
+ GLuint useBorderColor;
+ GLfloat u, v;
+
+ COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, s, u, width, i0, i1);
+ COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapT, t, v, height, j0, j1);
+
+ useBorderColor = 0;
+ if (img->Border) {
+ i0 += img->Border;
+ i1 += img->Border;
+ j0 += img->Border;
+ j1 += img->Border;
+ }
+ else {
+ if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
+ if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
+ if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT;
+ if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT;
+ }
+
+ {
+ const GLfloat a = myFrac(u);
+ const GLfloat b = myFrac(v);
+ /* compute sample weights in fixed point in [0,WEIGHT_SCALE] */
+ const GLint w00 = (GLint) ((1.0F-a)*(1.0F-b) * WEIGHT_SCALE + 0.5F);
+ const GLint w10 = (GLint) ( a *(1.0F-b) * WEIGHT_SCALE + 0.5F);
+ const GLint w01 = (GLint) ((1.0F-a)* b * WEIGHT_SCALE + 0.5F);
+ const GLint w11 = (GLint) ( a * b * WEIGHT_SCALE + 0.5F);
+ GLchan t00[4];
+ GLchan t10[4];
+ GLchan t01[4];
+ GLchan t11[4];
+
+ if (useBorderColor & (I0BIT | J0BIT)) {
+ COPY_CHAN4(t00, tObj->BorderColor);
+ }
+ else {
+ get_2d_texel( tObj, img, i0, j0, t00 );
+ }
+ if (useBorderColor & (I1BIT | J0BIT)) {
+ COPY_CHAN4(t10, tObj->BorderColor);
+ }
+ else {
+ get_2d_texel( tObj, img, i1, j0, t10 );
+ }
+ if (useBorderColor & (I0BIT | J1BIT)) {
+ COPY_CHAN4(t01, tObj->BorderColor);
+ }
+ else {
+ get_2d_texel( tObj, img, i0, j1, t01 );
+ }
+ if (useBorderColor & (I1BIT | J1BIT)) {
+ COPY_CHAN4(t11, tObj->BorderColor);
+ }
+ else {
+ get_2d_texel( tObj, img, i1, j1, t11 );
+ }
+
+ rgba[0] = (GLchan) ((w00 * t00[0] + w10 * t10[0] + w01 * t01[0] + w11 * t11[0]) >> WEIGHT_SHIFT);
+ rgba[1] = (GLchan) ((w00 * t00[1] + w10 * t10[1] + w01 * t01[1] + w11 * t11[1]) >> WEIGHT_SHIFT);
+ rgba[2] = (GLchan) ((w00 * t00[2] + w10 * t10[2] + w01 * t01[2] + w11 * t11[2]) >> WEIGHT_SHIFT);
+ rgba[3] = (GLchan) ((w00 * t00[3] + w10 * t10[3] + w01 * t01[3] + w11 * t11[3]) >> WEIGHT_SHIFT);
+ }
+
+}
+
+
+
+static void
+sample_2d_nearest_mipmap_nearest( const struct gl_texture_object *tObj,
+ GLfloat s, GLfloat t, GLfloat lambda,
+ GLchan rgba[4] )
+{
+ GLint level;
+ COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
+ sample_2d_nearest( tObj, tObj->Image[level], s, t, rgba );
+}
+
+
+
+static void
+sample_2d_linear_mipmap_nearest( const struct gl_texture_object *tObj,
+ GLfloat s, GLfloat t, GLfloat lambda,
+ GLchan rgba[4] )
+{
+ GLint level;
+ COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
+ sample_2d_linear( tObj, tObj->Image[level], s, t, rgba );
+}
+
+
+
+static void
+sample_2d_nearest_mipmap_linear( const struct gl_texture_object *tObj,
+ GLfloat s, GLfloat t, GLfloat lambda,
+ GLchan rgba[4] )
+{
+ GLint level;
+
+ COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
+
+ if (level >= tObj->P) {
+ sample_2d_nearest( tObj, tObj->Image[tObj->P], s, t, rgba );
+ }
+ else {
+ GLchan t0[4], t1[4]; /* texels */
+ const GLfloat f = myFrac(lambda);
+ sample_2d_nearest( tObj, tObj->Image[level ], s, t, t0 );
+ sample_2d_nearest( tObj, tObj->Image[level+1], s, t, t1 );
+ rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
+ rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
+ rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
+ rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
+ }
+}
+
+
+
+static void
+sample_2d_linear_mipmap_linear( const struct gl_texture_object *tObj,
+ GLfloat s, GLfloat t, GLfloat lambda,
+ GLchan rgba[4] )
+{
+ GLint level;
+
+ COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
+
+ if (level >= tObj->P) {
+ sample_2d_linear( tObj, tObj->Image[tObj->P], s, t, rgba );
+ }
+ else {
+ GLchan t0[4], t1[4]; /* texels */
+ const GLfloat f = myFrac(lambda);
+ sample_2d_linear( tObj, tObj->Image[level ], s, t, t0 );
+ sample_2d_linear( tObj, tObj->Image[level+1], s, t, t1 );
+ rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
+ rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
+ rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
+ rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
+ }
+}
+
+
+
+static void sample_nearest_2d( const struct gl_texture_object *tObj, GLuint n,
+ const GLfloat s[], const GLfloat t[],
+ const GLfloat u[], const GLfloat lambda[],
+ GLchan rgba[][4] )
+{
+ GLuint i;
+ struct gl_texture_image *image = tObj->Image[tObj->BaseLevel];
+ (void) u;
+ (void) lambda;
+ for (i=0;i<n;i++) {
+ sample_2d_nearest( tObj, image, s[i], t[i], rgba[i] );
+ }
+}
+
+
+
+static void sample_linear_2d( const struct gl_texture_object *tObj, GLuint n,
+ const GLfloat s[], const GLfloat t[],
+ const GLfloat u[], const GLfloat lambda[],
+ GLchan rgba[][4] )
+{
+ GLuint i;
+ struct gl_texture_image *image = tObj->Image[tObj->BaseLevel];
+ (void) u;
+ (void) lambda;
+ for (i=0;i<n;i++) {
+ sample_2d_linear( tObj, image, s[i], t[i], rgba[i] );
+ }
+}
+
+
+/*
+ * Given an (s,t) texture coordinate and lambda (level of detail) value,
+ * return a texture sample.
+ */
+static void sample_lambda_2d( const struct gl_texture_object *tObj,
+ GLuint n,
+ const GLfloat s[], const GLfloat t[],
+ const GLfloat u[], const GLfloat lambda[],
+ GLchan rgba[][4] )
+{
+ GLuint i;
+ (void) u;
+ for (i=0;i<n;i++) {
+ if (lambda[i] > tObj->MinMagThresh) {
+ /* minification */
+ switch (tObj->MinFilter) {
+ case GL_NEAREST:
+ sample_2d_nearest( tObj, tObj->Image[tObj->BaseLevel], s[i], t[i], rgba[i] );
+ break;
+ case GL_LINEAR:
+ sample_2d_linear( tObj, tObj->Image[tObj->BaseLevel], s[i], t[i], rgba[i] );
+ break;
+ case GL_NEAREST_MIPMAP_NEAREST:
+ sample_2d_nearest_mipmap_nearest( tObj, s[i], t[i], lambda[i], rgba[i] );
+ break;
+ case GL_LINEAR_MIPMAP_NEAREST:
+ sample_2d_linear_mipmap_nearest( tObj, s[i], t[i], lambda[i], rgba[i] );
+ break;
+ case GL_NEAREST_MIPMAP_LINEAR:
+ sample_2d_nearest_mipmap_linear( tObj, s[i], t[i], lambda[i], rgba[i] );
+ break;
+ case GL_LINEAR_MIPMAP_LINEAR:
+ sample_2d_linear_mipmap_linear( tObj, s[i], t[i], lambda[i], rgba[i] );
+ break;
+ default:
+ gl_problem(NULL, "Bad min filter in sample_2d_texture");
+ return;
+ }
+ }
+ else {
+ /* magnification */
+ switch (tObj->MagFilter) {
+ case GL_NEAREST:
+ sample_2d_nearest( tObj, tObj->Image[tObj->BaseLevel], s[i], t[i], rgba[i] );
+ break;
+ case GL_LINEAR:
+ sample_2d_linear( tObj, tObj->Image[tObj->BaseLevel], s[i], t[i], rgba[i] );
+ break;
+ default:
+ gl_problem(NULL, "Bad mag filter in sample_2d_texture");
+ }
+ }
+ }
+}
+
+
+/*
+ * Optimized 2-D texture sampling:
+ * S and T wrap mode == GL_REPEAT
+ * GL_NEAREST min/mag filter
+ * No border
+ * Format = GL_RGB
+ */
+static void opt_sample_rgb_2d( const struct gl_texture_object *tObj,
+ GLuint n, const GLfloat s[], const GLfloat t[],
+ const GLfloat u[], const GLfloat lambda[],
+ GLchan rgba[][4] )
+{
+ const struct gl_texture_image *img = tObj->Image[tObj->BaseLevel];
+ const GLfloat width = (GLfloat) img->Width;
+ const GLfloat height = (GLfloat) img->Height;
+ const GLint colMask = img->Width - 1;
+ const GLint rowMask = img->Height - 1;
+ const GLint shift = img->WidthLog2;
+ GLuint k;
+ (void) u;
+ (void) lambda;
+ ASSERT(tObj->WrapS==GL_REPEAT);
+ ASSERT(tObj->WrapT==GL_REPEAT);
+ ASSERT(tObj->MinFilter==GL_NEAREST);
+ ASSERT(tObj->MagFilter==GL_NEAREST);
+ ASSERT(img->Border==0);
+ ASSERT(img->Format==GL_RGB);
+
+ /* NOTE: negative float->int doesn't floor, add 10000 as to work-around */
+ for (k=0;k<n;k++) {
+ GLint i = (GLint) ((s[k] + 10000.0) * width) & colMask;
+ GLint j = (GLint) ((t[k] + 10000.0) * height) & rowMask;
+ GLint pos = (j << shift) | i;
+ GLchan *texel = img->Data + pos + pos + pos; /* pos*3 */
+ rgba[k][RCOMP] = texel[0];
+ rgba[k][GCOMP] = texel[1];
+ rgba[k][BCOMP] = texel[2];
+ }
+}
+
+
+/*
+ * Optimized 2-D texture sampling:
+ * S and T wrap mode == GL_REPEAT
+ * GL_NEAREST min/mag filter
+ * No border
+ * Format = GL_RGBA
+ */
+static void opt_sample_rgba_2d( const struct gl_texture_object *tObj,
+ GLuint n, const GLfloat s[], const GLfloat t[],
+ const GLfloat u[], const GLfloat lambda[],
+ GLchan rgba[][4] )
+{
+ const struct gl_texture_image *img = tObj->Image[tObj->BaseLevel];
+ const GLfloat width = (GLfloat) img->Width;
+ const GLfloat height = (GLfloat) img->Height;
+ const GLint colMask = img->Width - 1;
+ const GLint rowMask = img->Height - 1;
+ const GLint shift = img->WidthLog2;
+ GLuint k;
+ (void) u;
+ (void) lambda;
+ ASSERT(tObj->WrapS==GL_REPEAT);
+ ASSERT(tObj->WrapT==GL_REPEAT);
+ ASSERT(tObj->MinFilter==GL_NEAREST);
+ ASSERT(tObj->MagFilter==GL_NEAREST);
+ ASSERT(img->Border==0);
+ ASSERT(img->Format==GL_RGBA);
+
+ /* NOTE: negative float->int doesn't floor, add 10000 as to work-around */
+ for (k=0;k<n;k++) {
+ GLint i = (GLint) ((s[k] + 10000.0) * width) & colMask;
+ GLint j = (GLint) ((t[k] + 10000.0) * height) & rowMask;
+ GLint pos = (j << shift) | i;
+ GLchan *texel = img->Data + (pos << 2); /* pos*4 */
+ rgba[k][RCOMP] = texel[0];
+ rgba[k][GCOMP] = texel[1];
+ rgba[k][BCOMP] = texel[2];
+ rgba[k][ACOMP] = texel[3];
+ }
+}
+
+
+
+/**********************************************************************/
+/* 3-D Texture Sampling Functions */
+/**********************************************************************/
+
+/*
+ * Given a texture image and an (i,j,k) integer texel coordinate, return the
+ * texel color.
+ */
+static void get_3d_texel( const struct gl_texture_object *tObj,
+ const struct gl_texture_image *img,
+ GLint i, GLint j, GLint k,
+ GLchan rgba[4] )
+{
+ const GLint width = img->Width; /* includes border */
+ const GLint height = img->Height; /* includes border */
+ const GLint rectarea = width * height;
+ const GLchan *texel;
+
+#ifdef DEBUG
+ const GLint depth = img->Depth; /* includes border */
+ assert(i >= 0);
+ assert(i < width);
+ assert(j >= 0);
+ assert(j < height);
+ assert(k >= 0);
+ assert(k < depth);
+#endif
+
+ switch (img->Format) {
+ case GL_COLOR_INDEX:
+ {
+ GLint index = img->Data[ rectarea * k + width * j + i ];
+ palette_sample(tObj, index, rgba );
+ return;
+ }
+ case GL_ALPHA:
+ rgba[ACOMP] = img->Data[ rectarea * k + width * j + i ];
+ return;
+ case GL_LUMINANCE:
+ case GL_INTENSITY:
+ rgba[RCOMP] = img->Data[ rectarea * k + width * j + i ];
+ return;
+ case GL_LUMINANCE_ALPHA:
+ texel = img->Data + ( rectarea * k + width * j + i) * 2;
+ rgba[RCOMP] = texel[0];
+ rgba[ACOMP] = texel[1];
+ return;
+ case GL_RGB:
+ texel = img->Data + (rectarea * k + width * j + i) * 3;
+ rgba[RCOMP] = texel[0];
+ rgba[GCOMP] = texel[1];
+ rgba[BCOMP] = texel[2];
+ return;
+ case GL_RGBA:
+ texel = img->Data + (rectarea * k + width * j + i) * 4;
+ rgba[RCOMP] = texel[0];
+ rgba[GCOMP] = texel[1];
+ rgba[BCOMP] = texel[2];
+ rgba[ACOMP] = texel[3];
+ return;
+ default:
+ gl_problem(NULL, "Bad format in get_3d_texel");
+ }
+}
+
+
+/*
+ * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
+ */
+static void sample_3d_nearest( const struct gl_texture_object *tObj,
+ const struct gl_texture_image *img,
+ GLfloat s, GLfloat t, GLfloat r,
+ GLchan rgba[4] )
+{
+ const GLint imgWidth = img->Width; /* includes border, if any */
+ const GLint imgHeight = img->Height; /* includes border, if any */
+ const GLint width = img->Width2; /* without border, power of two */
+ const GLint height = img->Height2; /* without border, power of two */
+ const GLint depth = img->Depth2; /* without border, power of two */
+ const GLint rectarea = imgWidth * imgHeight;
+ const GLchan *texel;
+ GLint i, j, k;
+
+ COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, s, width, i);
+ COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapT, t, height, j);
+ COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapR, r, depth, k);
+
+ switch (tObj->Image[0]->Format) {
+ case GL_COLOR_INDEX:
+ {
+ GLint index = img->Data[ rectarea * k + j * imgWidth + i ];
+ palette_sample(tObj, index, rgba );
+ return;
+ }
+ case GL_ALPHA:
+ rgba[ACOMP] = img->Data[ rectarea * k + j * imgWidth + i ];
+ return;
+ case GL_LUMINANCE:
+ case GL_INTENSITY:
+ rgba[RCOMP] = img->Data[ rectarea * k + j * imgWidth + i ];
+ return;
+ case GL_LUMINANCE_ALPHA:
+ texel = img->Data + ((rectarea * k + j * imgWidth + i) << 1);
+ rgba[RCOMP] = texel[0];
+ rgba[ACOMP] = texel[1];
+ return;
+ case GL_RGB:
+ texel = img->Data + ( rectarea * k + j * imgWidth + i) * 3;
+ rgba[RCOMP] = texel[0];
+ rgba[GCOMP] = texel[1];
+ rgba[BCOMP] = texel[2];
+ return;
+ case GL_RGBA:
+ texel = img->Data + ((rectarea * k + j * imgWidth + i) << 2);
+ rgba[RCOMP] = texel[0];
+ rgba[GCOMP] = texel[1];
+ rgba[BCOMP] = texel[2];
+ rgba[ACOMP] = texel[3];
+ return;
+ default:
+ gl_problem(NULL, "Bad format in sample_3d_nearest");
+ }
+}
+
+
+
+/*
+ * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
+ */
+static void sample_3d_linear( const struct gl_texture_object *tObj,
+ const struct gl_texture_image *img,
+ GLfloat s, GLfloat t, GLfloat r,
+ GLchan rgba[4] )
+{
+ const GLint width = img->Width2;
+ const GLint height = img->Height2;
+ const GLint depth = img->Depth2;
+ GLint i0, j0, k0, i1, j1, k1;
+ GLuint useBorderColor;
+ GLfloat u, v, w;
+
+ COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, s, u, width, i0, i1);
+ COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapT, t, v, height, j0, j1);
+ COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapR, r, w, depth, k0, k1);
+
+ useBorderColor = 0;
+ if (img->Border) {
+ i0 += img->Border;
+ i1 += img->Border;
+ j0 += img->Border;
+ j1 += img->Border;
+ k0 += img->Border;
+ k1 += img->Border;
+ }
+ else {
+ /* check if sampling texture border color */
+ if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
+ if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
+ if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT;
+ if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT;
+ if (k0 < 0 || k0 >= depth) useBorderColor |= K0BIT;
+ if (k1 < 0 || k1 >= depth) useBorderColor |= K1BIT;
+ }
+
+ {
+ const GLfloat a = myFrac(u);
+ const GLfloat b = myFrac(v);
+ const GLfloat c = myFrac(w);
+ /* compute sample weights in fixed point in [0,WEIGHT_SCALE] */
+ GLint w000 = (GLint) ((1.0F-a)*(1.0F-b)*(1.0F-c) * WEIGHT_SCALE + 0.5F);
+ GLint w100 = (GLint) ( a *(1.0F-b)*(1.0F-c) * WEIGHT_SCALE + 0.5F);
+ GLint w010 = (GLint) ((1.0F-a)* b *(1.0F-c) * WEIGHT_SCALE + 0.5F);
+ GLint w110 = (GLint) ( a * b *(1.0F-c) * WEIGHT_SCALE + 0.5F);
+ GLint w001 = (GLint) ((1.0F-a)*(1.0F-b)* c * WEIGHT_SCALE + 0.5F);
+ GLint w101 = (GLint) ( a *(1.0F-b)* c * WEIGHT_SCALE + 0.5F);
+ GLint w011 = (GLint) ((1.0F-a)* b * c * WEIGHT_SCALE + 0.5F);
+ GLint w111 = (GLint) ( a * b * c * WEIGHT_SCALE + 0.5F);
+
+ GLchan t000[4], t010[4], t001[4], t011[4];
+ GLchan t100[4], t110[4], t101[4], t111[4];
+
+ if (useBorderColor & (I0BIT | J0BIT | K0BIT)) {
+ COPY_CHAN4(t000, tObj->BorderColor);
+ }
+ else {
+ get_3d_texel( tObj, img, i0, j0, k0, t000 );
+ }
+ if (useBorderColor & (I1BIT | J0BIT | K0BIT)) {
+ COPY_CHAN4(t100, tObj->BorderColor);
+ }
+ else {
+ get_3d_texel( tObj, img, i1, j0, k0, t100 );
+ }
+ if (useBorderColor & (I0BIT | J1BIT | K0BIT)) {
+ COPY_CHAN4(t010, tObj->BorderColor);
+ }
+ else {
+ get_3d_texel( tObj, img, i0, j1, k0, t010 );
+ }
+ if (useBorderColor & (I1BIT | J1BIT | K0BIT)) {
+ COPY_CHAN4(t110, tObj->BorderColor);
+ }
+ else {
+ get_3d_texel( tObj, img, i1, j1, k0, t110 );
+ }
+
+ if (useBorderColor & (I0BIT | J0BIT | K1BIT)) {
+ COPY_CHAN4(t001, tObj->BorderColor);
+ }
+ else {
+ get_3d_texel( tObj, img, i0, j0, k1, t001 );
+ }
+ if (useBorderColor & (I1BIT | J0BIT | K1BIT)) {
+ COPY_CHAN4(t101, tObj->BorderColor);
+ }
+ else {
+ get_3d_texel( tObj, img, i1, j0, k1, t101 );
+ }
+ if (useBorderColor & (I0BIT | J1BIT | K1BIT)) {
+ COPY_CHAN4(t011, tObj->BorderColor);
+ }
+ else {
+ get_3d_texel( tObj, img, i0, j1, k1, t011 );
+ }
+ if (useBorderColor & (I1BIT | J1BIT | K1BIT)) {
+ COPY_CHAN4(t111, tObj->BorderColor);
+ }
+ else {
+ get_3d_texel( tObj, img, i1, j1, k1, t111 );
+ }
+
+ rgba[0] = (GLchan) (
+ (w000*t000[0] + w010*t010[0] + w001*t001[0] + w011*t011[0] +
+ w100*t100[0] + w110*t110[0] + w101*t101[0] + w111*t111[0] )
+ >> WEIGHT_SHIFT);
+ rgba[1] = (GLchan) (
+ (w000*t000[1] + w010*t010[1] + w001*t001[1] + w011*t011[1] +
+ w100*t100[1] + w110*t110[1] + w101*t101[1] + w111*t111[1] )
+ >> WEIGHT_SHIFT);
+ rgba[2] = (GLchan) (
+ (w000*t000[2] + w010*t010[2] + w001*t001[2] + w011*t011[2] +
+ w100*t100[2] + w110*t110[2] + w101*t101[2] + w111*t111[2] )
+ >> WEIGHT_SHIFT);
+ rgba[3] = (GLchan) (
+ (w000*t000[3] + w010*t010[3] + w001*t001[3] + w011*t011[3] +
+ w100*t100[3] + w110*t110[3] + w101*t101[3] + w111*t111[3] )
+ >> WEIGHT_SHIFT);
+ }
+}
+
+
+
+static void
+sample_3d_nearest_mipmap_nearest( const struct gl_texture_object *tObj,
+ GLfloat s, GLfloat t, GLfloat r,
+ GLfloat lambda, GLchan rgba[4] )
+{
+ GLint level;
+ COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
+ sample_3d_nearest( tObj, tObj->Image[level], s, t, r, rgba );
+}
+
+
+static void
+sample_3d_linear_mipmap_nearest( const struct gl_texture_object *tObj,
+ GLfloat s, GLfloat t, GLfloat r,
+ GLfloat lambda, GLchan rgba[4] )
+{
+ GLint level;
+ COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
+ sample_3d_linear( tObj, tObj->Image[level], s, t, r, rgba );
+}
+
+
+static void
+sample_3d_nearest_mipmap_linear( const struct gl_texture_object *tObj,
+ GLfloat s, GLfloat t, GLfloat r,
+ GLfloat lambda, GLchan rgba[4] )
+{
+ GLint level;
+
+ COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
+
+ if (level >= tObj->P) {
+ sample_3d_nearest( tObj, tObj->Image[tObj->P], s, t, r, rgba );
+ }
+ else {
+ GLchan t0[4], t1[4]; /* texels */
+ const GLfloat f = myFrac(lambda);
+ sample_3d_nearest( tObj, tObj->Image[level ], s, t, r, t0 );
+ sample_3d_nearest( tObj, tObj->Image[level+1], s, t, r, t1 );
+ rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
+ rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
+ rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
+ rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
+ }
+}
+
+
+static void
+sample_3d_linear_mipmap_linear( const struct gl_texture_object *tObj,
+ GLfloat s, GLfloat t, GLfloat r,
+ GLfloat lambda, GLchan rgba[4] )
+{
+ GLint level;
+
+ COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
+
+ if (level >= tObj->P) {
+ sample_3d_linear( tObj, tObj->Image[tObj->P], s, t, r, rgba );
+ }
+ else {
+ GLchan t0[4], t1[4]; /* texels */
+ const GLfloat f = myFrac(lambda);
+ sample_3d_linear( tObj, tObj->Image[level ], s, t, r, t0 );
+ sample_3d_linear( tObj, tObj->Image[level+1], s, t, r, t1 );
+ rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
+ rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
+ rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
+ rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
+ }
+}
+
+
+static void sample_nearest_3d( const struct gl_texture_object *tObj, GLuint n,
+ const GLfloat s[], const GLfloat t[],
+ const GLfloat u[], const GLfloat lambda[],
+ GLchan rgba[][4] )
+{
+ GLuint i;
+ struct gl_texture_image *image = tObj->Image[tObj->BaseLevel];
+ (void) lambda;
+ for (i=0;i<n;i++) {
+ sample_3d_nearest( tObj, image, s[i], t[i], u[i], rgba[i] );
+ }
+}
+
+
+
+static void sample_linear_3d( const struct gl_texture_object *tObj, GLuint n,
+ const GLfloat s[], const GLfloat t[],
+ const GLfloat u[], const GLfloat lambda[],
+ GLchan rgba[][4] )
+{
+ GLuint i;
+ struct gl_texture_image *image = tObj->Image[tObj->BaseLevel];
+ (void) lambda;
+ for (i=0;i<n;i++) {
+ sample_3d_linear( tObj, image, s[i], t[i], u[i], rgba[i] );
+ }
+}
+
+
+/*
+ * Given an (s,t,r) texture coordinate and lambda (level of detail) value,
+ * return a texture sample.
+ */
+static void sample_lambda_3d( const struct gl_texture_object *tObj, GLuint n,
+ const GLfloat s[], const GLfloat t[],
+ const GLfloat u[], const GLfloat lambda[],
+ GLchan rgba[][4] )
+{
+ GLuint i;
+
+ for (i=0;i<n;i++) {
+
+ if (lambda[i] > tObj->MinMagThresh) {
+ /* minification */
+ switch (tObj->MinFilter) {
+ case GL_NEAREST:
+ sample_3d_nearest( tObj, tObj->Image[tObj->BaseLevel], s[i], t[i], u[i], rgba[i] );
+ break;
+ case GL_LINEAR:
+ sample_3d_linear( tObj, tObj->Image[tObj->BaseLevel], s[i], t[i], u[i], rgba[i] );
+ break;
+ case GL_NEAREST_MIPMAP_NEAREST:
+ sample_3d_nearest_mipmap_nearest( tObj, s[i], t[i], u[i], lambda[i], rgba[i] );
+ break;
+ case GL_LINEAR_MIPMAP_NEAREST:
+ sample_3d_linear_mipmap_nearest( tObj, s[i], t[i], u[i], lambda[i], rgba[i] );
+ break;
+ case GL_NEAREST_MIPMAP_LINEAR:
+ sample_3d_nearest_mipmap_linear( tObj, s[i], t[i], u[i], lambda[i], rgba[i] );
+ break;
+ case GL_LINEAR_MIPMAP_LINEAR:
+ sample_3d_linear_mipmap_linear( tObj, s[i], t[i], u[i], lambda[i], rgba[i] );
+ break;
+ default:
+ gl_problem(NULL, "Bad min filterin sample_3d_texture");
+ }
+ }
+ else {
+ /* magnification */
+ switch (tObj->MagFilter) {
+ case GL_NEAREST:
+ sample_3d_nearest( tObj, tObj->Image[tObj->BaseLevel], s[i], t[i], u[i], rgba[i] );
+ break;
+ case GL_LINEAR:
+ sample_3d_linear( tObj, tObj->Image[tObj->BaseLevel], s[i], t[i], u[i], rgba[i] );
+ break;
+ default:
+ gl_problem(NULL, "Bad mag filter in sample_3d_texture");
+ }
+ }
+ }
+}
+
+
+/**********************************************************************/
+/* Texture Cube Map Sampling Functions */
+/**********************************************************************/
+
+/*
+ * Choose one of six sides of a texture cube map given the texture
+ * coord (rx,ry,rz). Return pointer to corresponding array of texture
+ * images.
+ */
+static const struct gl_texture_image **
+choose_cube_face(const struct gl_texture_object *texObj,
+ GLfloat rx, GLfloat ry, GLfloat rz,
+ GLfloat *newS, GLfloat *newT)
+{
+/*
+ major axis
+ direction target sc tc ma
+ ---------- ------------------------------- --- --- ---
+ +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx
+ -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx
+ +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry
+ -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry
+ +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz
+ -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz
+*/
+ const struct gl_texture_image **imgArray;
+ const GLfloat arx = ABSF(rx), ary = ABSF(ry), arz = ABSF(rz);
+ GLfloat sc, tc, ma;
+
+ if (arx > ary && arx > arz) {
+ if (rx >= 0.0F) {
+ imgArray = (const struct gl_texture_image **) texObj->Image;
+ sc = -rz;
+ tc = -ry;
+ ma = arx;
+ }
+ else {
+ imgArray = (const struct gl_texture_image **) texObj->NegX;
+ sc = rz;
+ tc = -ry;
+ ma = arx;
+ }
+ }
+ else if (ary > arx && ary > arz) {
+ if (ry >= 0.0F) {
+ imgArray = (const struct gl_texture_image **) texObj->PosY;
+ sc = rx;
+ tc = rz;
+ ma = ary;
+ }
+ else {
+ imgArray = (const struct gl_texture_image **) texObj->NegY;
+ sc = rx;
+ tc = -rz;
+ ma = ary;
+ }
+ }
+ else {
+ if (rz > 0.0F) {
+ imgArray = (const struct gl_texture_image **) texObj->PosZ;
+ sc = rx;
+ tc = -ry;
+ ma = arz;
+ }
+ else {
+ imgArray = (const struct gl_texture_image **) texObj->NegZ;
+ sc = -rx;
+ tc = -ry;
+ ma = arz;
+ }
+ }
+
+ *newS = ( sc / ma + 1.0F ) * 0.5F;
+ *newT = ( tc / ma + 1.0F ) * 0.5F;
+ return imgArray;
+}
+
+
+static void
+sample_nearest_cube(const struct gl_texture_object *tObj, GLuint n,
+ const GLfloat s[], const GLfloat t[],
+ const GLfloat u[], const GLfloat lambda[],
+ GLchan rgba[][4])
+{
+ GLuint i;
+ (void) lambda;
+ for (i = 0; i < n; i++) {
+ const struct gl_texture_image **images;
+ GLfloat newS, newT;
+ images = choose_cube_face(tObj, s[i], t[i], u[i], &newS, &newT);
+ sample_2d_nearest( tObj, images[tObj->BaseLevel], newS, newT, rgba[i] );
+ }
+}
+
+
+static void
+sample_linear_cube(const struct gl_texture_object *tObj, GLuint n,
+ const GLfloat s[], const GLfloat t[],
+ const GLfloat u[], const GLfloat lambda[],
+ GLchan rgba[][4])
+{
+ GLuint i;
+ (void) lambda;
+ for (i = 0; i < n; i++) {
+ const struct gl_texture_image **images;
+ GLfloat newS, newT;
+ images = choose_cube_face(tObj, s[i], t[i], u[i], &newS, &newT);
+ sample_2d_linear( tObj, images[tObj->BaseLevel], newS, newT, rgba[i] );
+ }
+}
+
+
+static void
+sample_cube_nearest_mipmap_nearest( const struct gl_texture_object *tObj,
+ GLfloat s, GLfloat t, GLfloat u,
+ GLfloat lambda, GLchan rgba[4] )
+{
+ const struct gl_texture_image **images;
+ GLfloat newS, newT;
+ GLint level;
+
+ COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
+
+ images = choose_cube_face(tObj, s, t, u, &newS, &newT);
+ sample_2d_nearest( tObj, images[level], newS, newT, rgba );
+}
+
+
+static void
+sample_cube_linear_mipmap_nearest( const struct gl_texture_object *tObj,
+ GLfloat s, GLfloat t, GLfloat u,
+ GLfloat lambda, GLchan rgba[4] )
+{
+ const struct gl_texture_image **images;
+ GLfloat newS, newT;
+ GLint level;
+
+ COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
+
+ images = choose_cube_face(tObj, s, t, u, &newS, &newT);
+ sample_2d_linear( tObj, images[level], newS, newT, rgba );
+}
+
+
+static void
+sample_cube_nearest_mipmap_linear( const struct gl_texture_object *tObj,
+ GLfloat s, GLfloat t, GLfloat u,
+ GLfloat lambda, GLchan rgba[4] )
+{
+ const struct gl_texture_image **images;
+ GLfloat newS, newT;
+ GLint level;
+
+ COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
+
+ images = choose_cube_face(tObj, s, t, u, &newS, &newT);
+
+ if (level >= tObj->P) {
+ sample_2d_nearest( tObj, images[tObj->P], newS, newT, rgba );
+ }
+ else {
+ GLchan t0[4], t1[4]; /* texels */
+ const GLfloat f = myFrac(lambda);
+ sample_2d_nearest( tObj, images[level ], newS, newT, t0 );
+ sample_2d_nearest( tObj, images[level+1], newS, newT, t1 );
+ rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
+ rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
+ rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
+ rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
+ }
+}
+
+
+static void
+sample_cube_linear_mipmap_linear( const struct gl_texture_object *tObj,
+ GLfloat s, GLfloat t, GLfloat u,
+ GLfloat lambda, GLchan rgba[4] )
+{
+ const struct gl_texture_image **images;
+ GLfloat newS, newT;
+ GLint level;
+
+ COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
+
+ images = choose_cube_face(tObj, s, t, u, &newS, &newT);
+
+ if (level >= tObj->P) {
+ sample_2d_linear( tObj, images[tObj->P], newS, newT, rgba );
+ }
+ else {
+ GLchan t0[4], t1[4];
+ const GLfloat f = myFrac(lambda);
+ sample_2d_linear( tObj, images[level ], newS, newT, t0 );
+ sample_2d_linear( tObj, images[level+1], newS, newT, t1 );
+ rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
+ rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
+ rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
+ rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
+ }
+}
+
+
+static void
+sample_lambda_cube(const struct gl_texture_object *tObj, GLuint n,
+ const GLfloat s[], const GLfloat t[],
+ const GLfloat u[], const GLfloat lambda[],
+ GLchan rgba[][4])
+{
+ GLuint i;
+
+ for (i = 0; i < n; i++) {
+ if (lambda[i] > tObj->MinMagThresh) {
+ /* minification */
+ switch (tObj->MinFilter) {
+ case GL_NEAREST:
+ {
+ const struct gl_texture_image **images;
+ GLfloat newS, newT;
+ images = choose_cube_face(tObj, s[i], t[i], u[i],
+ &newS, &newT);
+ sample_2d_nearest( tObj, images[tObj->BaseLevel],
+ newS, newT, rgba[i] );
+ }
+ break;
+ case GL_LINEAR:
+ {
+ const struct gl_texture_image **images;
+ GLfloat newS, newT;
+ images = choose_cube_face(tObj, s[i], t[i], u[i],
+ &newS, &newT);
+ sample_2d_linear( tObj, images[tObj->BaseLevel],
+ newS, newT, rgba[i] );
+ }
+ break;
+ case GL_NEAREST_MIPMAP_NEAREST:
+ sample_cube_nearest_mipmap_nearest( tObj, s[i], t[i], u[i],
+ lambda[i], rgba[i] );
+ break;
+ case GL_LINEAR_MIPMAP_NEAREST:
+ sample_cube_linear_mipmap_nearest( tObj, s[i], t[i], u[i],
+ lambda[i], rgba[i] );
+ break;
+ case GL_NEAREST_MIPMAP_LINEAR:
+ sample_cube_nearest_mipmap_linear( tObj, s[i], t[i], u[i],
+ lambda[i], rgba[i] );
+ break;
+ case GL_LINEAR_MIPMAP_LINEAR:
+ sample_cube_linear_mipmap_linear( tObj, s[i], t[i], u[i],
+ lambda[i], rgba[i] );
+ break;
+ default:
+ gl_problem(NULL, "Bad min filter in sample_lambda_cube");
+ }
+ }
+ else {
+ /* magnification */
+ const struct gl_texture_image **images;
+ GLfloat newS, newT;
+ images = choose_cube_face(tObj, s[i], t[i], u[i],
+ &newS, &newT);
+ switch (tObj->MagFilter) {
+ case GL_NEAREST:
+ sample_2d_nearest( tObj, images[tObj->BaseLevel],
+ newS, newT, rgba[i] );
+ break;
+ case GL_LINEAR:
+ sample_2d_linear( tObj, images[tObj->BaseLevel],
+ newS, newT, rgba[i] );
+ break;
+ default:
+ gl_problem(NULL, "Bad mag filter in sample_lambda_cube");
+ }
+ }
+ }
+}
+
+
+/**********************************************************************/
+/* Texture Sampling Setup */
+/**********************************************************************/
+
+
+/*
+ * Setup the texture sampling function for this texture object.
+ */
+void
+_swrast_set_texture_sampler( struct gl_texture_object *t )
+{
+ if (!t->Complete) {
+ t->SampleFunc = NULL;
+ }
+ else {
+ GLboolean needLambda = (GLboolean) (t->MinFilter != t->MagFilter);
+
+ if (needLambda) {
+ /* Compute min/mag filter threshold */
+ if (t->MagFilter==GL_LINEAR
+ && (t->MinFilter==GL_NEAREST_MIPMAP_NEAREST ||
+ t->MinFilter==GL_LINEAR_MIPMAP_NEAREST)) {
+ t->MinMagThresh = 0.5F;
+ }
+ else {
+ t->MinMagThresh = 0.0F;
+ }
+ }
+
+ switch (t->Dimensions) {
+ case 1:
+ if (needLambda) {
+ t->SampleFunc = sample_lambda_1d;
+ }
+ else if (t->MinFilter==GL_LINEAR) {
+ t->SampleFunc = sample_linear_1d;
+ }
+ else {
+ ASSERT(t->MinFilter==GL_NEAREST);
+ t->SampleFunc = sample_nearest_1d;
+ }
+ break;
+ case 2:
+ if (needLambda) {
+ t->SampleFunc = sample_lambda_2d;
+ }
+ else if (t->MinFilter==GL_LINEAR) {
+ t->SampleFunc = sample_linear_2d;
+ }
+ else {
+ ASSERT(t->MinFilter==GL_NEAREST);
+ if (t->WrapS==GL_REPEAT && t->WrapT==GL_REPEAT
+ && t->Image[0]->Border==0 && t->Image[0]->Format==GL_RGB) {
+ t->SampleFunc = opt_sample_rgb_2d;
+ }
+ else if (t->WrapS==GL_REPEAT && t->WrapT==GL_REPEAT
+ && t->Image[0]->Border==0 && t->Image[0]->Format==GL_RGBA) {
+ t->SampleFunc = opt_sample_rgba_2d;
+ }
+ else
+ t->SampleFunc = sample_nearest_2d;
+ }
+ break;
+ case 3:
+ if (needLambda) {
+ t->SampleFunc = sample_lambda_3d;
+ }
+ else if (t->MinFilter==GL_LINEAR) {
+ t->SampleFunc = sample_linear_3d;
+ }
+ else {
+ ASSERT(t->MinFilter==GL_NEAREST);
+ t->SampleFunc = sample_nearest_3d;
+ }
+ break;
+ case 6: /* cube map */
+ if (needLambda) {
+ t->SampleFunc = sample_lambda_cube;
+ }
+ else if (t->MinFilter==GL_LINEAR) {
+ t->SampleFunc = sample_linear_cube;
+ }
+ else {
+ ASSERT(t->MinFilter==GL_NEAREST);
+ t->SampleFunc = sample_nearest_cube;
+ }
+ break;
+ default:
+ gl_problem(NULL, "invalid dimensions in _mesa_set_texture_sampler");
+ }
+ }
+}
+
+
+#define PROD(A,B) ( (GLuint)(A) * ((GLuint)(B)+1) )
+
+static INLINE void
+_mesa_texture_combine(const GLcontext *ctx,
+ const struct gl_texture_unit *textureUnit,
+ GLuint n,
+ GLchan (*primary_rgba)[4],
+ GLchan (*texel)[4],
+ GLchan (*rgba)[4])
+{
+ GLchan ccolor [3][3*MAX_WIDTH][4];
+ GLchan (*argRGB [3])[4];
+ GLchan (*argA [3])[4];
+ GLuint i, j;
+ const GLuint RGBshift = textureUnit->CombineScaleShiftRGB;
+ const GLuint Ashift = textureUnit->CombineScaleShiftA;
+
+ ASSERT(ctx->Extensions.EXT_texture_env_combine);
+
+ for (j = 0; j < 3; j++) {
+ switch (textureUnit->CombineSourceA[j]) {
+ case GL_TEXTURE:
+ argA[j] = texel;
+ break;
+ case GL_PRIMARY_COLOR_EXT:
+ argA[j] = primary_rgba;
+ break;
+ case GL_PREVIOUS_EXT:
+ argA[j] = rgba;
+ break;
+ case GL_CONSTANT_EXT:
+ {
+ GLchan (*c)[4] = ccolor[j];
+ GLchan alpha = FLOAT_TO_CHAN(textureUnit->EnvColor[3]);
+ for (i = 0; i < n; i++)
+ c[i][ACOMP] = alpha;
+ argA[j] = ccolor[j];
+ }
+ break;
+ default:
+ gl_problem(NULL, "invalid combine source");
+ }
+
+ switch (textureUnit->CombineSourceRGB[j]) {
+ case GL_TEXTURE:
+ argRGB[j] = texel;
+ break;
+ case GL_PRIMARY_COLOR_EXT:
+ argRGB[j] = primary_rgba;
+ break;
+ case GL_PREVIOUS_EXT:
+ argRGB[j] = rgba;
+ break;
+ case GL_CONSTANT_EXT:
+ {
+ GLchan (*c)[4] = ccolor[j];
+ const GLchan red = FLOAT_TO_CHAN(textureUnit->EnvColor[0]);
+ const GLchan green = FLOAT_TO_CHAN(textureUnit->EnvColor[1]);
+ const GLchan blue = FLOAT_TO_CHAN(textureUnit->EnvColor[2]);
+ for (i = 0; i < n; i++) {
+ c[i][RCOMP] = red;
+ c[i][GCOMP] = green;
+ c[i][BCOMP] = blue;
+ }
+ argRGB[j] = ccolor[j];
+ }
+ break;
+ default:
+ gl_problem(NULL, "invalid combine source");
+ }
+
+ if (textureUnit->CombineOperandRGB[j] != GL_SRC_COLOR) {
+ GLchan (*src)[4] = argRGB[j];
+ GLchan (*dst)[4] = ccolor[j];
+
+ argRGB[j] = ccolor[j];
+
+ if (textureUnit->CombineOperandRGB[j] == GL_ONE_MINUS_SRC_COLOR) {
+ for (i = 0; i < n; i++) {
+ dst[i][RCOMP] = CHAN_MAX - src[i][RCOMP];
+ dst[i][GCOMP] = CHAN_MAX - src[i][GCOMP];
+ dst[i][BCOMP] = CHAN_MAX - src[i][BCOMP];
+ }
+ }
+ else if (textureUnit->CombineOperandRGB[j] == GL_SRC_ALPHA) {
+ src = argA[j];
+ for (i = 0; i < n; i++) {
+ dst[i][RCOMP] = src[i][ACOMP];
+ dst[i][GCOMP] = src[i][ACOMP];
+ dst[i][BCOMP] = src[i][ACOMP];
+ }
+ }
+ else { /* GL_ONE_MINUS_SRC_ALPHA */
+ src = argA[j];
+ for (i = 0; i < n; i++) {
+ dst[i][RCOMP] = CHAN_MAX - src[i][ACOMP];
+ dst[i][GCOMP] = CHAN_MAX - src[i][ACOMP];
+ dst[i][BCOMP] = CHAN_MAX - src[i][ACOMP];
+ }
+ }
+ }
+
+ if (textureUnit->CombineOperandA[j] == GL_ONE_MINUS_SRC_ALPHA) {
+ GLchan (*src)[4] = argA[j];
+ GLchan (*dst)[4] = ccolor[j];
+ argA[j] = ccolor[j];
+ for (i = 0; i < n; i++) {
+ dst[i][ACOMP] = CHAN_MAX - src[i][ACOMP];
+ }
+ }
+
+ if (textureUnit->CombineModeRGB == GL_REPLACE &&
+ textureUnit->CombineModeA == GL_REPLACE) {
+ break; /* done, we need only arg0 */
+ }
+
+ if (j == 1 &&
+ textureUnit->CombineModeRGB != GL_INTERPOLATE_EXT &&
+ textureUnit->CombineModeA != GL_INTERPOLATE_EXT) {
+ break; /* arg0 and arg1 are done. we don't need arg2. */
+ }
+ }
+
+ switch (textureUnit->CombineModeRGB) {
+ case GL_REPLACE:
+ {
+ const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
+ if (RGBshift) {
+ for (i = 0; i < n; i++) {
+ GLuint r = (GLuint) arg0[i][RCOMP] << RGBshift;
+ GLuint g = (GLuint) arg0[i][GCOMP] << RGBshift;
+ GLuint b = (GLuint) arg0[i][BCOMP] << RGBshift;
+ rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
+ rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
+ rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
+ }
+ }
+ else {
+ for (i = 0; i < n; i++) {
+ rgba[i][RCOMP] = arg0[i][RCOMP];
+ rgba[i][GCOMP] = arg0[i][GCOMP];
+ rgba[i][BCOMP] = arg0[i][BCOMP];
+ }
+ }
+ }
+ break;
+ case GL_MODULATE:
+ {
+ const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
+ const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
+ const GLint shift = 8 - RGBshift;
+ for (i = 0; i < n; i++) {
+ GLuint r = PROD(arg0[i][0], arg1[i][RCOMP]) >> shift;
+ GLuint g = PROD(arg0[i][1], arg1[i][GCOMP]) >> shift;
+ GLuint b = PROD(arg0[i][2], arg1[i][BCOMP]) >> shift;
+ rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
+ rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
+ rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
+ }
+ }
+ break;
+ case GL_ADD:
+ {
+ const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
+ const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
+ for (i = 0; i < n; i++) {
+ GLint r = ((GLint) arg0[i][RCOMP] + (GLint) arg1[i][RCOMP]) << RGBshift;
+ GLint g = ((GLint) arg0[i][GCOMP] + (GLint) arg1[i][GCOMP]) << RGBshift;
+ GLint b = ((GLint) arg0[i][BCOMP] + (GLint) arg1[i][BCOMP]) << RGBshift;
+ rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
+ rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
+ rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
+ }
+ }
+ break;
+ case GL_ADD_SIGNED_EXT:
+ {
+ const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
+ const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
+ for (i = 0; i < n; i++) {
+ GLint r = (GLint) arg0[i][RCOMP] + (GLint) arg1[i][RCOMP] - 128;
+ GLint g = (GLint) arg0[i][GCOMP] + (GLint) arg1[i][GCOMP] - 128;
+ GLint b = (GLint) arg0[i][BCOMP] + (GLint) arg1[i][BCOMP] - 128;
+ r = (r < 0) ? 0 : r << RGBshift;
+ g = (g < 0) ? 0 : g << RGBshift;
+ b = (b < 0) ? 0 : b << RGBshift;
+ rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
+ rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
+ rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
+ }
+ }
+ break;
+ case GL_INTERPOLATE_EXT:
+ {
+ const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
+ const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
+ const GLchan (*arg2)[4] = (const GLchan (*)[4]) argRGB[2];
+ const GLint shift = 8 - RGBshift;
+ for (i = 0; i < n; i++) {
+ GLuint r = (PROD(arg0[i][RCOMP], arg2[i][RCOMP])
+ + PROD(arg1[i][RCOMP], CHAN_MAX - arg2[i][RCOMP]))
+ >> shift;
+ GLuint g = (PROD(arg0[i][GCOMP], arg2[i][GCOMP])
+ + PROD(arg1[i][GCOMP], CHAN_MAX - arg2[i][GCOMP]))
+ >> shift;
+ GLuint b = (PROD(arg0[i][BCOMP], arg2[i][BCOMP])
+ + PROD(arg1[i][BCOMP], CHAN_MAX - arg2[i][BCOMP]))
+ >> shift;
+ rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
+ rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
+ rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
+ }
+ }
+ break;
+ default:
+ gl_problem(NULL, "invalid combine mode");
+ }
+
+ switch (textureUnit->CombineModeA) {
+ case GL_REPLACE:
+ {
+ const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
+ if (Ashift) {
+ for (i = 0; i < n; i++) {
+ GLuint a = (GLuint) arg0[i][ACOMP] << Ashift;
+ rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
+ }
+ }
+ else {
+ for (i = 0; i < n; i++) {
+ rgba[i][ACOMP] = arg0[i][ACOMP];
+ }
+ }
+ }
+ break;
+ case GL_MODULATE:
+ {
+ const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
+ const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
+ const GLint shift = 8 - Ashift;
+ for (i = 0; i < n; i++) {
+ GLuint a = (PROD(arg0[i][ACOMP], arg1[i][ACOMP]) >> shift);
+ rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
+ }
+ }
+ break;
+ case GL_ADD:
+ {
+ const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
+ const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
+ for (i = 0; i < n; i++) {
+ GLint a = ((GLint) arg0[i][ACOMP] + arg1[i][ACOMP]) << Ashift;
+ rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
+ }
+ }
+ break;
+ case GL_ADD_SIGNED_EXT:
+ {
+ const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
+ const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
+ for (i = 0; i < n; i++) {
+ GLint a = (GLint) arg0[i][ACOMP] + (GLint) arg1[i][ACOMP] - 128;
+ a = (a < 0) ? 0 : a << Ashift;
+ rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
+ }
+ }
+ break;
+ case GL_INTERPOLATE_EXT:
+ {
+ const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
+ const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
+ const GLchan (*arg2)[4] = (const GLchan (*)[4]) argA[2];
+ const GLint shift = 8 - Ashift;
+ for (i=0; i<n; i++) {
+ GLuint a = (PROD(arg0[i][ACOMP], arg2[i][ACOMP])
+ + PROD(arg1[i][ACOMP], CHAN_MAX - arg2[i][ACOMP]))
+ >> shift;
+ rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
+ }
+ }
+ break;
+ default:
+ gl_problem(NULL, "invalid combine mode");
+ }
+}
+#undef PROD
+
+
+
+/**********************************************************************/
+/* Texture Application */
+/**********************************************************************/
+
+
+/*
+ * Combine incoming fragment color with texel color to produce output color.
+ * Input: textureUnit - pointer to texture unit to apply
+ * format - base internal texture format
+ * n - number of fragments
+ * primary_rgba - primary colors (may be rgba for single texture)
+ * texels - array of texel colors
+ * InOut: rgba - incoming fragment colors modified by texel colors
+ * according to the texture environment mode.
+ */
+static void
+apply_texture( const GLcontext *ctx,
+ const struct gl_texture_unit *texUnit,
+ GLuint n,
+ GLchan primary_rgba[][4], GLchan texel[][4],
+ GLchan rgba[][4] )
+{
+ GLint baseLevel;
+ GLuint i;
+ GLint Rc, Gc, Bc, Ac;
+ GLenum format;
+
+ ASSERT(texUnit);
+ ASSERT(texUnit->Current);
+
+ baseLevel = texUnit->Current->BaseLevel;
+ ASSERT(texUnit->Current->Image[baseLevel]);
+
+ format = texUnit->Current->Image[baseLevel]->Format;
+
+ if (format==GL_COLOR_INDEX) {
+ format = GL_RGBA; /* XXXX a hack! */
+ }
+
+ switch (texUnit->EnvMode) {
+ case GL_REPLACE:
+ switch (format) {
+ case GL_ALPHA:
+ for (i=0;i<n;i++) {
+ /* Cv = Cf */
+ /* Av = At */
+ rgba[i][ACOMP] = texel[i][ACOMP];
+ }
+ break;
+ case GL_LUMINANCE:
+ for (i=0;i<n;i++) {
+ /* Cv = Lt */
+ GLchan Lt = texel[i][RCOMP];
+ rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = Lt;
+ /* Av = Af */
+ }
+ break;
+ case GL_LUMINANCE_ALPHA:
+ for (i=0;i<n;i++) {
+ GLchan Lt = texel[i][RCOMP];
+ /* Cv = Lt */
+ rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = Lt;
+ /* Av = At */
+ rgba[i][ACOMP] = texel[i][ACOMP];
+ }
+ break;
+ case GL_INTENSITY:
+ for (i=0;i<n;i++) {
+ /* Cv = It */
+ GLchan It = texel[i][RCOMP];
+ rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = It;
+ /* Av = It */
+ rgba[i][ACOMP] = It;
+ }
+ break;
+ case GL_RGB:
+ for (i=0;i<n;i++) {
+ /* Cv = Ct */
+ rgba[i][RCOMP] = texel[i][RCOMP];
+ rgba[i][GCOMP] = texel[i][GCOMP];
+ rgba[i][BCOMP] = texel[i][BCOMP];
+ /* Av = Af */
+ }
+ break;
+ case GL_RGBA:
+ for (i=0;i<n;i++) {
+ /* Cv = Ct */
+ rgba[i][RCOMP] = texel[i][RCOMP];
+ rgba[i][GCOMP] = texel[i][GCOMP];
+ rgba[i][BCOMP] = texel[i][BCOMP];
+ /* Av = At */
+ rgba[i][ACOMP] = texel[i][ACOMP];
+ }
+ break;
+ default:
+ gl_problem(ctx, "Bad format (GL_REPLACE) in apply_texture");
+ return;
+ }
+ break;
+
+ case GL_MODULATE:
+ switch (format) {
+ case GL_ALPHA:
+ for (i=0;i<n;i++) {
+ /* Cv = Cf */
+ /* Av = AfAt */
+ rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], texel[i][ACOMP] );
+ }
+ break;
+ case GL_LUMINANCE:
+ for (i=0;i<n;i++) {
+ /* Cv = LtCf */
+ GLchan Lt = texel[i][RCOMP];
+ rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], Lt );
+ rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], Lt );
+ rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], Lt );
+ /* Av = Af */
+ }
+ break;
+ case GL_LUMINANCE_ALPHA:
+ for (i=0;i<n;i++) {
+ /* Cv = CfLt */
+ GLchan Lt = texel[i][RCOMP];
+ rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], Lt );
+ rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], Lt );
+ rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], Lt );
+ /* Av = AfAt */
+ rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], texel[i][ACOMP] );
+ }
+ break;
+ case GL_INTENSITY:
+ for (i=0;i<n;i++) {
+ /* Cv = CfIt */
+ GLchan It = texel[i][RCOMP];
+ rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], It );
+ rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], It );
+ rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], It );
+ /* Av = AfIt */
+ rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], It );
+ }
+ break;
+ case GL_RGB:
+ for (i=0;i<n;i++) {
+ /* Cv = CfCt */
+ rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], texel[i][RCOMP] );
+ rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], texel[i][GCOMP] );
+ rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], texel[i][BCOMP] );
+ /* Av = Af */
+ }
+ break;
+ case GL_RGBA:
+ for (i=0;i<n;i++) {
+ /* Cv = CfCt */
+ rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], texel[i][RCOMP] );
+ rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], texel[i][GCOMP] );
+ rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], texel[i][BCOMP] );
+ /* Av = AfAt */
+ rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], texel[i][ACOMP] );
+ }
+ break;
+ default:
+ gl_problem(ctx, "Bad format (GL_MODULATE) in apply_texture");
+ return;
+ }
+ break;
+
+ case GL_DECAL:
+ switch (format) {
+ case GL_ALPHA:
+ case GL_LUMINANCE:
+ case GL_LUMINANCE_ALPHA:
+ case GL_INTENSITY:
+ /* undefined */
+ break;
+ case GL_RGB:
+ for (i=0;i<n;i++) {
+ /* Cv = Ct */
+ rgba[i][RCOMP] = texel[i][RCOMP];
+ rgba[i][GCOMP] = texel[i][GCOMP];
+ rgba[i][BCOMP] = texel[i][BCOMP];
+ /* Av = Af */
+ }
+ break;
+ case GL_RGBA:
+ for (i=0;i<n;i++) {
+ /* Cv = Cf(1-At) + CtAt */
+ GLint t = texel[i][ACOMP], s = CHAN_MAX - t;
+ rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(texel[i][RCOMP],t);
+ rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(texel[i][GCOMP],t);
+ rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(texel[i][BCOMP],t);
+ /* Av = Af */
+ }
+ break;
+ default:
+ gl_problem(ctx, "Bad format (GL_DECAL) in apply_texture");
+ return;
+ }
+ break;
+
+ case GL_BLEND:
+ Rc = (GLint) (texUnit->EnvColor[0] * CHAN_MAXF);
+ Gc = (GLint) (texUnit->EnvColor[1] * CHAN_MAXF);
+ Bc = (GLint) (texUnit->EnvColor[2] * CHAN_MAXF);
+ Ac = (GLint) (texUnit->EnvColor[3] * CHAN_MAXF);
+ switch (format) {
+ case GL_ALPHA:
+ for (i=0;i<n;i++) {
+ /* Cv = Cf */
+ /* Av = AfAt */
+ rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
+ }
+ break;
+ case GL_LUMINANCE:
+ for (i=0;i<n;i++) {
+ /* Cv = Cf(1-Lt) + CcLt */
+ GLchan Lt = texel[i][RCOMP], s = CHAN_MAX - Lt;
+ rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(Rc, Lt);
+ rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(Gc, Lt);
+ rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(Bc, Lt);
+ /* Av = Af */
+ }
+ break;
+ case GL_LUMINANCE_ALPHA:
+ for (i=0;i<n;i++) {
+ /* Cv = Cf(1-Lt) + CcLt */
+ GLchan Lt = texel[i][RCOMP], s = CHAN_MAX - Lt;
+ rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(Rc, Lt);
+ rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(Gc, Lt);
+ rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(Bc, Lt);
+ /* Av = AfAt */
+ rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP],texel[i][ACOMP]);
+ }
+ break;
+ case GL_INTENSITY:
+ for (i=0;i<n;i++) {
+ /* Cv = Cf(1-It) + CcLt */
+ GLchan It = texel[i][RCOMP], s = CHAN_MAX - It;
+ rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(Rc, It);
+ rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(Gc, It);
+ rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(Bc, It);
+ /* Av = Af(1-It) + Ac*It */
+ rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], s) + CHAN_PRODUCT(Ac, It);
+ }
+ break;
+ case GL_RGB:
+ for (i=0;i<n;i++) {
+ /* Cv = Cf(1-Ct) + CcCt */
+ rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], (CHAN_MAX-texel[i][RCOMP])) + CHAN_PRODUCT(Rc,texel[i][RCOMP]);
+ rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], (CHAN_MAX-texel[i][GCOMP])) + CHAN_PRODUCT(Gc,texel[i][GCOMP]);
+ rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], (CHAN_MAX-texel[i][BCOMP])) + CHAN_PRODUCT(Bc,texel[i][BCOMP]);
+ /* Av = Af */
+ }
+ break;
+ case GL_RGBA:
+ for (i=0;i<n;i++) {
+ /* Cv = Cf(1-Ct) + CcCt */
+ rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], (CHAN_MAX-texel[i][RCOMP])) + CHAN_PRODUCT(Rc,texel[i][RCOMP]);
+ rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], (CHAN_MAX-texel[i][GCOMP])) + CHAN_PRODUCT(Gc,texel[i][GCOMP]);
+ rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], (CHAN_MAX-texel[i][BCOMP])) + CHAN_PRODUCT(Bc,texel[i][BCOMP]);
+ /* Av = AfAt */
+ rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP],texel[i][ACOMP]);
+ }
+ break;
+ default:
+ gl_problem(ctx, "Bad format (GL_BLEND) in apply_texture");
+ return;
+ }
+ break;
+
+ case GL_ADD: /* GL_EXT_texture_add_env */
+ switch (format) {
+ case GL_ALPHA:
+ for (i=0;i<n;i++) {
+ /* Rv = Rf */
+ /* Gv = Gf */
+ /* Bv = Bf */
+ rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
+ }
+ break;
+ case GL_LUMINANCE:
+ for (i=0;i<n;i++) {
+ GLuint Lt = texel[i][RCOMP];
+ GLuint r = rgba[i][RCOMP] + Lt;
+ GLuint g = rgba[i][GCOMP] + Lt;
+ GLuint b = rgba[i][BCOMP] + Lt;
+ rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
+ rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
+ rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
+ /* Av = Af */
+ }
+ break;
+ case GL_LUMINANCE_ALPHA:
+ for (i=0;i<n;i++) {
+ GLuint Lt = texel[i][RCOMP];
+ GLuint r = rgba[i][RCOMP] + Lt;
+ GLuint g = rgba[i][GCOMP] + Lt;
+ GLuint b = rgba[i][BCOMP] + Lt;
+ rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
+ rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
+ rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
+ rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
+ }
+ break;
+ case GL_INTENSITY:
+ for (i=0;i<n;i++) {
+ GLchan It = texel[i][RCOMP];
+ GLuint r = rgba[i][RCOMP] + It;
+ GLuint g = rgba[i][GCOMP] + It;
+ GLuint b = rgba[i][BCOMP] + It;
+ GLuint a = rgba[i][ACOMP] + It;
+ rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
+ rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
+ rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
+ rgba[i][ACOMP] = MIN2(a, CHAN_MAX);
+ }
+ break;
+ case GL_RGB:
+ for (i=0;i<n;i++) {
+ GLuint r = rgba[i][RCOMP] + texel[i][RCOMP];
+ GLuint g = rgba[i][GCOMP] + texel[i][GCOMP];
+ GLuint b = rgba[i][BCOMP] + texel[i][BCOMP];
+ rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
+ rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
+ rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
+ /* Av = Af */
+ }
+ break;
+ case GL_RGBA:
+ for (i=0;i<n;i++) {
+ GLuint r = rgba[i][RCOMP] + texel[i][RCOMP];
+ GLuint g = rgba[i][GCOMP] + texel[i][GCOMP];
+ GLuint b = rgba[i][BCOMP] + texel[i][BCOMP];
+ rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
+ rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
+ rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
+ rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
+ }
+ break;
+ default:
+ gl_problem(ctx, "Bad format (GL_ADD) in apply_texture");
+ return;
+ }
+ break;
+
+ case GL_COMBINE_EXT: /* GL_EXT_combine_ext; we modify texel array */
+ switch (format) {
+ case GL_ALPHA:
+ for (i=0;i<n;i++)
+ texel[i][RCOMP] = texel[i][GCOMP] = texel[i][BCOMP] = 0;
+ break;
+ case GL_LUMINANCE:
+ for (i=0;i<n;i++) {
+ /* Cv = Lt */
+ GLchan Lt = texel[i][RCOMP];
+ texel[i][GCOMP] = texel[i][BCOMP] = Lt;
+ /* Av = 1 */
+ texel[i][ACOMP] = CHAN_MAX;
+ }
+ break;
+ case GL_LUMINANCE_ALPHA:
+ for (i=0;i<n;i++) {
+ GLchan Lt = texel[i][RCOMP];
+ /* Cv = Lt */
+ texel[i][GCOMP] = texel[i][BCOMP] = Lt;
+ }
+ break;
+ case GL_INTENSITY:
+ for (i=0;i<n;i++) {
+ /* Cv = It */
+ GLchan It = texel[i][RCOMP];
+ texel[i][GCOMP] = texel[i][BCOMP] = It;
+ /* Av = It */
+ texel[i][ACOMP] = It;
+ }
+ break;
+ case GL_RGB:
+ for (i=0;i<n;i++) {
+ /* Av = 1 */
+ texel[i][ACOMP] = CHAN_MAX;
+ }
+ break;
+ case GL_RGBA: /* do nothing. */
+ break;
+ default:
+ gl_problem(ctx, "Bad format in apply_texture (GL_COMBINE_EXT)");
+ return;
+ }
+ _mesa_texture_combine(ctx, texUnit, n, primary_rgba, texel, rgba);
+ break;
+
+ default:
+ gl_problem(ctx, "Bad env mode in apply_texture");
+ return;
+ }
+}
+
+
+
+/*
+ * Apply a unit of texture mapping to the incoming fragments.
+ */
+void gl_texture_pixels( GLcontext *ctx, GLuint texUnit, GLuint n,
+ const GLfloat s[], const GLfloat t[],
+ const GLfloat r[], GLfloat lambda[],
+ GLchan primary_rgba[][4], GLchan rgba[][4] )
+{
+ const GLuint mask = TEXTURE0_ANY << (texUnit * 4);
+
+ if (ctx->Texture.ReallyEnabled & mask) {
+ const struct gl_texture_unit *textureUnit = &ctx->Texture.Unit[texUnit];
+
+ if (textureUnit->Current && textureUnit->Current->SampleFunc) {
+ GLchan texel[PB_SIZE][4];
+
+ if (textureUnit->LodBias != 0.0F) {
+ /* apply LOD bias, but don't clamp yet */
+ GLuint i;
+ for (i=0;i<n;i++) {
+ lambda[i] += textureUnit->LodBias;
+ }
+ }
+
+ if (textureUnit->Current->MinLod != -1000.0
+ || textureUnit->Current->MaxLod != 1000.0) {
+ /* apply LOD clamping to lambda */
+ GLfloat min = textureUnit->Current->MinLod;
+ GLfloat max = textureUnit->Current->MaxLod;
+ GLuint i;
+ for (i=0;i<n;i++) {
+ GLfloat l = lambda[i];
+ lambda[i] = CLAMP(l, min, max);
+ }
+ }
+
+ /* fetch texture images from device driver, if needed */
+ if (ctx->Driver.GetTexImage) {
+ if (!_mesa_get_teximages_from_driver(ctx, textureUnit->Current)) {
+ return;
+ }
+ }
+
+ /* Sample the texture. */
+ (*textureUnit->Current->SampleFunc)( textureUnit->Current, n,
+ s, t, r, lambda, texel );
+
+ apply_texture( ctx, textureUnit, n, primary_rgba, texel, rgba );
+ }
+ }
+}
diff --git a/src/mesa/swrast/s_texture.h b/src/mesa/swrast/s_texture.h
new file mode 100644
index 0000000000..8bb5662333
--- /dev/null
+++ b/src/mesa/swrast/s_texture.h
@@ -0,0 +1,46 @@
+/* $Id: s_texture.h,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.
+ */
+
+
+
+
+
+#ifndef S_TEXTURE_H
+#define S_TEXTURE_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+extern void gl_texture_pixels( GLcontext *ctx, GLuint texSet, GLuint n,
+ const GLfloat s[], const GLfloat t[],
+ const GLfloat r[], GLfloat lambda[],
+ GLchan primary_rgba[][4], GLchan rgba[][4] );
+
+
+#endif
+
diff --git a/src/mesa/swrast/s_triangle.c b/src/mesa/swrast/s_triangle.c
new file mode 100644
index 0000000000..4b00d8aff9
--- /dev/null
+++ b/src/mesa/swrast/s_triangle.c
@@ -0,0 +1,2448 @@
+/* $Id: s_triangle.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.
+ */
+
+
+/*
+ * Triangle rasterizers
+ * When the device driver doesn't implement triangle rasterization Mesa
+ * will use these functions to draw triangles.
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "feedback.h"
+#include "macros.h"
+#include "mem.h"
+#include "mmath.h"
+#include "teximage.h"
+#include "texstate.h"
+
+#include "s_aatriangle.h"
+#include "s_depth.h"
+#include "s_span.h"
+
+static GLboolean cull_triangle( GLcontext *ctx,
+ GLuint v0, GLuint v1, GLuint v2, GLuint pv )
+{
+ struct vertex_buffer *VB = ctx->VB;
+ GLfloat (*win)[4] = VB->Win.data;
+ GLfloat ex = win[v1][0] - win[v0][0];
+ GLfloat ey = win[v1][1] - win[v0][1];
+ GLfloat fx = win[v2][0] - win[v0][0];
+ GLfloat fy = win[v2][1] - win[v0][1];
+ GLfloat c = ex*fy-ey*fx;
+
+ if (c * ctx->backface_sign > 0)
+ return 0;
+
+ return 1;
+}
+
+
+/*
+ * Render a flat-shaded color index triangle.
+ */
+static void flat_ci_triangle( GLcontext *ctx,
+ GLuint v0, GLuint v1, GLuint v2, GLuint pv )
+{
+#define INTERP_Z 1
+#define SETUP_CODE \
+ GLuint index = VB->IndexPtr->data[pv]; \
+ if (1) { \
+ /* set the color index */ \
+ (*ctx->Driver.Index)( ctx, index ); \
+ }
+
+#define INNER_LOOP( LEFT, RIGHT, Y ) \
+ { \
+ const GLint n = RIGHT-LEFT; \
+ GLint i; \
+ GLdepth zspan[MAX_WIDTH]; \
+ GLfixed fogspan[MAX_WIDTH]; \
+ if (n>0) { \
+ for (i=0;i<n;i++) { \
+ zspan[i] = FixedToDepth(ffz); \
+ ffz += fdzdx; \
+ fogspan[i] = fffog / 256; \
+ fffog += fdfogdx; \
+ } \
+ gl_write_monoindex_span( ctx, n, LEFT, Y, zspan, \
+ fogspan, index, GL_POLYGON ); \
+ } \
+ }
+
+#include "s_tritemp.h"
+}
+
+
+
+/*
+ * Render a smooth-shaded color index triangle.
+ */
+static void smooth_ci_triangle( GLcontext *ctx,
+ GLuint v0, GLuint v1, GLuint v2, GLuint pv )
+{
+ (void) pv;
+#define INTERP_Z 1
+#define INTERP_INDEX 1
+
+#define INNER_LOOP( LEFT, RIGHT, Y ) \
+ { \
+ const GLint n = RIGHT-LEFT; \
+ GLint i; \
+ GLdepth zspan[MAX_WIDTH]; \
+ GLfixed fogspan[MAX_WIDTH]; \
+ GLuint index[MAX_WIDTH]; \
+ if (n>0) { \
+ for (i=0;i<n;i++) { \
+ zspan[i] = FixedToDepth(ffz); \
+ ffz += fdzdx; \
+ index[i] = FixedToInt(ffi); \
+ ffi += fdidx; \
+ fogspan[i] = fffog / 256; \
+ fffog += fdfogdx; \
+ } \
+ gl_write_index_span( ctx, n, LEFT, Y, zspan, fogspan, \
+ index, GL_POLYGON ); \
+ } \
+ }
+
+#include "s_tritemp.h"
+}
+
+
+
+/*
+ * Render a flat-shaded RGBA triangle.
+ */
+static void flat_rgba_triangle( GLcontext *ctx,
+ GLuint v0, GLuint v1, GLuint v2, GLuint pv )
+{
+#define INTERP_Z 1
+#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
+
+#define SETUP_CODE \
+ if (1) { \
+ /* set the color */ \
+ GLchan r = VB->ColorPtr->data[pv][0]; \
+ GLchan g = VB->ColorPtr->data[pv][1]; \
+ GLchan b = VB->ColorPtr->data[pv][2]; \
+ GLchan a = VB->ColorPtr->data[pv][3]; \
+ (*ctx->Driver.Color)( ctx, r, g, b, a ); \
+ }
+
+#define INNER_LOOP( LEFT, RIGHT, Y ) \
+ { \
+ const GLint n = RIGHT-LEFT; \
+ GLint i; \
+ GLdepth zspan[MAX_WIDTH]; \
+ GLfixed fogspan[MAX_WIDTH]; \
+ if (n>0) { \
+ for (i=0;i<n;i++) { \
+ zspan[i] = FixedToDepth(ffz); \
+ ffz += fdzdx; \
+ fogspan[i] = fffog / 256; \
+ fffog += fdfogdx; \
+ } \
+ gl_write_monocolor_span( ctx, n, LEFT, Y, zspan, \
+ fogspan, \
+ VB->ColorPtr->data[pv], \
+ GL_POLYGON ); \
+ } \
+ }
+
+#include "s_tritemp.h"
+
+ ASSERT(!ctx->Texture.ReallyEnabled); /* texturing must be off */
+ ASSERT(ctx->Light.ShadeModel==GL_FLAT);
+}
+
+
+
+/*
+ * Render a smooth-shaded RGBA triangle.
+ */
+static void smooth_rgba_triangle( GLcontext *ctx,
+ GLuint v0, GLuint v1, GLuint v2, GLuint pv )
+{
+ (void) pv;
+#define INTERP_Z 1
+#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+
+#define INNER_LOOP( LEFT, RIGHT, Y ) \
+ { \
+ const GLint n = RIGHT-LEFT; \
+ GLint i; \
+ GLdepth zspan[MAX_WIDTH]; \
+ GLchan rgba[MAX_WIDTH][4]; \
+ GLfixed fogspan[MAX_WIDTH]; \
+ if (n>0) { \
+ for (i=0;i<n;i++) { \
+ zspan[i] = FixedToDepth(ffz); \
+ rgba[i][RCOMP] = FixedToInt(ffr); \
+ rgba[i][GCOMP] = FixedToInt(ffg); \
+ rgba[i][BCOMP] = FixedToInt(ffb); \
+ rgba[i][ACOMP] = FixedToInt(ffa); \
+ fogspan[i] = fffog / 256; \
+ fffog += fdfogdx; \
+ ffz += fdzdx; \
+ ffr += fdrdx; \
+ ffg += fdgdx; \
+ ffb += fdbdx; \
+ ffa += fdadx; \
+ } \
+ gl_write_rgba_span( ctx, n, LEFT, Y, \
+ (CONST GLdepth *) zspan, \
+ fogspan, \
+ rgba, GL_POLYGON ); \
+ } \
+ }
+
+#include "s_tritemp.h"
+
+ ASSERT(!ctx->Texture.ReallyEnabled); /* texturing must be off */
+ ASSERT(ctx->Light.ShadeModel==GL_SMOOTH);
+}
+
+
+/*
+ * Render an RGB, GL_DECAL, textured triangle.
+ * Interpolate S,T only w/out mipmapping or perspective correction.
+ *
+ * No fog.
+ */
+static void simple_textured_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
+ GLuint v2, GLuint pv )
+{
+#define INTERP_INT_TEX 1
+#define S_SCALE twidth
+#define T_SCALE theight
+#define SETUP_CODE \
+ struct gl_texture_object *obj = ctx->Texture.Unit[0].CurrentD[2]; \
+ GLint b = obj->BaseLevel; \
+ GLfloat twidth = (GLfloat) obj->Image[b]->Width; \
+ GLfloat theight = (GLfloat) obj->Image[b]->Height; \
+ GLint twidth_log2 = obj->Image[b]->WidthLog2; \
+ GLchan *texture = obj->Image[b]->Data; \
+ GLint smask = obj->Image[b]->Width - 1; \
+ GLint tmask = obj->Image[b]->Height - 1; \
+ (void) pv; \
+ if (!texture) { \
+ if (!_mesa_get_teximages_from_driver(ctx, obj)) \
+ return; \
+ texture = obj->Image[b]->Data; \
+ ASSERT(texture); \
+ }
+
+#define INNER_LOOP( LEFT, RIGHT, Y ) \
+ { \
+ CONST GLint n = RIGHT-LEFT; \
+ GLint i; \
+ GLchan rgb[MAX_WIDTH][3]; \
+ if (n>0) { \
+ ffs -= FIXED_HALF; /* off-by-one error? */ \
+ fft -= FIXED_HALF; \
+ for (i=0;i<n;i++) { \
+ GLint s = FixedToInt(ffs) & smask; \
+ GLint t = FixedToInt(fft) & tmask; \
+ GLint pos = (t << twidth_log2) + s; \
+ pos = pos + pos + pos; /* multiply by 3 */ \
+ rgb[i][RCOMP] = texture[pos]; \
+ rgb[i][GCOMP] = texture[pos+1]; \
+ rgb[i][BCOMP] = texture[pos+2]; \
+ ffs += fdsdx; \
+ fft += fdtdx; \
+ } \
+ (*ctx->Driver.WriteRGBSpan)( ctx, n, LEFT, Y, \
+ (CONST GLchan (*)[3]) rgb, NULL ); \
+ } \
+ }
+
+#include "s_tritemp.h"
+}
+
+
+/*
+ * Render an RGB, GL_DECAL, textured triangle.
+ * Interpolate S,T, GL_LESS depth test, w/out mipmapping or
+ * perspective correction.
+ *
+ * No fog.
+ */
+static void simple_z_textured_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
+ GLuint v2, GLuint pv )
+{
+#define INTERP_Z 1
+#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
+#define INTERP_INT_TEX 1
+#define S_SCALE twidth
+#define T_SCALE theight
+#define SETUP_CODE \
+ struct gl_texture_object *obj = ctx->Texture.Unit[0].CurrentD[2]; \
+ GLint b = obj->BaseLevel; \
+ GLfloat twidth = (GLfloat) obj->Image[b]->Width; \
+ GLfloat theight = (GLfloat) obj->Image[b]->Height; \
+ GLint twidth_log2 = obj->Image[b]->WidthLog2; \
+ GLchan *texture = obj->Image[b]->Data; \
+ GLint smask = obj->Image[b]->Width - 1; \
+ GLint tmask = obj->Image[b]->Height - 1; \
+ (void) pv; \
+ if (!texture) { \
+ if (!_mesa_get_teximages_from_driver(ctx, obj)) \
+ return; \
+ texture = obj->Image[b]->Data; \
+ ASSERT(texture); \
+ }
+
+#define INNER_LOOP( LEFT, RIGHT, Y ) \
+ { \
+ CONST GLint n = RIGHT-LEFT; \
+ GLint i; \
+ GLchan rgb[MAX_WIDTH][3]; \
+ GLubyte mask[MAX_WIDTH]; \
+ (void) fffog; \
+ if (n>0) { \
+ ffs -= FIXED_HALF; /* off-by-one error? */ \
+ fft -= FIXED_HALF; \
+ for (i=0;i<n;i++) { \
+ GLdepth z = FixedToDepth(ffz); \
+ if (z < zRow[i]) { \
+ GLint s = FixedToInt(ffs) & smask; \
+ GLint t = FixedToInt(fft) & tmask; \
+ GLint pos = (t << twidth_log2) + s; \
+ pos = pos + pos + pos; /* multiply by 3 */ \
+ rgb[i][RCOMP] = texture[pos]; \
+ rgb[i][GCOMP] = texture[pos+1]; \
+ rgb[i][BCOMP] = texture[pos+2]; \
+ zRow[i] = z; \
+ mask[i] = 1; \
+ } \
+ else { \
+ mask[i] = 0; \
+ } \
+ ffz += fdzdx; \
+ ffs += fdsdx; \
+ fft += fdtdx; \
+ } \
+ (*ctx->Driver.WriteRGBSpan)( ctx, n, LEFT, Y, \
+ (CONST GLchan (*)[3]) rgb, mask ); \
+ } \
+ }
+
+#include "s_tritemp.h"
+}
+
+
+
+/*
+ * Render an RGB/RGBA textured triangle without perspective correction.
+ */
+static void affine_textured_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
+ GLuint v2, GLuint pv )
+{
+#define INTERP_Z 1
+#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+#define INTERP_INT_TEX 1
+#define S_SCALE twidth
+#define T_SCALE theight
+#define SETUP_CODE \
+ struct gl_texture_unit *unit = ctx->Texture.Unit+0; \
+ struct gl_texture_object *obj = unit->CurrentD[2]; \
+ GLint b = obj->BaseLevel; \
+ GLfloat twidth = (GLfloat) obj->Image[b]->Width; \
+ GLfloat theight = (GLfloat) obj->Image[b]->Height; \
+ GLint twidth_log2 = obj->Image[b]->WidthLog2; \
+ GLchan *texture = obj->Image[b]->Data; \
+ GLint smask = obj->Image[b]->Width - 1; \
+ GLint tmask = obj->Image[b]->Height - 1; \
+ GLint format = obj->Image[b]->Format; \
+ GLint filter = obj->MinFilter; \
+ GLint envmode = unit->EnvMode; \
+ GLint comp, tbytesline, tsize; \
+ GLfixed er, eg, eb, ea; \
+ GLint tr, tg, tb, ta; \
+ if (!texture) { \
+ if (!_mesa_get_teximages_from_driver(ctx, obj)) \
+ return; \
+ texture = obj->Image[b]->Data; \
+ ASSERT(texture); \
+ } \
+ if (envmode == GL_BLEND || envmode == GL_ADD) { \
+ /* potential off-by-one error here? (1.0f -> 2048 -> 0) */ \
+ er = FloatToFixed(unit->EnvColor[0]); \
+ eg = FloatToFixed(unit->EnvColor[1]); \
+ eb = FloatToFixed(unit->EnvColor[2]); \
+ ea = FloatToFixed(unit->EnvColor[3]); \
+ } \
+ switch (format) { \
+ case GL_ALPHA: \
+ case GL_LUMINANCE: \
+ case GL_INTENSITY: \
+ comp = 1; \
+ break; \
+ case GL_LUMINANCE_ALPHA: \
+ comp = 2; \
+ break; \
+ case GL_RGB: \
+ comp = 3; \
+ break; \
+ case GL_RGBA: \
+ comp = 4; \
+ break; \
+ default: \
+ gl_problem(NULL, "Bad texture format in affine_texture_triangle");\
+ return; \
+ } \
+ tbytesline = obj->Image[b]->Width * comp; \
+ tsize = theight * tbytesline;
+ (void) pv;
+
+ /* Instead of defining a function for each mode, a test is done
+ * between the outer and inner loops. This is to reduce code size
+ * and complexity. Observe that an optimizing compiler kills
+ * unused variables (for instance tf,sf,ti,si in case of GL_NEAREST).
+ */
+
+#define NEAREST_RGB \
+ tr = tex00[0]; \
+ tg = tex00[1]; \
+ tb = tex00[2]; \
+ ta = 0xff
+
+#define LINEAR_RGB \
+ tr = (ti * (si * tex00[0] + sf * tex01[0]) + \
+ tf * (si * tex10[0] + sf * tex11[0])) >> 2 * FIXED_SHIFT; \
+ tg = (ti * (si * tex00[1] + sf * tex01[1]) + \
+ tf * (si * tex10[1] + sf * tex11[1])) >> 2 * FIXED_SHIFT; \
+ tb = (ti * (si * tex00[2] + sf * tex01[2]) + \
+ tf * (si * tex10[2] + sf * tex11[2])) >> 2 * FIXED_SHIFT; \
+ ta = 0xff
+
+#define NEAREST_RGBA \
+ tr = tex00[0]; \
+ tg = tex00[1]; \
+ tb = tex00[2]; \
+ ta = tex00[3]
+
+#define LINEAR_RGBA \
+ tr = (ti * (si * tex00[0] + sf * tex01[0]) + \
+ tf * (si * tex10[0] + sf * tex11[0])) >> 2 * FIXED_SHIFT; \
+ tg = (ti * (si * tex00[1] + sf * tex01[1]) + \
+ tf * (si * tex10[1] + sf * tex11[1])) >> 2 * FIXED_SHIFT; \
+ tb = (ti * (si * tex00[2] + sf * tex01[2]) + \
+ tf * (si * tex10[2] + sf * tex11[2])) >> 2 * FIXED_SHIFT; \
+ ta = (ti * (si * tex00[3] + sf * tex01[3]) + \
+ tf * (si * tex10[3] + sf * tex11[3])) >> 2 * FIXED_SHIFT
+
+#define MODULATE \
+ dest[0] = ffr * (tr + 1) >> (FIXED_SHIFT + 8); \
+ dest[1] = ffg * (tg + 1) >> (FIXED_SHIFT + 8); \
+ dest[2] = ffb * (tb + 1) >> (FIXED_SHIFT + 8); \
+ dest[3] = ffa * (ta + 1) >> (FIXED_SHIFT + 8)
+
+#define DECAL \
+ dest[0] = ((0xff - ta) * ffr + ((ta + 1) * tr << FIXED_SHIFT)) >> (FIXED_SHIFT + 8); \
+ dest[1] = ((0xff - ta) * ffg + ((ta + 1) * tg << FIXED_SHIFT)) >> (FIXED_SHIFT + 8); \
+ dest[2] = ((0xff - ta) * ffb + ((ta + 1) * tb << FIXED_SHIFT)) >> (FIXED_SHIFT + 8); \
+ dest[3] = FixedToInt(ffa)
+
+#define BLEND \
+ dest[0] = ((0xff - tr) * ffr + (tr + 1) * er) >> (FIXED_SHIFT + 8); \
+ dest[1] = ((0xff - tg) * ffg + (tg + 1) * eg) >> (FIXED_SHIFT + 8); \
+ dest[2] = ((0xff - tb) * ffb + (tb + 1) * eb) >> (FIXED_SHIFT + 8); \
+ dest[3] = ffa * (ta + 1) >> (FIXED_SHIFT + 8)
+
+#define REPLACE \
+ dest[0] = tr; \
+ dest[1] = tg; \
+ dest[2] = tb; \
+ dest[3] = ta
+
+#define ADD \
+ dest[0] = ((ffr << 8) + (tr + 1) * er) >> (FIXED_SHIFT + 8); \
+ dest[1] = ((ffg << 8) + (tg + 1) * eg) >> (FIXED_SHIFT + 8); \
+ dest[2] = ((ffb << 8) + (tb + 1) * eb) >> (FIXED_SHIFT + 8); \
+ dest[3] = ffa * (ta + 1) >> (FIXED_SHIFT + 8)
+
+/* shortcuts */
+
+#define NEAREST_RGB_REPLACE NEAREST_RGB;REPLACE
+
+#define NEAREST_RGBA_REPLACE *(GLint *)dest = *(GLint *)tex00
+
+#define SPAN1(DO_TEX,COMP) \
+ for (i=0;i<n;i++) { \
+ GLint s = FixedToInt(ffs) & smask; \
+ GLint t = FixedToInt(fft) & tmask; \
+ GLint pos = (t << twidth_log2) + s; \
+ GLchan *tex00 = texture + COMP * pos; \
+ zspan[i] = FixedToDepth(ffz); \
+ fogspan[i] = fffog / 256; \
+ DO_TEX; \
+ fffog += fdfogdx; \
+ ffz += fdzdx; \
+ ffr += fdrdx; \
+ ffg += fdgdx; \
+ ffb += fdbdx; \
+ ffa += fdadx; \
+ ffs += fdsdx; \
+ fft += fdtdx; \
+ dest += 4; \
+ }
+
+#define SPAN2(DO_TEX,COMP) \
+ for (i=0;i<n;i++) { \
+ GLint s = FixedToInt(ffs) & smask; \
+ GLint t = FixedToInt(fft) & tmask; \
+ GLint sf = ffs & FIXED_FRAC_MASK; \
+ GLint tf = fft & FIXED_FRAC_MASK; \
+ GLint si = FIXED_FRAC_MASK - sf; \
+ GLint ti = FIXED_FRAC_MASK - tf; \
+ GLint pos = (t << twidth_log2) + s; \
+ GLchan *tex00 = texture + COMP * pos; \
+ GLchan *tex10 = tex00 + tbytesline; \
+ GLchan *tex01 = tex00 + COMP; \
+ GLchan *tex11 = tex10 + COMP; \
+ if (t == tmask) { \
+ tex10 -= tsize; \
+ tex11 -= tsize; \
+ } \
+ if (s == smask) { \
+ tex01 -= tbytesline; \
+ tex11 -= tbytesline; \
+ } \
+ zspan[i] = FixedToDepth(ffz); \
+ fogspan[i] = fffog / 256; \
+ DO_TEX; \
+ fffog += fdfogdx; \
+ ffz += fdzdx; \
+ ffr += fdrdx; \
+ ffg += fdgdx; \
+ ffb += fdbdx; \
+ ffa += fdadx; \
+ ffs += fdsdx; \
+ fft += fdtdx; \
+ dest += 4; \
+ }
+
+/* here comes the heavy part.. (something for the compiler to chew on) */
+#define INNER_LOOP( LEFT, RIGHT, Y ) \
+ { \
+ CONST GLint n = RIGHT-LEFT; \
+ GLint i; \
+ GLdepth zspan[MAX_WIDTH]; \
+ GLfixed fogspan[MAX_WIDTH]; \
+ GLchan rgba[MAX_WIDTH][4]; \
+ if (n>0) { \
+ GLchan *dest = rgba[0]; \
+ ffs -= FIXED_HALF; /* off-by-one error? */ \
+ fft -= FIXED_HALF; \
+ switch (filter) { \
+ case GL_NEAREST: \
+ switch (format) { \
+ case GL_RGB: \
+ switch (envmode) { \
+ case GL_MODULATE: \
+ SPAN1(NEAREST_RGB;MODULATE,3); \
+ break; \
+ case GL_DECAL: \
+ case GL_REPLACE: \
+ SPAN1(NEAREST_RGB_REPLACE,3); \
+ break; \
+ case GL_BLEND: \
+ SPAN1(NEAREST_RGB;BLEND,3); \
+ break; \
+ case GL_ADD: \
+ SPAN1(NEAREST_RGB;ADD,3); \
+ break; \
+ default: /* unexpected env mode */ \
+ abort(); \
+ } \
+ break; \
+ case GL_RGBA: \
+ switch(envmode) { \
+ case GL_MODULATE: \
+ SPAN1(NEAREST_RGBA;MODULATE,4); \
+ break; \
+ case GL_DECAL: \
+ SPAN1(NEAREST_RGBA;DECAL,4); \
+ break; \
+ case GL_BLEND: \
+ SPAN1(NEAREST_RGBA;BLEND,4); \
+ break; \
+ case GL_ADD: \
+ SPAN1(NEAREST_RGBA;ADD,4); \
+ break; \
+ case GL_REPLACE: \
+ SPAN1(NEAREST_RGBA_REPLACE,4); \
+ break; \
+ default: /* unexpected env mode */ \
+ abort(); \
+ } \
+ break; \
+ } \
+ break; \
+ case GL_LINEAR: \
+ ffs -= FIXED_HALF; \
+ fft -= FIXED_HALF; \
+ switch (format) { \
+ case GL_RGB: \
+ switch (envmode) { \
+ case GL_MODULATE: \
+ SPAN2(LINEAR_RGB;MODULATE,3); \
+ break; \
+ case GL_DECAL: \
+ case GL_REPLACE: \
+ SPAN2(LINEAR_RGB;REPLACE,3); \
+ break; \
+ case GL_BLEND: \
+ SPAN2(LINEAR_RGB;BLEND,3); \
+ break; \
+ case GL_ADD: \
+ SPAN2(LINEAR_RGB;ADD,3); \
+ break; \
+ default: /* unexpected env mode */ \
+ abort(); \
+ } \
+ break; \
+ case GL_RGBA: \
+ switch (envmode) { \
+ case GL_MODULATE: \
+ SPAN2(LINEAR_RGBA;MODULATE,4); \
+ break; \
+ case GL_DECAL: \
+ SPAN2(LINEAR_RGBA;DECAL,4); \
+ break; \
+ case GL_BLEND: \
+ SPAN2(LINEAR_RGBA;BLEND,4); \
+ break; \
+ case GL_ADD: \
+ SPAN2(LINEAR_RGBA;ADD,4); \
+ break; \
+ case GL_REPLACE: \
+ SPAN2(LINEAR_RGBA;REPLACE,4); \
+ break; \
+ default: /* unexpected env mode */ \
+ abort(); \
+ } \
+ break; \
+ } \
+ break; \
+ } \
+ gl_write_rgba_span(ctx, n, LEFT, Y, zspan, \
+ fogspan, \
+ rgba, GL_POLYGON); \
+ /* explicit kill of variables: */ \
+ ffr = ffg = ffb = ffa = 0; \
+ } \
+ }
+
+#include "s_tritemp.h"
+#undef SPAN1
+#undef SPAN2
+}
+
+
+
+/*
+ * Render an perspective corrected RGB/RGBA textured triangle.
+ * The Q (aka V in Mesa) coordinate must be zero such that the divide
+ * by interpolated Q/W comes out right.
+ *
+ * This function only renders textured triangles that use GL_NEAREST.
+ * Perspective correction works right.
+ *
+ * This function written by Klaus Niederkrueger <klaus@math.leidenuniv.nl>
+ * Send all questions and bug reports to him.
+ */
+static void near_persp_textured_triangle(GLcontext *ctx, GLuint v0, GLuint v1,
+ GLuint v2, GLuint pv )
+{
+/* The BIAS value is used to shift negative values into positive values.
+ * Without this, negative texture values don't GL_REPEAT correctly at just
+ * below zero, because (int)-0.5 = 0 = (int)0.5. We're not going to worry
+ * about texture coords less than -BIAS. This could be fixed by using
+ * FLOORF etc. instead, but this is slower...
+ */
+#define BIAS 4096.0F
+
+#define INTERP_Z 1
+#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+#define INTERP_TEX 1
+#define SETUP_CODE \
+ struct gl_texture_unit *unit = ctx->Texture.Unit+0; \
+ struct gl_texture_object *obj = unit->CurrentD[2]; \
+ const GLint b = obj->BaseLevel; \
+ const GLfloat twidth = (GLfloat) obj->Image[b]->Width; \
+ const GLfloat theight = (GLfloat) obj->Image[b]->Height; \
+ const GLint twidth_log2 = obj->Image[b]->WidthLog2; \
+ GLchan *texture = obj->Image[b]->Data; \
+ const GLint smask = (obj->Image[b]->Width - 1); \
+ const GLint tmask = (obj->Image[b]->Height - 1); \
+ const GLint format = obj->Image[b]->Format; \
+ const GLint envmode = unit->EnvMode; \
+ GLfloat sscale, tscale; \
+ /*GLint comp, tbytesline, tsize; */ \
+ GLfixed er, eg, eb, ea; \
+ GLint tr, tg, tb, ta; \
+ if (!texture) { \
+ if (!_mesa_get_teximages_from_driver(ctx, obj)) \
+ return; \
+ texture = obj->Image[b]->Data; \
+ ASSERT(texture); \
+ } \
+ if (envmode == GL_BLEND || envmode == GL_ADD) { \
+ er = FloatToFixed(unit->EnvColor[0]); \
+ eg = FloatToFixed(unit->EnvColor[1]); \
+ eb = FloatToFixed(unit->EnvColor[2]); \
+ ea = FloatToFixed(unit->EnvColor[3]); \
+ } \
+ /*switch (format) { \
+ case GL_ALPHA: \
+ case GL_LUMINANCE: \
+ case GL_INTENSITY: \
+ comp = 1; \
+ break; \
+ case GL_LUMINANCE_ALPHA: \
+ comp = 2; \
+ break; \
+ case GL_RGB: \
+ comp = 3; \
+ break; \
+ case GL_RGBA: \
+ comp = 4; \
+ break; \
+ default: \
+ gl_problem(NULL, "Bad texture format in near_persp_texture_triangle"); \
+ return; \
+ } */ \
+ sscale = twidth; \
+ tscale = theight; \
+ /*tbytesline = obj->Image[b]->Width * comp; \
+ tsize = theight * tbytesline;*/
+ (void) pv;
+
+#define OLD_SPAN(DO_TEX,COMP) \
+ for (i=0;i<n;i++) { \
+ GLfloat invQ = 1.0f / vv; \
+ GLint s = (int)(SS * invQ + BIAS) & smask; \
+ GLint t = (int)(TT * invQ + BIAS) & tmask; \
+ GLint pos = COMP * ((t << twidth_log2) + s); \
+ GLchan *tex00 = texture + pos; \
+ zspan[i] = FixedToDepth(ffz); \
+ fogspan[i] = fffog / 256; \
+ DO_TEX; \
+ fffog += fdfogdx; \
+ ffz += fdzdx; \
+ ffr += fdrdx; \
+ ffg += fdgdx; \
+ ffb += fdbdx; \
+ ffa += fdadx; \
+ SS += dSdx; \
+ TT += dTdx; \
+ vv += dvdx; \
+ dest += 4; \
+ }
+
+#define X_Y_TEX_COORD(X, Y) ((((int)(X) & tmask) << twidth_log2) + ((int)(Y) & smask))
+#define Y_X_TEX_COORD(X, Y) ((((int)(Y) & tmask) << twidth_log2) + ((int)(X) & smask))
+
+#define SPAN1(DO_TEX, COMP, TEX_COORD) { \
+ GLfloat x_max = CEILF(x_tex); \
+ GLfloat y_max = y_tex + (x_max - x_tex) * dy_dx; \
+ GLint j, x_m = (int)x_max; \
+ GLint pos; \
+ if ((int)y_max != (int)y_tex) { \
+ GLfloat x_mid = x_tex + (CEILF(y_tex)-y_tex) * dx_dy; \
+ j = (nominator + vv * x_mid)/(denominator - dvdx*x_mid); \
+ pos = COMP * TEX_COORD(x_tex, y_tex); \
+ DRAW_LINE (DO_TEX); \
+ y_tex = y_max; \
+ } \
+ nominator += vv * x_max; \
+ denominator -= dvdx * x_max; \
+ j = nominator / denominator; \
+ pos = COMP * TEX_COORD(x_tex, y_tex); \
+ DRAW_LINE (DO_TEX); \
+ while (i<n) { \
+ y_tex = y_max; \
+ y_max += dy_dx; \
+ if ((int)y_max != (int)y_tex) { \
+ GLfloat x_mid = (CEILF(y_tex)-y_tex) * dx_dy; \
+ j = (nominator + vv * x_mid)/(denominator - dvdx*x_mid); \
+ pos = COMP * TEX_COORD(x_m, y_tex); \
+ DRAW_LINE (DO_TEX); \
+ y_tex = y_max; \
+ } \
+ nominator += vv; \
+ denominator -= dvdx; \
+ j = nominator/denominator; \
+ pos = COMP * TEX_COORD(x_m, y_tex); \
+ DRAW_LINE (DO_TEX); \
+ x_m ++; \
+ } \
+}
+
+#define SPAN2(DO_TEX, COMP, TEX_COORD) { \
+ GLfloat x_max = CEILF (x_tex); \
+ GLfloat y_max = y_tex + (x_max - x_tex) * dy_dx; \
+ GLint j, x_m = (int) x_max; \
+ GLint pos; \
+ if ((int)y_max != (int)y_tex) { \
+ GLfloat x_mid = x_tex + (FLOORF(y_tex)-y_tex) * dx_dy; \
+ j = (nominator + vv * x_mid)/(denominator - dvdx*x_mid); \
+ pos = COMP * TEX_COORD(x_tex, y_tex); \
+ DRAW_LINE (DO_TEX); \
+ y_tex = y_max; \
+ } \
+ nominator += vv * x_max; \
+ denominator -= dvdx * x_max; \
+ j = nominator / denominator; \
+ pos = COMP * TEX_COORD(x_tex, y_tex); \
+ DRAW_LINE (DO_TEX); \
+ while (i<n) { \
+ y_tex = y_max; \
+ y_max += dy_dx; \
+ if ((int)y_max != (int)y_tex) { \
+ GLfloat x_mid = (FLOORF(y_tex)-y_tex) * dx_dy; \
+ j = (nominator + vv * x_mid)/(denominator - dvdx*x_mid);\
+ pos = COMP * TEX_COORD(x_m, y_tex); \
+ DRAW_LINE (DO_TEX); \
+ y_tex = y_max; \
+ } \
+ nominator += vv; \
+ denominator -= dvdx; \
+ j = nominator/denominator; \
+ pos = COMP * TEX_COORD(x_m, y_tex); \
+ DRAW_LINE (DO_TEX); \
+ x_m ++; \
+ } \
+}
+
+#define SPAN3(DO_TEX, COMP, TEX_COORD) { \
+ GLfloat x_min = FLOORF (x_tex); \
+ GLfloat y_min = y_tex + (x_min - x_tex) * dy_dx; \
+ GLint j, x_m = (int)x_min; \
+ GLint pos; \
+ if ((int)y_min != (int)y_tex) { \
+ GLfloat x_mid = x_tex + (CEILF(y_tex)-y_tex) * dx_dy; \
+ j = (nominator + vv * x_mid)/(denominator - dvdx*x_mid); \
+ pos = COMP * TEX_COORD(x_m, y_tex); \
+ DRAW_LINE (DO_TEX); \
+ y_tex = y_min; \
+ } \
+ nominator += vv*x_min; \
+ denominator -= dvdx*x_min; \
+ j = nominator / denominator; \
+ pos = COMP * TEX_COORD(x_m, y_tex); \
+ DRAW_LINE (DO_TEX); \
+ while (i<n) { \
+ x_m --; \
+ y_tex = y_min; \
+ y_min -= dy_dx; \
+ if ((int)y_min != (int)y_tex) { \
+ GLfloat x_mid = (CEILF(y_tex)-y_tex) * dx_dy; \
+ j = (nominator + vv * x_mid)/(denominator - dvdx*x_mid); \
+ pos = COMP * TEX_COORD(x_m, y_tex); \
+ DRAW_LINE (DO_TEX); \
+ y_tex = y_min; \
+ } \
+ nominator -= vv; \
+ denominator += dvdx; \
+ j = nominator/denominator; \
+ pos = COMP * TEX_COORD(x_m, y_tex); \
+ DRAW_LINE (DO_TEX); \
+ } \
+}
+
+#define SPAN4(DO_TEX, COMP, TEX_COORD) \
+{ \
+ GLfloat x_min = FLOORF(x_tex); \
+ GLint x_m = (int)x_min; \
+ GLfloat y_min = y_tex + (x_min - x_tex) * dy_dx; \
+ GLint j; \
+ GLint pos; \
+ if ((int)y_min != (int)y_tex) { \
+ GLfloat x_mid = x_tex + (FLOORF(y_tex)-y_tex) * dx_dy; \
+ j = (nominator + vv * x_mid)/(denominator - dvdx*x_mid); \
+ pos = COMP * TEX_COORD(x_m, y_tex); \
+ DRAW_LINE (DO_TEX); \
+ y_tex = y_min; \
+ } \
+ nominator += vv * x_min; \
+ denominator -= dvdx * x_min; \
+ j = nominator / denominator; \
+ pos = COMP * TEX_COORD(x_m, y_tex); \
+ DRAW_LINE (DO_TEX); \
+ while (i<n) { \
+ x_m --; \
+ y_tex = y_min; \
+ y_min -= dy_dx; \
+ if ((int)y_min != (int)y_tex) { \
+ GLfloat x_mid = (FLOORF(y_tex)-y_tex) * dx_dy; \
+ j = (nominator + vv * x_mid)/(denominator - dvdx*x_mid); \
+ pos = COMP * TEX_COORD(x_m, (y_tex)); \
+ DRAW_LINE (DO_TEX); \
+ y_tex = y_min; \
+ } \
+ nominator -= vv; \
+ denominator += dvdx; \
+ j = nominator/denominator; \
+ pos = COMP * TEX_COORD(x_m, y_tex); \
+ DRAW_LINE (DO_TEX); \
+ } \
+}
+
+#define DRAW_LINE(DO_TEX) \
+ { \
+ GLchan *tex00 = texture + pos; \
+ if (j>n || j<-100000) \
+ j = n; \
+ while (i<j) { \
+ zspan[i] = FixedToDepth(ffz); \
+ fogspan[i] = fffog / 256; \
+ DO_TEX; \
+ fffog += fdfogdx; \
+ ffz += fdzdx; \
+ ffr += fdrdx; \
+ ffg += fdgdx; \
+ ffb += fdbdx; \
+ ffa += fdadx; \
+ dest += 4; \
+ i++; \
+ } \
+ }
+
+#define INNER_LOOP( LEFT, RIGHT, Y ) \
+ { \
+ GLint i = 0; \
+ const GLint n = RIGHT-LEFT; \
+ GLdepth zspan[MAX_WIDTH]; \
+ GLfixed fogspan[MAX_WIDTH]; \
+ GLchan rgba[MAX_WIDTH][4]; \
+ (void)uu; /* please GCC */ \
+ if (n > 0) { \
+ GLchan *dest = rgba[0]; \
+ GLfloat SS = ss * sscale; \
+ GLfloat TT = tt * tscale; \
+ GLfloat dSdx = dsdx * sscale; \
+ GLfloat dTdx = dtdx * tscale; \
+ GLfloat x_tex; \
+ GLfloat y_tex; \
+ GLfloat dx_tex; \
+ GLfloat dy_tex; \
+ if (n<5) /* When line very short, setup-time > speed-gain. */ \
+ goto old_span; /* So: take old method */ \
+ x_tex = SS / vv, \
+ y_tex = TT / vv; \
+ dx_tex = (SS + n * dSdx) / (vv + n * dvdx) - x_tex, \
+ dy_tex = (TT + n * dTdx) / (vv + n * dvdx) - y_tex; \
+ /* Choose between walking over texture or over pixelline: */ \
+ /* If there are few texels, walk over texture otherwise */ \
+ /* walk over pixelarray. The quotient on the right side */ \
+ /* should give the timeratio needed to draw one texel in */ \
+ /* comparison to one pixel. Depends on CPU. */ \
+ if (dx_tex*dx_tex + dy_tex*dy_tex < (n*n)/16) { \
+ x_tex += BIAS; \
+ y_tex += BIAS; \
+ if (dx_tex*dx_tex > dy_tex*dy_tex) { \
+ /* if (FABSF(dx_tex) > FABSF(dy_tex)) */ \
+ GLfloat nominator = - SS - vv * BIAS; \
+ GLfloat denominator = dvdx * BIAS + dSdx; \
+ GLfloat dy_dx; \
+ GLfloat dx_dy; \
+ if (dy_tex != 0.0f) { \
+ dy_dx = dy_tex / dx_tex; \
+ dx_dy = 1.0f/dy_dx; \
+ } \
+ else \
+ dy_dx = 0.0f; \
+ if (dx_tex > 0.0f) { \
+ if (dy_tex > 0.0f) { \
+ switch (format) { \
+ case GL_RGB: \
+ switch (envmode) { \
+ case GL_MODULATE: \
+ SPAN1(NEAREST_RGB;MODULATE,3, Y_X_TEX_COORD);\
+ break; \
+ case GL_DECAL: \
+ case GL_REPLACE: \
+ SPAN1(NEAREST_RGB_REPLACE,3, Y_X_TEX_COORD); \
+ break; \
+ case GL_BLEND: \
+ SPAN1(NEAREST_RGB;BLEND,3, Y_X_TEX_COORD); \
+ break; \
+ case GL_ADD: \
+ SPAN1(NEAREST_RGB;ADD,3, Y_X_TEX_COORD); \
+ break; \
+ default: /* unexpected env mode */ \
+ abort(); \
+ } \
+ break; \
+ case GL_RGBA: \
+ switch(envmode) { \
+ case GL_MODULATE: \
+ SPAN1(NEAREST_RGBA;MODULATE,4, Y_X_TEX_COORD);\
+ break; \
+ case GL_DECAL: \
+ SPAN1(NEAREST_RGBA;DECAL,4, Y_X_TEX_COORD); \
+ break; \
+ case GL_BLEND: \
+ SPAN1(NEAREST_RGBA;BLEND,4, Y_X_TEX_COORD); \
+ break; \
+ case GL_ADD: \
+ SPAN1(NEAREST_RGBA;ADD,4, Y_X_TEX_COORD); \
+ break; \
+ case GL_REPLACE: \
+ SPAN1(NEAREST_RGBA_REPLACE,4, Y_X_TEX_COORD);\
+ break; \
+ default: /* unexpected env mode */ \
+ abort(); \
+ } \
+ break; \
+ } \
+ } \
+ else { /* dy_tex <= 0.0f */ \
+ switch (format) { \
+ case GL_RGB: \
+ switch (envmode) { \
+ case GL_MODULATE: \
+ SPAN2(NEAREST_RGB;MODULATE,3, Y_X_TEX_COORD);\
+ break; \
+ case GL_DECAL: \
+ case GL_REPLACE: \
+ SPAN2(NEAREST_RGB_REPLACE,3, Y_X_TEX_COORD); \
+ break; \
+ case GL_BLEND: \
+ SPAN2(NEAREST_RGB;BLEND,3, Y_X_TEX_COORD); \
+ break; \
+ case GL_ADD: \
+ SPAN2(NEAREST_RGB;ADD,3, Y_X_TEX_COORD); \
+ break; \
+ default: /* unexpected env mode */ \
+ abort(); \
+ } \
+ break; \
+ case GL_RGBA: \
+ switch(envmode) { \
+ case GL_MODULATE: \
+ SPAN2(NEAREST_RGBA;MODULATE,4, Y_X_TEX_COORD);\
+ break; \
+ case GL_DECAL: \
+ SPAN2(NEAREST_RGBA;DECAL,4, Y_X_TEX_COORD); \
+ break; \
+ case GL_BLEND: \
+ SPAN2(NEAREST_RGBA;BLEND,4, Y_X_TEX_COORD); \
+ break; \
+ case GL_ADD: \
+ SPAN2(NEAREST_RGBA;ADD,4, Y_X_TEX_COORD); \
+ break; \
+ case GL_REPLACE: \
+ SPAN2(NEAREST_RGBA_REPLACE,4, Y_X_TEX_COORD);\
+ break; \
+ default: /* unexpected env mode */ \
+ abort(); \
+ } \
+ break; \
+ } \
+ } \
+ } \
+ else { /* dx_tex < 0.0f */ \
+ if (dy_tex > 0.0f) { \
+ switch (format) { \
+ case GL_RGB: \
+ switch (envmode) { \
+ case GL_MODULATE: \
+ SPAN3(NEAREST_RGB;MODULATE,3, Y_X_TEX_COORD);\
+ break; \
+ case GL_DECAL: \
+ case GL_REPLACE: \
+ SPAN3(NEAREST_RGB_REPLACE,3, Y_X_TEX_COORD); \
+ break; \
+ case GL_BLEND: \
+ SPAN3(NEAREST_RGB;BLEND,3, Y_X_TEX_COORD); \
+ break; \
+ case GL_ADD: \
+ SPAN3(NEAREST_RGB;ADD,3, Y_X_TEX_COORD); \
+ break; \
+ default: /* unexpected env mode */ \
+ abort(); \
+ } \
+ break; \
+ case GL_RGBA: \
+ switch(envmode) { \
+ case GL_MODULATE: \
+ SPAN3(NEAREST_RGBA;MODULATE,4, Y_X_TEX_COORD);\
+ break; \
+ case GL_DECAL: \
+ SPAN3(NEAREST_RGBA;DECAL,4, Y_X_TEX_COORD); \
+ break; \
+ case GL_BLEND: \
+ SPAN3(NEAREST_RGBA;BLEND,4, Y_X_TEX_COORD); \
+ break; \
+ case GL_ADD: \
+ SPAN3(NEAREST_RGBA;ADD,4, Y_X_TEX_COORD); \
+ break; \
+ case GL_REPLACE: \
+ SPAN3(NEAREST_RGBA_REPLACE,4, Y_X_TEX_COORD);\
+ break; \
+ default: /* unexpected env mode */ \
+ abort(); \
+ } \
+ break; \
+ } \
+ } \
+ else { /* dy_tex <= 0.0f */ \
+ switch (format) { \
+ case GL_RGB: \
+ switch (envmode) { \
+ case GL_MODULATE: \
+ SPAN4(NEAREST_RGB;MODULATE,3, Y_X_TEX_COORD);\
+ break; \
+ case GL_DECAL: \
+ case GL_REPLACE: \
+ SPAN4(NEAREST_RGB_REPLACE,3, Y_X_TEX_COORD); \
+ break; \
+ case GL_BLEND: \
+ SPAN4(NEAREST_RGB;BLEND,3, Y_X_TEX_COORD); \
+ break; \
+ case GL_ADD: \
+ SPAN4(NEAREST_RGB;ADD,3, Y_X_TEX_COORD); \
+ break; \
+ default: \
+ abort(); \
+ } \
+ break; \
+ case GL_RGBA: \
+ switch(envmode) { \
+ case GL_MODULATE: \
+ SPAN4(NEAREST_RGBA;MODULATE,4, Y_X_TEX_COORD);\
+ break; \
+ case GL_DECAL: \
+ SPAN4(NEAREST_RGBA;DECAL,4, Y_X_TEX_COORD); \
+ break; \
+ case GL_BLEND: \
+ SPAN4(NEAREST_RGBA;BLEND,4, Y_X_TEX_COORD); \
+ break; \
+ case GL_ADD: \
+ SPAN4(NEAREST_RGBA;ADD,4, Y_X_TEX_COORD); \
+ break; \
+ case GL_REPLACE: \
+ SPAN4(NEAREST_RGBA_REPLACE,4, Y_X_TEX_COORD);\
+ break; \
+ default: /* unexpected env mode */ \
+ abort(); \
+ } \
+ break; \
+ } \
+ } \
+ } \
+ } \
+ else { /* FABSF(dx_tex) > FABSF(dy_tex) */ \
+ GLfloat swap; \
+ GLfloat dy_dx; \
+ GLfloat dx_dy; \
+ GLfloat nominator, denominator; \
+ if (dx_tex == 0.0f /* && dy_tex == 0.0f*/) \
+ goto old_span; /* case so special, that use old */ \
+ /* swap some x-values and y-values */ \
+ SS = TT; \
+ dSdx = dTdx; \
+ swap = x_tex, x_tex = y_tex, y_tex = swap; \
+ swap = dx_tex, dx_tex = dy_tex, dy_tex = swap; \
+ nominator = - SS - vv * BIAS; \
+ denominator = dvdx * BIAS + dSdx; \
+ if (dy_tex != 0.0f) { \
+ dy_dx = dy_tex / dx_tex; \
+ dx_dy = 1.0f/dy_dx; \
+ } \
+ else \
+ dy_dx = 0.0f; \
+ if (dx_tex > 0.0f) { \
+ if (dy_tex > 0.0f) { \
+ switch (format) { \
+ case GL_RGB: \
+ switch (envmode) { \
+ case GL_MODULATE: \
+ SPAN1(NEAREST_RGB;MODULATE,3, X_Y_TEX_COORD);\
+ break; \
+ case GL_DECAL: \
+ case GL_REPLACE: \
+ SPAN1(NEAREST_RGB_REPLACE,3, X_Y_TEX_COORD); \
+ break; \
+ case GL_BLEND: \
+ SPAN1(NEAREST_RGB;BLEND,3, X_Y_TEX_COORD); \
+ break; \
+ case GL_ADD: \
+ SPAN1(NEAREST_RGB;ADD,3, X_Y_TEX_COORD); \
+ break; \
+ default: /* unexpected env mode */ \
+ abort(); \
+ } \
+ break; \
+ case GL_RGBA: \
+ switch(envmode) { \
+ case GL_MODULATE: \
+ SPAN1(NEAREST_RGBA;MODULATE,4, X_Y_TEX_COORD);\
+ break; \
+ case GL_DECAL: \
+ SPAN1(NEAREST_RGBA;DECAL,4, X_Y_TEX_COORD); \
+ break; \
+ case GL_BLEND: \
+ SPAN1(NEAREST_RGBA;BLEND,4, X_Y_TEX_COORD); \
+ break; \
+ case GL_ADD: \
+ SPAN1(NEAREST_RGBA;ADD,4, X_Y_TEX_COORD); \
+ break; \
+ case GL_REPLACE: \
+ SPAN1(NEAREST_RGBA_REPLACE,4, X_Y_TEX_COORD);\
+ break; \
+ default: \
+ abort(); \
+ } \
+ break; \
+ } \
+ } \
+ else { /* dy_tex <= 0.0f */ \
+ switch (format) { \
+ case GL_RGB: \
+ switch (envmode) { \
+ case GL_MODULATE: \
+ SPAN2(NEAREST_RGB;MODULATE,3, X_Y_TEX_COORD);\
+ break; \
+ case GL_DECAL: \
+ case GL_REPLACE: \
+ SPAN2(NEAREST_RGB_REPLACE,3, X_Y_TEX_COORD); \
+ break; \
+ case GL_BLEND: \
+ SPAN2(NEAREST_RGB;BLEND,3, X_Y_TEX_COORD); \
+ break; \
+ case GL_ADD: \
+ SPAN2(NEAREST_RGB;ADD,3, X_Y_TEX_COORD); \
+ break; \
+ default: \
+ abort(); \
+ } \
+ break; \
+ case GL_RGBA: \
+ switch(envmode) { \
+ case GL_MODULATE: \
+ SPAN2(NEAREST_RGBA;MODULATE,4, X_Y_TEX_COORD);\
+ break; \
+ case GL_DECAL: \
+ SPAN2(NEAREST_RGBA;DECAL,4, X_Y_TEX_COORD); \
+ break; \
+ case GL_BLEND: \
+ SPAN2(NEAREST_RGBA;BLEND,4, X_Y_TEX_COORD); \
+ break; \
+ case GL_ADD: \
+ SPAN2(NEAREST_RGBA;ADD,4, X_Y_TEX_COORD); \
+ break; \
+ case GL_REPLACE: \
+ SPAN2(NEAREST_RGBA_REPLACE,4, X_Y_TEX_COORD);\
+ break; \
+ default: \
+ abort(); \
+ } \
+ break; \
+ } \
+ } \
+ } \
+ else { /* dx_tex < 0.0f */ \
+ if (dy_tex > 0.0f) { \
+ switch (format) { \
+ case GL_RGB: \
+ switch (envmode) { \
+ case GL_MODULATE: \
+ SPAN3(NEAREST_RGB;MODULATE,3, X_Y_TEX_COORD);\
+ break; \
+ case GL_DECAL: \
+ case GL_REPLACE: \
+ SPAN3(NEAREST_RGB_REPLACE,3, X_Y_TEX_COORD); \
+ break; \
+ case GL_BLEND: \
+ SPAN3(NEAREST_RGB;BLEND,3, X_Y_TEX_COORD); \
+ break; \
+ case GL_ADD: \
+ SPAN3(NEAREST_RGB;ADD,3, X_Y_TEX_COORD); \
+ break; \
+ default: \
+ abort(); \
+ } \
+ break; \
+ case GL_RGBA: \
+ switch(envmode) { \
+ case GL_MODULATE: \
+ SPAN3(NEAREST_RGBA;MODULATE,4, X_Y_TEX_COORD);\
+ break; \
+ case GL_DECAL: \
+ SPAN3(NEAREST_RGBA;DECAL,4, X_Y_TEX_COORD); \
+ break; \
+ case GL_BLEND: \
+ SPAN3(NEAREST_RGBA;BLEND,4, X_Y_TEX_COORD); \
+ break; \
+ case GL_ADD: \
+ SPAN3(NEAREST_RGBA;ADD,4, X_Y_TEX_COORD); \
+ break; \
+ case GL_REPLACE: \
+ SPAN3(NEAREST_RGBA_REPLACE,4, X_Y_TEX_COORD);\
+ break; \
+ default: \
+ abort(); \
+ } \
+ break; \
+ } \
+ } \
+ else { /* dy_tex <= 0.0f */ \
+ switch (format) { \
+ case GL_RGB: \
+ switch (envmode) { \
+ case GL_MODULATE: \
+ SPAN4(NEAREST_RGB;MODULATE,3, X_Y_TEX_COORD);\
+ break; \
+ case GL_DECAL: \
+ case GL_REPLACE: \
+ SPAN4(NEAREST_RGB_REPLACE,3, X_Y_TEX_COORD); \
+ break; \
+ case GL_BLEND: \
+ SPAN4(NEAREST_RGB;BLEND,3, X_Y_TEX_COORD); \
+ break; \
+ case GL_ADD: \
+ SPAN4(NEAREST_RGB;ADD,3, X_Y_TEX_COORD); \
+ break; \
+ default: \
+ abort(); \
+ } \
+ break; \
+ case GL_RGBA: \
+ switch(envmode) { \
+ case GL_MODULATE: \
+ SPAN4(NEAREST_RGBA;MODULATE,4, X_Y_TEX_COORD);\
+ break; \
+ case GL_DECAL: \
+ SPAN4(NEAREST_RGBA;DECAL,4, X_Y_TEX_COORD); \
+ break; \
+ case GL_BLEND: \
+ SPAN4(NEAREST_RGBA;BLEND,4, X_Y_TEX_COORD); \
+ break; \
+ case GL_ADD: \
+ SPAN4(NEAREST_RGBA;ADD,4, X_Y_TEX_COORD); \
+ break; \
+ case GL_REPLACE: \
+ SPAN4(NEAREST_RGBA_REPLACE,4, X_Y_TEX_COORD);\
+ break; \
+ default: \
+ abort(); \
+ } \
+ break; \
+ } \
+ } \
+ } \
+ } \
+ } \
+ else { \
+ old_span: \
+ switch (format) { \
+ case GL_RGB: \
+ switch (envmode) { \
+ case GL_MODULATE: \
+ OLD_SPAN(NEAREST_RGB;MODULATE,3); \
+ break; \
+ case GL_DECAL: \
+ case GL_REPLACE: \
+ OLD_SPAN(NEAREST_RGB_REPLACE,3); \
+ break; \
+ case GL_BLEND: \
+ OLD_SPAN(NEAREST_RGB;BLEND,3); \
+ break; \
+ case GL_ADD: \
+ OLD_SPAN(NEAREST_RGB;ADD,3); \
+ break; \
+ default: \
+ abort(); \
+ } \
+ break; \
+ case GL_RGBA: \
+ switch(envmode) { \
+ case GL_MODULATE: \
+ OLD_SPAN(NEAREST_RGBA;MODULATE,4); \
+ break; \
+ case GL_DECAL: \
+ OLD_SPAN(NEAREST_RGBA;DECAL,4); \
+ break; \
+ case GL_BLEND: \
+ OLD_SPAN(NEAREST_RGBA;BLEND,4); \
+ break; \
+ case GL_ADD: \
+ OLD_SPAN(NEAREST_RGBA;ADD,4); \
+ break; \
+ case GL_REPLACE: \
+ OLD_SPAN(NEAREST_RGBA_REPLACE,4); \
+ break; \
+ default: \
+ abort(); \
+ } \
+ break; \
+ } \
+ } \
+ gl_write_rgba_span( ctx, n, LEFT, Y, zspan, \
+ fogspan, rgba, GL_POLYGON); \
+ ffr = ffg = ffb = ffa = 0; \
+ } \
+ } \
+
+#include "s_tritemp.h"
+#undef OLD_SPAN
+#undef SPAN1
+#undef SPAN2
+#undef SPAN3
+#undef SPAN4
+#undef X_Y_TEX_COORD
+#undef Y_X_TEX_COORD
+#undef DRAW_LINE
+#undef BIAS
+}
+
+
+
+/*
+ * Render an perspective corrected RGB/RGBA textured triangle.
+ * The Q (aka V in Mesa) coordinate must be zero such that the divide
+ * by interpolated Q/W comes out right.
+ *
+ * This function written by Klaus Niederkrueger <klaus@math.leidenuniv.nl>
+ * Send all questions and bug reports to him.
+ */
+static void lin_persp_textured_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
+ GLuint v2, GLuint pv )
+{
+#define INTERP_Z 1
+#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+#define INTERP_TEX 1
+#define SETUP_CODE \
+ struct gl_texture_unit *unit = ctx->Texture.Unit+0; \
+ struct gl_texture_object *obj = unit->CurrentD[2]; \
+ const GLint b = obj->BaseLevel; \
+ const GLfloat twidth = (GLfloat) obj->Image[b]->Width; \
+ const GLfloat theight = (GLfloat) obj->Image[b]->Height; \
+ const GLint twidth_log2 = obj->Image[b]->WidthLog2; \
+ GLchan *texture = obj->Image[b]->Data; \
+ const GLint smask = (obj->Image[b]->Width - 1); \
+ const GLint tmask = (obj->Image[b]->Height - 1); \
+ const GLint format = obj->Image[b]->Format; \
+ const GLint envmode = unit->EnvMode; \
+ GLfloat sscale, tscale; \
+ GLint comp, tbytesline, tsize; \
+ GLfixed er, eg, eb, ea; \
+ GLint tr, tg, tb, ta; \
+ if (!texture) { \
+ if (!_mesa_get_teximages_from_driver(ctx, obj)) \
+ return; \
+ texture = obj->Image[b]->Data; \
+ ASSERT(texture); \
+ } \
+ if (envmode == GL_BLEND || envmode == GL_ADD) { \
+ er = FloatToFixed(unit->EnvColor[0]); \
+ eg = FloatToFixed(unit->EnvColor[1]); \
+ eb = FloatToFixed(unit->EnvColor[2]); \
+ ea = FloatToFixed(unit->EnvColor[3]); \
+ } \
+ switch (format) { \
+ case GL_ALPHA: \
+ case GL_LUMINANCE: \
+ case GL_INTENSITY: \
+ comp = 1; \
+ break; \
+ case GL_LUMINANCE_ALPHA: \
+ comp = 2; \
+ break; \
+ case GL_RGB: \
+ comp = 3; \
+ break; \
+ case GL_RGBA: \
+ comp = 4; \
+ break; \
+ default: \
+ gl_problem(NULL, "Bad texture format in lin_persp_texture_triangle"); \
+ return; \
+ } \
+ sscale = FIXED_SCALE * twidth; \
+ tscale = FIXED_SCALE * theight; \
+ tbytesline = obj->Image[b]->Width * comp; \
+ tsize = theight * tbytesline;
+ (void) pv;
+
+#define SPAN(DO_TEX,COMP) \
+ for (i=0;i<n;i++) { \
+ GLfloat invQ = 1.0f / vv; \
+ GLfixed ffs = (int)(SS * invQ); \
+ GLfixed fft = (int)(TT * invQ); \
+ GLint s = FixedToInt(ffs) & smask; \
+ GLint t = FixedToInt(fft) & tmask; \
+ GLint sf = ffs & FIXED_FRAC_MASK; \
+ GLint tf = fft & FIXED_FRAC_MASK; \
+ GLint si = FIXED_FRAC_MASK - sf; \
+ GLint ti = FIXED_FRAC_MASK - tf; \
+ GLint pos = COMP * ((t << twidth_log2) + s); \
+ GLchan *tex00 = texture + pos; \
+ GLchan *tex10 = tex00 + tbytesline; \
+ GLchan *tex01 = tex00 + COMP; \
+ GLchan *tex11 = tex10 + COMP; \
+ if (t == tmask) { \
+ tex10 -= tsize; \
+ tex11 -= tsize; \
+ } \
+ if (s == smask) { \
+ tex01 -= tbytesline; \
+ tex11 -= tbytesline; \
+ } \
+ zspan[i] = FixedToDepth(ffz); \
+ fogspan[i] = fffog / 256; \
+ DO_TEX; \
+ fffog += fdfogdx; \
+ ffz += fdzdx; \
+ ffr += fdrdx; \
+ ffg += fdgdx; \
+ ffb += fdbdx; \
+ ffa += fdadx; \
+ SS += dSdx; \
+ TT += dTdx; \
+ vv += dvdx; \
+ dest += 4; \
+ }
+
+#define INNER_LOOP( LEFT, RIGHT, Y ) \
+ { \
+ GLint i; \
+ const GLint n = RIGHT-LEFT; \
+ GLdepth zspan[MAX_WIDTH]; \
+ GLfixed fogspan[MAX_WIDTH]; \
+ GLchan rgba[MAX_WIDTH][4]; \
+ (void) uu; /* please GCC */ \
+ if (n > 0) { \
+ GLfloat SS = ss * sscale; \
+ GLfloat TT = tt * tscale; \
+ GLfloat dSdx = dsdx * sscale; \
+ GLfloat dTdx = dtdx * tscale; \
+ GLchan *dest = rgba[0]; \
+ SS -= 0.5f * FIXED_SCALE * vv; \
+ TT -= 0.5f * FIXED_SCALE * vv; \
+ switch (format) { \
+ case GL_RGB: \
+ switch (envmode) { \
+ case GL_MODULATE: \
+ SPAN(LINEAR_RGB;MODULATE,3); \
+ break; \
+ case GL_DECAL: \
+ case GL_REPLACE: \
+ SPAN(LINEAR_RGB;REPLACE,3); \
+ break; \
+ case GL_BLEND: \
+ SPAN(LINEAR_RGB;BLEND,3); \
+ break; \
+ case GL_ADD: \
+ SPAN(LINEAR_RGB;ADD,3); \
+ break; \
+ default: \
+ abort(); \
+ } \
+ break; \
+ case GL_RGBA: \
+ switch (envmode) { \
+ case GL_MODULATE: \
+ SPAN(LINEAR_RGBA;MODULATE,4); \
+ break; \
+ case GL_DECAL: \
+ SPAN(LINEAR_RGBA;DECAL,4); \
+ break; \
+ case GL_BLEND: \
+ SPAN(LINEAR_RGBA;BLEND,4); \
+ break; \
+ case GL_REPLACE: \
+ SPAN(LINEAR_RGBA;REPLACE,4); \
+ break; \
+ case GL_ADD: \
+ SPAN(LINEAR_RGBA;ADD,4); \
+ break; \
+ default: /* unexpected env mode */ \
+ abort(); \
+ } \
+ } \
+ gl_write_rgba_span( ctx, n, LEFT, Y, zspan, \
+ fogspan, \
+ rgba, GL_POLYGON ); \
+ ffr = ffg = ffb = ffa = 0; \
+ } \
+ }
+
+
+#include "s_tritemp.h"
+#undef SPAN
+}
+
+
+
+/*
+ * Render a smooth-shaded, textured, RGBA triangle.
+ * Interpolate S,T,U with perspective correction, w/out mipmapping.
+ * Note: we use texture coordinates S,T,U,V instead of S,T,R,Q because
+ * R is already used for red.
+ */
+static void general_textured_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
+ GLuint v2, GLuint pv )
+{
+#define INTERP_Z 1
+#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+#define INTERP_TEX 1
+#define SETUP_CODE \
+ GLboolean flat_shade = (ctx->Light.ShadeModel==GL_FLAT); \
+ GLint r, g, b, a; \
+ if (flat_shade) { \
+ r = VB->ColorPtr->data[pv][0]; \
+ g = VB->ColorPtr->data[pv][1]; \
+ b = VB->ColorPtr->data[pv][2]; \
+ a = VB->ColorPtr->data[pv][3]; \
+ }
+#define INNER_LOOP( LEFT, RIGHT, Y ) \
+ { \
+ GLint i; \
+ const GLint n = RIGHT-LEFT; \
+ GLdepth zspan[MAX_WIDTH]; \
+ GLfixed fogspan[MAX_WIDTH]; \
+ GLchan rgba[MAX_WIDTH][4]; \
+ GLfloat s[MAX_WIDTH], t[MAX_WIDTH], u[MAX_WIDTH]; \
+ if (n>0) { \
+ if (flat_shade) { \
+ for (i=0;i<n;i++) { \
+ GLdouble invQ = 1.0 / vv; \
+ zspan[i] = FixedToDepth(ffz); \
+ fogspan[i] = fffog / 256; \
+ rgba[i][RCOMP] = r; \
+ rgba[i][GCOMP] = g; \
+ rgba[i][BCOMP] = b; \
+ rgba[i][ACOMP] = a; \
+ s[i] = ss*invQ; \
+ t[i] = tt*invQ; \
+ u[i] = uu*invQ; \
+ fffog += fdfogdx; \
+ ffz += fdzdx; \
+ ss += dsdx; \
+ tt += dtdx; \
+ uu += dudx; \
+ vv += dvdx; \
+ } \
+ } \
+ else { \
+ for (i=0;i<n;i++) { \
+ GLdouble invQ = 1.0 / vv; \
+ zspan[i] = FixedToDepth(ffz); \
+ rgba[i][RCOMP] = FixedToInt(ffr); \
+ rgba[i][GCOMP] = FixedToInt(ffg); \
+ rgba[i][BCOMP] = FixedToInt(ffb); \
+ rgba[i][ACOMP] = FixedToInt(ffa); \
+ fogspan[i] = fffog / 256; \
+ s[i] = ss*invQ; \
+ t[i] = tt*invQ; \
+ u[i] = uu*invQ; \
+ fffog += fdfogdx; \
+ ffz += fdzdx; \
+ ffr += fdrdx; \
+ ffg += fdgdx; \
+ ffb += fdbdx; \
+ ffa += fdadx; \
+ ss += dsdx; \
+ tt += dtdx; \
+ uu += dudx; \
+ vv += dvdx; \
+ } \
+ } \
+ gl_write_texture_span( ctx, n, LEFT, Y, zspan, fogspan, \
+ s, t, u, NULL, \
+ rgba, \
+ NULL, GL_POLYGON ); \
+ } \
+ }
+
+#include "s_tritemp.h"
+}
+
+
+/*
+ * Render a smooth-shaded, textured, RGBA triangle with separate specular
+ * color interpolation.
+ * Interpolate S,T,U with perspective correction, w/out mipmapping.
+ * Note: we use texture coordinates S,T,U,V instead of S,T,R,Q because
+ * R is already used for red.
+ */
+static void general_textured_spec_triangle1( GLcontext *ctx, GLuint v0,
+ GLuint v1, GLuint v2, GLuint pv,
+ GLdepth zspan[MAX_WIDTH],
+ GLfixed fogspan[MAX_WIDTH],
+ GLchan rgba[MAX_WIDTH][4],
+ GLchan spec[MAX_WIDTH][4] )
+{
+#define INTERP_Z 1
+#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
+#define INTERP_RGB 1
+#define INTERP_SPEC 1
+#define INTERP_ALPHA 1
+#define INTERP_TEX 1
+#define SETUP_CODE \
+ GLboolean flat_shade = (ctx->Light.ShadeModel==GL_FLAT); \
+ GLint r, g, b, a, sr, sg, sb; \
+ if (flat_shade) { \
+ r = VB->ColorPtr->data[pv][0]; \
+ g = VB->ColorPtr->data[pv][1]; \
+ b = VB->ColorPtr->data[pv][2]; \
+ a = VB->ColorPtr->data[pv][3]; \
+ sr = VB->SecondaryColorPtr->data[pv][0]; \
+ sg = VB->SecondaryColorPtr->data[pv][1]; \
+ sb = VB->SecondaryColorPtr->data[pv][2]; \
+ }
+#define INNER_LOOP( LEFT, RIGHT, Y ) \
+ { \
+ GLint i; \
+ const GLint n = RIGHT-LEFT; \
+ GLfloat s[MAX_WIDTH], t[MAX_WIDTH], u[MAX_WIDTH]; \
+ if (n>0) { \
+ if (flat_shade) { \
+ for (i=0;i<n;i++) { \
+ GLdouble invQ = 1.0 / vv; \
+ zspan[i] = FixedToDepth(ffz); \
+ fogspan[i] = fffog / 256; \
+ rgba[i][RCOMP] = r; \
+ rgba[i][GCOMP] = g; \
+ rgba[i][BCOMP] = b; \
+ rgba[i][ACOMP] = a; \
+ spec[i][RCOMP] = sr; \
+ spec[i][GCOMP] = sg; \
+ spec[i][BCOMP] = sb; \
+ s[i] = ss*invQ; \
+ t[i] = tt*invQ; \
+ u[i] = uu*invQ; \
+ fffog += fdfogdx; \
+ ffz += fdzdx; \
+ ss += dsdx; \
+ tt += dtdx; \
+ uu += dudx; \
+ vv += dvdx; \
+ } \
+ } \
+ else { \
+ for (i=0;i<n;i++) { \
+ GLdouble invQ = 1.0 / vv; \
+ zspan[i] = FixedToDepth(ffz); \
+ fogspan[i] = fffog / 256; \
+ rgba[i][RCOMP] = FixedToInt(ffr); \
+ rgba[i][GCOMP] = FixedToInt(ffg); \
+ rgba[i][BCOMP] = FixedToInt(ffb); \
+ rgba[i][ACOMP] = FixedToInt(ffa); \
+ spec[i][RCOMP] = FixedToInt(ffsr); \
+ spec[i][GCOMP] = FixedToInt(ffsg); \
+ spec[i][BCOMP] = FixedToInt(ffsb); \
+ s[i] = ss*invQ; \
+ t[i] = tt*invQ; \
+ u[i] = uu*invQ; \
+ fffog += fdfogdx; \
+ ffz += fdzdx; \
+ ffr += fdrdx; \
+ ffg += fdgdx; \
+ ffb += fdbdx; \
+ ffa += fdadx; \
+ ffsr += fdsrdx; \
+ ffsg += fdsgdx; \
+ ffsb += fdsbdx; \
+ ss += dsdx; \
+ tt += dtdx; \
+ uu += dudx; \
+ vv += dvdx; \
+ } \
+ } \
+ gl_write_texture_span( ctx, n, LEFT, Y, zspan, \
+ fogspan, \
+ s, t, u, NULL, rgba, \
+ (CONST GLchan (*)[4]) spec, \
+ GL_POLYGON ); \
+ } \
+ }
+
+#include "s_tritemp.h"
+}
+
+
+
+/*
+ * Compute the lambda value for a fragment. (texture level of detail)
+ */
+static INLINE GLfloat
+compute_lambda( GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
+ GLfloat invQ, GLfloat width, GLfloat height )
+{
+ GLfloat dudx = dsdx * invQ * width;
+ GLfloat dudy = dsdy * invQ * width;
+ GLfloat dvdx = dtdx * invQ * height;
+ GLfloat dvdy = dtdy * invQ * height;
+ GLfloat r1 = dudx * dudx + dudy * dudy;
+ GLfloat r2 = dvdx * dvdx + dvdy * dvdy;
+ GLfloat rho2 = r1 + r2; /* used to be: rho2 = MAX2(r1,r2); */
+ /* return log base 2 of rho */
+ return log(rho2) * 1.442695 * 0.5; /* 1.442695 = 1/log(2) */
+}
+
+
+/*
+ * Render a smooth-shaded, textured, RGBA triangle.
+ * Interpolate S,T,U with perspective correction and compute lambda for
+ * each fragment. Lambda is used to determine whether to use the
+ * minification or magnification filter. If minification and using
+ * mipmaps, lambda is also used to select the texture level of detail.
+ */
+static void lambda_textured_triangle1( GLcontext *ctx, GLuint v0, GLuint v1,
+ GLuint v2, GLuint pv,
+ GLfloat s[MAX_WIDTH],
+ GLfloat t[MAX_WIDTH],
+ GLfloat u[MAX_WIDTH] )
+{
+#define INTERP_Z 1
+#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+#define INTERP_TEX 1
+
+#define SETUP_CODE \
+ const struct gl_texture_object *obj = ctx->Texture.Unit[0].Current; \
+ const GLint baseLevel = obj->BaseLevel; \
+ const struct gl_texture_image *texImage = obj->Image[baseLevel]; \
+ const GLfloat twidth = (GLfloat) texImage->Width; \
+ const GLfloat theight = (GLfloat) texImage->Height; \
+ const GLboolean flat_shade = (ctx->Light.ShadeModel==GL_FLAT); \
+ GLint r, g, b, a; \
+ if (flat_shade) { \
+ r = VB->ColorPtr->data[pv][0]; \
+ g = VB->ColorPtr->data[pv][1]; \
+ b = VB->ColorPtr->data[pv][2]; \
+ a = VB->ColorPtr->data[pv][3]; \
+ }
+
+#define INNER_LOOP( LEFT, RIGHT, Y ) \
+ { \
+ GLint i; \
+ const GLint n = RIGHT-LEFT; \
+ GLdepth zspan[MAX_WIDTH]; \
+ GLfixed fogspan[MAX_WIDTH]; \
+ GLchan rgba[MAX_WIDTH][4]; \
+ GLfloat lambda[MAX_WIDTH]; \
+ if (n>0) { \
+ if (flat_shade) { \
+ for (i=0;i<n;i++) { \
+ GLdouble invQ = 1.0 / vv; \
+ zspan[i] = FixedToDepth(ffz); \
+ fogspan[i] = fffog / 256; \
+ rgba[i][RCOMP] = r; \
+ rgba[i][GCOMP] = g; \
+ rgba[i][BCOMP] = b; \
+ rgba[i][ACOMP] = a; \
+ s[i] = ss*invQ; \
+ t[i] = tt*invQ; \
+ u[i] = uu*invQ; \
+ lambda[i] = compute_lambda( dsdx, dsdy, dtdx, dtdy, \
+ invQ, twidth, theight );\
+ ffz += fdzdx; \
+ fffog += fdfogdx; \
+ ss += dsdx; \
+ tt += dtdx; \
+ uu += dudx; \
+ vv += dvdx; \
+ } \
+ } \
+ else { \
+ for (i=0;i<n;i++) { \
+ GLdouble invQ = 1.0 / vv; \
+ zspan[i] = FixedToDepth(ffz); \
+ fogspan[i] = fffog / 256; \
+ rgba[i][RCOMP] = FixedToInt(ffr); \
+ rgba[i][GCOMP] = FixedToInt(ffg); \
+ rgba[i][BCOMP] = FixedToInt(ffb); \
+ rgba[i][ACOMP] = FixedToInt(ffa); \
+ s[i] = ss*invQ; \
+ t[i] = tt*invQ; \
+ u[i] = uu*invQ; \
+ lambda[i] = compute_lambda( dsdx, dsdy, dtdx, dtdy, \
+ invQ, twidth, theight );\
+ ffz += fdzdx; \
+ fffog += fdfogdx; \
+ ffr += fdrdx; \
+ ffg += fdgdx; \
+ ffb += fdbdx; \
+ ffa += fdadx; \
+ ss += dsdx; \
+ tt += dtdx; \
+ uu += dudx; \
+ vv += dvdx; \
+ } \
+ } \
+ gl_write_texture_span( ctx, n, LEFT, Y, zspan, fogspan, \
+ s, t, u, lambda, \
+ rgba, NULL, GL_POLYGON ); \
+ } \
+ }
+
+#include "s_tritemp.h"
+}
+
+
+/*
+ * Render a smooth-shaded, textured, RGBA triangle with separate specular
+ * interpolation.
+ * Interpolate S,T,U with perspective correction and compute lambda for
+ * each fragment. Lambda is used to determine whether to use the
+ * minification or magnification filter. If minification and using
+ * mipmaps, lambda is also used to select the texture level of detail.
+ */
+static void lambda_textured_spec_triangle1( GLcontext *ctx, GLuint v0,
+ GLuint v1, GLuint v2, GLuint pv,
+ GLfloat s[MAX_WIDTH],
+ GLfloat t[MAX_WIDTH],
+ GLfloat u[MAX_WIDTH] )
+{
+#define INTERP_Z 1
+#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
+#define INTERP_RGB 1
+#define INTERP_SPEC 1
+#define INTERP_ALPHA 1
+#define INTERP_TEX 1
+
+#define SETUP_CODE \
+ const struct gl_texture_object *obj = ctx->Texture.Unit[0].Current; \
+ const GLint baseLevel = obj->BaseLevel; \
+ const struct gl_texture_image *texImage = obj->Image[baseLevel]; \
+ const GLfloat twidth = (GLfloat) texImage->Width; \
+ const GLfloat theight = (GLfloat) texImage->Height; \
+ const GLboolean flat_shade = (ctx->Light.ShadeModel==GL_FLAT); \
+ GLint r, g, b, a, sr, sg, sb; \
+ if (flat_shade) { \
+ r = VB->ColorPtr->data[pv][0]; \
+ g = VB->ColorPtr->data[pv][1]; \
+ b = VB->ColorPtr->data[pv][2]; \
+ a = VB->ColorPtr->data[pv][3]; \
+ sr = VB->SecondaryColorPtr->data[pv][0]; \
+ sg = VB->SecondaryColorPtr->data[pv][1]; \
+ sb = VB->SecondaryColorPtr->data[pv][2]; \
+ }
+
+#define INNER_LOOP( LEFT, RIGHT, Y ) \
+ { \
+ GLint i; \
+ const GLint n = RIGHT-LEFT; \
+ GLdepth zspan[MAX_WIDTH]; \
+ GLfixed fogspan[MAX_WIDTH]; \
+ GLchan spec[MAX_WIDTH][4]; \
+ GLchan rgba[MAX_WIDTH][4]; \
+ GLfloat lambda[MAX_WIDTH]; \
+ if (n>0) { \
+ if (flat_shade) { \
+ for (i=0;i<n;i++) { \
+ GLdouble invQ = 1.0 / vv; \
+ zspan[i] = FixedToDepth(ffz); \
+ fogspan[i] = fffog / 256; \
+ rgba[i][RCOMP] = r; \
+ rgba[i][GCOMP] = g; \
+ rgba[i][BCOMP] = b; \
+ rgba[i][ACOMP] = a; \
+ spec[i][RCOMP] = sr; \
+ spec[i][GCOMP] = sg; \
+ spec[i][BCOMP] = sb; \
+ s[i] = ss*invQ; \
+ t[i] = tt*invQ; \
+ u[i] = uu*invQ; \
+ lambda[i] = compute_lambda( dsdx, dsdy, dtdx, dtdy, \
+ invQ, twidth, theight );\
+ fffog += fdfogdx; \
+ ffz += fdzdx; \
+ ss += dsdx; \
+ tt += dtdx; \
+ uu += dudx; \
+ vv += dvdx; \
+ } \
+ } \
+ else { \
+ for (i=0;i<n;i++) { \
+ GLdouble invQ = 1.0 / vv; \
+ zspan[i] = FixedToDepth(ffz); \
+ fogspan[i] = fffog / 256; \
+ rgba[i][RCOMP] = FixedToInt(ffr); \
+ rgba[i][GCOMP] = FixedToInt(ffg); \
+ rgba[i][BCOMP] = FixedToInt(ffb); \
+ rgba[i][ACOMP] = FixedToInt(ffa); \
+ spec[i][RCOMP] = FixedToInt(ffsr); \
+ spec[i][GCOMP] = FixedToInt(ffsg); \
+ spec[i][BCOMP] = FixedToInt(ffsb); \
+ s[i] = ss*invQ; \
+ t[i] = tt*invQ; \
+ u[i] = uu*invQ; \
+ lambda[i] = compute_lambda( dsdx, dsdy, dtdx, dtdy, \
+ invQ, twidth, theight );\
+ fffog += fdfogdx; \
+ ffz += fdzdx; \
+ ffr += fdrdx; \
+ ffg += fdgdx; \
+ ffb += fdbdx; \
+ ffa += fdadx; \
+ ffsr += fdsrdx; \
+ ffsg += fdsgdx; \
+ ffsb += fdsbdx; \
+ ss += dsdx; \
+ tt += dtdx; \
+ uu += dudx; \
+ vv += dvdx; \
+ } \
+ } \
+ gl_write_texture_span( ctx, n, LEFT, Y, zspan, fogspan, \
+ s, t, u, lambda, \
+ rgba, (CONST GLchan (*)[4]) spec, \
+ GL_POLYGON ); \
+ } \
+ }
+
+#include "s_tritemp.h"
+}
+
+
+/*
+ * This is the big one!
+ * Interpolate Z, RGB, Alpha, and two sets of texture coordinates.
+ * Yup, it's slow.
+ */
+static void lambda_multitextured_triangle1( GLcontext *ctx, GLuint v0,
+ GLuint v1, GLuint v2, GLuint pv,
+ GLfloat s[MAX_TEXTURE_UNITS][MAX_WIDTH],
+ GLfloat t[MAX_TEXTURE_UNITS][MAX_WIDTH],
+ GLfloat u[MAX_TEXTURE_UNITS][MAX_WIDTH]
+ )
+{
+#define INTERP_Z 1
+#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
+#define INTERP_RGB 1
+#define INTERP_ALPHA 1
+#define INTERP_MULTITEX 1
+
+#define SETUP_CODE \
+ GLchan rgba[MAX_WIDTH][4]; \
+ const GLboolean flat_shade = (ctx->Light.ShadeModel==GL_FLAT); \
+ GLfloat twidth[MAX_TEXTURE_UNITS], theight[MAX_TEXTURE_UNITS]; \
+ GLint r, g, b, a; \
+ if (flat_shade) { \
+ r = VB->ColorPtr->data[pv][0]; \
+ g = VB->ColorPtr->data[pv][1]; \
+ b = VB->ColorPtr->data[pv][2]; \
+ a = VB->ColorPtr->data[pv][3]; \
+ } \
+ { \
+ GLuint unit; \
+ for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { \
+ if (ctx->Texture.Unit[unit].ReallyEnabled) { \
+ const struct gl_texture_object *obj = ctx->Texture.Unit[unit].Current; \
+ const GLint baseLevel = obj->BaseLevel; \
+ const struct gl_texture_image *texImage = obj->Image[baseLevel]; \
+ twidth[unit] = (GLfloat) texImage->Width; \
+ theight[unit] = (GLfloat) texImage->Height; \
+ } \
+ } \
+ }
+
+
+
+#define INNER_LOOP( LEFT, RIGHT, Y ) \
+ { \
+ GLint i; \
+ const GLint n = RIGHT-LEFT; \
+ GLdepth zspan[MAX_WIDTH]; \
+ GLfixed fogspan[MAX_WIDTH]; \
+ GLfloat lambda[MAX_TEXTURE_UNITS][MAX_WIDTH]; \
+ if (n > 0) { \
+ if (flat_shade) { \
+ for (i=0;i<n;i++) { \
+ zspan[i] = FixedToDepth(ffz); \
+ fogspan[i] = fffog / 256; \
+ fffog += fdfogdx; \
+ ffz += fdzdx; \
+ rgba[i][RCOMP] = r; \
+ rgba[i][GCOMP] = g; \
+ rgba[i][BCOMP] = b; \
+ rgba[i][ACOMP] = a; \
+ { \
+ GLuint unit; \
+ for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { \
+ if (ctx->Texture.Unit[unit].ReallyEnabled) { \
+ GLdouble invQ = 1.0 / vv[unit]; \
+ s[unit][i] = ss[unit] * invQ; \
+ t[unit][i] = tt[unit] * invQ; \
+ u[unit][i] = uu[unit] * invQ; \
+ lambda[unit][i] = compute_lambda(dsdx[unit], dsdy[unit],\
+ dtdx[unit], dtdy[unit], invQ, \
+ twidth[unit], theight[unit] ); \
+ ss[unit] += dsdx[unit]; \
+ tt[unit] += dtdx[unit]; \
+ uu[unit] += dudx[unit]; \
+ vv[unit] += dvdx[unit]; \
+ } \
+ } \
+ } \
+ } \
+ } \
+ else { /* smooth shade */ \
+ for (i=0;i<n;i++) { \
+ zspan[i] = FixedToDepth(ffz); \
+ fogspan[i] = fffog / 256; \
+ ffz += fdzdx; \
+ fffog += fdfogdx; \
+ rgba[i][RCOMP] = FixedToInt(ffr); \
+ rgba[i][GCOMP] = FixedToInt(ffg); \
+ rgba[i][BCOMP] = FixedToInt(ffb); \
+ rgba[i][ACOMP] = FixedToInt(ffa); \
+ ffr += fdrdx; \
+ ffg += fdgdx; \
+ ffb += fdbdx; \
+ ffa += fdadx; \
+ { \
+ GLuint unit; \
+ for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { \
+ if (ctx->Texture.Unit[unit].ReallyEnabled) { \
+ GLdouble invQ = 1.0 / vv[unit]; \
+ s[unit][i] = ss[unit] * invQ; \
+ t[unit][i] = tt[unit] * invQ; \
+ u[unit][i] = uu[unit] * invQ; \
+ lambda[unit][i] = compute_lambda(dsdx[unit], dsdy[unit],\
+ dtdx[unit], dtdy[unit], invQ, \
+ twidth[unit], theight[unit] ); \
+ ss[unit] += dsdx[unit]; \
+ tt[unit] += dtdx[unit]; \
+ uu[unit] += dudx[unit]; \
+ vv[unit] += dvdx[unit]; \
+ } \
+ } \
+ } \
+ } \
+ } \
+ gl_write_multitexture_span( ctx, n, LEFT, Y, zspan, fogspan, \
+ (const GLfloat (*)[MAX_WIDTH]) s, \
+ (const GLfloat (*)[MAX_WIDTH]) t, \
+ (const GLfloat (*)[MAX_WIDTH]) u, \
+ (GLfloat (*)[MAX_WIDTH]) lambda, \
+ rgba, NULL, GL_POLYGON ); \
+ } \
+ }
+#include "s_tritemp.h"
+}
+
+
+/*
+ * These wrappers are needed to deal with the 32KB / stack frame limit
+ * on Mac / PowerPC systems.
+ */
+
+static void general_textured_spec_triangle(GLcontext *ctx, GLuint v0,
+ GLuint v1, GLuint v2, GLuint pv)
+{
+ GLdepth zspan[MAX_WIDTH];
+ GLfixed fogspan[MAX_WIDTH];
+ GLchan rgba[MAX_WIDTH][4], spec[MAX_WIDTH][4];
+ general_textured_spec_triangle1(ctx,v0,v1,v2,pv,zspan,fogspan,rgba,spec);
+}
+
+static void lambda_textured_triangle( GLcontext *ctx, GLuint v0,
+ GLuint v1, GLuint v2, GLuint pv )
+{
+ GLfloat s[MAX_WIDTH], t[MAX_WIDTH], u[MAX_WIDTH];
+ lambda_textured_triangle1(ctx,v0,v1,v2,pv,s,t,u);
+}
+
+static void lambda_textured_spec_triangle( GLcontext *ctx, GLuint v0,
+ GLuint v1, GLuint v2, GLuint pv )
+{
+ GLfloat s[MAX_WIDTH];
+ GLfloat t[MAX_WIDTH];
+ GLfloat u[MAX_WIDTH];
+ lambda_textured_spec_triangle1(ctx,v0,v1,v2,pv,s,t,u);
+}
+
+
+static void lambda_multitextured_triangle( GLcontext *ctx, GLuint v0,
+ GLuint v1, GLuint v2, GLuint pv)
+{
+
+ GLfloat s[MAX_TEXTURE_UNITS][MAX_WIDTH];
+ GLfloat t[MAX_TEXTURE_UNITS][MAX_WIDTH];
+ DEFMARRAY(GLfloat,u,MAX_TEXTURE_UNITS,MAX_WIDTH);
+ CHECKARRAY(u,return);
+
+ lambda_multitextured_triangle1(ctx,v0,v1,v2,pv,s,t,u);
+
+ UNDEFARRAY(u);
+}
+
+
+
+static void occlusion_zless_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
+ GLuint v2, GLuint pv )
+{
+ (void)pv;
+ if (ctx->OcclusionResult) {
+ return;
+ }
+
+#define DO_OCCLUSION_TEST
+#define INTERP_Z 1
+#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
+#define INNER_LOOP( LEFT, RIGHT, Y ) \
+ { \
+ GLint i; \
+ const GLint len = RIGHT-LEFT; \
+ for (i=0;i<len;i++) { \
+ GLdepth z = FixedToDepth(ffz); \
+ (void) fffog; \
+ if (z < zRow[i]) { \
+ ctx->OcclusionResult = GL_TRUE; \
+ return; \
+ } \
+ ffz += fdzdx; \
+ } \
+ }
+#include "s_tritemp.h"
+}
+
+
+
+/*
+ * Null rasterizer for measuring transformation speed.
+ */
+static void null_triangle( GLcontext *ctx, GLuint v0, GLuint v1,
+ GLuint v2, GLuint pv )
+{
+ (void) ctx;
+ (void) v0;
+ (void) v1;
+ (void) v2;
+ (void) pv;
+}
+
+
+#if 0
+# define dputs(s) puts(s)
+#else
+# define dputs(s)
+#endif
+
+
+
+/*
+ * Determine which triangle rendering function to use given the current
+ * rendering context.
+ *
+ * Please update the summary flag _SWRAST_NEW_TRIANGLE if you add or
+ * remove tests to this code.
+ */
+void
+_swrast_set_triangle_function( GLcontext *ctx )
+{
+ const GLboolean rgbmode = ctx->Visual.RGBAflag;
+
+ if (ctx->RenderMode==GL_RENDER) {
+ if (ctx->NoRaster) {
+ ctx->Driver.TriangleFunc = null_triangle;
+ return;
+ }
+ if (ctx->Driver.TriangleFunc) {
+ /* Device driver will draw triangles. */
+ dputs("Driver triangle");
+ return;
+ }
+
+ if (ctx->Polygon.SmoothFlag) {
+ _mesa_set_aa_triangle_function(ctx);
+ ASSERT(ctx->Driver.TriangleFunc);
+ return;
+ }
+
+ if (ctx->Depth.OcclusionTest &&
+ ctx->Depth.Test &&
+ ctx->Depth.Mask == GL_FALSE &&
+ ctx->Depth.Func == GL_LESS &&
+ !ctx->Stencil.Enabled) {
+ if ((rgbmode &&
+ ctx->Color.ColorMask[0] == 0 &&
+ ctx->Color.ColorMask[1] == 0 &&
+ ctx->Color.ColorMask[2] == 0 &&
+ ctx->Color.ColorMask[3] == 0)
+ ||
+ (!rgbmode && ctx->Color.IndexMask == 0)) {
+ dputs("occlusion_test_triangle");
+ ctx->Driver.TriangleFunc = occlusion_zless_triangle;
+ return;
+ }
+ }
+
+ if (ctx->Texture.ReallyEnabled) {
+ /* Ugh, we do a _lot_ of tests to pick the best textured tri func */
+ GLint format, filter;
+ const struct gl_texture_object *current2Dtex = ctx->Texture.Unit[0].CurrentD[2];
+ const struct gl_texture_image *image;
+ /* First see if we can used an optimized 2-D texture function */
+ if (ctx->Texture.ReallyEnabled==TEXTURE0_2D
+ && current2Dtex->WrapS==GL_REPEAT
+ && current2Dtex->WrapT==GL_REPEAT
+ && ((image = current2Dtex->Image[current2Dtex->BaseLevel]) != 0) /* correct! */
+ && image->Border==0
+ && ((format = image->Format)==GL_RGB || format==GL_RGBA)
+ && (filter = current2Dtex->MinFilter)==current2Dtex->MagFilter
+ && ctx->Light.Model.ColorControl==GL_SINGLE_COLOR
+ && ctx->Texture.Unit[0].EnvMode!=GL_COMBINE_EXT) {
+
+ if (ctx->Hint.PerspectiveCorrection==GL_FASTEST) {
+
+ if (filter==GL_NEAREST
+ && format==GL_RGB
+ && (ctx->Texture.Unit[0].EnvMode==GL_REPLACE
+ || ctx->Texture.Unit[0].EnvMode==GL_DECAL)
+ && ((ctx->RasterMask==DEPTH_BIT
+ && ctx->Depth.Func==GL_LESS
+ && ctx->Depth.Mask==GL_TRUE)
+ || ctx->RasterMask==0)
+ && ctx->Polygon.StippleFlag==GL_FALSE) {
+
+ if (ctx->RasterMask==DEPTH_BIT) {
+ ctx->Driver.TriangleFunc = simple_z_textured_triangle;
+ dputs("simple_z_textured_triangle");
+ }
+ else {
+ ctx->Driver.TriangleFunc = simple_textured_triangle;
+ dputs("simple_textured_triangle");
+ }
+ }
+ else {
+ if (ctx->Texture.Unit[0].EnvMode==GL_ADD) {
+ ctx->Driver.TriangleFunc = general_textured_triangle;
+ dputs("general_textured_triangle");
+ }
+ else {
+ ctx->Driver.TriangleFunc = affine_textured_triangle;
+ dputs("affine_textured_triangle");
+ }
+ }
+ }
+ else {
+ if (filter==GL_NEAREST) {
+ ctx->Driver.TriangleFunc = near_persp_textured_triangle;
+ dputs("near_persp_textured_triangle");
+ }
+ else {
+ ctx->Driver.TriangleFunc = lin_persp_textured_triangle;
+ dputs("lin_persp_textured_triangle");
+ }
+ }
+ }
+ else {
+ /* More complicated textures (mipmap, multi-tex, sep specular) */
+ GLboolean needLambda;
+ /* if mag filter != min filter we need to compute lambda */
+ const struct gl_texture_object *obj = ctx->Texture.Unit[0].Current;
+ if (obj && obj->MinFilter != obj->MagFilter)
+ needLambda = GL_TRUE;
+ else
+ needLambda = GL_FALSE;
+ if (ctx->Texture.MultiTextureEnabled) {
+ ctx->Driver.TriangleFunc = lambda_multitextured_triangle;
+ dputs("lambda_multitextured_triangle");
+ }
+ else if ((ctx->Light.Enabled &&
+ ctx->Light.Model.ColorControl==GL_SEPARATE_SPECULAR_COLOR)
+ || ctx->Fog.ColorSumEnabled) {
+ /* separate specular color interpolation */
+ if (needLambda) {
+ ctx->Driver.TriangleFunc = lambda_textured_spec_triangle;
+ dputs("lambda_textured_spec_triangle");
+ }
+ else {
+ ctx->Driver.TriangleFunc = general_textured_spec_triangle;
+ dputs("general_textured_spec_triangle");
+ }
+ }
+ else {
+ if (needLambda) {
+ ctx->Driver.TriangleFunc = lambda_textured_triangle;
+ dputs("lambda_textured_triangle");
+ }
+ else {
+ ctx->Driver.TriangleFunc = general_textured_triangle;
+ dputs("general_textured_triangle");
+ }
+ }
+ }
+ }
+ else {
+ if (ctx->Light.ShadeModel==GL_SMOOTH) {
+ /* smooth shaded, no texturing, stippled or some raster ops */
+ if (rgbmode) {
+ dputs("smooth_rgba_triangle");
+ ctx->Driver.TriangleFunc = smooth_rgba_triangle;
+ }
+ else {
+ dputs("smooth_ci_triangle");
+ ctx->Driver.TriangleFunc = smooth_ci_triangle;
+ }
+ }
+ else {
+ /* flat shaded, no texturing, stippled or some raster ops */
+ if (rgbmode) {
+ dputs("flat_rgba_triangle");
+ ctx->Driver.TriangleFunc = flat_rgba_triangle;
+ }
+ else {
+ dputs("flat_ci_triangle");
+ ctx->Driver.TriangleFunc = flat_ci_triangle;
+ }
+ }
+ }
+ }
+ else if (ctx->RenderMode==GL_FEEDBACK) {
+ ctx->Driver.TriangleFunc = gl_feedback_triangle;
+ }
+ else {
+ /* GL_SELECT mode */
+ ctx->Driver.TriangleFunc = gl_select_triangle;
+ }
+}
diff --git a/src/mesa/swrast/s_triangle.h b/src/mesa/swrast/s_triangle.h
new file mode 100644
index 0000000000..71c79a4a7c
--- /dev/null
+++ b/src/mesa/swrast/s_triangle.h
@@ -0,0 +1,44 @@
+/* $Id: s_triangle.h,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.1
+ *
+ * Copyright (C) 1999 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.
+ */
+
+
+
+
+
+#ifndef S_TRIANGLES_H
+#define S_TRIANGLES_H
+
+
+#include "types.h"
+#include "swrast.h"
+
+
+void gl_set_triangle_function( GLcontext *ctx );
+GLboolean gl_cull_triangle( GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv );
+
+
+#endif
+
diff --git a/src/mesa/swrast/s_tritemp.h b/src/mesa/swrast/s_tritemp.h
new file mode 100644
index 0000000000..21e7ceef5a
--- /dev/null
+++ b/src/mesa/swrast/s_tritemp.h
@@ -0,0 +1,1191 @@
+/* $Id: s_tritemp.h,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.
+ */
+
+
+/*
+ * Triangle Rasterizer Template
+ *
+ * This file is #include'd to generate custom triangle rasterizers.
+ *
+ * The following macros may be defined to indicate what auxillary information
+ * must be interplated across the triangle:
+ * INTERP_Z - if defined, interpolate Z values
+ * INTERP_RGB - if defined, interpolate RGB values
+ * INTERP_SPEC - if defined, interpolate specular RGB values
+ * INTERP_ALPHA - if defined, interpolate Alpha values
+ * INTERP_INDEX - if defined, interpolate color index values
+ * INTERP_INT_TEX - if defined, interpolate integer ST texcoords
+ * (fast, simple 2-D texture mapping)
+ * INTERP_TEX - if defined, interpolate set 0 float STRQ texcoords
+ * NOTE: OpenGL STRQ = Mesa STUV (R was taken for red)
+ * INTERP_MULTITEX - if defined, interpolate N units of STRQ texcoords
+ *
+ * When one can directly address pixels in the color buffer the following
+ * macros can be defined and used to compute pixel addresses during
+ * rasterization (see pRow):
+ * PIXEL_TYPE - the datatype of a pixel (GLubyte, GLushort, GLuint)
+ * BYTES_PER_ROW - number of bytes per row in the color buffer
+ * PIXEL_ADDRESS(X,Y) - returns the address of pixel at (X,Y) where
+ * Y==0 at bottom of screen and increases upward.
+ *
+ * Similarly, for direct depth buffer access, this type is used for depth
+ * buffer addressing:
+ * DEPTH_TYPE - either GLushort or GLuint
+ *
+ * Optionally, one may provide one-time setup code per triangle:
+ * SETUP_CODE - code which is to be executed once per triangle
+ *
+ * The following macro MUST be defined:
+ * INNER_LOOP(LEFT,RIGHT,Y) - code to write a span of pixels.
+ * Something like:
+ *
+ * for (x=LEFT; x<RIGHT;x++) {
+ * put_pixel(x,Y);
+ * // increment fixed point interpolants
+ * }
+ *
+ * This code was designed for the origin to be in the lower-left corner.
+ *
+ * Inspired by triangle rasterizer code written by Allen Akin. Thanks Allen!
+ */
+
+
+/*void triangle( GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv )*/
+{
+ typedef struct {
+ GLint v0, v1; /* Y(v0) < Y(v1) */
+ GLfloat dx; /* X(v1) - X(v0) */
+ GLfloat dy; /* Y(v1) - Y(v0) */
+ GLfixed fdxdy; /* dx/dy in fixed-point */
+ GLfixed fsx; /* first sample point x coord */
+ GLfixed fsy;
+ GLfloat adjy; /* adjust from v[0]->fy to fsy, scaled */
+ GLint lines; /* number of lines to be sampled on this edge */
+ GLfixed fx0; /* fixed pt X of lower endpoint */
+ } EdgeT;
+
+#ifdef INTERP_Z
+ const GLint depthBits = ctx->Visual.DepthBits;
+ const GLint fixedToDepthShift = depthBits <= 16 ? FIXED_SHIFT : 0;
+ const GLfloat maxDepth = ctx->Visual.DepthMaxF;
+#define FixedToDepth(F) ((F) >> fixedToDepthShift)
+#endif
+ const struct vertex_buffer *VB = ctx->VB;
+ EdgeT eMaj, eTop, eBot;
+ GLfloat oneOverArea;
+ int vMin, vMid, vMax; /* vertex indexes: Y(vMin)<=Y(vMid)<=Y(vMax) */
+ float bf = ctx->backface_sign;
+
+ /* find the order of the 3 vertices along the Y axis */
+ {
+ GLfloat y0 = VB->Win.data[v0][1];
+ GLfloat y1 = VB->Win.data[v1][1];
+ GLfloat y2 = VB->Win.data[v2][1];
+
+ if (y0<=y1) {
+ if (y1<=y2) {
+ vMin = v0; vMid = v1; vMax = v2; /* y0<=y1<=y2 */
+ }
+ else if (y2<=y0) {
+ vMin = v2; vMid = v0; vMax = v1; /* y2<=y0<=y1 */
+ }
+ else {
+ vMin = v0; vMid = v2; vMax = v1; bf = -bf; /* y0<=y2<=y1 */
+ }
+ }
+ else {
+ if (y0<=y2) {
+ vMin = v1; vMid = v0; vMax = v2; bf = -bf; /* y1<=y0<=y2 */
+ }
+ else if (y2<=y1) {
+ vMin = v2; vMid = v1; vMax = v0; bf = -bf; /* y2<=y1<=y0 */
+ }
+ else {
+ vMin = v1; vMid = v2; vMax = v0; /* y1<=y2<=y0 */
+ }
+ }
+ }
+
+ /* vertex/edge relationship */
+ eMaj.v0 = vMin; eMaj.v1 = vMax; /*TODO: .v1's not needed */
+ eTop.v0 = vMid; eTop.v1 = vMax;
+ eBot.v0 = vMin; eBot.v1 = vMid;
+
+ /* compute deltas for each edge: vertex[v1] - vertex[v0] */
+ eMaj.dx = VB->Win.data[vMax][0] - VB->Win.data[vMin][0];
+ eMaj.dy = VB->Win.data[vMax][1] - VB->Win.data[vMin][1];
+ eTop.dx = VB->Win.data[vMax][0] - VB->Win.data[vMid][0];
+ eTop.dy = VB->Win.data[vMax][1] - VB->Win.data[vMid][1];
+ eBot.dx = VB->Win.data[vMid][0] - VB->Win.data[vMin][0];
+ eBot.dy = VB->Win.data[vMid][1] - VB->Win.data[vMin][1];
+
+ /* compute oneOverArea */
+ {
+ const GLfloat area = eMaj.dx * eBot.dy - eBot.dx * eMaj.dy;
+
+ /* Do backface culling */
+ if (area * bf < 0.0)
+ return;
+
+ if (area == 0.0F)
+ return;
+
+ /* check for very tiny triangle */
+ if (area * area < 0.0025F) /* square it to ensure positive value */
+ oneOverArea = 1.0F / 0.0025F; /* a close-enough value */
+ else
+ oneOverArea = 1.0F / area;
+ }
+
+#ifndef DO_OCCLUSION_TEST
+ ctx->OcclusionResult = GL_TRUE;
+#endif
+
+ /* Edge setup. For a triangle strip these could be reused... */
+ {
+ /* fixed point Y coordinates */
+ GLfixed vMin_fx = FloatToFixed(VB->Win.data[vMin][0] + 0.5F);
+ GLfixed vMin_fy = FloatToFixed(VB->Win.data[vMin][1] - 0.5F);
+ GLfixed vMid_fx = FloatToFixed(VB->Win.data[vMid][0] + 0.5F);
+ GLfixed vMid_fy = FloatToFixed(VB->Win.data[vMid][1] - 0.5F);
+ GLfixed vMax_fy = FloatToFixed(VB->Win.data[vMax][1] - 0.5F);
+
+ eMaj.fsy = FixedCeil(vMin_fy);
+ eMaj.lines = FixedToInt(vMax_fy + FIXED_ONE - FIXED_EPSILON - eMaj.fsy);
+ if (eMaj.lines > 0) {
+ GLfloat dxdy = eMaj.dx / eMaj.dy;
+ eMaj.fdxdy = SignedFloatToFixed(dxdy);
+ eMaj.adjy = (GLfloat) (eMaj.fsy - vMin_fy); /* SCALED! */
+ eMaj.fx0 = vMin_fx;
+ eMaj.fsx = eMaj.fx0 + (GLfixed) (eMaj.adjy * dxdy);
+ }
+ else {
+ return; /*CULLED*/
+ }
+
+ eTop.fsy = FixedCeil(vMid_fy);
+ eTop.lines = FixedToInt(vMax_fy + FIXED_ONE - FIXED_EPSILON - eTop.fsy);
+ if (eTop.lines > 0) {
+ GLfloat dxdy = eTop.dx / eTop.dy;
+ eTop.fdxdy = SignedFloatToFixed(dxdy);
+ eTop.adjy = (GLfloat) (eTop.fsy - vMid_fy); /* SCALED! */
+ eTop.fx0 = vMid_fx;
+ eTop.fsx = eTop.fx0 + (GLfixed) (eTop.adjy * dxdy);
+ }
+
+ eBot.fsy = FixedCeil(vMin_fy);
+ eBot.lines = FixedToInt(vMid_fy + FIXED_ONE - FIXED_EPSILON - eBot.fsy);
+ if (eBot.lines > 0) {
+ GLfloat dxdy = eBot.dx / eBot.dy;
+ eBot.fdxdy = SignedFloatToFixed(dxdy);
+ eBot.adjy = (GLfloat) (eBot.fsy - vMin_fy); /* SCALED! */
+ eBot.fx0 = vMin_fx;
+ eBot.fsx = eBot.fx0 + (GLfixed) (eBot.adjy * dxdy);
+ }
+ }
+
+ /*
+ * Conceptually, we view a triangle as two subtriangles
+ * separated by a perfectly horizontal line. The edge that is
+ * intersected by this line is one with maximal absolute dy; we
+ * call it a ``major'' edge. The other two edges are the
+ * ``top'' edge (for the upper subtriangle) and the ``bottom''
+ * edge (for the lower subtriangle). If either of these two
+ * edges is horizontal or very close to horizontal, the
+ * corresponding subtriangle might cover zero sample points;
+ * we take care to handle such cases, for performance as well
+ * as correctness.
+ *
+ * By stepping rasterization parameters along the major edge,
+ * we can avoid recomputing them at the discontinuity where
+ * the top and bottom edges meet. However, this forces us to
+ * be able to scan both left-to-right and right-to-left.
+ * Also, we must determine whether the major edge is at the
+ * left or right side of the triangle. We do this by
+ * computing the magnitude of the cross-product of the major
+ * and top edges. Since this magnitude depends on the sine of
+ * the angle between the two edges, its sign tells us whether
+ * we turn to the left or to the right when travelling along
+ * the major edge to the top edge, and from this we infer
+ * whether the major edge is on the left or the right.
+ *
+ * Serendipitously, this cross-product magnitude is also a
+ * value we need to compute the iteration parameter
+ * derivatives for the triangle, and it can be used to perform
+ * backface culling because its sign tells us whether the
+ * triangle is clockwise or counterclockwise. In this code we
+ * refer to it as ``area'' because it's also proportional to
+ * the pixel area of the triangle.
+ */
+
+ {
+ GLint ltor; /* true if scanning left-to-right */
+#ifdef INTERP_Z
+ GLfloat dzdx, dzdy; GLfixed fdzdx;
+ GLfloat dfogdx, dfogdy; GLfixed fdfogdx;
+#endif
+#ifdef INTERP_RGB
+ GLfloat drdx, drdy; GLfixed fdrdx;
+ GLfloat dgdx, dgdy; GLfixed fdgdx;
+ GLfloat dbdx, dbdy; GLfixed fdbdx;
+#endif
+#ifdef INTERP_SPEC
+ GLfloat dsrdx, dsrdy; GLfixed fdsrdx;
+ GLfloat dsgdx, dsgdy; GLfixed fdsgdx;
+ GLfloat dsbdx, dsbdy; GLfixed fdsbdx;
+#endif
+#ifdef INTERP_ALPHA
+ GLfloat dadx, dady; GLfixed fdadx;
+#endif
+#ifdef INTERP_INDEX
+ GLfloat didx, didy; GLfixed fdidx;
+#endif
+#ifdef INTERP_INT_TEX
+ GLfloat dsdx, dsdy; GLfixed fdsdx;
+ GLfloat dtdx, dtdy; GLfixed fdtdx;
+#endif
+#ifdef INTERP_TEX
+ GLfloat dsdx, dsdy;
+ GLfloat dtdx, dtdy;
+ GLfloat dudx, dudy;
+ GLfloat dvdx, dvdy;
+#endif
+#ifdef INTERP_MULTITEX
+ GLfloat dsdx[MAX_TEXTURE_UNITS], dsdy[MAX_TEXTURE_UNITS];
+ GLfloat dtdx[MAX_TEXTURE_UNITS], dtdy[MAX_TEXTURE_UNITS];
+ GLfloat dudx[MAX_TEXTURE_UNITS], dudy[MAX_TEXTURE_UNITS];
+ GLfloat dvdx[MAX_TEXTURE_UNITS], dvdy[MAX_TEXTURE_UNITS];
+#endif
+
+ /*
+ * Execute user-supplied setup code
+ */
+#ifdef SETUP_CODE
+ SETUP_CODE
+#endif
+
+ ltor = (oneOverArea < 0.0F);
+
+ /* compute d?/dx and d?/dy derivatives */
+#ifdef INTERP_Z
+ {
+ GLfloat eMaj_dz, eBot_dz;
+ eMaj_dz = VB->Win.data[vMax][2] - VB->Win.data[vMin][2];
+ eBot_dz = VB->Win.data[vMid][2] - VB->Win.data[vMin][2];
+ dzdx = oneOverArea * (eMaj_dz * eBot.dy - eMaj.dy * eBot_dz);
+ if (dzdx > maxDepth || dzdx < -maxDepth) {
+ /* probably a sliver triangle */
+ dzdx = 0.0;
+ dzdy = 0.0;
+ }
+ else {
+ dzdy = oneOverArea * (eMaj.dx * eBot_dz - eMaj_dz * eBot.dx);
+ }
+ if (depthBits <= 16)
+ fdzdx = SignedFloatToFixed(dzdx);
+ else
+ fdzdx = (GLint) dzdx;
+ }
+ {
+ GLfloat eMaj_dfog, eBot_dfog;
+ eMaj_dfog = (VB->FogCoordPtr->data[vMax] - VB->FogCoordPtr->data[vMin]) * 256;
+ eBot_dfog = (VB->FogCoordPtr->data[vMid] - VB->FogCoordPtr->data[vMin]) * 256;
+ dfogdx = oneOverArea * (eMaj_dfog * eBot.dy - eMaj.dy * eBot_dfog);
+ fdfogdx = SignedFloatToFixed(dfogdx);
+ dfogdy = oneOverArea * (eMaj.dx * eBot_dfog - eMaj_dfog * eBot.dx);
+ }
+#endif
+#ifdef INTERP_RGB
+ {
+ GLfloat eMaj_dr, eBot_dr;
+ eMaj_dr = (GLint) VB->ColorPtr->data[vMax][0]
+ - (GLint) VB->ColorPtr->data[vMin][0];
+ eBot_dr = (GLint) VB->ColorPtr->data[vMid][0]
+ - (GLint) VB->ColorPtr->data[vMin][0];
+ drdx = oneOverArea * (eMaj_dr * eBot.dy - eMaj.dy * eBot_dr);
+ fdrdx = SignedFloatToFixed(drdx);
+ drdy = oneOverArea * (eMaj.dx * eBot_dr - eMaj_dr * eBot.dx);
+ }
+ {
+ GLfloat eMaj_dg, eBot_dg;
+ eMaj_dg = (GLint) VB->ColorPtr->data[vMax][1]
+ - (GLint) VB->ColorPtr->data[vMin][1];
+ eBot_dg = (GLint) VB->ColorPtr->data[vMid][1]
+ - (GLint) VB->ColorPtr->data[vMin][1];
+ dgdx = oneOverArea * (eMaj_dg * eBot.dy - eMaj.dy * eBot_dg);
+ fdgdx = SignedFloatToFixed(dgdx);
+ dgdy = oneOverArea * (eMaj.dx * eBot_dg - eMaj_dg * eBot.dx);
+ }
+ {
+ GLfloat eMaj_db, eBot_db;
+ eMaj_db = (GLint) VB->ColorPtr->data[vMax][2]
+ - (GLint) VB->ColorPtr->data[vMin][2];
+ eBot_db = (GLint) VB->ColorPtr->data[vMid][2]
+ - (GLint) VB->ColorPtr->data[vMin][2];
+ dbdx = oneOverArea * (eMaj_db * eBot.dy - eMaj.dy * eBot_db);
+ fdbdx = SignedFloatToFixed(dbdx);
+ dbdy = oneOverArea * (eMaj.dx * eBot_db - eMaj_db * eBot.dx);
+ }
+#endif
+#ifdef INTERP_SPEC
+ {
+ GLfloat eMaj_dsr, eBot_dsr;
+ eMaj_dsr = (GLint) VB->SecondaryColorPtr->data[vMax][0]
+ - (GLint) VB->SecondaryColorPtr->data[vMin][0];
+ eBot_dsr = (GLint) VB->SecondaryColorPtr->data[vMid][0]
+ - (GLint) VB->SecondaryColorPtr->data[vMin][0];
+ dsrdx = oneOverArea * (eMaj_dsr * eBot.dy - eMaj.dy * eBot_dsr);
+ fdsrdx = SignedFloatToFixed(dsrdx);
+ dsrdy = oneOverArea * (eMaj.dx * eBot_dsr - eMaj_dsr * eBot.dx);
+ }
+ {
+ GLfloat eMaj_dsg, eBot_dsg;
+ eMaj_dsg = (GLint) VB->SecondaryColorPtr->data[vMax][1]
+ - (GLint) VB->SecondaryColorPtr->data[vMin][1];
+ eBot_dsg = (GLint) VB->SecondaryColorPtr->data[vMid][1]
+ - (GLint) VB->SecondaryColorPtr->data[vMin][1];
+ dsgdx = oneOverArea * (eMaj_dsg * eBot.dy - eMaj.dy * eBot_dsg);
+ fdsgdx = SignedFloatToFixed(dsgdx);
+ dsgdy = oneOverArea * (eMaj.dx * eBot_dsg - eMaj_dsg * eBot.dx);
+ }
+ {
+ GLfloat eMaj_dsb, eBot_dsb;
+ eMaj_dsb = (GLint) VB->SecondaryColorPtr->data[vMax][2]
+ - (GLint) VB->SecondaryColorPtr->data[vMin][2];
+ eBot_dsb = (GLint) VB->SecondaryColorPtr->data[vMid][2]
+ - (GLint) VB->SecondaryColorPtr->data[vMin][2];
+ dsbdx = oneOverArea * (eMaj_dsb * eBot.dy - eMaj.dy * eBot_dsb);
+ fdsbdx = SignedFloatToFixed(dsbdx);
+ dsbdy = oneOverArea * (eMaj.dx * eBot_dsb - eMaj_dsb * eBot.dx);
+ }
+#endif
+#ifdef INTERP_ALPHA
+ {
+ GLfloat eMaj_da, eBot_da;
+ eMaj_da = (GLint) VB->ColorPtr->data[vMax][3]
+ - (GLint) VB->ColorPtr->data[vMin][3];
+ eBot_da = (GLint) VB->ColorPtr->data[vMid][3]
+ - (GLint) VB->ColorPtr->data[vMin][3];
+ dadx = oneOverArea * (eMaj_da * eBot.dy - eMaj.dy * eBot_da);
+ fdadx = SignedFloatToFixed(dadx);
+ dady = oneOverArea * (eMaj.dx * eBot_da - eMaj_da * eBot.dx);
+ }
+#endif
+#ifdef INTERP_INDEX
+ {
+ GLfloat eMaj_di, eBot_di;
+ eMaj_di = (GLint) VB->IndexPtr->data[vMax]
+ - (GLint) VB->IndexPtr->data[vMin];
+ eBot_di = (GLint) VB->IndexPtr->data[vMid]
+ - (GLint) VB->IndexPtr->data[vMin];
+ didx = oneOverArea * (eMaj_di * eBot.dy - eMaj.dy * eBot_di);
+ fdidx = SignedFloatToFixed(didx);
+ didy = oneOverArea * (eMaj.dx * eBot_di - eMaj_di * eBot.dx);
+ }
+#endif
+#ifdef INTERP_INT_TEX
+ {
+ GLfloat eMaj_ds, eBot_ds;
+ eMaj_ds = (VB->TexCoordPtr[0]->data[vMax][0]
+ - VB->TexCoordPtr[0]->data[vMin][0]) * S_SCALE;
+ eBot_ds = (VB->TexCoordPtr[0]->data[vMid][0]
+ - VB->TexCoordPtr[0]->data[vMin][0]) * S_SCALE;
+ dsdx = oneOverArea * (eMaj_ds * eBot.dy - eMaj.dy * eBot_ds);
+ fdsdx = SignedFloatToFixed(dsdx);
+ dsdy = oneOverArea * (eMaj.dx * eBot_ds - eMaj_ds * eBot.dx);
+ }
+ if (VB->TexCoordPtr[0]->size > 1) {
+ GLfloat eMaj_dt, eBot_dt;
+ eMaj_dt = (VB->TexCoordPtr[0]->data[vMax][1]
+ - VB->TexCoordPtr[0]->data[vMin][1]) * T_SCALE;
+ eBot_dt = (VB->TexCoordPtr[0]->data[vMid][1]
+ - VB->TexCoordPtr[0]->data[vMin][1]) * T_SCALE;
+ dtdx = oneOverArea * (eMaj_dt * eBot.dy - eMaj.dy * eBot_dt);
+ fdtdx = SignedFloatToFixed(dtdx);
+ dtdy = oneOverArea * (eMaj.dx * eBot_dt - eMaj_dt * eBot.dx);
+ }
+ else {
+ dtdx = 0;
+ fdtdx = SignedFloatToFixed(dtdx);
+ dtdy = 0;
+ }
+
+#endif
+#ifdef INTERP_TEX
+ {
+ GLfloat wMax = VB->Win.data[vMax][3];
+ GLfloat wMin = VB->Win.data[vMin][3];
+ GLfloat wMid = VB->Win.data[vMid][3];
+ GLfloat eMaj_ds, eBot_ds;
+ GLfloat eMaj_dt, eBot_dt;
+ GLfloat eMaj_du, eBot_du;
+ GLfloat eMaj_dv, eBot_dv;
+
+ eMaj_ds = VB->TexCoordPtr[0]->data[vMax][0] * wMax
+ - VB->TexCoordPtr[0]->data[vMin][0] * wMin;
+ eBot_ds = VB->TexCoordPtr[0]->data[vMid][0] * wMid
+ - VB->TexCoordPtr[0]->data[vMin][0] * wMin;
+ dsdx = oneOverArea * (eMaj_ds * eBot.dy - eMaj.dy * eBot_ds);
+ dsdy = oneOverArea * (eMaj.dx * eBot_ds - eMaj_ds * eBot.dx);
+
+
+ if (VB->TexCoordPtr[0]->size > 1) {
+ eMaj_dt = VB->TexCoordPtr[0]->data[vMax][1] * wMax
+ - VB->TexCoordPtr[0]->data[vMin][1] * wMin;
+ eBot_dt = VB->TexCoordPtr[0]->data[vMid][1] * wMid
+ - VB->TexCoordPtr[0]->data[vMin][1] * wMin;
+ dtdx = oneOverArea * (eMaj_dt * eBot.dy - eMaj.dy * eBot_dt);
+ dtdy = oneOverArea * (eMaj.dx * eBot_dt - eMaj_dt * eBot.dx);
+ }
+ else {
+ dtdx = 0;
+ dtdy = 0;
+ }
+
+ if (VB->TexCoordPtr[0]->size > 2) {
+ eMaj_du = VB->TexCoordPtr[0]->data[vMax][2] * wMax
+ - VB->TexCoordPtr[0]->data[vMin][2] * wMin;
+ eBot_du = VB->TexCoordPtr[0]->data[vMid][2] * wMid
+ - VB->TexCoordPtr[0]->data[vMin][2] * wMin;
+ dudx = oneOverArea * (eMaj_du * eBot.dy - eMaj.dy * eBot_du);
+ dudy = oneOverArea * (eMaj.dx * eBot_du - eMaj_du * eBot.dx);
+ }
+ else {
+ dudx = 0;
+ dudy = 0;
+ }
+
+ if (VB->TexCoordPtr[0]->size > 3) {
+ eMaj_dv = VB->TexCoordPtr[0]->data[vMax][3] * wMax
+ - VB->TexCoordPtr[0]->data[vMin][3] * wMin;
+ eBot_dv = VB->TexCoordPtr[0]->data[vMid][3] * wMid
+ - VB->TexCoordPtr[0]->data[vMin][3] * wMin;
+ dvdx = oneOverArea * (eMaj_dv * eBot.dy - eMaj.dy * eBot_dv);
+ dvdy = oneOverArea * (eMaj.dx * eBot_dv - eMaj_dv * eBot.dx);
+ }
+ else {
+ eMaj_dv = wMax - wMin;
+ eBot_dv = wMid - wMin;
+ dvdx = oneOverArea * (eMaj_dv * eBot.dy - eMaj.dy * eBot_dv);
+ dvdy = oneOverArea * (eMaj.dx * eBot_dv - eMaj_dv * eBot.dx);
+ }
+ }
+#endif
+#ifdef INTERP_MULTITEX
+ {
+ GLfloat wMax = VB->Win.data[vMax][3];
+ GLfloat wMin = VB->Win.data[vMin][3];
+ GLfloat wMid = VB->Win.data[vMid][3];
+ GLuint u;
+ for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+ if (ctx->Texture.Unit[u].ReallyEnabled) {
+ GLfloat eMaj_ds, eBot_ds;
+ GLfloat eMaj_dt, eBot_dt;
+ GLfloat eMaj_du, eBot_du;
+ GLfloat eMaj_dv, eBot_dv;
+ eMaj_ds = VB->TexCoordPtr[u]->data[vMax][0] * wMax
+ - VB->TexCoordPtr[u]->data[vMin][0] * wMin;
+ eBot_ds = VB->TexCoordPtr[u]->data[vMid][0] * wMid
+ - VB->TexCoordPtr[u]->data[vMin][0] * wMin;
+ dsdx[u] = oneOverArea * (eMaj_ds * eBot.dy - eMaj.dy * eBot_ds);
+ dsdy[u] = oneOverArea * (eMaj.dx * eBot_ds - eMaj_ds * eBot.dx);
+
+ if (VB->TexCoordPtr[u]->size > 1) {
+ eMaj_dt = VB->TexCoordPtr[u]->data[vMax][1] * wMax
+ - VB->TexCoordPtr[u]->data[vMin][1] * wMin;
+ eBot_dt = VB->TexCoordPtr[u]->data[vMid][1] * wMid
+ - VB->TexCoordPtr[u]->data[vMin][1] * wMin;
+ dtdx[u] = oneOverArea * (eMaj_dt * eBot.dy - eMaj.dy * eBot_dt);
+ dtdy[u] = oneOverArea * (eMaj.dx * eBot_dt - eMaj_dt * eBot.dx);
+ }
+ else {
+ dtdx[u] = 0.0;
+ dtdy[u] = 0.0;
+ }
+
+ if (VB->TexCoordPtr[u]->size > 2) {
+ eMaj_du = VB->TexCoordPtr[u]->data[vMax][2] * wMax
+ - VB->TexCoordPtr[u]->data[vMin][2] * wMin;
+ eBot_du = VB->TexCoordPtr[u]->data[vMid][2] * wMid
+ - VB->TexCoordPtr[u]->data[vMin][2] * wMin;
+ dudx[u] = oneOverArea * (eMaj_du * eBot.dy - eMaj.dy * eBot_du);
+ dudy[u] = oneOverArea * (eMaj.dx * eBot_du - eMaj_du * eBot.dx);
+ }
+ else {
+ dudx[u] = 0.0;
+ dudy[u] = 0.0;
+ }
+
+ if (VB->TexCoordPtr[u]->size > 3) {
+ eMaj_dv = VB->TexCoordPtr[u]->data[vMax][3] * wMax
+ - VB->TexCoordPtr[u]->data[vMin][3] * wMin;
+ eBot_dv = VB->TexCoordPtr[u]->data[vMid][3] * wMid
+ - VB->TexCoordPtr[u]->data[vMin][3] * wMin;
+ dvdx[u] = oneOverArea * (eMaj_dv * eBot.dy - eMaj.dy * eBot_dv);
+ dvdy[u] = oneOverArea * (eMaj.dx * eBot_dv - eMaj_dv * eBot.dx);
+ }
+ else {
+ eMaj_dv = wMax - wMin;
+ eBot_dv = wMid - wMin;
+ dvdx[u] = oneOverArea * (eMaj_dv * eBot.dy - eMaj.dy * eBot_dv);
+ dvdy[u] = oneOverArea * (eMaj.dx * eBot_dv - eMaj_dv * eBot.dx);
+ }
+ }
+ }
+ }
+#endif
+
+ /*
+ * We always sample at pixel centers. However, we avoid
+ * explicit half-pixel offsets in this code by incorporating
+ * the proper offset in each of x and y during the
+ * transformation to window coordinates.
+ *
+ * We also apply the usual rasterization rules to prevent
+ * cracks and overlaps. A pixel is considered inside a
+ * subtriangle if it meets all of four conditions: it is on or
+ * to the right of the left edge, strictly to the left of the
+ * right edge, on or below the top edge, and strictly above
+ * the bottom edge. (Some edges may be degenerate.)
+ *
+ * The following discussion assumes left-to-right scanning
+ * (that is, the major edge is on the left); the right-to-left
+ * case is a straightforward variation.
+ *
+ * We start by finding the half-integral y coordinate that is
+ * at or below the top of the triangle. This gives us the
+ * first scan line that could possibly contain pixels that are
+ * inside the triangle.
+ *
+ * Next we creep down the major edge until we reach that y,
+ * and compute the corresponding x coordinate on the edge.
+ * Then we find the half-integral x that lies on or just
+ * inside the edge. This is the first pixel that might lie in
+ * the interior of the triangle. (We won't know for sure
+ * until we check the other edges.)
+ *
+ * As we rasterize the triangle, we'll step down the major
+ * edge. For each step in y, we'll move an integer number
+ * of steps in x. There are two possible x step sizes, which
+ * we'll call the ``inner'' step (guaranteed to land on the
+ * edge or inside it) and the ``outer'' step (guaranteed to
+ * land on the edge or outside it). The inner and outer steps
+ * differ by one. During rasterization we maintain an error
+ * term that indicates our distance from the true edge, and
+ * select either the inner step or the outer step, whichever
+ * gets us to the first pixel that falls inside the triangle.
+ *
+ * All parameters (z, red, etc.) as well as the buffer
+ * addresses for color and z have inner and outer step values,
+ * so that we can increment them appropriately. This method
+ * eliminates the need to adjust parameters by creeping a
+ * sub-pixel amount into the triangle at each scanline.
+ */
+
+ {
+ int subTriangle;
+ GLfixed fx, fxLeftEdge, fxRightEdge, fdxLeftEdge, fdxRightEdge;
+ GLfixed fdxOuter;
+ int idxOuter;
+ float dxOuter;
+ GLfixed fError, fdError;
+ float adjx, adjy;
+ GLfixed fy;
+ int iy;
+#ifdef PIXEL_ADDRESS
+ PIXEL_TYPE *pRow;
+ int dPRowOuter, dPRowInner; /* offset in bytes */
+#endif
+#ifdef INTERP_Z
+# ifdef DEPTH_TYPE
+ DEPTH_TYPE *zRow;
+ int dZRowOuter, dZRowInner; /* offset in bytes */
+# endif
+ GLfixed fz, fdzOuter, fdzInner;
+ GLfixed ffog, fdfogOuter, fdfogInner;
+#endif
+#ifdef INTERP_RGB
+ GLfixed fr, fdrOuter, fdrInner;
+ GLfixed fg, fdgOuter, fdgInner;
+ GLfixed fb, fdbOuter, fdbInner;
+#endif
+#ifdef INTERP_SPEC
+ GLfixed fsr, fdsrOuter, fdsrInner;
+ GLfixed fsg, fdsgOuter, fdsgInner;
+ GLfixed fsb, fdsbOuter, fdsbInner;
+#endif
+#ifdef INTERP_ALPHA
+ GLfixed fa, fdaOuter, fdaInner;
+#endif
+#ifdef INTERP_INDEX
+ GLfixed fi, fdiOuter, fdiInner;
+#endif
+#ifdef INTERP_INT_TEX
+ GLfixed fs, fdsOuter, fdsInner;
+ GLfixed ft, fdtOuter, fdtInner;
+#endif
+#ifdef INTERP_TEX
+ GLfloat sLeft, dsOuter, dsInner;
+ GLfloat tLeft, dtOuter, dtInner;
+ GLfloat uLeft, duOuter, duInner;
+ GLfloat vLeft, dvOuter, dvInner;
+#endif
+#ifdef INTERP_MULTITEX
+ GLfloat sLeft[MAX_TEXTURE_UNITS];
+ GLfloat tLeft[MAX_TEXTURE_UNITS];
+ GLfloat uLeft[MAX_TEXTURE_UNITS];
+ GLfloat vLeft[MAX_TEXTURE_UNITS];
+ GLfloat dsOuter[MAX_TEXTURE_UNITS], dsInner[MAX_TEXTURE_UNITS];
+ GLfloat dtOuter[MAX_TEXTURE_UNITS], dtInner[MAX_TEXTURE_UNITS];
+ GLfloat duOuter[MAX_TEXTURE_UNITS], duInner[MAX_TEXTURE_UNITS];
+ GLfloat dvOuter[MAX_TEXTURE_UNITS], dvInner[MAX_TEXTURE_UNITS];
+#endif
+
+ for (subTriangle=0; subTriangle<=1; subTriangle++) {
+ EdgeT *eLeft, *eRight;
+ int setupLeft, setupRight;
+ int lines;
+
+ if (subTriangle==0) {
+ /* bottom half */
+ if (ltor) {
+ eLeft = &eMaj;
+ eRight = &eBot;
+ lines = eRight->lines;
+ setupLeft = 1;
+ setupRight = 1;
+ }
+ else {
+ eLeft = &eBot;
+ eRight = &eMaj;
+ lines = eLeft->lines;
+ setupLeft = 1;
+ setupRight = 1;
+ }
+ }
+ else {
+ /* top half */
+ if (ltor) {
+ eLeft = &eMaj;
+ eRight = &eTop;
+ lines = eRight->lines;
+ setupLeft = 0;
+ setupRight = 1;
+ }
+ else {
+ eLeft = &eTop;
+ eRight = &eMaj;
+ lines = eLeft->lines;
+ setupLeft = 1;
+ setupRight = 0;
+ }
+ if (lines == 0)
+ return;
+ }
+
+ if (setupLeft && eLeft->lines > 0) {
+ GLint vLower;
+ GLfixed fsx = eLeft->fsx;
+ fx = FixedCeil(fsx);
+ fError = fx - fsx - FIXED_ONE;
+ fxLeftEdge = fsx - FIXED_EPSILON;
+ fdxLeftEdge = eLeft->fdxdy;
+ fdxOuter = FixedFloor(fdxLeftEdge - FIXED_EPSILON);
+ fdError = fdxOuter - fdxLeftEdge + FIXED_ONE;
+ idxOuter = FixedToInt(fdxOuter);
+ dxOuter = (float) idxOuter;
+ (void) dxOuter;
+
+ fy = eLeft->fsy;
+ iy = FixedToInt(fy);
+
+ adjx = (float)(fx - eLeft->fx0); /* SCALED! */
+ adjy = eLeft->adjy; /* SCALED! */
+ (void) adjx; /* silence compiler warnings */
+ (void) adjy; /* silence compiler warnings */
+
+ vLower = eLeft->v0;
+ (void) vLower; /* silence compiler warnings */
+
+#ifdef PIXEL_ADDRESS
+ {
+ pRow = PIXEL_ADDRESS( FixedToInt(fxLeftEdge), iy );
+ dPRowOuter = -((int)BYTES_PER_ROW) + idxOuter * sizeof(PIXEL_TYPE);
+ /* negative because Y=0 at bottom and increases upward */
+ }
+#endif
+ /*
+ * Now we need the set of parameter (z, color, etc.) values at
+ * the point (fx, fy). This gives us properly-sampled parameter
+ * values that we can step from pixel to pixel. Furthermore,
+ * although we might have intermediate results that overflow
+ * the normal parameter range when we step temporarily outside
+ * the triangle, we shouldn't overflow or underflow for any
+ * pixel that's actually inside the triangle.
+ */
+
+#ifdef INTERP_Z
+ {
+ GLfloat z0 = VB->Win.data[vLower][2] + ctx->PolygonZoffset;
+ if (depthBits <= 16) {
+ /* interpolate fixed-pt values */
+ GLfloat tmp = (z0 * FIXED_SCALE +
+ dzdx * adjx + dzdy * adjy) + FIXED_HALF;
+ if (tmp < MAX_GLUINT / 2)
+ fz = (GLfixed) tmp;
+ else
+ fz = MAX_GLUINT / 2;
+ fdzOuter = SignedFloatToFixed(dzdy + dxOuter * dzdx);
+ }
+ else {
+ /* interpolate depth values exactly */
+ fz = (GLint) (z0 + dzdx*FixedToFloat(adjx) + dzdy*FixedToFloat(adjy));
+ fdzOuter = (GLint) (dzdy + dxOuter * dzdx);
+ }
+# ifdef DEPTH_TYPE
+ zRow = (DEPTH_TYPE *) _mesa_zbuffer_address(ctx, FixedToInt(fxLeftEdge), iy);
+ dZRowOuter = (ctx->DrawBuffer->Width + idxOuter) * sizeof(DEPTH_TYPE);
+# endif
+ }
+ ffog = FloatToFixed(VB->FogCoordPtr->data[vLower]) * 256 + dfogdx * adjx + dfogdy * adjy + FIXED_HALF;
+ fdfogOuter = SignedFloatToFixed(dfogdy + dxOuter * dfogdx);
+#endif
+#ifdef INTERP_RGB
+ fr = (GLfixed)(IntToFixed(VB->ColorPtr->data[vLower][0])
+ + drdx * adjx + drdy * adjy) + FIXED_HALF;
+ fdrOuter = SignedFloatToFixed(drdy + dxOuter * drdx);
+
+ fg = (GLfixed)(IntToFixed(VB->ColorPtr->data[vLower][1])
+ + dgdx * adjx + dgdy * adjy) + FIXED_HALF;
+ fdgOuter = SignedFloatToFixed(dgdy + dxOuter * dgdx);
+
+ fb = (GLfixed)(IntToFixed(VB->ColorPtr->data[vLower][2])
+ + dbdx * adjx + dbdy * adjy) + FIXED_HALF;
+ fdbOuter = SignedFloatToFixed(dbdy + dxOuter * dbdx);
+#endif
+#ifdef INTERP_SPEC
+ fsr = (GLfixed)(IntToFixed(VB->SecondaryColorPtr->data[vLower][0])
+ + dsrdx * adjx + dsrdy * adjy) + FIXED_HALF;
+ fdsrOuter = SignedFloatToFixed(dsrdy + dxOuter * dsrdx);
+
+ fsg = (GLfixed)(IntToFixed(VB->SecondaryColorPtr->data[vLower][1])
+ + dsgdx * adjx + dsgdy * adjy) + FIXED_HALF;
+ fdsgOuter = SignedFloatToFixed(dsgdy + dxOuter * dsgdx);
+
+ fsb = (GLfixed)(IntToFixed(VB->SecondaryColorPtr->data[vLower][2])
+ + dsbdx * adjx + dsbdy * adjy) + FIXED_HALF;
+ fdsbOuter = SignedFloatToFixed(dsbdy + dxOuter * dsbdx);
+#endif
+#ifdef INTERP_ALPHA
+ fa = (GLfixed)(IntToFixed(VB->ColorPtr->data[vLower][3])
+ + dadx * adjx + dady * adjy) + FIXED_HALF;
+ fdaOuter = SignedFloatToFixed(dady + dxOuter * dadx);
+#endif
+#ifdef INTERP_INDEX
+ fi = (GLfixed)(VB->IndexPtr->data[vLower] * FIXED_SCALE
+ + didx * adjx + didy * adjy) + FIXED_HALF;
+ fdiOuter = SignedFloatToFixed(didy + dxOuter * didx);
+#endif
+#ifdef INTERP_INT_TEX
+ {
+ GLfloat s0, t0;
+ s0 = VB->TexCoordPtr[0]->data[vLower][0] * S_SCALE;
+ fs = (GLfixed)(s0 * FIXED_SCALE + dsdx * adjx + dsdy * adjy) + FIXED_HALF;
+ fdsOuter = SignedFloatToFixed(dsdy + dxOuter * dsdx);
+
+ if (VB->TexCoordPtr[0]->size > 1)
+ {
+ t0 = VB->TexCoordPtr[0]->data[vLower][1] * T_SCALE;
+ ft = (GLfixed)(t0 * FIXED_SCALE + dtdx * adjx + dtdy * adjy) + FIXED_HALF;
+ fdtOuter = SignedFloatToFixed(dtdy + dxOuter * dtdx);
+ }
+ else
+ {
+ t0 = 0;
+ ft = (GLfixed) FIXED_HALF;
+ fdtOuter = SignedFloatToFixed(0);
+ }
+ }
+#endif
+#ifdef INTERP_TEX
+ {
+ GLfloat invW = VB->Win.data[vLower][3];
+ GLfloat s0, t0, u0, v0;
+ s0 = VB->TexCoordPtr[0]->data[vLower][0] * invW;
+ sLeft = s0 + (dsdx * adjx + dsdy * adjy) * (1.0F/FIXED_SCALE);
+ dsOuter = dsdy + dxOuter * dsdx;
+ if (VB->TexCoordPtr[0]->size > 1) {
+ t0 = VB->TexCoordPtr[0]->data[vLower][1] * invW;
+ tLeft = t0 + (dtdx * adjx + dtdy * adjy) * (1.0F/FIXED_SCALE);
+ dtOuter = dtdy + dxOuter * dtdx;
+ }
+ else {
+ tLeft = dtOuter = 0.0;
+ }
+ if (VB->TexCoordPtr[0]->size > 2) {
+ u0 = VB->TexCoordPtr[0]->data[vLower][2] * invW;
+ uLeft = u0 + (dudx * adjx + dudy * adjy) * (1.0F/FIXED_SCALE);
+ duOuter = dudy + dxOuter * dudx;
+ }
+ else {
+ uLeft = duOuter = 0.0;
+ }
+ if (VB->TexCoordPtr[0]->size > 3) {
+ v0 = VB->TexCoordPtr[0]->data[vLower][3] * invW;
+ }
+ else {
+ v0 = invW;
+ }
+ vLeft = v0 + (dvdx * adjx + dvdy * adjy) * (1.0F/FIXED_SCALE);
+ dvOuter = dvdy + dxOuter * dvdx;
+ }
+#endif
+#ifdef INTERP_MULTITEX
+ {
+ GLuint u;
+ for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+ if (ctx->Texture.Unit[u].ReallyEnabled) {
+ GLfloat invW = VB->Win.data[vLower][3];
+ GLfloat s0, t0, u0, v0;
+ s0 = VB->TexCoordPtr[u]->data[vLower][0] * invW;
+ sLeft[u] = s0 + (dsdx[u] * adjx + dsdy[u] * adjy) * (1.0F/FIXED_SCALE);
+ dsOuter[u] = dsdy[u] + dxOuter * dsdx[u];
+ if (VB->TexCoordPtr[u]->size > 1) {
+ t0 = VB->TexCoordPtr[u]->data[vLower][1] * invW;
+ tLeft[u] = t0 + (dtdx[u] * adjx + dtdy[u] * adjy) * (1.0F/FIXED_SCALE);
+ dtOuter[u] = dtdy[u] + dxOuter * dtdx[u];
+ }
+ else {
+ tLeft[u] = dtOuter[u] = 0.0;
+ }
+ if (VB->TexCoordPtr[u]->size > 2) {
+ u0 = VB->TexCoordPtr[u]->data[vLower][2] * invW;
+ uLeft[u] = u0 + (dudx[u] * adjx + dudy[u] * adjy) * (1.0F/FIXED_SCALE);
+ duOuter[u] = dudy[u] + dxOuter * dudx[u];
+ }
+ else {
+ uLeft[u] = duOuter[u] = 0.0;
+ }
+ if (VB->TexCoordPtr[u]->size > 3) {
+ v0 = VB->TexCoordPtr[u]->data[vLower][3] * invW;
+ }
+ else {
+ v0 = invW;
+ }
+ vLeft[u] = v0 + (dvdx[u] * adjx + dvdy[u] * adjy) * (1.0F/FIXED_SCALE);
+ dvOuter[u] = dvdy[u] + dxOuter * dvdx[u];
+ }
+ }
+ }
+#endif
+
+ } /*if setupLeft*/
+
+
+ if (setupRight && eRight->lines>0) {
+ fxRightEdge = eRight->fsx - FIXED_EPSILON;
+ fdxRightEdge = eRight->fdxdy;
+ }
+
+ if (lines==0) {
+ continue;
+ }
+
+
+ /* Rasterize setup */
+#ifdef PIXEL_ADDRESS
+ dPRowInner = dPRowOuter + sizeof(PIXEL_TYPE);
+#endif
+#ifdef INTERP_Z
+# ifdef DEPTH_TYPE
+ dZRowInner = dZRowOuter + sizeof(DEPTH_TYPE);
+# endif
+ fdzInner = fdzOuter + fdzdx;
+ fdfogInner = fdfogOuter + fdfogdx;
+#endif
+#ifdef INTERP_RGB
+ fdrInner = fdrOuter + fdrdx;
+ fdgInner = fdgOuter + fdgdx;
+ fdbInner = fdbOuter + fdbdx;
+#endif
+#ifdef INTERP_SPEC
+ fdsrInner = fdsrOuter + fdsrdx;
+ fdsgInner = fdsgOuter + fdsgdx;
+ fdsbInner = fdsbOuter + fdsbdx;
+#endif
+#ifdef INTERP_ALPHA
+ fdaInner = fdaOuter + fdadx;
+#endif
+#ifdef INTERP_INDEX
+ fdiInner = fdiOuter + fdidx;
+#endif
+#ifdef INTERP_INT_TEX
+ fdsInner = fdsOuter + fdsdx;
+ fdtInner = fdtOuter + fdtdx;
+#endif
+#ifdef INTERP_TEX
+ dsInner = dsOuter + dsdx;
+ dtInner = dtOuter + dtdx;
+ duInner = duOuter + dudx;
+ dvInner = dvOuter + dvdx;
+#endif
+#ifdef INTERP_MULTITEX
+ {
+ GLuint u;
+ for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+ if (ctx->Texture.Unit[u].ReallyEnabled) {
+ dsInner[u] = dsOuter[u] + dsdx[u];
+ dtInner[u] = dtOuter[u] + dtdx[u];
+ duInner[u] = duOuter[u] + dudx[u];
+ dvInner[u] = dvOuter[u] + dvdx[u];
+ }
+ }
+ }
+#endif
+
+ while (lines>0) {
+ /* initialize the span interpolants to the leftmost value */
+ /* ff = fixed-pt fragment */
+ GLint left = FixedToInt(fxLeftEdge);
+ GLint right = FixedToInt(fxRightEdge);
+#ifdef INTERP_Z
+ GLfixed ffz = fz;
+ GLfixed fffog = ffog;
+#endif
+#ifdef INTERP_RGB
+ GLfixed ffr = fr, ffg = fg, ffb = fb;
+#endif
+#ifdef INTERP_SPEC
+ GLfixed ffsr = fsr, ffsg = fsg, ffsb = fsb;
+#endif
+#ifdef INTERP_ALPHA
+ GLfixed ffa = fa;
+#endif
+#ifdef INTERP_INDEX
+ GLfixed ffi = fi;
+#endif
+#ifdef INTERP_INT_TEX
+ GLfixed ffs = fs, fft = ft;
+#endif
+#ifdef INTERP_TEX
+ GLfloat ss = sLeft, tt = tLeft, uu = uLeft, vv = vLeft;
+#endif
+#ifdef INTERP_MULTITEX
+ GLfloat ss[MAX_TEXTURE_UNITS];
+ GLfloat tt[MAX_TEXTURE_UNITS];
+ GLfloat uu[MAX_TEXTURE_UNITS];
+ GLfloat vv[MAX_TEXTURE_UNITS];
+ {
+ GLuint u;
+ for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+ if (ctx->Texture.Unit[u].ReallyEnabled) {
+ ss[u] = sLeft[u];
+ tt[u] = tLeft[u];
+ uu[u] = uLeft[u];
+ vv[u] = vLeft[u];
+ }
+ }
+ }
+#endif
+
+#ifdef INTERP_RGB
+ {
+ /* need this to accomodate round-off errors */
+ GLfixed ffrend = ffr+(right-left-1)*fdrdx;
+ GLfixed ffgend = ffg+(right-left-1)*fdgdx;
+ GLfixed ffbend = ffb+(right-left-1)*fdbdx;
+ if (ffrend<0) ffr -= ffrend;
+ if (ffgend<0) ffg -= ffgend;
+ if (ffbend<0) ffb -= ffbend;
+ if (ffr<0) ffr = 0;
+ if (ffg<0) ffg = 0;
+ if (ffb<0) ffb = 0;
+ }
+#endif
+#ifdef INTERP_SPEC
+ {
+ /* need this to accomodate round-off errors */
+ GLfixed ffsrend = ffsr+(right-left-1)*fdsrdx;
+ GLfixed ffsgend = ffsg+(right-left-1)*fdsgdx;
+ GLfixed ffsbend = ffsb+(right-left-1)*fdsbdx;
+ if (ffsrend<0) ffsr -= ffsrend;
+ if (ffsgend<0) ffsg -= ffsgend;
+ if (ffsbend<0) ffsb -= ffsbend;
+ if (ffsr<0) ffsr = 0;
+ if (ffsg<0) ffsg = 0;
+ if (ffsb<0) ffsb = 0;
+ }
+#endif
+#ifdef INTERP_ALPHA
+ {
+ GLfixed ffaend = ffa+(right-left-1)*fdadx;
+ if (ffaend<0) ffa -= ffaend;
+ if (ffa<0) ffa = 0;
+ }
+#endif
+#ifdef INTERP_INDEX
+ if (ffi<0) ffi = 0;
+#endif
+
+ INNER_LOOP( left, right, iy );
+
+ /*
+ * Advance to the next scan line. Compute the
+ * new edge coordinates, and adjust the
+ * pixel-center x coordinate so that it stays
+ * on or inside the major edge.
+ */
+ iy++;
+ lines--;
+
+ fxLeftEdge += fdxLeftEdge;
+ fxRightEdge += fdxRightEdge;
+
+
+ fError += fdError;
+ if (fError >= 0) {
+ fError -= FIXED_ONE;
+#ifdef PIXEL_ADDRESS
+ pRow = (PIXEL_TYPE *) ((GLubyte*)pRow + dPRowOuter);
+#endif
+#ifdef INTERP_Z
+# ifdef DEPTH_TYPE
+ zRow = (DEPTH_TYPE *) ((GLubyte*)zRow + dZRowOuter);
+# endif
+ fz += fdzOuter;
+ ffog += fdfogOuter;
+#endif
+#ifdef INTERP_RGB
+ fr += fdrOuter; fg += fdgOuter; fb += fdbOuter;
+#endif
+#ifdef INTERP_SPEC
+ fsr += fdsrOuter; fsg += fdsgOuter; fsb += fdsbOuter;
+#endif
+#ifdef INTERP_ALPHA
+ fa += fdaOuter;
+#endif
+#ifdef INTERP_INDEX
+ fi += fdiOuter;
+#endif
+#ifdef INTERP_INT_TEX
+ fs += fdsOuter; ft += fdtOuter;
+#endif
+#ifdef INTERP_TEX
+ sLeft += dsOuter;
+ tLeft += dtOuter;
+ uLeft += duOuter;
+ vLeft += dvOuter;
+#endif
+#ifdef INTERP_MULTITEX
+ {
+ GLuint u;
+ for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+ if (ctx->Texture.Unit[u].ReallyEnabled) {
+ sLeft[u] += dsOuter[u];
+ tLeft[u] += dtOuter[u];
+ uLeft[u] += duOuter[u];
+ vLeft[u] += dvOuter[u];
+ }
+ }
+ }
+#endif
+ }
+ else {
+#ifdef PIXEL_ADDRESS
+ pRow = (PIXEL_TYPE *) ((GLubyte*)pRow + dPRowInner);
+#endif
+#ifdef INTERP_Z
+# ifdef DEPTH_TYPE
+ zRow = (DEPTH_TYPE *) ((GLubyte*)zRow + dZRowInner);
+# endif
+ fz += fdzInner;
+ ffog += fdfogInner;
+#endif
+#ifdef INTERP_RGB
+ fr += fdrInner; fg += fdgInner; fb += fdbInner;
+#endif
+#ifdef INTERP_SPEC
+ fsr += fdsrInner; fsg += fdsgInner; fsb += fdsbInner;
+#endif
+#ifdef INTERP_ALPHA
+ fa += fdaInner;
+#endif
+#ifdef INTERP_INDEX
+ fi += fdiInner;
+#endif
+#ifdef INTERP_INT_TEX
+ fs += fdsInner; ft += fdtInner;
+#endif
+#ifdef INTERP_TEX
+ sLeft += dsInner;
+ tLeft += dtInner;
+ uLeft += duInner;
+ vLeft += dvInner;
+#endif
+#ifdef INTERP_MULTITEX
+ {
+ GLuint u;
+ for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
+ if (ctx->Texture.Unit[u].ReallyEnabled) {
+ sLeft[u] += dsInner[u];
+ tLeft[u] += dtInner[u];
+ uLeft[u] += duInner[u];
+ vLeft[u] += dvInner[u];
+ }
+ }
+ }
+#endif
+ }
+ } /*while lines>0*/
+
+ } /* for subTriangle */
+
+ }
+ }
+}
+
+#undef SETUP_CODE
+#undef INNER_LOOP
+
+#undef PIXEL_TYPE
+#undef BYTES_PER_ROW
+#undef PIXEL_ADDRESS
+
+#undef INTERP_Z
+#undef INTERP_RGB
+#undef INTERP_SPEC
+#undef INTERP_ALPHA
+#undef INTERP_INDEX
+#undef INTERP_INT_TEX
+#undef INTERP_TEX
+#undef INTERP_MULTITEX
+
+#undef S_SCALE
+#undef T_SCALE
+
+#undef FixedToDepth
+
+#undef DO_OCCLUSION_TEST
diff --git a/src/mesa/swrast/s_zoom.c b/src/mesa/swrast/s_zoom.c
new file mode 100644
index 0000000000..3520fd506a
--- /dev/null
+++ b/src/mesa/swrast/s_zoom.c
@@ -0,0 +1,453 @@
+/* $Id: s_zoom.c,v 1.1 2000/10/31 18:00:05 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.
+ */
+
+#include "glheader.h"
+#include "macros.h"
+
+#include "s_span.h"
+#include "s_stencil.h"
+#include "s_zoom.h"
+
+
+
+/*
+ * Write a span of pixels to the frame buffer while applying a pixel zoom.
+ * This is only used by glDrawPixels and glCopyPixels.
+ * Input: n - number of pixels in input row
+ * x, y - destination of the span
+ * z - depth values for the span
+ * red, green, blue, alpha - array of colors
+ * y0 - location of first row in the image we're drawing.
+ */
+void
+gl_write_zoomed_rgba_span( GLcontext *ctx,
+ GLuint n, GLint x, GLint y, const GLdepth z[],
+ const GLfixed *fog,
+ CONST GLchan rgba[][4], GLint y0 )
+{
+ GLint m;
+ GLint r0, r1, row, r;
+ GLint i, j, skipcol;
+ GLchan zrgba[MAX_WIDTH][4]; /* zoomed pixel colors */
+ GLdepth zdepth[MAX_WIDTH]; /* zoomed depth values */
+ GLfixed zfog[MAX_WIDTH]; /* zoomed fog values */
+ GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH );
+ const GLuint *srcRGBA32 = (const GLuint *) rgba;
+ GLuint *dstRGBA32 = (GLuint *) zrgba;
+
+ /* compute width of output row */
+ m = (GLint) ABSF( n * ctx->Pixel.ZoomX );
+ if (m==0) {
+ return;
+ }
+ if (ctx->Pixel.ZoomX<0.0) {
+ /* adjust x coordinate for left/right mirroring */
+ x = x - m;
+ }
+
+ /* compute which rows to draw */
+ row = y-y0;
+ r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY);
+ r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY);
+ if (r0==r1) {
+ return;
+ }
+ else if (r1<r0) {
+ GLint rtmp = r1;
+ r1 = r0;
+ r0 = rtmp;
+ }
+
+ /* return early if r0...r1 is above or below window */
+ if (r0<0 && r1<0) {
+ /* below window */
+ return;
+ }
+ if (r0>=ctx->DrawBuffer->Height && r1>=ctx->DrawBuffer->Height) {
+ /* above window */
+ return;
+ }
+
+ /* check if left edge is outside window */
+ skipcol = 0;
+ if (x<0) {
+ skipcol = -x;
+ m += x;
+ }
+ /* make sure span isn't too long or short */
+ if (m>maxwidth) {
+ m = maxwidth;
+ }
+ else if (m<=0) {
+ return;
+ }
+
+ assert( m <= MAX_WIDTH );
+
+ /* zoom the span horizontally */
+ if (ctx->Pixel.ZoomX==-1.0F) {
+ /* n==m */
+ for (j=0;j<m;j++) {
+ i = n - (j+skipcol) - 1;
+ dstRGBA32[j] = srcRGBA32[i];
+ zdepth[j] = z[i];
+ }
+ if (fog && ctx->Fog.Enabled) {
+ for (j=0;j<m;j++) {
+ i = n - (j+skipcol) - 1;
+ zfog[j] = fog[i];
+ }
+ }
+ }
+ else {
+ GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
+ for (j=0;j<m;j++) {
+ i = (GLint) ((j+skipcol) * xscale);
+ if (i<0) i = n + i - 1;
+ dstRGBA32[j] = srcRGBA32[i];
+ zdepth[j] = z[i];
+ }
+ if (fog && ctx->Fog.Enabled) {
+ for (j=0;j<m;j++) {
+ i = (GLint) ((j+skipcol) * xscale);
+ if (i<0) i = n + i - 1;
+ zfog[j] = fog[i];
+ }
+ }
+ }
+
+ /* write the span */
+ for (r=r0; r<r1; r++) {
+ gl_write_rgba_span( ctx, m, x+skipcol, r, zdepth,
+ (fog ? zfog : 0),
+ zrgba, GL_BITMAP );
+ }
+}
+
+
+
+void
+gl_write_zoomed_rgb_span( GLcontext *ctx,
+ GLuint n, GLint x, GLint y, const GLdepth z[],
+ const GLfixed *fog,
+ CONST GLchan rgb[][3], GLint y0 )
+{
+ GLint m;
+ GLint r0, r1, row, r;
+ GLint i, j, skipcol;
+ GLchan zrgba[MAX_WIDTH][4]; /* zoomed pixel colors */
+ GLdepth zdepth[MAX_WIDTH]; /* zoomed depth values */
+ GLfixed zfog[MAX_WIDTH]; /* zoomed fog values */
+ GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH );
+
+ /* compute width of output row */
+ m = (GLint) ABSF( n * ctx->Pixel.ZoomX );
+ if (m==0) {
+ return;
+ }
+ if (ctx->Pixel.ZoomX<0.0) {
+ /* adjust x coordinate for left/right mirroring */
+ x = x - m;
+ }
+
+ /* compute which rows to draw */
+ row = y-y0;
+ r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY);
+ r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY);
+ if (r0==r1) {
+ return;
+ }
+ else if (r1<r0) {
+ GLint rtmp = r1;
+ r1 = r0;
+ r0 = rtmp;
+ }
+
+ /* return early if r0...r1 is above or below window */
+ if (r0<0 && r1<0) {
+ /* below window */
+ return;
+ }
+ if (r0>=ctx->DrawBuffer->Height && r1>=ctx->DrawBuffer->Height) {
+ /* above window */
+ return;
+ }
+
+ /* check if left edge is outside window */
+ skipcol = 0;
+ if (x<0) {
+ skipcol = -x;
+ m += x;
+ }
+ /* make sure span isn't too long or short */
+ if (m>maxwidth) {
+ m = maxwidth;
+ }
+ else if (m<=0) {
+ return;
+ }
+
+ assert( m <= MAX_WIDTH );
+
+ /* zoom the span horizontally */
+ if (ctx->Pixel.ZoomX==-1.0F) {
+ /* n==m */
+ for (j=0;j<m;j++) {
+ i = n - (j+skipcol) - 1;
+ zrgba[j][0] = rgb[i][0];
+ zrgba[j][1] = rgb[i][1];
+ zrgba[j][2] = rgb[i][2];
+ zrgba[j][3] = CHAN_MAX;
+ zdepth[j] = z[i];
+ }
+ if (fog && ctx->Fog.Enabled) {
+ for (j=0;j<m;j++) {
+ i = n - (j+skipcol) - 1;
+ zfog[j] = fog[i];
+ }
+ }
+ }
+ else {
+ GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
+ for (j=0;j<m;j++) {
+ i = (GLint) ((j+skipcol) * xscale);
+ if (i<0) i = n + i - 1;
+ zrgba[j][0] = rgb[i][0];
+ zrgba[j][1] = rgb[i][1];
+ zrgba[j][2] = rgb[i][2];
+ zrgba[j][3] = CHAN_MAX;
+ zdepth[j] = z[i];
+ }
+ if (fog && ctx->Fog.Enabled) {
+ for (j=0;j<m;j++) {
+ i = (GLint) ((j+skipcol) * xscale);
+ if (i<0) i = n + i - 1;
+ zfog[j] = fog[i];
+ }
+ }
+ }
+
+ /* write the span */
+ for (r=r0; r<r1; r++) {
+ gl_write_rgba_span( ctx, m, x+skipcol, r, zdepth,
+ (fog ? zfog : 0), zrgba, GL_BITMAP );
+ }
+}
+
+
+
+/*
+ * As above, but write CI pixels.
+ */
+void
+gl_write_zoomed_index_span( GLcontext *ctx,
+ GLuint n, GLint x, GLint y, const GLdepth z[],
+ const GLfixed *fog,
+ const GLuint indexes[], GLint y0 )
+{
+ GLint m;
+ GLint r0, r1, row, r;
+ GLint i, j, skipcol;
+ GLuint zindexes[MAX_WIDTH]; /* zoomed color indexes */
+ GLdepth zdepth[MAX_WIDTH]; /* zoomed depth values */
+ GLfixed zfog[MAX_WIDTH]; /* zoomed fog values */
+ GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH );
+
+ /* compute width of output row */
+ m = (GLint) ABSF( n * ctx->Pixel.ZoomX );
+ if (m==0) {
+ return;
+ }
+ if (ctx->Pixel.ZoomX<0.0) {
+ /* adjust x coordinate for left/right mirroring */
+ x = x - m;
+ }
+
+ /* compute which rows to draw */
+ row = y-y0;
+ r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY);
+ r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY);
+ if (r0==r1) {
+ return;
+ }
+ else if (r1<r0) {
+ GLint rtmp = r1;
+ r1 = r0;
+ r0 = rtmp;
+ }
+
+ /* return early if r0...r1 is above or below window */
+ if (r0<0 && r1<0) {
+ /* below window */
+ return;
+ }
+ if (r0>=ctx->DrawBuffer->Height && r1>=ctx->DrawBuffer->Height) {
+ /* above window */
+ return;
+ }
+
+ /* check if left edge is outside window */
+ skipcol = 0;
+ if (x<0) {
+ skipcol = -x;
+ m += x;
+ }
+ /* make sure span isn't too long or short */
+ if (m>maxwidth) {
+ m = maxwidth;
+ }
+ else if (m<=0) {
+ return;
+ }
+
+ assert( m <= MAX_WIDTH );
+
+ /* zoom the span horizontally */
+ if (ctx->Pixel.ZoomX==-1.0F) {
+ /* n==m */
+ for (j=0;j<m;j++) {
+ i = n - (j+skipcol) - 1;
+ zindexes[j] = indexes[i];
+ zdepth[j] = z[i];
+ }
+ if (fog && ctx->Fog.Enabled) {
+ for (j=0;j<m;j++) {
+ i = n - (j+skipcol) - 1;
+ zfog[j] = fog[i];
+ }
+ }
+ }
+ else {
+ GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
+ for (j=0;j<m;j++) {
+ i = (GLint) ((j+skipcol) * xscale);
+ if (i<0) i = n + i - 1;
+ zindexes[j] = indexes[i];
+ zdepth[j] = z[i];
+ }
+ if (fog && ctx->Fog.Enabled) {
+ for (j=0;j<m;j++) {
+ i = (GLint) ((j+skipcol) * xscale);
+ if (i<0) i = n + i - 1;
+ zfog[j] = fog[i];
+ }
+ }
+ }
+
+ /* write the span */
+ for (r=r0; r<r1; r++) {
+ gl_write_index_span( ctx, m, x+skipcol, r, zdepth,
+ (fog ? zfog : 0), zindexes, GL_BITMAP );
+ }
+}
+
+
+
+/*
+ * As above, but write stencil values.
+ */
+void
+gl_write_zoomed_stencil_span( GLcontext *ctx,
+ GLuint n, GLint x, GLint y,
+ const GLstencil stencil[], GLint y0 )
+{
+ GLint m;
+ GLint r0, r1, row, r;
+ GLint i, j, skipcol;
+ GLstencil zstencil[MAX_WIDTH]; /* zoomed stencil values */
+ GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH );
+
+ /* compute width of output row */
+ m = (GLint) ABSF( n * ctx->Pixel.ZoomX );
+ if (m==0) {
+ return;
+ }
+ if (ctx->Pixel.ZoomX<0.0) {
+ /* adjust x coordinate for left/right mirroring */
+ x = x - m;
+ }
+
+ /* compute which rows to draw */
+ row = y-y0;
+ r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY);
+ r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY);
+ if (r0==r1) {
+ return;
+ }
+ else if (r1<r0) {
+ GLint rtmp = r1;
+ r1 = r0;
+ r0 = rtmp;
+ }
+
+ /* return early if r0...r1 is above or below window */
+ if (r0<0 && r1<0) {
+ /* below window */
+ return;
+ }
+ if (r0>=ctx->DrawBuffer->Height && r1>=ctx->DrawBuffer->Height) {
+ /* above window */
+ return;
+ }
+
+ /* check if left edge is outside window */
+ skipcol = 0;
+ if (x<0) {
+ skipcol = -x;
+ m += x;
+ }
+ /* make sure span isn't too long or short */
+ if (m>maxwidth) {
+ m = maxwidth;
+ }
+ else if (m<=0) {
+ return;
+ }
+
+ assert( m <= MAX_WIDTH );
+
+ /* zoom the span horizontally */
+ if (ctx->Pixel.ZoomX==-1.0F) {
+ /* n==m */
+ for (j=0;j<m;j++) {
+ i = n - (j+skipcol) - 1;
+ zstencil[j] = stencil[i];
+ }
+ }
+ else {
+ GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
+ for (j=0;j<m;j++) {
+ i = (GLint) ((j+skipcol) * xscale);
+ if (i<0) i = n + i - 1;
+ zstencil[j] = stencil[i];
+ }
+ }
+
+ /* write the span */
+ for (r=r0; r<r1; r++) {
+ _mesa_write_stencil_span( ctx, m, x+skipcol, r, zstencil );
+ }
+}
diff --git a/src/mesa/swrast/s_zoom.h b/src/mesa/swrast/s_zoom.h
new file mode 100644
index 0000000000..55a8ffb21e
--- /dev/null
+++ b/src/mesa/swrast/s_zoom.h
@@ -0,0 +1,62 @@
+/* $Id: s_zoom.h,v 1.1 2000/10/31 18:00:05 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.
+ */
+
+
+#ifndef S_ZOOM_H
+#define S_ZOOM_H
+
+
+#include "types.h"
+
+
+extern void
+gl_write_zoomed_rgba_span( GLcontext *ctx,
+ GLuint n, GLint x, GLint y, const GLdepth z[],
+ const GLfixed *fog,
+ CONST GLchan rgba[][4], GLint y0 );
+
+
+extern void
+gl_write_zoomed_rgb_span( GLcontext *ctx,
+ GLuint n, GLint x, GLint y, const GLdepth z[],
+ const GLfixed *fog,
+ CONST GLchan rgb[][3], GLint y0 );
+
+
+extern void
+gl_write_zoomed_index_span( GLcontext *ctx,
+ GLuint n, GLint x, GLint y, const GLdepth z[],
+ const GLfixed *fog,
+ const GLuint indexes[], GLint y0 );
+
+
+extern void
+gl_write_zoomed_stencil_span( GLcontext *ctx,
+ GLuint n, GLint x, GLint y,
+ const GLstencil stencil[], GLint y0 );
+
+
+#endif
diff --git a/src/mesa/swrast/swrast.h b/src/mesa/swrast/swrast.h
new file mode 100644
index 0000000000..4e8627e695
--- /dev/null
+++ b/src/mesa/swrast/swrast.h
@@ -0,0 +1,108 @@
+#ifndef SWRAST_H
+#define SWRAST_H
+
+#include "types.h"
+
+/* These are the functions exported from swrast. (more to come)
+ */
+void
+_swrast_alloc_buffers( GLcontext *ctx );
+
+
+void
+_swrast_Bitmap( GLcontext *ctx,
+ GLint px, GLint py,
+ GLsizei width, GLsizei height,
+ const struct gl_pixelstore_attrib *unpack,
+ const GLubyte *bitmap );
+
+void
+_swrast_CopyPixels( GLcontext *ctx,
+ GLint srcx, GLint srcy,
+ GLint destx, GLint desty,
+ GLsizei width, GLsizei height,
+ GLenum type );
+
+void
+_swrast_DrawPixels( GLcontext *ctx,
+ GLint x, GLint y,
+ GLsizei width, GLsizei height,
+ GLenum format, GLenum type,
+ const struct gl_pixelstore_attrib *unpack,
+ const GLvoid *pixels );
+
+void
+_swrast_ReadPixels( GLcontext *ctx,
+ GLint x, GLint y, GLsizei width, GLsizei height,
+ GLenum format, GLenum type,
+ const struct gl_pixelstore_attrib *unpack,
+ GLvoid *pixels );
+
+void
+_swrast_Clear( GLcontext *ctx, GLbitfield mask, GLboolean all,
+ GLint x, GLint y, GLint width, GLint height );
+
+void
+_swrast_Accum( GLcontext *ctx, GLenum op,
+ GLfloat value, GLint xpos, GLint ypos,
+ GLint width, GLint height );
+
+void
+_swrast_set_line_function( GLcontext *ctx );
+
+void
+_swrast_set_point_function( GLcontext *ctx );
+
+void
+_swrast_set_triangle_function( GLcontext *ctx );
+
+void
+_swrast_set_quad_function( GLcontext *ctx );
+
+void
+_swrast_flush( GLcontext *ctx );
+
+GLboolean
+_swrast_create_context( GLcontext *ctx );
+
+void
+_swrast_destroy_context( GLcontext *ctx );
+
+
+/* Replace:
+ */
+void
+_swrast_set_texture_sampler( struct gl_texture_object *t );
+
+
+
+#define _SWRAST_NEW_TRIANGLE (_NEW_RENDERMODE| \
+ _NEW_POLYGON| \
+ _NEW_DEPTH| \
+ _NEW_STENCIL| \
+ _NEW_COLOR| \
+ _NEW_TEXTURE| \
+ _NEW_HINT| \
+ _SWRAST_NEW_RASTERMASK| \
+ _NEW_LIGHT| \
+ _NEW_FOG)
+
+#define _SWRAST_NEW_LINE (_NEW_RENDERMODE| \
+ _NEW_LINE| \
+ _NEW_TEXTURE| \
+ _NEW_LIGHT| \
+ _NEW_FOG| \
+ _NEW_DEPTH)
+
+#define _SWRAST_NEW_POINT (_NEW_RENDERMODE | \
+ _NEW_POINT | \
+ _NEW_TEXTURE | \
+ _NEW_LIGHT | \
+ _NEW_FOG)
+
+
+
+
+
+
+#endif