diff options
author | Keith Whitwell <[email protected]> | 2000-10-31 18:00:04 +0000 |
---|---|---|
committer | Keith Whitwell <[email protected]> | 2000-10-31 18:00:04 +0000 |
commit | e3a051e0538a605551f4d58294c94f5eb00ed07f (patch) | |
tree | ea5ccfd6d578fee1f8adb5a5c7f34f12d601c1c9 | |
parent | 6e0f0f51e0371688a434ed65c4ae0da1b061a4b5 (diff) |
Moved software rasterizer functionality to new directory.
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 00000000000..347322cf65e --- /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 00000000000..d28a10d8eb4 --- /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 00000000000..30cc1647c72 --- /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 00000000000..21ac29153c2 --- /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 00000000000..7ec2236ec1d --- /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 00000000000..07e8dacd4ab --- /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 00000000000..6688a89142e --- /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 00000000000..ed7b9cbded1 --- /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 00000000000..b24a4b8eeb8 --- /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 00000000000..646081b83e1 --- /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 00000000000..0e65229c4a2 --- /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 00000000000..45c32f90889 --- /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 00000000000..b62198f091e --- /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 00000000000..87a20018498 --- /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 00000000000..eddfe390371 --- /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 00000000000..e9dd63093c2 --- /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 00000000000..e5de2189b76 --- /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 00000000000..ba6ea07e540 --- /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 00000000000..1edac140974 --- /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 00000000000..32fafe617c8 --- /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 00000000000..e550412ece9 --- /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 00000000000..672d163d8cf --- /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 00000000000..75a01cf12eb --- /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 00000000000..a79badbff19 --- /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 00000000000..760d7e7065d --- /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 00000000000..d1b8739cbbf --- /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 00000000000..5831edf9c01 --- /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 00000000000..3f25461ddcc --- /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 00000000000..854482a2516 --- /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 00000000000..50946423e2e --- /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 00000000000..b24fc642ac1 --- /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 00000000000..74a4d682661 --- /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 00000000000..ca02802ceb7 --- /dev/null +++ b/src/mesa/swrast/s_span.c @@ -0,0 +1,1109 @@ +/* $Id: s_span.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +/* + * pixel span rasterization: + * These functions implement the rasterization pipeline. + */ + + +#include "glheader.h" +#include "colormac.h" +#include "macros.h" +#include "mem.h" + +#include "s_alpha.h" +#include "s_alphabuf.h" +#include "s_blend.h" +#include "s_depth.h" +#include "s_fog.h" +#include "s_logic.h" +#include "s_masking.h" +#include "s_scissor.h" +#include "s_span.h" +#include "s_stencil.h" +#include "s_texture.h" + + + + +/* + * Apply the current polygon stipple pattern to a span of pixels. + */ +static void stipple_polygon_span( GLcontext *ctx, + GLuint n, GLint x, GLint y, GLubyte mask[] ) +{ + register GLuint i, m, stipple, highbit=0x80000000; + + stipple = ctx->PolygonStipple[y % 32]; + m = highbit >> (GLuint) (x % 32); + + for (i=0;i<n;i++) { + if ((m & stipple)==0) { + mask[i] = 0; + } + m = m >> 1; + if (m==0) { + m = 0x80000000; + } + } +} + + + +/* + * Clip a pixel span to the current buffer/window boundaries. + * Return: 0 = all pixels clipped + * 1 = at least one pixel is visible + */ +static GLuint clip_span( GLcontext *ctx, + GLint n, GLint x, GLint y, GLubyte mask[] ) +{ + GLint i; + + /* Clip to top and bottom */ + if (y < 0 || y >= ctx->DrawBuffer->Height) { + return 0; + } + + /* Clip to left and right */ + if (x >= 0 && x + n <= ctx->DrawBuffer->Width) { + /* no clipping needed */ + return 1; + } + else if (x + n <= 0) { + /* completely off left side */ + return 0; + } + else if (x >= ctx->DrawBuffer->Width) { + /* completely off right side */ + return 0; + } + else { + /* clip-test each pixel, this could be done better */ + for (i=0;i<n;i++) { + if (x + i < 0 || x + i >= ctx->DrawBuffer->Width) { + mask[i] = 0; + } + } + return 1; + } +} + + + +/* + * Draw to more than one color buffer (or none). + */ +static void multi_write_index_span( GLcontext *ctx, GLuint n, + GLint x, GLint y, const GLuint indexes[], + const GLubyte mask[] ) +{ + GLuint bufferBit; + + if (ctx->Color.DrawBuffer == GL_NONE) + return; + + /* loop over four possible dest color buffers */ + for (bufferBit = 1; bufferBit <= 8; bufferBit = bufferBit << 1) { + if (bufferBit & ctx->Color.DrawDestMask) { + GLuint indexTmp[MAX_WIDTH]; + ASSERT(n < MAX_WIDTH); + + if (bufferBit == FRONT_LEFT_BIT) + (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_LEFT); + else if (bufferBit == FRONT_RIGHT_BIT) + (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_RIGHT); + else if (bufferBit == BACK_LEFT_BIT) + (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_LEFT); + else + (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_RIGHT); + + /* make copy of incoming indexes */ + MEMCPY( indexTmp, indexes, n * sizeof(GLuint) ); + if (ctx->Color.IndexLogicOpEnabled) { + _mesa_logicop_ci_span( ctx, n, x, y, indexTmp, mask ); + } + if (ctx->Color.IndexMask == 0) { + break; + } + else if (ctx->Color.IndexMask != 0xffffffff) { + _mesa_mask_index_span( ctx, n, x, y, indexTmp ); + } + (*ctx->Driver.WriteCI32Span)( ctx, n, x, y, indexTmp, mask ); + } + } + + /* restore default dest buffer */ + (void) (*ctx->Driver.SetDrawBuffer)( ctx, ctx->Color.DriverDrawBuffer); +} + + + +/* + * Write a horizontal span of color index pixels to the frame buffer. + * Stenciling, Depth-testing, etc. are done as needed. + * Input: n - number of pixels in the span + * x, y - location of leftmost pixel in the span + * z - array of [n] z-values + * index - array of [n] color indexes + * primitive - either GL_POINT, GL_LINE, GL_POLYGON, or GL_BITMAP + */ +void gl_write_index_span( GLcontext *ctx, + GLuint n, GLint x, GLint y, const GLdepth z[], + const GLfixed fog[], + GLuint indexIn[], GLenum primitive ) +{ + const GLuint modBits = FOG_BIT | BLEND_BIT | MASKING_BIT | LOGIC_OP_BIT; + GLubyte mask[MAX_WIDTH]; + GLuint indexBackup[MAX_WIDTH]; + GLuint *index; /* points to indexIn or indexBackup */ + + /* init mask to 1's (all pixels are to be written) */ + MEMSET(mask, 1, n); + + if ((ctx->RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { + if (clip_span(ctx,n,x,y,mask)==0) { + return; + } + } + + if ((primitive==GL_BITMAP && (ctx->RasterMask & modBits)) + || (ctx->RasterMask & MULTI_DRAW_BIT)) { + /* Make copy of color indexes */ + MEMCPY( indexBackup, indexIn, n * sizeof(GLuint) ); + index = indexBackup; + } + else { + index = indexIn; + } + + /* Per-pixel fog */ + if (ctx->Fog.Enabled) { + if (fog && ctx->Hint.Fog != GL_NICEST) + _mesa_fog_ci_pixels( ctx, n, fog, index ); + else + _mesa_depth_fog_ci_pixels( ctx, n, z, index ); + } + + /* Do the scissor test */ + if (ctx->Scissor.Enabled) { + if (gl_scissor_span( ctx, n, x, y, mask )==0) { + return; + } + } + + /* Polygon Stippling */ + if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { + stipple_polygon_span( ctx, n, x, y, mask ); + } + + if (ctx->Stencil.Enabled) { + /* first stencil test */ + if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) { + return; + } + } + else if (ctx->Depth.Test) { + /* regular depth testing */ + if (_mesa_depth_test_span( ctx, n, x, y, z, mask )==0) return; + } + + /* if we get here, something passed the depth test */ + ctx->OcclusionResult = GL_TRUE; + + if (ctx->RasterMask & MULTI_DRAW_BIT) { + /* draw to zero or two or more buffers */ + multi_write_index_span( ctx, n, x, y, index, mask ); + } + else { + /* normal situation: draw to exactly one buffer */ + if (ctx->Color.IndexLogicOpEnabled) { + _mesa_logicop_ci_span( ctx, n, x, y, index, mask ); + } + + if (ctx->Color.IndexMask == 0) { + return; + } + else if (ctx->Color.IndexMask != 0xffffffff) { + _mesa_mask_index_span( ctx, n, x, y, index ); + } + + /* write pixels */ + (*ctx->Driver.WriteCI32Span)( ctx, n, x, y, index, mask ); + } +} + + + + +void gl_write_monoindex_span( GLcontext *ctx, + GLuint n, GLint x, GLint y, + const GLdepth z[], + const GLfixed fog[], + GLuint index, GLenum primitive ) +{ + GLubyte mask[MAX_WIDTH]; + GLuint i; + + /* init mask to 1's (all pixels are to be written) */ + MEMSET(mask, 1, n); + + if ((ctx->RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { + if (clip_span( ctx, n, x, y, mask)==0) { + return; + } + } + + /* Do the scissor test */ + if (ctx->Scissor.Enabled) { + if (gl_scissor_span( ctx, n, x, y, mask )==0) { + return; + } + } + + /* Polygon Stippling */ + if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { + stipple_polygon_span( ctx, n, x, y, mask ); + } + + if (ctx->Stencil.Enabled) { + /* first stencil test */ + if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) { + return; + } + } + else if (ctx->Depth.Test) { + /* regular depth testing */ + if (_mesa_depth_test_span( ctx, n, x, y, z, mask )==0) return; + } + + /* if we get here, something passed the depth test */ + ctx->OcclusionResult = GL_TRUE; + + if (ctx->Color.DrawBuffer == GL_NONE) { + /* write no pixels */ + return; + } + + if (ctx->Fog.Enabled + || ctx->Color.IndexLogicOpEnabled + || ctx->Color.IndexMask != 0xffffffff) { + /* different index per pixel */ + GLuint indexes[MAX_WIDTH]; + for (i=0;i<n;i++) { + indexes[i] = index; + } + + if (ctx->Fog.Enabled) { + if (fog && ctx->Hint.Fog != GL_NICEST) + _mesa_fog_ci_pixels( ctx, n, fog, indexes ); + else + _mesa_depth_fog_ci_pixels( ctx, n, z, indexes ); + } + + if (ctx->Color.IndexLogicOpEnabled) { + _mesa_logicop_ci_span( ctx, n, x, y, indexes, mask ); + } + + if (ctx->RasterMask & MULTI_DRAW_BIT) { + /* draw to zero or two or more buffers */ + multi_write_index_span( ctx, n, x, y, indexes, mask ); + } + else { + /* normal situation: draw to exactly one buffer */ + if (ctx->Color.IndexLogicOpEnabled) { + _mesa_logicop_ci_span( ctx, n, x, y, indexes, mask ); + } + if (ctx->Color.IndexMask == 0) { + return; + } + else if (ctx->Color.IndexMask != 0xffffffff) { + _mesa_mask_index_span( ctx, n, x, y, indexes ); + } + (*ctx->Driver.WriteCI32Span)( ctx, n, x, y, indexes, mask ); + } + } + else { + /* same color index for all pixels */ + ASSERT(!ctx->Color.IndexLogicOpEnabled); + ASSERT(ctx->Color.IndexMask == 0xffffffff); + if (ctx->RasterMask & MULTI_DRAW_BIT) { + /* draw to zero or two or more buffers */ + GLuint indexes[MAX_WIDTH]; + for (i=0;i<n;i++) + indexes[i] = index; + multi_write_index_span( ctx, n, x, y, indexes, mask ); + } + else { + /* normal situation: draw to exactly one buffer */ + (*ctx->Driver.WriteMonoCISpan)( ctx, n, x, y, mask ); + } + } +} + + + +/* + * Draw to more than one RGBA color buffer (or none). + */ +static void multi_write_rgba_span( GLcontext *ctx, GLuint n, + GLint x, GLint y, CONST GLchan rgba[][4], + const GLubyte mask[] ) +{ + const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask); + GLuint bufferBit; + + if (ctx->Color.DrawBuffer == GL_NONE) + return; + + /* loop over four possible dest color buffers */ + for (bufferBit = 1; bufferBit <= 8; bufferBit = bufferBit << 1) { + if (bufferBit & ctx->Color.DrawDestMask) { + GLchan rgbaTmp[MAX_WIDTH][4]; + ASSERT(n < MAX_WIDTH); + + if (bufferBit == FRONT_LEFT_BIT) { + (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_LEFT); + ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontLeftAlpha; + } + else if (bufferBit == FRONT_RIGHT_BIT) { + (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_FRONT_RIGHT); + ctx->DrawBuffer->Alpha = ctx->DrawBuffer->FrontRightAlpha; + } + else if (bufferBit == BACK_LEFT_BIT) { + (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_LEFT); + ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackLeftAlpha; + } + else { + (void) (*ctx->Driver.SetDrawBuffer)( ctx, GL_BACK_RIGHT); + ctx->DrawBuffer->Alpha = ctx->DrawBuffer->BackRightAlpha; + } + + /* make copy of incoming colors */ + MEMCPY( rgbaTmp, rgba, 4 * n * sizeof(GLchan) ); + + if (ctx->Color.ColorLogicOpEnabled) { + _mesa_logicop_rgba_span( ctx, n, x, y, rgbaTmp, mask ); + } + else if (ctx->Color.BlendEnabled) { + _mesa_blend_span( ctx, n, x, y, rgbaTmp, mask ); + } + if (colorMask == 0x0) { + break; + } + else if (colorMask != 0xffffffff) { + _mesa_mask_rgba_span( ctx, n, x, y, rgbaTmp ); + } + + (*ctx->Driver.WriteRGBASpan)( ctx, n, x, y, + (const GLchan (*)[4]) rgbaTmp, mask ); + if (ctx->RasterMask & ALPHABUF_BIT) { + _mesa_write_alpha_span( ctx, n, x, y, + (const GLchan (*)[4])rgbaTmp, mask ); + } + } + } + + /* restore default dest buffer */ + (void) (*ctx->Driver.SetDrawBuffer)( ctx, ctx->Color.DriverDrawBuffer ); +} + + + +void gl_write_rgba_span( GLcontext *ctx, + GLuint n, GLint x, GLint y, const GLdepth z[], + const GLfixed *fog, + GLchan rgbaIn[][4], + GLenum primitive ) +{ + const GLuint modBits = FOG_BIT | BLEND_BIT | MASKING_BIT | + LOGIC_OP_BIT | TEXTURE_BIT; + GLubyte mask[MAX_WIDTH]; + GLboolean write_all = GL_TRUE; + GLchan rgbaBackup[MAX_WIDTH][4]; + GLchan (*rgba)[4]; + const GLubyte *Null = 0; + + /* init mask to 1's (all pixels are to be written) */ + MEMSET(mask, 1, n); + + if ((ctx->RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { + if (clip_span( ctx,n,x,y,mask)==0) { + return; + } + write_all = GL_FALSE; + } + + if ((primitive==GL_BITMAP && (ctx->RasterMask & modBits)) + || (ctx->RasterMask & MULTI_DRAW_BIT)) { + /* must make a copy of the colors since they may be modified */ + MEMCPY( rgbaBackup, rgbaIn, 4 * n * sizeof(GLchan) ); + rgba = rgbaBackup; + } + else { + rgba = rgbaIn; + } + + /* Per-pixel fog */ + if (ctx->Fog.Enabled) { + if (fog && ctx->Hint.Fog != GL_NICEST) + _mesa_fog_rgba_pixels( ctx, n, fog, rgba ); + else + _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba ); + } + + /* Do the scissor test */ + if (ctx->Scissor.Enabled) { + if (gl_scissor_span( ctx, n, x, y, mask )==0) { + return; + } + write_all = GL_FALSE; + } + + /* Polygon Stippling */ + if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { + stipple_polygon_span( ctx, n, x, y, mask ); + write_all = GL_FALSE; + } + + /* Do the alpha test */ + if (ctx->Color.AlphaEnabled) { + if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4]) rgba, mask )==0) { + return; + } + write_all = GL_FALSE; + } + + if (ctx->Stencil.Enabled) { + /* first stencil test */ + if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) { + return; + } + write_all = GL_FALSE; + } + else if (ctx->Depth.Test) { + /* regular depth testing */ + GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask ); + if (m==0) { + return; + } + if (m<n) { + write_all = GL_FALSE; + } + } + + /* if we get here, something passed the depth test */ + ctx->OcclusionResult = GL_TRUE; + + if (ctx->RasterMask & MULTI_DRAW_BIT) { + multi_write_rgba_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, mask ); + } + else { + /* normal: write to exactly one buffer */ + /* logic op or blending */ + const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask); + + if (ctx->Color.ColorLogicOpEnabled) { + _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask ); + } + else if (ctx->Color.BlendEnabled) { + _mesa_blend_span( ctx, n, x, y, rgba, mask ); + } + + /* Color component masking */ + if (colorMask == 0x0) { + return; + } + else if (colorMask != 0xffffffff) { + _mesa_mask_rgba_span( ctx, n, x, y, rgba ); + } + + /* write pixels */ + (*ctx->Driver.WriteRGBASpan)( ctx, n, x, y, + (const GLchan (*)[4]) rgba, + write_all ? Null : mask ); + + if (ctx->RasterMask & ALPHABUF_BIT) { + _mesa_write_alpha_span( ctx, n, x, y, + (const GLchan (*)[4]) rgba, + write_all ? Null : mask ); + } + + } +} + + + +/* + * Write a horizontal span of color pixels to the frame buffer. + * The color is initially constant for the whole span. + * Alpha-testing, stenciling, depth-testing, and blending are done as needed. + * Input: n - number of pixels in the span + * x, y - location of leftmost pixel in the span + * z - array of [n] z-values + * r, g, b, a - the color of the pixels + * primitive - either GL_POINT, GL_LINE, GL_POLYGON or GL_BITMAP. + */ +void gl_write_monocolor_span( GLcontext *ctx, + GLuint n, GLint x, GLint y, const GLdepth z[], + const GLfixed fog[], + const GLchan color[4], + GLenum primitive ) +{ + const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask); + GLuint i; + GLubyte mask[MAX_WIDTH]; + GLboolean write_all = GL_TRUE; + GLchan rgba[MAX_WIDTH][4]; + const GLubyte *Null = 0; + + /* init mask to 1's (all pixels are to be written) */ + MEMSET(mask, 1, n); + + if ((ctx->RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { + if (clip_span( ctx,n,x,y,mask)==0) { + return; + } + write_all = GL_FALSE; + } + + /* Do the scissor test */ + if (ctx->Scissor.Enabled) { + if (gl_scissor_span( ctx, n, x, y, mask )==0) { + return; + } + write_all = GL_FALSE; + } + + /* Polygon Stippling */ + if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { + stipple_polygon_span( ctx, n, x, y, mask ); + write_all = GL_FALSE; + } + + /* Do the alpha test */ + if (ctx->Color.AlphaEnabled) { + for (i=0;i<n;i++) { + rgba[i][ACOMP] = color[ACOMP]; + } + if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4])rgba, mask )==0) { + return; + } + write_all = GL_FALSE; + } + + if (ctx->Stencil.Enabled) { + /* first stencil test */ + if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) { + return; + } + write_all = GL_FALSE; + } + else if (ctx->Depth.Test) { + /* regular depth testing */ + GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask ); + if (m==0) { + return; + } + if (m<n) { + write_all = GL_FALSE; + } + } + + /* if we get here, something passed the depth test */ + ctx->OcclusionResult = GL_TRUE; + + if (ctx->Color.DrawBuffer == GL_NONE) { + /* write no pixels */ + return; + } + + if (ctx->Color.ColorLogicOpEnabled || colorMask != 0xffffffff || + (ctx->RasterMask & (BLEND_BIT | FOG_BIT))) { + /* assign same color to each pixel */ + for (i=0;i<n;i++) { + if (mask[i]) { + COPY_CHAN4(rgba[i], color); + } + } + + /* Per-pixel fog */ + if (ctx->Fog.Enabled) { + if (fog && ctx->Hint.Fog != GL_NICEST) + _mesa_fog_rgba_pixels( ctx, n, fog, rgba ); + else + _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba ); + } + + if (ctx->RasterMask & MULTI_DRAW_BIT) { + multi_write_rgba_span( ctx, n, x, y, + (const GLchan (*)[4]) rgba, mask ); + } + else { + /* normal: write to exactly one buffer */ + if (ctx->Color.ColorLogicOpEnabled) { + _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask ); + } + else if (ctx->Color.BlendEnabled) { + _mesa_blend_span( ctx, n, x, y, rgba, mask ); + } + + /* Color component masking */ + if (colorMask == 0x0) { + return; + } + else if (colorMask != 0xffffffff) { + _mesa_mask_rgba_span( ctx, n, x, y, rgba ); + } + + /* write pixels */ + (*ctx->Driver.WriteRGBASpan)( ctx, n, x, y, + (const GLchan (*)[4]) rgba, + write_all ? Null : mask ); + if (ctx->RasterMask & ALPHABUF_BIT) { + _mesa_write_alpha_span( ctx, n, x, y, + (const GLchan (*)[4]) rgba, + write_all ? Null : mask ); + } + } + } + else { + /* same color for all pixels */ + ASSERT(!ctx->Color.BlendEnabled); + ASSERT(!ctx->Color.ColorLogicOpEnabled); + + if (ctx->RasterMask & MULTI_DRAW_BIT) { + for (i=0;i<n;i++) { + if (mask[i]) { + COPY_CHAN4(rgba[i], color); + } + } + multi_write_rgba_span( ctx, n, x, y, + (const GLchan (*)[4]) rgba, mask ); + } + else { + (*ctx->Driver.WriteMonoRGBASpan)( ctx, n, x, y, mask ); + if (ctx->RasterMask & ALPHABUF_BIT) { + _mesa_write_mono_alpha_span( ctx, n, x, y, (GLchan) color[ACOMP], + write_all ? Null : mask ); + } + } + } +} + + + +/* + * Add specular color to base color. This is used only when + * GL_LIGHT_MODEL_COLOR_CONTROL = GL_SEPARATE_SPECULAR_COLOR. + */ +static void add_colors(GLuint n, GLchan rgba[][4], CONST GLchan specular[][4] ) +{ + GLuint i; + for (i=0; i<n; i++) { + GLint r = rgba[i][RCOMP] + specular[i][RCOMP]; + GLint g = rgba[i][GCOMP] + specular[i][GCOMP]; + GLint b = rgba[i][BCOMP] + specular[i][BCOMP]; + rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX); + rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX); + rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX); + } +} + + +/* + * Write a horizontal span of textured pixels to the frame buffer. + * The color of each pixel is different. + * Alpha-testing, stenciling, depth-testing, and blending are done + * as needed. + * Input: n - number of pixels in the span + * x, y - location of leftmost pixel in the span + * z - array of [n] z-values + * s, t - array of (s,t) texture coordinates for each pixel + * lambda - array of texture lambda values + * rgba - array of [n] color components + * primitive - either GL_POINT, GL_LINE, GL_POLYGON or GL_BITMAP. + */ +void gl_write_texture_span( GLcontext *ctx, + GLuint n, GLint x, GLint y, const GLdepth z[], + const GLfixed fog[], + const GLfloat s[], const GLfloat t[], + const GLfloat u[], GLfloat lambda[], + GLchan rgbaIn[][4], CONST GLchan spec[][4], + GLenum primitive ) +{ + const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask); + GLubyte mask[MAX_WIDTH]; + GLboolean write_all = GL_TRUE; + GLchan rgbaBackup[MAX_WIDTH][4]; + GLchan (*rgba)[4]; /* points to either rgbaIn or rgbaBackup */ + const GLubyte *Null = 0; + + /* init mask to 1's (all pixels are to be written) */ + MEMSET(mask, 1, n); + + if ((ctx->RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { + if (clip_span(ctx, n, x, y, mask)==0) { + return; + } + write_all = GL_FALSE; + } + + + if (primitive==GL_BITMAP || (ctx->RasterMask & MULTI_DRAW_BIT)) { + /* must make a copy of the colors since they may be modified */ + MEMCPY(rgbaBackup, rgbaIn, 4 * n * sizeof(GLchan)); + rgba = rgbaBackup; + } + else { + rgba = rgbaIn; + } + + /* Texture */ + ASSERT(ctx->Texture.ReallyEnabled); + gl_texture_pixels( ctx, 0, n, s, t, u, lambda, rgba, rgba ); + + /* Add base and specular colors */ + if (spec && ctx->Light.Enabled + && ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR) + add_colors( n, rgba, spec ); /* rgba = rgba + spec */ + + /* Per-pixel fog */ + if (ctx->Fog.Enabled) { + if (fog && ctx->Hint.Fog != GL_NICEST) + _mesa_fog_rgba_pixels( ctx, n, fog, rgba ); + else + _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba ); + } + + /* Do the scissor test */ + if (ctx->Scissor.Enabled) { + if (gl_scissor_span( ctx, n, x, y, mask )==0) { + return; + } + write_all = GL_FALSE; + } + + /* Polygon Stippling */ + if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { + stipple_polygon_span( ctx, n, x, y, mask ); + write_all = GL_FALSE; + } + + /* Do the alpha test */ + if (ctx->Color.AlphaEnabled) { + if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4]) rgba, mask )==0) { + return; + } + write_all = GL_FALSE; + } + + if (ctx->Stencil.Enabled) { + /* first stencil test */ + if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) { + return; + } + write_all = GL_FALSE; + } + else if (ctx->Depth.Test) { + /* regular depth testing */ + GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask ); + if (m==0) { + return; + } + if (m<n) { + write_all = GL_FALSE; + } + } + + /* if we get here, something passed the depth test */ + ctx->OcclusionResult = GL_TRUE; + + if (ctx->RasterMask & MULTI_DRAW_BIT) { + multi_write_rgba_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, mask ); + } + else { + /* normal: write to exactly one buffer */ + if (ctx->Color.ColorLogicOpEnabled) { + _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask ); + } + else if (ctx->Color.BlendEnabled) { + _mesa_blend_span( ctx, n, x, y, rgba, mask ); + } + if (colorMask == 0x0) { + return; + } + else if (colorMask != 0xffffffff) { + _mesa_mask_rgba_span( ctx, n, x, y, rgba ); + } + + (*ctx->Driver.WriteRGBASpan)( ctx, n, x, y, (const GLchan (*)[4])rgba, + write_all ? Null : mask ); + if (ctx->RasterMask & ALPHABUF_BIT) { + _mesa_write_alpha_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, + write_all ? Null : mask ); + } + } +} + + + +/* + * As above but perform multiple stages of texture application. + */ +void +gl_write_multitexture_span( GLcontext *ctx, + GLuint n, GLint x, GLint y, + const GLdepth z[], + const GLfixed fog[], + CONST GLfloat s[MAX_TEXTURE_UNITS][MAX_WIDTH], + CONST GLfloat t[MAX_TEXTURE_UNITS][MAX_WIDTH], + CONST GLfloat u[MAX_TEXTURE_UNITS][MAX_WIDTH], + GLfloat lambda[][MAX_WIDTH], + GLchan rgbaIn[MAX_TEXTURE_UNITS][4], + CONST GLchan spec[MAX_TEXTURE_UNITS][4], + GLenum primitive ) +{ + GLubyte mask[MAX_WIDTH]; + GLboolean write_all = GL_TRUE; + GLchan rgbaBackup[MAX_WIDTH][4]; + GLchan (*rgba)[4]; /* points to either rgbaIn or rgbaBackup */ + GLuint i; + const GLubyte *Null = 0; + const GLuint texUnits = ctx->Const.MaxTextureUnits; + + /* init mask to 1's (all pixels are to be written) */ + MEMSET(mask, 1, n); + + if ((ctx->RasterMask & WINCLIP_BIT) || primitive==GL_BITMAP) { + if (clip_span(ctx, n, x, y, mask)==0) { + return; + } + write_all = GL_FALSE; + } + + + if (primitive==GL_BITMAP || (ctx->RasterMask & MULTI_DRAW_BIT) + || texUnits > 1) { + /* must make a copy of the colors since they may be modified */ + MEMCPY(rgbaBackup, rgbaIn, 4 * n * sizeof(GLchan)); + rgba = rgbaBackup; + } + else { + rgba = rgbaIn; + } + + /* Texture */ + ASSERT(ctx->Texture.ReallyEnabled); + for (i = 0; i < texUnits; i++) + gl_texture_pixels( ctx, i, n, s[i], t[i], u[i], lambda[i], rgbaIn, rgba ); + + /* Add base and specular colors */ + if (spec && ctx->Light.Enabled + && ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR) + add_colors( n, rgba, spec ); /* rgba = rgba + spec */ + + /* Per-pixel fog */ + if (ctx->Fog.Enabled) { + if (fog && ctx->Hint.Fog != GL_NICEST) + _mesa_fog_rgba_pixels( ctx, n, fog, rgba ); + else + _mesa_depth_fog_rgba_pixels( ctx, n, z, rgba ); + } + + /* Do the scissor test */ + if (ctx->Scissor.Enabled) { + if (gl_scissor_span( ctx, n, x, y, mask )==0) { + return; + } + write_all = GL_FALSE; + } + + /* Polygon Stippling */ + if (ctx->Polygon.StippleFlag && primitive==GL_POLYGON) { + stipple_polygon_span( ctx, n, x, y, mask ); + write_all = GL_FALSE; + } + + /* Do the alpha test */ + if (ctx->Color.AlphaEnabled) { + if (_mesa_alpha_test( ctx, n, (const GLchan (*)[4])rgba, mask )==0) { + return; + } + write_all = GL_FALSE; + } + + if (ctx->Stencil.Enabled) { + /* first stencil test */ + if (_mesa_stencil_and_ztest_span(ctx, n, x, y, z, mask) == GL_FALSE) { + return; + } + write_all = GL_FALSE; + } + else if (ctx->Depth.Test) { + /* regular depth testing */ + GLuint m = _mesa_depth_test_span( ctx, n, x, y, z, mask ); + if (m==0) { + return; + } + if (m<n) { + write_all = GL_FALSE; + } + } + + /* if we get here, something passed the depth test */ + ctx->OcclusionResult = GL_TRUE; + + if (ctx->RasterMask & MULTI_DRAW_BIT) { + multi_write_rgba_span( ctx, n, x, y, (const GLchan (*)[4]) rgba, mask ); + } + else { + /* normal: write to exactly one buffer */ + const GLuint colorMask = *((GLuint *) ctx->Color.ColorMask); + + if (ctx->Color.ColorLogicOpEnabled) { + _mesa_logicop_rgba_span( ctx, n, x, y, rgba, mask ); + } + else if (ctx->Color.BlendEnabled) { + _mesa_blend_span( ctx, n, x, y, rgba, mask ); + } + + if (colorMask == 0x0) { + return; + } + else if (colorMask != 0xffffffff) { + _mesa_mask_rgba_span( ctx, n, x, y, rgba ); + } + + (*ctx->Driver.WriteRGBASpan)( ctx, n, x, y, (const GLchan (*)[4])rgba, write_all ? Null : mask ); + if (ctx->RasterMask & ALPHABUF_BIT) { + _mesa_write_alpha_span( ctx, n, x, y, (const GLchan (*)[4])rgba, + write_all ? Null : mask ); + } + } +} + + + +/* + * Read RGBA pixels from frame buffer. Clipping will be done to prevent + * reading ouside the buffer's boundaries. + */ +void gl_read_rgba_span( GLcontext *ctx, GLframebuffer *buffer, + GLuint n, GLint x, GLint y, + GLchan rgba[][4] ) +{ + if (y < 0 || y >= buffer->Height + || x + (GLint) n < 0 || x >= buffer->Width) { + /* completely above, below, or right */ + /* XXX maybe leave undefined? */ + BZERO(rgba, 4 * n * sizeof(GLchan)); + } + else { + GLint skip, length; + if (x < 0) { + /* left edge clippping */ + skip = -x; + length = (GLint) n - skip; + if (length < 0) { + /* completely left of window */ + return; + } + if (length > buffer->Width) { + length = buffer->Width; + } + } + else if ((GLint) (x + n) > buffer->Width) { + /* right edge clipping */ + skip = 0; + length = buffer->Width - x; + if (length < 0) { + /* completely to right of window */ + return; + } + } + else { + /* no clipping */ + skip = 0; + length = (GLint) n; + } + + (*ctx->Driver.ReadRGBASpan)( ctx, length, x + skip, y, rgba + skip ); + if (buffer->UseSoftwareAlphaBuffers) { + _mesa_read_alpha_span( ctx, length, x + skip, y, rgba + skip ); + } + } +} + + + + +/* + * Read CI pixels from frame buffer. Clipping will be done to prevent + * reading ouside the buffer's boundaries. + */ +void gl_read_index_span( GLcontext *ctx, GLframebuffer *buffer, + GLuint n, GLint x, GLint y, GLuint indx[] ) +{ + if (y < 0 || y >= buffer->Height + || x + (GLint) n < 0 || x >= buffer->Width) { + /* completely above, below, or right */ + BZERO(indx, n * sizeof(GLuint)); + } + else { + GLint skip, length; + if (x < 0) { + /* left edge clippping */ + skip = -x; + length = (GLint) n - skip; + if (length < 0) { + /* completely left of window */ + return; + } + if (length > buffer->Width) { + length = buffer->Width; + } + } + else if ((GLint) (x + n) > buffer->Width) { + /* right edge clipping */ + skip = 0; + length = buffer->Width - x; + if (length < 0) { + /* completely to right of window */ + return; + } + } + else { + /* no clipping */ + skip = 0; + length = (GLint) n; + } + + (*ctx->Driver.ReadCI32Span)( ctx, length, skip + x, y, indx + skip ); + } +} diff --git a/src/mesa/swrast/s_span.h b/src/mesa/swrast/s_span.h new file mode 100644 index 00000000000..61411b9f98c --- /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 00000000000..c957a683a16 --- /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 00000000000..80e6a67213c --- /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 00000000000..04f8645b97f --- /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 <[email protected]>. + */ +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 00000000000..8bb5662333c --- /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 00000000000..4b00d8aff9a --- /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 <[email protected]> + * 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 <[email protected]> + * 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 00000000000..71c79a4a7c0 --- /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 00000000000..21e7ceef5af --- /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 00000000000..3520fd506ac --- /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 00000000000..55a8ffb21e5 --- /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 00000000000..4e8627e6955 --- /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 |