diff options
author | Keith Whitwell <keith@tungstengraphics.com> | 2000-10-31 18:00:04 +0000 |
---|---|---|
committer | Keith Whitwell <keith@tungstengraphics.com> | 2000-10-31 18:00:04 +0000 |
commit | e3a051e0538a605551f4d58294c94f5eb00ed07f (patch) | |
tree | ea5ccfd6d578fee1f8adb5a5c7f34f12d601c1c9 /src/mesa/swrast/s_triangle.c | |
parent | 6e0f0f51e0371688a434ed65c4ae0da1b061a4b5 (diff) |
Moved software rasterizer functionality to new directory.
Diffstat (limited to 'src/mesa/swrast/s_triangle.c')
-rw-r--r-- | src/mesa/swrast/s_triangle.c | 2448 |
1 files changed, 2448 insertions, 0 deletions
diff --git a/src/mesa/swrast/s_triangle.c b/src/mesa/swrast/s_triangle.c new file mode 100644 index 0000000000..4b00d8aff9 --- /dev/null +++ b/src/mesa/swrast/s_triangle.c @@ -0,0 +1,2448 @@ +/* $Id: s_triangle.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +/* + * Triangle rasterizers + * When the device driver doesn't implement triangle rasterization Mesa + * will use these functions to draw triangles. + */ + + +#include "glheader.h" +#include "context.h" +#include "feedback.h" +#include "macros.h" +#include "mem.h" +#include "mmath.h" +#include "teximage.h" +#include "texstate.h" + +#include "s_aatriangle.h" +#include "s_depth.h" +#include "s_span.h" + +static GLboolean cull_triangle( GLcontext *ctx, + GLuint v0, GLuint v1, GLuint v2, GLuint pv ) +{ + struct vertex_buffer *VB = ctx->VB; + GLfloat (*win)[4] = VB->Win.data; + GLfloat ex = win[v1][0] - win[v0][0]; + GLfloat ey = win[v1][1] - win[v0][1]; + GLfloat fx = win[v2][0] - win[v0][0]; + GLfloat fy = win[v2][1] - win[v0][1]; + GLfloat c = ex*fy-ey*fx; + + if (c * ctx->backface_sign > 0) + return 0; + + return 1; +} + + +/* + * Render a flat-shaded color index triangle. + */ +static void flat_ci_triangle( GLcontext *ctx, + GLuint v0, GLuint v1, GLuint v2, GLuint pv ) +{ +#define INTERP_Z 1 +#define SETUP_CODE \ + GLuint index = VB->IndexPtr->data[pv]; \ + if (1) { \ + /* set the color index */ \ + (*ctx->Driver.Index)( ctx, index ); \ + } + +#define INNER_LOOP( LEFT, RIGHT, Y ) \ + { \ + const GLint n = RIGHT-LEFT; \ + GLint i; \ + GLdepth zspan[MAX_WIDTH]; \ + GLfixed fogspan[MAX_WIDTH]; \ + if (n>0) { \ + for (i=0;i<n;i++) { \ + zspan[i] = FixedToDepth(ffz); \ + ffz += fdzdx; \ + fogspan[i] = fffog / 256; \ + fffog += fdfogdx; \ + } \ + gl_write_monoindex_span( ctx, n, LEFT, Y, zspan, \ + fogspan, index, GL_POLYGON ); \ + } \ + } + +#include "s_tritemp.h" +} + + + +/* + * Render a smooth-shaded color index triangle. + */ +static void smooth_ci_triangle( GLcontext *ctx, + GLuint v0, GLuint v1, GLuint v2, GLuint pv ) +{ + (void) pv; +#define INTERP_Z 1 +#define INTERP_INDEX 1 + +#define INNER_LOOP( LEFT, RIGHT, Y ) \ + { \ + const GLint n = RIGHT-LEFT; \ + GLint i; \ + GLdepth zspan[MAX_WIDTH]; \ + GLfixed fogspan[MAX_WIDTH]; \ + GLuint index[MAX_WIDTH]; \ + if (n>0) { \ + for (i=0;i<n;i++) { \ + zspan[i] = FixedToDepth(ffz); \ + ffz += fdzdx; \ + index[i] = FixedToInt(ffi); \ + ffi += fdidx; \ + fogspan[i] = fffog / 256; \ + fffog += fdfogdx; \ + } \ + gl_write_index_span( ctx, n, LEFT, Y, zspan, fogspan, \ + index, GL_POLYGON ); \ + } \ + } + +#include "s_tritemp.h" +} + + + +/* + * Render a flat-shaded RGBA triangle. + */ +static void flat_rgba_triangle( GLcontext *ctx, + GLuint v0, GLuint v1, GLuint v2, GLuint pv ) +{ +#define INTERP_Z 1 +#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE + +#define SETUP_CODE \ + if (1) { \ + /* set the color */ \ + GLchan r = VB->ColorPtr->data[pv][0]; \ + GLchan g = VB->ColorPtr->data[pv][1]; \ + GLchan b = VB->ColorPtr->data[pv][2]; \ + GLchan a = VB->ColorPtr->data[pv][3]; \ + (*ctx->Driver.Color)( ctx, r, g, b, a ); \ + } + +#define INNER_LOOP( LEFT, RIGHT, Y ) \ + { \ + const GLint n = RIGHT-LEFT; \ + GLint i; \ + GLdepth zspan[MAX_WIDTH]; \ + GLfixed fogspan[MAX_WIDTH]; \ + if (n>0) { \ + for (i=0;i<n;i++) { \ + zspan[i] = FixedToDepth(ffz); \ + ffz += fdzdx; \ + fogspan[i] = fffog / 256; \ + fffog += fdfogdx; \ + } \ + gl_write_monocolor_span( ctx, n, LEFT, Y, zspan, \ + fogspan, \ + VB->ColorPtr->data[pv], \ + GL_POLYGON ); \ + } \ + } + +#include "s_tritemp.h" + + ASSERT(!ctx->Texture.ReallyEnabled); /* texturing must be off */ + ASSERT(ctx->Light.ShadeModel==GL_FLAT); +} + + + +/* + * Render a smooth-shaded RGBA triangle. + */ +static void smooth_rgba_triangle( GLcontext *ctx, + GLuint v0, GLuint v1, GLuint v2, GLuint pv ) +{ + (void) pv; +#define INTERP_Z 1 +#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE +#define INTERP_RGB 1 +#define INTERP_ALPHA 1 + +#define INNER_LOOP( LEFT, RIGHT, Y ) \ + { \ + const GLint n = RIGHT-LEFT; \ + GLint i; \ + GLdepth zspan[MAX_WIDTH]; \ + GLchan rgba[MAX_WIDTH][4]; \ + GLfixed fogspan[MAX_WIDTH]; \ + if (n>0) { \ + for (i=0;i<n;i++) { \ + zspan[i] = FixedToDepth(ffz); \ + rgba[i][RCOMP] = FixedToInt(ffr); \ + rgba[i][GCOMP] = FixedToInt(ffg); \ + rgba[i][BCOMP] = FixedToInt(ffb); \ + rgba[i][ACOMP] = FixedToInt(ffa); \ + fogspan[i] = fffog / 256; \ + fffog += fdfogdx; \ + ffz += fdzdx; \ + ffr += fdrdx; \ + ffg += fdgdx; \ + ffb += fdbdx; \ + ffa += fdadx; \ + } \ + gl_write_rgba_span( ctx, n, LEFT, Y, \ + (CONST GLdepth *) zspan, \ + fogspan, \ + rgba, GL_POLYGON ); \ + } \ + } + +#include "s_tritemp.h" + + ASSERT(!ctx->Texture.ReallyEnabled); /* texturing must be off */ + ASSERT(ctx->Light.ShadeModel==GL_SMOOTH); +} + + +/* + * Render an RGB, GL_DECAL, textured triangle. + * Interpolate S,T only w/out mipmapping or perspective correction. + * + * No fog. + */ +static void simple_textured_triangle( GLcontext *ctx, GLuint v0, GLuint v1, + GLuint v2, GLuint pv ) +{ +#define INTERP_INT_TEX 1 +#define S_SCALE twidth +#define T_SCALE theight +#define SETUP_CODE \ + struct gl_texture_object *obj = ctx->Texture.Unit[0].CurrentD[2]; \ + GLint b = obj->BaseLevel; \ + GLfloat twidth = (GLfloat) obj->Image[b]->Width; \ + GLfloat theight = (GLfloat) obj->Image[b]->Height; \ + GLint twidth_log2 = obj->Image[b]->WidthLog2; \ + GLchan *texture = obj->Image[b]->Data; \ + GLint smask = obj->Image[b]->Width - 1; \ + GLint tmask = obj->Image[b]->Height - 1; \ + (void) pv; \ + if (!texture) { \ + if (!_mesa_get_teximages_from_driver(ctx, obj)) \ + return; \ + texture = obj->Image[b]->Data; \ + ASSERT(texture); \ + } + +#define INNER_LOOP( LEFT, RIGHT, Y ) \ + { \ + CONST GLint n = RIGHT-LEFT; \ + GLint i; \ + GLchan rgb[MAX_WIDTH][3]; \ + if (n>0) { \ + ffs -= FIXED_HALF; /* off-by-one error? */ \ + fft -= FIXED_HALF; \ + for (i=0;i<n;i++) { \ + GLint s = FixedToInt(ffs) & smask; \ + GLint t = FixedToInt(fft) & tmask; \ + GLint pos = (t << twidth_log2) + s; \ + pos = pos + pos + pos; /* multiply by 3 */ \ + rgb[i][RCOMP] = texture[pos]; \ + rgb[i][GCOMP] = texture[pos+1]; \ + rgb[i][BCOMP] = texture[pos+2]; \ + ffs += fdsdx; \ + fft += fdtdx; \ + } \ + (*ctx->Driver.WriteRGBSpan)( ctx, n, LEFT, Y, \ + (CONST GLchan (*)[3]) rgb, NULL ); \ + } \ + } + +#include "s_tritemp.h" +} + + +/* + * Render an RGB, GL_DECAL, textured triangle. + * Interpolate S,T, GL_LESS depth test, w/out mipmapping or + * perspective correction. + * + * No fog. + */ +static void simple_z_textured_triangle( GLcontext *ctx, GLuint v0, GLuint v1, + GLuint v2, GLuint pv ) +{ +#define INTERP_Z 1 +#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE +#define INTERP_INT_TEX 1 +#define S_SCALE twidth +#define T_SCALE theight +#define SETUP_CODE \ + struct gl_texture_object *obj = ctx->Texture.Unit[0].CurrentD[2]; \ + GLint b = obj->BaseLevel; \ + GLfloat twidth = (GLfloat) obj->Image[b]->Width; \ + GLfloat theight = (GLfloat) obj->Image[b]->Height; \ + GLint twidth_log2 = obj->Image[b]->WidthLog2; \ + GLchan *texture = obj->Image[b]->Data; \ + GLint smask = obj->Image[b]->Width - 1; \ + GLint tmask = obj->Image[b]->Height - 1; \ + (void) pv; \ + if (!texture) { \ + if (!_mesa_get_teximages_from_driver(ctx, obj)) \ + return; \ + texture = obj->Image[b]->Data; \ + ASSERT(texture); \ + } + +#define INNER_LOOP( LEFT, RIGHT, Y ) \ + { \ + CONST GLint n = RIGHT-LEFT; \ + GLint i; \ + GLchan rgb[MAX_WIDTH][3]; \ + GLubyte mask[MAX_WIDTH]; \ + (void) fffog; \ + if (n>0) { \ + ffs -= FIXED_HALF; /* off-by-one error? */ \ + fft -= FIXED_HALF; \ + for (i=0;i<n;i++) { \ + GLdepth z = FixedToDepth(ffz); \ + if (z < zRow[i]) { \ + GLint s = FixedToInt(ffs) & smask; \ + GLint t = FixedToInt(fft) & tmask; \ + GLint pos = (t << twidth_log2) + s; \ + pos = pos + pos + pos; /* multiply by 3 */ \ + rgb[i][RCOMP] = texture[pos]; \ + rgb[i][GCOMP] = texture[pos+1]; \ + rgb[i][BCOMP] = texture[pos+2]; \ + zRow[i] = z; \ + mask[i] = 1; \ + } \ + else { \ + mask[i] = 0; \ + } \ + ffz += fdzdx; \ + ffs += fdsdx; \ + fft += fdtdx; \ + } \ + (*ctx->Driver.WriteRGBSpan)( ctx, n, LEFT, Y, \ + (CONST GLchan (*)[3]) rgb, mask ); \ + } \ + } + +#include "s_tritemp.h" +} + + + +/* + * Render an RGB/RGBA textured triangle without perspective correction. + */ +static void affine_textured_triangle( GLcontext *ctx, GLuint v0, GLuint v1, + GLuint v2, GLuint pv ) +{ +#define INTERP_Z 1 +#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE +#define INTERP_RGB 1 +#define INTERP_ALPHA 1 +#define INTERP_INT_TEX 1 +#define S_SCALE twidth +#define T_SCALE theight +#define SETUP_CODE \ + struct gl_texture_unit *unit = ctx->Texture.Unit+0; \ + struct gl_texture_object *obj = unit->CurrentD[2]; \ + GLint b = obj->BaseLevel; \ + GLfloat twidth = (GLfloat) obj->Image[b]->Width; \ + GLfloat theight = (GLfloat) obj->Image[b]->Height; \ + GLint twidth_log2 = obj->Image[b]->WidthLog2; \ + GLchan *texture = obj->Image[b]->Data; \ + GLint smask = obj->Image[b]->Width - 1; \ + GLint tmask = obj->Image[b]->Height - 1; \ + GLint format = obj->Image[b]->Format; \ + GLint filter = obj->MinFilter; \ + GLint envmode = unit->EnvMode; \ + GLint comp, tbytesline, tsize; \ + GLfixed er, eg, eb, ea; \ + GLint tr, tg, tb, ta; \ + if (!texture) { \ + if (!_mesa_get_teximages_from_driver(ctx, obj)) \ + return; \ + texture = obj->Image[b]->Data; \ + ASSERT(texture); \ + } \ + if (envmode == GL_BLEND || envmode == GL_ADD) { \ + /* potential off-by-one error here? (1.0f -> 2048 -> 0) */ \ + er = FloatToFixed(unit->EnvColor[0]); \ + eg = FloatToFixed(unit->EnvColor[1]); \ + eb = FloatToFixed(unit->EnvColor[2]); \ + ea = FloatToFixed(unit->EnvColor[3]); \ + } \ + switch (format) { \ + case GL_ALPHA: \ + case GL_LUMINANCE: \ + case GL_INTENSITY: \ + comp = 1; \ + break; \ + case GL_LUMINANCE_ALPHA: \ + comp = 2; \ + break; \ + case GL_RGB: \ + comp = 3; \ + break; \ + case GL_RGBA: \ + comp = 4; \ + break; \ + default: \ + gl_problem(NULL, "Bad texture format in affine_texture_triangle");\ + return; \ + } \ + tbytesline = obj->Image[b]->Width * comp; \ + tsize = theight * tbytesline; + (void) pv; + + /* Instead of defining a function for each mode, a test is done + * between the outer and inner loops. This is to reduce code size + * and complexity. Observe that an optimizing compiler kills + * unused variables (for instance tf,sf,ti,si in case of GL_NEAREST). + */ + +#define NEAREST_RGB \ + tr = tex00[0]; \ + tg = tex00[1]; \ + tb = tex00[2]; \ + ta = 0xff + +#define LINEAR_RGB \ + tr = (ti * (si * tex00[0] + sf * tex01[0]) + \ + tf * (si * tex10[0] + sf * tex11[0])) >> 2 * FIXED_SHIFT; \ + tg = (ti * (si * tex00[1] + sf * tex01[1]) + \ + tf * (si * tex10[1] + sf * tex11[1])) >> 2 * FIXED_SHIFT; \ + tb = (ti * (si * tex00[2] + sf * tex01[2]) + \ + tf * (si * tex10[2] + sf * tex11[2])) >> 2 * FIXED_SHIFT; \ + ta = 0xff + +#define NEAREST_RGBA \ + tr = tex00[0]; \ + tg = tex00[1]; \ + tb = tex00[2]; \ + ta = tex00[3] + +#define LINEAR_RGBA \ + tr = (ti * (si * tex00[0] + sf * tex01[0]) + \ + tf * (si * tex10[0] + sf * tex11[0])) >> 2 * FIXED_SHIFT; \ + tg = (ti * (si * tex00[1] + sf * tex01[1]) + \ + tf * (si * tex10[1] + sf * tex11[1])) >> 2 * FIXED_SHIFT; \ + tb = (ti * (si * tex00[2] + sf * tex01[2]) + \ + tf * (si * tex10[2] + sf * tex11[2])) >> 2 * FIXED_SHIFT; \ + ta = (ti * (si * tex00[3] + sf * tex01[3]) + \ + tf * (si * tex10[3] + sf * tex11[3])) >> 2 * FIXED_SHIFT + +#define MODULATE \ + dest[0] = ffr * (tr + 1) >> (FIXED_SHIFT + 8); \ + dest[1] = ffg * (tg + 1) >> (FIXED_SHIFT + 8); \ + dest[2] = ffb * (tb + 1) >> (FIXED_SHIFT + 8); \ + dest[3] = ffa * (ta + 1) >> (FIXED_SHIFT + 8) + +#define DECAL \ + dest[0] = ((0xff - ta) * ffr + ((ta + 1) * tr << FIXED_SHIFT)) >> (FIXED_SHIFT + 8); \ + dest[1] = ((0xff - ta) * ffg + ((ta + 1) * tg << FIXED_SHIFT)) >> (FIXED_SHIFT + 8); \ + dest[2] = ((0xff - ta) * ffb + ((ta + 1) * tb << FIXED_SHIFT)) >> (FIXED_SHIFT + 8); \ + dest[3] = FixedToInt(ffa) + +#define BLEND \ + dest[0] = ((0xff - tr) * ffr + (tr + 1) * er) >> (FIXED_SHIFT + 8); \ + dest[1] = ((0xff - tg) * ffg + (tg + 1) * eg) >> (FIXED_SHIFT + 8); \ + dest[2] = ((0xff - tb) * ffb + (tb + 1) * eb) >> (FIXED_SHIFT + 8); \ + dest[3] = ffa * (ta + 1) >> (FIXED_SHIFT + 8) + +#define REPLACE \ + dest[0] = tr; \ + dest[1] = tg; \ + dest[2] = tb; \ + dest[3] = ta + +#define ADD \ + dest[0] = ((ffr << 8) + (tr + 1) * er) >> (FIXED_SHIFT + 8); \ + dest[1] = ((ffg << 8) + (tg + 1) * eg) >> (FIXED_SHIFT + 8); \ + dest[2] = ((ffb << 8) + (tb + 1) * eb) >> (FIXED_SHIFT + 8); \ + dest[3] = ffa * (ta + 1) >> (FIXED_SHIFT + 8) + +/* shortcuts */ + +#define NEAREST_RGB_REPLACE NEAREST_RGB;REPLACE + +#define NEAREST_RGBA_REPLACE *(GLint *)dest = *(GLint *)tex00 + +#define SPAN1(DO_TEX,COMP) \ + for (i=0;i<n;i++) { \ + GLint s = FixedToInt(ffs) & smask; \ + GLint t = FixedToInt(fft) & tmask; \ + GLint pos = (t << twidth_log2) + s; \ + GLchan *tex00 = texture + COMP * pos; \ + zspan[i] = FixedToDepth(ffz); \ + fogspan[i] = fffog / 256; \ + DO_TEX; \ + fffog += fdfogdx; \ + ffz += fdzdx; \ + ffr += fdrdx; \ + ffg += fdgdx; \ + ffb += fdbdx; \ + ffa += fdadx; \ + ffs += fdsdx; \ + fft += fdtdx; \ + dest += 4; \ + } + +#define SPAN2(DO_TEX,COMP) \ + for (i=0;i<n;i++) { \ + GLint s = FixedToInt(ffs) & smask; \ + GLint t = FixedToInt(fft) & tmask; \ + GLint sf = ffs & FIXED_FRAC_MASK; \ + GLint tf = fft & FIXED_FRAC_MASK; \ + GLint si = FIXED_FRAC_MASK - sf; \ + GLint ti = FIXED_FRAC_MASK - tf; \ + GLint pos = (t << twidth_log2) + s; \ + GLchan *tex00 = texture + COMP * pos; \ + GLchan *tex10 = tex00 + tbytesline; \ + GLchan *tex01 = tex00 + COMP; \ + GLchan *tex11 = tex10 + COMP; \ + if (t == tmask) { \ + tex10 -= tsize; \ + tex11 -= tsize; \ + } \ + if (s == smask) { \ + tex01 -= tbytesline; \ + tex11 -= tbytesline; \ + } \ + zspan[i] = FixedToDepth(ffz); \ + fogspan[i] = fffog / 256; \ + DO_TEX; \ + fffog += fdfogdx; \ + ffz += fdzdx; \ + ffr += fdrdx; \ + ffg += fdgdx; \ + ffb += fdbdx; \ + ffa += fdadx; \ + ffs += fdsdx; \ + fft += fdtdx; \ + dest += 4; \ + } + +/* here comes the heavy part.. (something for the compiler to chew on) */ +#define INNER_LOOP( LEFT, RIGHT, Y ) \ + { \ + CONST GLint n = RIGHT-LEFT; \ + GLint i; \ + GLdepth zspan[MAX_WIDTH]; \ + GLfixed fogspan[MAX_WIDTH]; \ + GLchan rgba[MAX_WIDTH][4]; \ + if (n>0) { \ + GLchan *dest = rgba[0]; \ + ffs -= FIXED_HALF; /* off-by-one error? */ \ + fft -= FIXED_HALF; \ + switch (filter) { \ + case GL_NEAREST: \ + switch (format) { \ + case GL_RGB: \ + switch (envmode) { \ + case GL_MODULATE: \ + SPAN1(NEAREST_RGB;MODULATE,3); \ + break; \ + case GL_DECAL: \ + case GL_REPLACE: \ + SPAN1(NEAREST_RGB_REPLACE,3); \ + break; \ + case GL_BLEND: \ + SPAN1(NEAREST_RGB;BLEND,3); \ + break; \ + case GL_ADD: \ + SPAN1(NEAREST_RGB;ADD,3); \ + break; \ + default: /* unexpected env mode */ \ + abort(); \ + } \ + break; \ + case GL_RGBA: \ + switch(envmode) { \ + case GL_MODULATE: \ + SPAN1(NEAREST_RGBA;MODULATE,4); \ + break; \ + case GL_DECAL: \ + SPAN1(NEAREST_RGBA;DECAL,4); \ + break; \ + case GL_BLEND: \ + SPAN1(NEAREST_RGBA;BLEND,4); \ + break; \ + case GL_ADD: \ + SPAN1(NEAREST_RGBA;ADD,4); \ + break; \ + case GL_REPLACE: \ + SPAN1(NEAREST_RGBA_REPLACE,4); \ + break; \ + default: /* unexpected env mode */ \ + abort(); \ + } \ + break; \ + } \ + break; \ + case GL_LINEAR: \ + ffs -= FIXED_HALF; \ + fft -= FIXED_HALF; \ + switch (format) { \ + case GL_RGB: \ + switch (envmode) { \ + case GL_MODULATE: \ + SPAN2(LINEAR_RGB;MODULATE,3); \ + break; \ + case GL_DECAL: \ + case GL_REPLACE: \ + SPAN2(LINEAR_RGB;REPLACE,3); \ + break; \ + case GL_BLEND: \ + SPAN2(LINEAR_RGB;BLEND,3); \ + break; \ + case GL_ADD: \ + SPAN2(LINEAR_RGB;ADD,3); \ + break; \ + default: /* unexpected env mode */ \ + abort(); \ + } \ + break; \ + case GL_RGBA: \ + switch (envmode) { \ + case GL_MODULATE: \ + SPAN2(LINEAR_RGBA;MODULATE,4); \ + break; \ + case GL_DECAL: \ + SPAN2(LINEAR_RGBA;DECAL,4); \ + break; \ + case GL_BLEND: \ + SPAN2(LINEAR_RGBA;BLEND,4); \ + break; \ + case GL_ADD: \ + SPAN2(LINEAR_RGBA;ADD,4); \ + break; \ + case GL_REPLACE: \ + SPAN2(LINEAR_RGBA;REPLACE,4); \ + break; \ + default: /* unexpected env mode */ \ + abort(); \ + } \ + break; \ + } \ + break; \ + } \ + gl_write_rgba_span(ctx, n, LEFT, Y, zspan, \ + fogspan, \ + rgba, GL_POLYGON); \ + /* explicit kill of variables: */ \ + ffr = ffg = ffb = ffa = 0; \ + } \ + } + +#include "s_tritemp.h" +#undef SPAN1 +#undef SPAN2 +} + + + +/* + * Render an perspective corrected RGB/RGBA textured triangle. + * The Q (aka V in Mesa) coordinate must be zero such that the divide + * by interpolated Q/W comes out right. + * + * This function only renders textured triangles that use GL_NEAREST. + * Perspective correction works right. + * + * This function written by Klaus Niederkrueger <klaus@math.leidenuniv.nl> + * Send all questions and bug reports to him. + */ +static void near_persp_textured_triangle(GLcontext *ctx, GLuint v0, GLuint v1, + GLuint v2, GLuint pv ) +{ +/* The BIAS value is used to shift negative values into positive values. + * Without this, negative texture values don't GL_REPEAT correctly at just + * below zero, because (int)-0.5 = 0 = (int)0.5. We're not going to worry + * about texture coords less than -BIAS. This could be fixed by using + * FLOORF etc. instead, but this is slower... + */ +#define BIAS 4096.0F + +#define INTERP_Z 1 +#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE +#define INTERP_RGB 1 +#define INTERP_ALPHA 1 +#define INTERP_TEX 1 +#define SETUP_CODE \ + struct gl_texture_unit *unit = ctx->Texture.Unit+0; \ + struct gl_texture_object *obj = unit->CurrentD[2]; \ + const GLint b = obj->BaseLevel; \ + const GLfloat twidth = (GLfloat) obj->Image[b]->Width; \ + const GLfloat theight = (GLfloat) obj->Image[b]->Height; \ + const GLint twidth_log2 = obj->Image[b]->WidthLog2; \ + GLchan *texture = obj->Image[b]->Data; \ + const GLint smask = (obj->Image[b]->Width - 1); \ + const GLint tmask = (obj->Image[b]->Height - 1); \ + const GLint format = obj->Image[b]->Format; \ + const GLint envmode = unit->EnvMode; \ + GLfloat sscale, tscale; \ + /*GLint comp, tbytesline, tsize; */ \ + GLfixed er, eg, eb, ea; \ + GLint tr, tg, tb, ta; \ + if (!texture) { \ + if (!_mesa_get_teximages_from_driver(ctx, obj)) \ + return; \ + texture = obj->Image[b]->Data; \ + ASSERT(texture); \ + } \ + if (envmode == GL_BLEND || envmode == GL_ADD) { \ + er = FloatToFixed(unit->EnvColor[0]); \ + eg = FloatToFixed(unit->EnvColor[1]); \ + eb = FloatToFixed(unit->EnvColor[2]); \ + ea = FloatToFixed(unit->EnvColor[3]); \ + } \ + /*switch (format) { \ + case GL_ALPHA: \ + case GL_LUMINANCE: \ + case GL_INTENSITY: \ + comp = 1; \ + break; \ + case GL_LUMINANCE_ALPHA: \ + comp = 2; \ + break; \ + case GL_RGB: \ + comp = 3; \ + break; \ + case GL_RGBA: \ + comp = 4; \ + break; \ + default: \ + gl_problem(NULL, "Bad texture format in near_persp_texture_triangle"); \ + return; \ + } */ \ + sscale = twidth; \ + tscale = theight; \ + /*tbytesline = obj->Image[b]->Width * comp; \ + tsize = theight * tbytesline;*/ + (void) pv; + +#define OLD_SPAN(DO_TEX,COMP) \ + for (i=0;i<n;i++) { \ + GLfloat invQ = 1.0f / vv; \ + GLint s = (int)(SS * invQ + BIAS) & smask; \ + GLint t = (int)(TT * invQ + BIAS) & tmask; \ + GLint pos = COMP * ((t << twidth_log2) + s); \ + GLchan *tex00 = texture + pos; \ + zspan[i] = FixedToDepth(ffz); \ + fogspan[i] = fffog / 256; \ + DO_TEX; \ + fffog += fdfogdx; \ + ffz += fdzdx; \ + ffr += fdrdx; \ + ffg += fdgdx; \ + ffb += fdbdx; \ + ffa += fdadx; \ + SS += dSdx; \ + TT += dTdx; \ + vv += dvdx; \ + dest += 4; \ + } + +#define X_Y_TEX_COORD(X, Y) ((((int)(X) & tmask) << twidth_log2) + ((int)(Y) & smask)) +#define Y_X_TEX_COORD(X, Y) ((((int)(Y) & tmask) << twidth_log2) + ((int)(X) & smask)) + +#define SPAN1(DO_TEX, COMP, TEX_COORD) { \ + GLfloat x_max = CEILF(x_tex); \ + GLfloat y_max = y_tex + (x_max - x_tex) * dy_dx; \ + GLint j, x_m = (int)x_max; \ + GLint pos; \ + if ((int)y_max != (int)y_tex) { \ + GLfloat x_mid = x_tex + (CEILF(y_tex)-y_tex) * dx_dy; \ + j = (nominator + vv * x_mid)/(denominator - dvdx*x_mid); \ + pos = COMP * TEX_COORD(x_tex, y_tex); \ + DRAW_LINE (DO_TEX); \ + y_tex = y_max; \ + } \ + nominator += vv * x_max; \ + denominator -= dvdx * x_max; \ + j = nominator / denominator; \ + pos = COMP * TEX_COORD(x_tex, y_tex); \ + DRAW_LINE (DO_TEX); \ + while (i<n) { \ + y_tex = y_max; \ + y_max += dy_dx; \ + if ((int)y_max != (int)y_tex) { \ + GLfloat x_mid = (CEILF(y_tex)-y_tex) * dx_dy; \ + j = (nominator + vv * x_mid)/(denominator - dvdx*x_mid); \ + pos = COMP * TEX_COORD(x_m, y_tex); \ + DRAW_LINE (DO_TEX); \ + y_tex = y_max; \ + } \ + nominator += vv; \ + denominator -= dvdx; \ + j = nominator/denominator; \ + pos = COMP * TEX_COORD(x_m, y_tex); \ + DRAW_LINE (DO_TEX); \ + x_m ++; \ + } \ +} + +#define SPAN2(DO_TEX, COMP, TEX_COORD) { \ + GLfloat x_max = CEILF (x_tex); \ + GLfloat y_max = y_tex + (x_max - x_tex) * dy_dx; \ + GLint j, x_m = (int) x_max; \ + GLint pos; \ + if ((int)y_max != (int)y_tex) { \ + GLfloat x_mid = x_tex + (FLOORF(y_tex)-y_tex) * dx_dy; \ + j = (nominator + vv * x_mid)/(denominator - dvdx*x_mid); \ + pos = COMP * TEX_COORD(x_tex, y_tex); \ + DRAW_LINE (DO_TEX); \ + y_tex = y_max; \ + } \ + nominator += vv * x_max; \ + denominator -= dvdx * x_max; \ + j = nominator / denominator; \ + pos = COMP * TEX_COORD(x_tex, y_tex); \ + DRAW_LINE (DO_TEX); \ + while (i<n) { \ + y_tex = y_max; \ + y_max += dy_dx; \ + if ((int)y_max != (int)y_tex) { \ + GLfloat x_mid = (FLOORF(y_tex)-y_tex) * dx_dy; \ + j = (nominator + vv * x_mid)/(denominator - dvdx*x_mid);\ + pos = COMP * TEX_COORD(x_m, y_tex); \ + DRAW_LINE (DO_TEX); \ + y_tex = y_max; \ + } \ + nominator += vv; \ + denominator -= dvdx; \ + j = nominator/denominator; \ + pos = COMP * TEX_COORD(x_m, y_tex); \ + DRAW_LINE (DO_TEX); \ + x_m ++; \ + } \ +} + +#define SPAN3(DO_TEX, COMP, TEX_COORD) { \ + GLfloat x_min = FLOORF (x_tex); \ + GLfloat y_min = y_tex + (x_min - x_tex) * dy_dx; \ + GLint j, x_m = (int)x_min; \ + GLint pos; \ + if ((int)y_min != (int)y_tex) { \ + GLfloat x_mid = x_tex + (CEILF(y_tex)-y_tex) * dx_dy; \ + j = (nominator + vv * x_mid)/(denominator - dvdx*x_mid); \ + pos = COMP * TEX_COORD(x_m, y_tex); \ + DRAW_LINE (DO_TEX); \ + y_tex = y_min; \ + } \ + nominator += vv*x_min; \ + denominator -= dvdx*x_min; \ + j = nominator / denominator; \ + pos = COMP * TEX_COORD(x_m, y_tex); \ + DRAW_LINE (DO_TEX); \ + while (i<n) { \ + x_m --; \ + y_tex = y_min; \ + y_min -= dy_dx; \ + if ((int)y_min != (int)y_tex) { \ + GLfloat x_mid = (CEILF(y_tex)-y_tex) * dx_dy; \ + j = (nominator + vv * x_mid)/(denominator - dvdx*x_mid); \ + pos = COMP * TEX_COORD(x_m, y_tex); \ + DRAW_LINE (DO_TEX); \ + y_tex = y_min; \ + } \ + nominator -= vv; \ + denominator += dvdx; \ + j = nominator/denominator; \ + pos = COMP * TEX_COORD(x_m, y_tex); \ + DRAW_LINE (DO_TEX); \ + } \ +} + +#define SPAN4(DO_TEX, COMP, TEX_COORD) \ +{ \ + GLfloat x_min = FLOORF(x_tex); \ + GLint x_m = (int)x_min; \ + GLfloat y_min = y_tex + (x_min - x_tex) * dy_dx; \ + GLint j; \ + GLint pos; \ + if ((int)y_min != (int)y_tex) { \ + GLfloat x_mid = x_tex + (FLOORF(y_tex)-y_tex) * dx_dy; \ + j = (nominator + vv * x_mid)/(denominator - dvdx*x_mid); \ + pos = COMP * TEX_COORD(x_m, y_tex); \ + DRAW_LINE (DO_TEX); \ + y_tex = y_min; \ + } \ + nominator += vv * x_min; \ + denominator -= dvdx * x_min; \ + j = nominator / denominator; \ + pos = COMP * TEX_COORD(x_m, y_tex); \ + DRAW_LINE (DO_TEX); \ + while (i<n) { \ + x_m --; \ + y_tex = y_min; \ + y_min -= dy_dx; \ + if ((int)y_min != (int)y_tex) { \ + GLfloat x_mid = (FLOORF(y_tex)-y_tex) * dx_dy; \ + j = (nominator + vv * x_mid)/(denominator - dvdx*x_mid); \ + pos = COMP * TEX_COORD(x_m, (y_tex)); \ + DRAW_LINE (DO_TEX); \ + y_tex = y_min; \ + } \ + nominator -= vv; \ + denominator += dvdx; \ + j = nominator/denominator; \ + pos = COMP * TEX_COORD(x_m, y_tex); \ + DRAW_LINE (DO_TEX); \ + } \ +} + +#define DRAW_LINE(DO_TEX) \ + { \ + GLchan *tex00 = texture + pos; \ + if (j>n || j<-100000) \ + j = n; \ + while (i<j) { \ + zspan[i] = FixedToDepth(ffz); \ + fogspan[i] = fffog / 256; \ + DO_TEX; \ + fffog += fdfogdx; \ + ffz += fdzdx; \ + ffr += fdrdx; \ + ffg += fdgdx; \ + ffb += fdbdx; \ + ffa += fdadx; \ + dest += 4; \ + i++; \ + } \ + } + +#define INNER_LOOP( LEFT, RIGHT, Y ) \ + { \ + GLint i = 0; \ + const GLint n = RIGHT-LEFT; \ + GLdepth zspan[MAX_WIDTH]; \ + GLfixed fogspan[MAX_WIDTH]; \ + GLchan rgba[MAX_WIDTH][4]; \ + (void)uu; /* please GCC */ \ + if (n > 0) { \ + GLchan *dest = rgba[0]; \ + GLfloat SS = ss * sscale; \ + GLfloat TT = tt * tscale; \ + GLfloat dSdx = dsdx * sscale; \ + GLfloat dTdx = dtdx * tscale; \ + GLfloat x_tex; \ + GLfloat y_tex; \ + GLfloat dx_tex; \ + GLfloat dy_tex; \ + if (n<5) /* When line very short, setup-time > speed-gain. */ \ + goto old_span; /* So: take old method */ \ + x_tex = SS / vv, \ + y_tex = TT / vv; \ + dx_tex = (SS + n * dSdx) / (vv + n * dvdx) - x_tex, \ + dy_tex = (TT + n * dTdx) / (vv + n * dvdx) - y_tex; \ + /* Choose between walking over texture or over pixelline: */ \ + /* If there are few texels, walk over texture otherwise */ \ + /* walk over pixelarray. The quotient on the right side */ \ + /* should give the timeratio needed to draw one texel in */ \ + /* comparison to one pixel. Depends on CPU. */ \ + if (dx_tex*dx_tex + dy_tex*dy_tex < (n*n)/16) { \ + x_tex += BIAS; \ + y_tex += BIAS; \ + if (dx_tex*dx_tex > dy_tex*dy_tex) { \ + /* if (FABSF(dx_tex) > FABSF(dy_tex)) */ \ + GLfloat nominator = - SS - vv * BIAS; \ + GLfloat denominator = dvdx * BIAS + dSdx; \ + GLfloat dy_dx; \ + GLfloat dx_dy; \ + if (dy_tex != 0.0f) { \ + dy_dx = dy_tex / dx_tex; \ + dx_dy = 1.0f/dy_dx; \ + } \ + else \ + dy_dx = 0.0f; \ + if (dx_tex > 0.0f) { \ + if (dy_tex > 0.0f) { \ + switch (format) { \ + case GL_RGB: \ + switch (envmode) { \ + case GL_MODULATE: \ + SPAN1(NEAREST_RGB;MODULATE,3, Y_X_TEX_COORD);\ + break; \ + case GL_DECAL: \ + case GL_REPLACE: \ + SPAN1(NEAREST_RGB_REPLACE,3, Y_X_TEX_COORD); \ + break; \ + case GL_BLEND: \ + SPAN1(NEAREST_RGB;BLEND,3, Y_X_TEX_COORD); \ + break; \ + case GL_ADD: \ + SPAN1(NEAREST_RGB;ADD,3, Y_X_TEX_COORD); \ + break; \ + default: /* unexpected env mode */ \ + abort(); \ + } \ + break; \ + case GL_RGBA: \ + switch(envmode) { \ + case GL_MODULATE: \ + SPAN1(NEAREST_RGBA;MODULATE,4, Y_X_TEX_COORD);\ + break; \ + case GL_DECAL: \ + SPAN1(NEAREST_RGBA;DECAL,4, Y_X_TEX_COORD); \ + break; \ + case GL_BLEND: \ + SPAN1(NEAREST_RGBA;BLEND,4, Y_X_TEX_COORD); \ + break; \ + case GL_ADD: \ + SPAN1(NEAREST_RGBA;ADD,4, Y_X_TEX_COORD); \ + break; \ + case GL_REPLACE: \ + SPAN1(NEAREST_RGBA_REPLACE,4, Y_X_TEX_COORD);\ + break; \ + default: /* unexpected env mode */ \ + abort(); \ + } \ + break; \ + } \ + } \ + else { /* dy_tex <= 0.0f */ \ + switch (format) { \ + case GL_RGB: \ + switch (envmode) { \ + case GL_MODULATE: \ + SPAN2(NEAREST_RGB;MODULATE,3, Y_X_TEX_COORD);\ + break; \ + case GL_DECAL: \ + case GL_REPLACE: \ + SPAN2(NEAREST_RGB_REPLACE,3, Y_X_TEX_COORD); \ + break; \ + case GL_BLEND: \ + SPAN2(NEAREST_RGB;BLEND,3, Y_X_TEX_COORD); \ + break; \ + case GL_ADD: \ + SPAN2(NEAREST_RGB;ADD,3, Y_X_TEX_COORD); \ + break; \ + default: /* unexpected env mode */ \ + abort(); \ + } \ + break; \ + case GL_RGBA: \ + switch(envmode) { \ + case GL_MODULATE: \ + SPAN2(NEAREST_RGBA;MODULATE,4, Y_X_TEX_COORD);\ + break; \ + case GL_DECAL: \ + SPAN2(NEAREST_RGBA;DECAL,4, Y_X_TEX_COORD); \ + break; \ + case GL_BLEND: \ + SPAN2(NEAREST_RGBA;BLEND,4, Y_X_TEX_COORD); \ + break; \ + case GL_ADD: \ + SPAN2(NEAREST_RGBA;ADD,4, Y_X_TEX_COORD); \ + break; \ + case GL_REPLACE: \ + SPAN2(NEAREST_RGBA_REPLACE,4, Y_X_TEX_COORD);\ + break; \ + default: /* unexpected env mode */ \ + abort(); \ + } \ + break; \ + } \ + } \ + } \ + else { /* dx_tex < 0.0f */ \ + if (dy_tex > 0.0f) { \ + switch (format) { \ + case GL_RGB: \ + switch (envmode) { \ + case GL_MODULATE: \ + SPAN3(NEAREST_RGB;MODULATE,3, Y_X_TEX_COORD);\ + break; \ + case GL_DECAL: \ + case GL_REPLACE: \ + SPAN3(NEAREST_RGB_REPLACE,3, Y_X_TEX_COORD); \ + break; \ + case GL_BLEND: \ + SPAN3(NEAREST_RGB;BLEND,3, Y_X_TEX_COORD); \ + break; \ + case GL_ADD: \ + SPAN3(NEAREST_RGB;ADD,3, Y_X_TEX_COORD); \ + break; \ + default: /* unexpected env mode */ \ + abort(); \ + } \ + break; \ + case GL_RGBA: \ + switch(envmode) { \ + case GL_MODULATE: \ + SPAN3(NEAREST_RGBA;MODULATE,4, Y_X_TEX_COORD);\ + break; \ + case GL_DECAL: \ + SPAN3(NEAREST_RGBA;DECAL,4, Y_X_TEX_COORD); \ + break; \ + case GL_BLEND: \ + SPAN3(NEAREST_RGBA;BLEND,4, Y_X_TEX_COORD); \ + break; \ + case GL_ADD: \ + SPAN3(NEAREST_RGBA;ADD,4, Y_X_TEX_COORD); \ + break; \ + case GL_REPLACE: \ + SPAN3(NEAREST_RGBA_REPLACE,4, Y_X_TEX_COORD);\ + break; \ + default: /* unexpected env mode */ \ + abort(); \ + } \ + break; \ + } \ + } \ + else { /* dy_tex <= 0.0f */ \ + switch (format) { \ + case GL_RGB: \ + switch (envmode) { \ + case GL_MODULATE: \ + SPAN4(NEAREST_RGB;MODULATE,3, Y_X_TEX_COORD);\ + break; \ + case GL_DECAL: \ + case GL_REPLACE: \ + SPAN4(NEAREST_RGB_REPLACE,3, Y_X_TEX_COORD); \ + break; \ + case GL_BLEND: \ + SPAN4(NEAREST_RGB;BLEND,3, Y_X_TEX_COORD); \ + break; \ + case GL_ADD: \ + SPAN4(NEAREST_RGB;ADD,3, Y_X_TEX_COORD); \ + break; \ + default: \ + abort(); \ + } \ + break; \ + case GL_RGBA: \ + switch(envmode) { \ + case GL_MODULATE: \ + SPAN4(NEAREST_RGBA;MODULATE,4, Y_X_TEX_COORD);\ + break; \ + case GL_DECAL: \ + SPAN4(NEAREST_RGBA;DECAL,4, Y_X_TEX_COORD); \ + break; \ + case GL_BLEND: \ + SPAN4(NEAREST_RGBA;BLEND,4, Y_X_TEX_COORD); \ + break; \ + case GL_ADD: \ + SPAN4(NEAREST_RGBA;ADD,4, Y_X_TEX_COORD); \ + break; \ + case GL_REPLACE: \ + SPAN4(NEAREST_RGBA_REPLACE,4, Y_X_TEX_COORD);\ + break; \ + default: /* unexpected env mode */ \ + abort(); \ + } \ + break; \ + } \ + } \ + } \ + } \ + else { /* FABSF(dx_tex) > FABSF(dy_tex) */ \ + GLfloat swap; \ + GLfloat dy_dx; \ + GLfloat dx_dy; \ + GLfloat nominator, denominator; \ + if (dx_tex == 0.0f /* && dy_tex == 0.0f*/) \ + goto old_span; /* case so special, that use old */ \ + /* swap some x-values and y-values */ \ + SS = TT; \ + dSdx = dTdx; \ + swap = x_tex, x_tex = y_tex, y_tex = swap; \ + swap = dx_tex, dx_tex = dy_tex, dy_tex = swap; \ + nominator = - SS - vv * BIAS; \ + denominator = dvdx * BIAS + dSdx; \ + if (dy_tex != 0.0f) { \ + dy_dx = dy_tex / dx_tex; \ + dx_dy = 1.0f/dy_dx; \ + } \ + else \ + dy_dx = 0.0f; \ + if (dx_tex > 0.0f) { \ + if (dy_tex > 0.0f) { \ + switch (format) { \ + case GL_RGB: \ + switch (envmode) { \ + case GL_MODULATE: \ + SPAN1(NEAREST_RGB;MODULATE,3, X_Y_TEX_COORD);\ + break; \ + case GL_DECAL: \ + case GL_REPLACE: \ + SPAN1(NEAREST_RGB_REPLACE,3, X_Y_TEX_COORD); \ + break; \ + case GL_BLEND: \ + SPAN1(NEAREST_RGB;BLEND,3, X_Y_TEX_COORD); \ + break; \ + case GL_ADD: \ + SPAN1(NEAREST_RGB;ADD,3, X_Y_TEX_COORD); \ + break; \ + default: /* unexpected env mode */ \ + abort(); \ + } \ + break; \ + case GL_RGBA: \ + switch(envmode) { \ + case GL_MODULATE: \ + SPAN1(NEAREST_RGBA;MODULATE,4, X_Y_TEX_COORD);\ + break; \ + case GL_DECAL: \ + SPAN1(NEAREST_RGBA;DECAL,4, X_Y_TEX_COORD); \ + break; \ + case GL_BLEND: \ + SPAN1(NEAREST_RGBA;BLEND,4, X_Y_TEX_COORD); \ + break; \ + case GL_ADD: \ + SPAN1(NEAREST_RGBA;ADD,4, X_Y_TEX_COORD); \ + break; \ + case GL_REPLACE: \ + SPAN1(NEAREST_RGBA_REPLACE,4, X_Y_TEX_COORD);\ + break; \ + default: \ + abort(); \ + } \ + break; \ + } \ + } \ + else { /* dy_tex <= 0.0f */ \ + switch (format) { \ + case GL_RGB: \ + switch (envmode) { \ + case GL_MODULATE: \ + SPAN2(NEAREST_RGB;MODULATE,3, X_Y_TEX_COORD);\ + break; \ + case GL_DECAL: \ + case GL_REPLACE: \ + SPAN2(NEAREST_RGB_REPLACE,3, X_Y_TEX_COORD); \ + break; \ + case GL_BLEND: \ + SPAN2(NEAREST_RGB;BLEND,3, X_Y_TEX_COORD); \ + break; \ + case GL_ADD: \ + SPAN2(NEAREST_RGB;ADD,3, X_Y_TEX_COORD); \ + break; \ + default: \ + abort(); \ + } \ + break; \ + case GL_RGBA: \ + switch(envmode) { \ + case GL_MODULATE: \ + SPAN2(NEAREST_RGBA;MODULATE,4, X_Y_TEX_COORD);\ + break; \ + case GL_DECAL: \ + SPAN2(NEAREST_RGBA;DECAL,4, X_Y_TEX_COORD); \ + break; \ + case GL_BLEND: \ + SPAN2(NEAREST_RGBA;BLEND,4, X_Y_TEX_COORD); \ + break; \ + case GL_ADD: \ + SPAN2(NEAREST_RGBA;ADD,4, X_Y_TEX_COORD); \ + break; \ + case GL_REPLACE: \ + SPAN2(NEAREST_RGBA_REPLACE,4, X_Y_TEX_COORD);\ + break; \ + default: \ + abort(); \ + } \ + break; \ + } \ + } \ + } \ + else { /* dx_tex < 0.0f */ \ + if (dy_tex > 0.0f) { \ + switch (format) { \ + case GL_RGB: \ + switch (envmode) { \ + case GL_MODULATE: \ + SPAN3(NEAREST_RGB;MODULATE,3, X_Y_TEX_COORD);\ + break; \ + case GL_DECAL: \ + case GL_REPLACE: \ + SPAN3(NEAREST_RGB_REPLACE,3, X_Y_TEX_COORD); \ + break; \ + case GL_BLEND: \ + SPAN3(NEAREST_RGB;BLEND,3, X_Y_TEX_COORD); \ + break; \ + case GL_ADD: \ + SPAN3(NEAREST_RGB;ADD,3, X_Y_TEX_COORD); \ + break; \ + default: \ + abort(); \ + } \ + break; \ + case GL_RGBA: \ + switch(envmode) { \ + case GL_MODULATE: \ + SPAN3(NEAREST_RGBA;MODULATE,4, X_Y_TEX_COORD);\ + break; \ + case GL_DECAL: \ + SPAN3(NEAREST_RGBA;DECAL,4, X_Y_TEX_COORD); \ + break; \ + case GL_BLEND: \ + SPAN3(NEAREST_RGBA;BLEND,4, X_Y_TEX_COORD); \ + break; \ + case GL_ADD: \ + SPAN3(NEAREST_RGBA;ADD,4, X_Y_TEX_COORD); \ + break; \ + case GL_REPLACE: \ + SPAN3(NEAREST_RGBA_REPLACE,4, X_Y_TEX_COORD);\ + break; \ + default: \ + abort(); \ + } \ + break; \ + } \ + } \ + else { /* dy_tex <= 0.0f */ \ + switch (format) { \ + case GL_RGB: \ + switch (envmode) { \ + case GL_MODULATE: \ + SPAN4(NEAREST_RGB;MODULATE,3, X_Y_TEX_COORD);\ + break; \ + case GL_DECAL: \ + case GL_REPLACE: \ + SPAN4(NEAREST_RGB_REPLACE,3, X_Y_TEX_COORD); \ + break; \ + case GL_BLEND: \ + SPAN4(NEAREST_RGB;BLEND,3, X_Y_TEX_COORD); \ + break; \ + case GL_ADD: \ + SPAN4(NEAREST_RGB;ADD,3, X_Y_TEX_COORD); \ + break; \ + default: \ + abort(); \ + } \ + break; \ + case GL_RGBA: \ + switch(envmode) { \ + case GL_MODULATE: \ + SPAN4(NEAREST_RGBA;MODULATE,4, X_Y_TEX_COORD);\ + break; \ + case GL_DECAL: \ + SPAN4(NEAREST_RGBA;DECAL,4, X_Y_TEX_COORD); \ + break; \ + case GL_BLEND: \ + SPAN4(NEAREST_RGBA;BLEND,4, X_Y_TEX_COORD); \ + break; \ + case GL_ADD: \ + SPAN4(NEAREST_RGBA;ADD,4, X_Y_TEX_COORD); \ + break; \ + case GL_REPLACE: \ + SPAN4(NEAREST_RGBA_REPLACE,4, X_Y_TEX_COORD);\ + break; \ + default: \ + abort(); \ + } \ + break; \ + } \ + } \ + } \ + } \ + } \ + else { \ + old_span: \ + switch (format) { \ + case GL_RGB: \ + switch (envmode) { \ + case GL_MODULATE: \ + OLD_SPAN(NEAREST_RGB;MODULATE,3); \ + break; \ + case GL_DECAL: \ + case GL_REPLACE: \ + OLD_SPAN(NEAREST_RGB_REPLACE,3); \ + break; \ + case GL_BLEND: \ + OLD_SPAN(NEAREST_RGB;BLEND,3); \ + break; \ + case GL_ADD: \ + OLD_SPAN(NEAREST_RGB;ADD,3); \ + break; \ + default: \ + abort(); \ + } \ + break; \ + case GL_RGBA: \ + switch(envmode) { \ + case GL_MODULATE: \ + OLD_SPAN(NEAREST_RGBA;MODULATE,4); \ + break; \ + case GL_DECAL: \ + OLD_SPAN(NEAREST_RGBA;DECAL,4); \ + break; \ + case GL_BLEND: \ + OLD_SPAN(NEAREST_RGBA;BLEND,4); \ + break; \ + case GL_ADD: \ + OLD_SPAN(NEAREST_RGBA;ADD,4); \ + break; \ + case GL_REPLACE: \ + OLD_SPAN(NEAREST_RGBA_REPLACE,4); \ + break; \ + default: \ + abort(); \ + } \ + break; \ + } \ + } \ + gl_write_rgba_span( ctx, n, LEFT, Y, zspan, \ + fogspan, rgba, GL_POLYGON); \ + ffr = ffg = ffb = ffa = 0; \ + } \ + } \ + +#include "s_tritemp.h" +#undef OLD_SPAN +#undef SPAN1 +#undef SPAN2 +#undef SPAN3 +#undef SPAN4 +#undef X_Y_TEX_COORD +#undef Y_X_TEX_COORD +#undef DRAW_LINE +#undef BIAS +} + + + +/* + * Render an perspective corrected RGB/RGBA textured triangle. + * The Q (aka V in Mesa) coordinate must be zero such that the divide + * by interpolated Q/W comes out right. + * + * This function written by Klaus Niederkrueger <klaus@math.leidenuniv.nl> + * Send all questions and bug reports to him. + */ +static void lin_persp_textured_triangle( GLcontext *ctx, GLuint v0, GLuint v1, + GLuint v2, GLuint pv ) +{ +#define INTERP_Z 1 +#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE +#define INTERP_RGB 1 +#define INTERP_ALPHA 1 +#define INTERP_TEX 1 +#define SETUP_CODE \ + struct gl_texture_unit *unit = ctx->Texture.Unit+0; \ + struct gl_texture_object *obj = unit->CurrentD[2]; \ + const GLint b = obj->BaseLevel; \ + const GLfloat twidth = (GLfloat) obj->Image[b]->Width; \ + const GLfloat theight = (GLfloat) obj->Image[b]->Height; \ + const GLint twidth_log2 = obj->Image[b]->WidthLog2; \ + GLchan *texture = obj->Image[b]->Data; \ + const GLint smask = (obj->Image[b]->Width - 1); \ + const GLint tmask = (obj->Image[b]->Height - 1); \ + const GLint format = obj->Image[b]->Format; \ + const GLint envmode = unit->EnvMode; \ + GLfloat sscale, tscale; \ + GLint comp, tbytesline, tsize; \ + GLfixed er, eg, eb, ea; \ + GLint tr, tg, tb, ta; \ + if (!texture) { \ + if (!_mesa_get_teximages_from_driver(ctx, obj)) \ + return; \ + texture = obj->Image[b]->Data; \ + ASSERT(texture); \ + } \ + if (envmode == GL_BLEND || envmode == GL_ADD) { \ + er = FloatToFixed(unit->EnvColor[0]); \ + eg = FloatToFixed(unit->EnvColor[1]); \ + eb = FloatToFixed(unit->EnvColor[2]); \ + ea = FloatToFixed(unit->EnvColor[3]); \ + } \ + switch (format) { \ + case GL_ALPHA: \ + case GL_LUMINANCE: \ + case GL_INTENSITY: \ + comp = 1; \ + break; \ + case GL_LUMINANCE_ALPHA: \ + comp = 2; \ + break; \ + case GL_RGB: \ + comp = 3; \ + break; \ + case GL_RGBA: \ + comp = 4; \ + break; \ + default: \ + gl_problem(NULL, "Bad texture format in lin_persp_texture_triangle"); \ + return; \ + } \ + sscale = FIXED_SCALE * twidth; \ + tscale = FIXED_SCALE * theight; \ + tbytesline = obj->Image[b]->Width * comp; \ + tsize = theight * tbytesline; + (void) pv; + +#define SPAN(DO_TEX,COMP) \ + for (i=0;i<n;i++) { \ + GLfloat invQ = 1.0f / vv; \ + GLfixed ffs = (int)(SS * invQ); \ + GLfixed fft = (int)(TT * invQ); \ + GLint s = FixedToInt(ffs) & smask; \ + GLint t = FixedToInt(fft) & tmask; \ + GLint sf = ffs & FIXED_FRAC_MASK; \ + GLint tf = fft & FIXED_FRAC_MASK; \ + GLint si = FIXED_FRAC_MASK - sf; \ + GLint ti = FIXED_FRAC_MASK - tf; \ + GLint pos = COMP * ((t << twidth_log2) + s); \ + GLchan *tex00 = texture + pos; \ + GLchan *tex10 = tex00 + tbytesline; \ + GLchan *tex01 = tex00 + COMP; \ + GLchan *tex11 = tex10 + COMP; \ + if (t == tmask) { \ + tex10 -= tsize; \ + tex11 -= tsize; \ + } \ + if (s == smask) { \ + tex01 -= tbytesline; \ + tex11 -= tbytesline; \ + } \ + zspan[i] = FixedToDepth(ffz); \ + fogspan[i] = fffog / 256; \ + DO_TEX; \ + fffog += fdfogdx; \ + ffz += fdzdx; \ + ffr += fdrdx; \ + ffg += fdgdx; \ + ffb += fdbdx; \ + ffa += fdadx; \ + SS += dSdx; \ + TT += dTdx; \ + vv += dvdx; \ + dest += 4; \ + } + +#define INNER_LOOP( LEFT, RIGHT, Y ) \ + { \ + GLint i; \ + const GLint n = RIGHT-LEFT; \ + GLdepth zspan[MAX_WIDTH]; \ + GLfixed fogspan[MAX_WIDTH]; \ + GLchan rgba[MAX_WIDTH][4]; \ + (void) uu; /* please GCC */ \ + if (n > 0) { \ + GLfloat SS = ss * sscale; \ + GLfloat TT = tt * tscale; \ + GLfloat dSdx = dsdx * sscale; \ + GLfloat dTdx = dtdx * tscale; \ + GLchan *dest = rgba[0]; \ + SS -= 0.5f * FIXED_SCALE * vv; \ + TT -= 0.5f * FIXED_SCALE * vv; \ + switch (format) { \ + case GL_RGB: \ + switch (envmode) { \ + case GL_MODULATE: \ + SPAN(LINEAR_RGB;MODULATE,3); \ + break; \ + case GL_DECAL: \ + case GL_REPLACE: \ + SPAN(LINEAR_RGB;REPLACE,3); \ + break; \ + case GL_BLEND: \ + SPAN(LINEAR_RGB;BLEND,3); \ + break; \ + case GL_ADD: \ + SPAN(LINEAR_RGB;ADD,3); \ + break; \ + default: \ + abort(); \ + } \ + break; \ + case GL_RGBA: \ + switch (envmode) { \ + case GL_MODULATE: \ + SPAN(LINEAR_RGBA;MODULATE,4); \ + break; \ + case GL_DECAL: \ + SPAN(LINEAR_RGBA;DECAL,4); \ + break; \ + case GL_BLEND: \ + SPAN(LINEAR_RGBA;BLEND,4); \ + break; \ + case GL_REPLACE: \ + SPAN(LINEAR_RGBA;REPLACE,4); \ + break; \ + case GL_ADD: \ + SPAN(LINEAR_RGBA;ADD,4); \ + break; \ + default: /* unexpected env mode */ \ + abort(); \ + } \ + } \ + gl_write_rgba_span( ctx, n, LEFT, Y, zspan, \ + fogspan, \ + rgba, GL_POLYGON ); \ + ffr = ffg = ffb = ffa = 0; \ + } \ + } + + +#include "s_tritemp.h" +#undef SPAN +} + + + +/* + * Render a smooth-shaded, textured, RGBA triangle. + * Interpolate S,T,U with perspective correction, w/out mipmapping. + * Note: we use texture coordinates S,T,U,V instead of S,T,R,Q because + * R is already used for red. + */ +static void general_textured_triangle( GLcontext *ctx, GLuint v0, GLuint v1, + GLuint v2, GLuint pv ) +{ +#define INTERP_Z 1 +#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE +#define INTERP_RGB 1 +#define INTERP_ALPHA 1 +#define INTERP_TEX 1 +#define SETUP_CODE \ + GLboolean flat_shade = (ctx->Light.ShadeModel==GL_FLAT); \ + GLint r, g, b, a; \ + if (flat_shade) { \ + r = VB->ColorPtr->data[pv][0]; \ + g = VB->ColorPtr->data[pv][1]; \ + b = VB->ColorPtr->data[pv][2]; \ + a = VB->ColorPtr->data[pv][3]; \ + } +#define INNER_LOOP( LEFT, RIGHT, Y ) \ + { \ + GLint i; \ + const GLint n = RIGHT-LEFT; \ + GLdepth zspan[MAX_WIDTH]; \ + GLfixed fogspan[MAX_WIDTH]; \ + GLchan rgba[MAX_WIDTH][4]; \ + GLfloat s[MAX_WIDTH], t[MAX_WIDTH], u[MAX_WIDTH]; \ + if (n>0) { \ + if (flat_shade) { \ + for (i=0;i<n;i++) { \ + GLdouble invQ = 1.0 / vv; \ + zspan[i] = FixedToDepth(ffz); \ + fogspan[i] = fffog / 256; \ + rgba[i][RCOMP] = r; \ + rgba[i][GCOMP] = g; \ + rgba[i][BCOMP] = b; \ + rgba[i][ACOMP] = a; \ + s[i] = ss*invQ; \ + t[i] = tt*invQ; \ + u[i] = uu*invQ; \ + fffog += fdfogdx; \ + ffz += fdzdx; \ + ss += dsdx; \ + tt += dtdx; \ + uu += dudx; \ + vv += dvdx; \ + } \ + } \ + else { \ + for (i=0;i<n;i++) { \ + GLdouble invQ = 1.0 / vv; \ + zspan[i] = FixedToDepth(ffz); \ + rgba[i][RCOMP] = FixedToInt(ffr); \ + rgba[i][GCOMP] = FixedToInt(ffg); \ + rgba[i][BCOMP] = FixedToInt(ffb); \ + rgba[i][ACOMP] = FixedToInt(ffa); \ + fogspan[i] = fffog / 256; \ + s[i] = ss*invQ; \ + t[i] = tt*invQ; \ + u[i] = uu*invQ; \ + fffog += fdfogdx; \ + ffz += fdzdx; \ + ffr += fdrdx; \ + ffg += fdgdx; \ + ffb += fdbdx; \ + ffa += fdadx; \ + ss += dsdx; \ + tt += dtdx; \ + uu += dudx; \ + vv += dvdx; \ + } \ + } \ + gl_write_texture_span( ctx, n, LEFT, Y, zspan, fogspan, \ + s, t, u, NULL, \ + rgba, \ + NULL, GL_POLYGON ); \ + } \ + } + +#include "s_tritemp.h" +} + + +/* + * Render a smooth-shaded, textured, RGBA triangle with separate specular + * color interpolation. + * Interpolate S,T,U with perspective correction, w/out mipmapping. + * Note: we use texture coordinates S,T,U,V instead of S,T,R,Q because + * R is already used for red. + */ +static void general_textured_spec_triangle1( GLcontext *ctx, GLuint v0, + GLuint v1, GLuint v2, GLuint pv, + GLdepth zspan[MAX_WIDTH], + GLfixed fogspan[MAX_WIDTH], + GLchan rgba[MAX_WIDTH][4], + GLchan spec[MAX_WIDTH][4] ) +{ +#define INTERP_Z 1 +#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE +#define INTERP_RGB 1 +#define INTERP_SPEC 1 +#define INTERP_ALPHA 1 +#define INTERP_TEX 1 +#define SETUP_CODE \ + GLboolean flat_shade = (ctx->Light.ShadeModel==GL_FLAT); \ + GLint r, g, b, a, sr, sg, sb; \ + if (flat_shade) { \ + r = VB->ColorPtr->data[pv][0]; \ + g = VB->ColorPtr->data[pv][1]; \ + b = VB->ColorPtr->data[pv][2]; \ + a = VB->ColorPtr->data[pv][3]; \ + sr = VB->SecondaryColorPtr->data[pv][0]; \ + sg = VB->SecondaryColorPtr->data[pv][1]; \ + sb = VB->SecondaryColorPtr->data[pv][2]; \ + } +#define INNER_LOOP( LEFT, RIGHT, Y ) \ + { \ + GLint i; \ + const GLint n = RIGHT-LEFT; \ + GLfloat s[MAX_WIDTH], t[MAX_WIDTH], u[MAX_WIDTH]; \ + if (n>0) { \ + if (flat_shade) { \ + for (i=0;i<n;i++) { \ + GLdouble invQ = 1.0 / vv; \ + zspan[i] = FixedToDepth(ffz); \ + fogspan[i] = fffog / 256; \ + rgba[i][RCOMP] = r; \ + rgba[i][GCOMP] = g; \ + rgba[i][BCOMP] = b; \ + rgba[i][ACOMP] = a; \ + spec[i][RCOMP] = sr; \ + spec[i][GCOMP] = sg; \ + spec[i][BCOMP] = sb; \ + s[i] = ss*invQ; \ + t[i] = tt*invQ; \ + u[i] = uu*invQ; \ + fffog += fdfogdx; \ + ffz += fdzdx; \ + ss += dsdx; \ + tt += dtdx; \ + uu += dudx; \ + vv += dvdx; \ + } \ + } \ + else { \ + for (i=0;i<n;i++) { \ + GLdouble invQ = 1.0 / vv; \ + zspan[i] = FixedToDepth(ffz); \ + fogspan[i] = fffog / 256; \ + rgba[i][RCOMP] = FixedToInt(ffr); \ + rgba[i][GCOMP] = FixedToInt(ffg); \ + rgba[i][BCOMP] = FixedToInt(ffb); \ + rgba[i][ACOMP] = FixedToInt(ffa); \ + spec[i][RCOMP] = FixedToInt(ffsr); \ + spec[i][GCOMP] = FixedToInt(ffsg); \ + spec[i][BCOMP] = FixedToInt(ffsb); \ + s[i] = ss*invQ; \ + t[i] = tt*invQ; \ + u[i] = uu*invQ; \ + fffog += fdfogdx; \ + ffz += fdzdx; \ + ffr += fdrdx; \ + ffg += fdgdx; \ + ffb += fdbdx; \ + ffa += fdadx; \ + ffsr += fdsrdx; \ + ffsg += fdsgdx; \ + ffsb += fdsbdx; \ + ss += dsdx; \ + tt += dtdx; \ + uu += dudx; \ + vv += dvdx; \ + } \ + } \ + gl_write_texture_span( ctx, n, LEFT, Y, zspan, \ + fogspan, \ + s, t, u, NULL, rgba, \ + (CONST GLchan (*)[4]) spec, \ + GL_POLYGON ); \ + } \ + } + +#include "s_tritemp.h" +} + + + +/* + * Compute the lambda value for a fragment. (texture level of detail) + */ +static INLINE GLfloat +compute_lambda( GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy, + GLfloat invQ, GLfloat width, GLfloat height ) +{ + GLfloat dudx = dsdx * invQ * width; + GLfloat dudy = dsdy * invQ * width; + GLfloat dvdx = dtdx * invQ * height; + GLfloat dvdy = dtdy * invQ * height; + GLfloat r1 = dudx * dudx + dudy * dudy; + GLfloat r2 = dvdx * dvdx + dvdy * dvdy; + GLfloat rho2 = r1 + r2; /* used to be: rho2 = MAX2(r1,r2); */ + /* return log base 2 of rho */ + return log(rho2) * 1.442695 * 0.5; /* 1.442695 = 1/log(2) */ +} + + +/* + * Render a smooth-shaded, textured, RGBA triangle. + * Interpolate S,T,U with perspective correction and compute lambda for + * each fragment. Lambda is used to determine whether to use the + * minification or magnification filter. If minification and using + * mipmaps, lambda is also used to select the texture level of detail. + */ +static void lambda_textured_triangle1( GLcontext *ctx, GLuint v0, GLuint v1, + GLuint v2, GLuint pv, + GLfloat s[MAX_WIDTH], + GLfloat t[MAX_WIDTH], + GLfloat u[MAX_WIDTH] ) +{ +#define INTERP_Z 1 +#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE +#define INTERP_RGB 1 +#define INTERP_ALPHA 1 +#define INTERP_TEX 1 + +#define SETUP_CODE \ + const struct gl_texture_object *obj = ctx->Texture.Unit[0].Current; \ + const GLint baseLevel = obj->BaseLevel; \ + const struct gl_texture_image *texImage = obj->Image[baseLevel]; \ + const GLfloat twidth = (GLfloat) texImage->Width; \ + const GLfloat theight = (GLfloat) texImage->Height; \ + const GLboolean flat_shade = (ctx->Light.ShadeModel==GL_FLAT); \ + GLint r, g, b, a; \ + if (flat_shade) { \ + r = VB->ColorPtr->data[pv][0]; \ + g = VB->ColorPtr->data[pv][1]; \ + b = VB->ColorPtr->data[pv][2]; \ + a = VB->ColorPtr->data[pv][3]; \ + } + +#define INNER_LOOP( LEFT, RIGHT, Y ) \ + { \ + GLint i; \ + const GLint n = RIGHT-LEFT; \ + GLdepth zspan[MAX_WIDTH]; \ + GLfixed fogspan[MAX_WIDTH]; \ + GLchan rgba[MAX_WIDTH][4]; \ + GLfloat lambda[MAX_WIDTH]; \ + if (n>0) { \ + if (flat_shade) { \ + for (i=0;i<n;i++) { \ + GLdouble invQ = 1.0 / vv; \ + zspan[i] = FixedToDepth(ffz); \ + fogspan[i] = fffog / 256; \ + rgba[i][RCOMP] = r; \ + rgba[i][GCOMP] = g; \ + rgba[i][BCOMP] = b; \ + rgba[i][ACOMP] = a; \ + s[i] = ss*invQ; \ + t[i] = tt*invQ; \ + u[i] = uu*invQ; \ + lambda[i] = compute_lambda( dsdx, dsdy, dtdx, dtdy, \ + invQ, twidth, theight );\ + ffz += fdzdx; \ + fffog += fdfogdx; \ + ss += dsdx; \ + tt += dtdx; \ + uu += dudx; \ + vv += dvdx; \ + } \ + } \ + else { \ + for (i=0;i<n;i++) { \ + GLdouble invQ = 1.0 / vv; \ + zspan[i] = FixedToDepth(ffz); \ + fogspan[i] = fffog / 256; \ + rgba[i][RCOMP] = FixedToInt(ffr); \ + rgba[i][GCOMP] = FixedToInt(ffg); \ + rgba[i][BCOMP] = FixedToInt(ffb); \ + rgba[i][ACOMP] = FixedToInt(ffa); \ + s[i] = ss*invQ; \ + t[i] = tt*invQ; \ + u[i] = uu*invQ; \ + lambda[i] = compute_lambda( dsdx, dsdy, dtdx, dtdy, \ + invQ, twidth, theight );\ + ffz += fdzdx; \ + fffog += fdfogdx; \ + ffr += fdrdx; \ + ffg += fdgdx; \ + ffb += fdbdx; \ + ffa += fdadx; \ + ss += dsdx; \ + tt += dtdx; \ + uu += dudx; \ + vv += dvdx; \ + } \ + } \ + gl_write_texture_span( ctx, n, LEFT, Y, zspan, fogspan, \ + s, t, u, lambda, \ + rgba, NULL, GL_POLYGON ); \ + } \ + } + +#include "s_tritemp.h" +} + + +/* + * Render a smooth-shaded, textured, RGBA triangle with separate specular + * interpolation. + * Interpolate S,T,U with perspective correction and compute lambda for + * each fragment. Lambda is used to determine whether to use the + * minification or magnification filter. If minification and using + * mipmaps, lambda is also used to select the texture level of detail. + */ +static void lambda_textured_spec_triangle1( GLcontext *ctx, GLuint v0, + GLuint v1, GLuint v2, GLuint pv, + GLfloat s[MAX_WIDTH], + GLfloat t[MAX_WIDTH], + GLfloat u[MAX_WIDTH] ) +{ +#define INTERP_Z 1 +#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE +#define INTERP_RGB 1 +#define INTERP_SPEC 1 +#define INTERP_ALPHA 1 +#define INTERP_TEX 1 + +#define SETUP_CODE \ + const struct gl_texture_object *obj = ctx->Texture.Unit[0].Current; \ + const GLint baseLevel = obj->BaseLevel; \ + const struct gl_texture_image *texImage = obj->Image[baseLevel]; \ + const GLfloat twidth = (GLfloat) texImage->Width; \ + const GLfloat theight = (GLfloat) texImage->Height; \ + const GLboolean flat_shade = (ctx->Light.ShadeModel==GL_FLAT); \ + GLint r, g, b, a, sr, sg, sb; \ + if (flat_shade) { \ + r = VB->ColorPtr->data[pv][0]; \ + g = VB->ColorPtr->data[pv][1]; \ + b = VB->ColorPtr->data[pv][2]; \ + a = VB->ColorPtr->data[pv][3]; \ + sr = VB->SecondaryColorPtr->data[pv][0]; \ + sg = VB->SecondaryColorPtr->data[pv][1]; \ + sb = VB->SecondaryColorPtr->data[pv][2]; \ + } + +#define INNER_LOOP( LEFT, RIGHT, Y ) \ + { \ + GLint i; \ + const GLint n = RIGHT-LEFT; \ + GLdepth zspan[MAX_WIDTH]; \ + GLfixed fogspan[MAX_WIDTH]; \ + GLchan spec[MAX_WIDTH][4]; \ + GLchan rgba[MAX_WIDTH][4]; \ + GLfloat lambda[MAX_WIDTH]; \ + if (n>0) { \ + if (flat_shade) { \ + for (i=0;i<n;i++) { \ + GLdouble invQ = 1.0 / vv; \ + zspan[i] = FixedToDepth(ffz); \ + fogspan[i] = fffog / 256; \ + rgba[i][RCOMP] = r; \ + rgba[i][GCOMP] = g; \ + rgba[i][BCOMP] = b; \ + rgba[i][ACOMP] = a; \ + spec[i][RCOMP] = sr; \ + spec[i][GCOMP] = sg; \ + spec[i][BCOMP] = sb; \ + s[i] = ss*invQ; \ + t[i] = tt*invQ; \ + u[i] = uu*invQ; \ + lambda[i] = compute_lambda( dsdx, dsdy, dtdx, dtdy, \ + invQ, twidth, theight );\ + fffog += fdfogdx; \ + ffz += fdzdx; \ + ss += dsdx; \ + tt += dtdx; \ + uu += dudx; \ + vv += dvdx; \ + } \ + } \ + else { \ + for (i=0;i<n;i++) { \ + GLdouble invQ = 1.0 / vv; \ + zspan[i] = FixedToDepth(ffz); \ + fogspan[i] = fffog / 256; \ + rgba[i][RCOMP] = FixedToInt(ffr); \ + rgba[i][GCOMP] = FixedToInt(ffg); \ + rgba[i][BCOMP] = FixedToInt(ffb); \ + rgba[i][ACOMP] = FixedToInt(ffa); \ + spec[i][RCOMP] = FixedToInt(ffsr); \ + spec[i][GCOMP] = FixedToInt(ffsg); \ + spec[i][BCOMP] = FixedToInt(ffsb); \ + s[i] = ss*invQ; \ + t[i] = tt*invQ; \ + u[i] = uu*invQ; \ + lambda[i] = compute_lambda( dsdx, dsdy, dtdx, dtdy, \ + invQ, twidth, theight );\ + fffog += fdfogdx; \ + ffz += fdzdx; \ + ffr += fdrdx; \ + ffg += fdgdx; \ + ffb += fdbdx; \ + ffa += fdadx; \ + ffsr += fdsrdx; \ + ffsg += fdsgdx; \ + ffsb += fdsbdx; \ + ss += dsdx; \ + tt += dtdx; \ + uu += dudx; \ + vv += dvdx; \ + } \ + } \ + gl_write_texture_span( ctx, n, LEFT, Y, zspan, fogspan, \ + s, t, u, lambda, \ + rgba, (CONST GLchan (*)[4]) spec, \ + GL_POLYGON ); \ + } \ + } + +#include "s_tritemp.h" +} + + +/* + * This is the big one! + * Interpolate Z, RGB, Alpha, and two sets of texture coordinates. + * Yup, it's slow. + */ +static void lambda_multitextured_triangle1( GLcontext *ctx, GLuint v0, + GLuint v1, GLuint v2, GLuint pv, + GLfloat s[MAX_TEXTURE_UNITS][MAX_WIDTH], + GLfloat t[MAX_TEXTURE_UNITS][MAX_WIDTH], + GLfloat u[MAX_TEXTURE_UNITS][MAX_WIDTH] + ) +{ +#define INTERP_Z 1 +#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE +#define INTERP_RGB 1 +#define INTERP_ALPHA 1 +#define INTERP_MULTITEX 1 + +#define SETUP_CODE \ + GLchan rgba[MAX_WIDTH][4]; \ + const GLboolean flat_shade = (ctx->Light.ShadeModel==GL_FLAT); \ + GLfloat twidth[MAX_TEXTURE_UNITS], theight[MAX_TEXTURE_UNITS]; \ + GLint r, g, b, a; \ + if (flat_shade) { \ + r = VB->ColorPtr->data[pv][0]; \ + g = VB->ColorPtr->data[pv][1]; \ + b = VB->ColorPtr->data[pv][2]; \ + a = VB->ColorPtr->data[pv][3]; \ + } \ + { \ + GLuint unit; \ + for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { \ + if (ctx->Texture.Unit[unit].ReallyEnabled) { \ + const struct gl_texture_object *obj = ctx->Texture.Unit[unit].Current; \ + const GLint baseLevel = obj->BaseLevel; \ + const struct gl_texture_image *texImage = obj->Image[baseLevel]; \ + twidth[unit] = (GLfloat) texImage->Width; \ + theight[unit] = (GLfloat) texImage->Height; \ + } \ + } \ + } + + + +#define INNER_LOOP( LEFT, RIGHT, Y ) \ + { \ + GLint i; \ + const GLint n = RIGHT-LEFT; \ + GLdepth zspan[MAX_WIDTH]; \ + GLfixed fogspan[MAX_WIDTH]; \ + GLfloat lambda[MAX_TEXTURE_UNITS][MAX_WIDTH]; \ + if (n > 0) { \ + if (flat_shade) { \ + for (i=0;i<n;i++) { \ + zspan[i] = FixedToDepth(ffz); \ + fogspan[i] = fffog / 256; \ + fffog += fdfogdx; \ + ffz += fdzdx; \ + rgba[i][RCOMP] = r; \ + rgba[i][GCOMP] = g; \ + rgba[i][BCOMP] = b; \ + rgba[i][ACOMP] = a; \ + { \ + GLuint unit; \ + for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { \ + if (ctx->Texture.Unit[unit].ReallyEnabled) { \ + GLdouble invQ = 1.0 / vv[unit]; \ + s[unit][i] = ss[unit] * invQ; \ + t[unit][i] = tt[unit] * invQ; \ + u[unit][i] = uu[unit] * invQ; \ + lambda[unit][i] = compute_lambda(dsdx[unit], dsdy[unit],\ + dtdx[unit], dtdy[unit], invQ, \ + twidth[unit], theight[unit] ); \ + ss[unit] += dsdx[unit]; \ + tt[unit] += dtdx[unit]; \ + uu[unit] += dudx[unit]; \ + vv[unit] += dvdx[unit]; \ + } \ + } \ + } \ + } \ + } \ + else { /* smooth shade */ \ + for (i=0;i<n;i++) { \ + zspan[i] = FixedToDepth(ffz); \ + fogspan[i] = fffog / 256; \ + ffz += fdzdx; \ + fffog += fdfogdx; \ + rgba[i][RCOMP] = FixedToInt(ffr); \ + rgba[i][GCOMP] = FixedToInt(ffg); \ + rgba[i][BCOMP] = FixedToInt(ffb); \ + rgba[i][ACOMP] = FixedToInt(ffa); \ + ffr += fdrdx; \ + ffg += fdgdx; \ + ffb += fdbdx; \ + ffa += fdadx; \ + { \ + GLuint unit; \ + for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { \ + if (ctx->Texture.Unit[unit].ReallyEnabled) { \ + GLdouble invQ = 1.0 / vv[unit]; \ + s[unit][i] = ss[unit] * invQ; \ + t[unit][i] = tt[unit] * invQ; \ + u[unit][i] = uu[unit] * invQ; \ + lambda[unit][i] = compute_lambda(dsdx[unit], dsdy[unit],\ + dtdx[unit], dtdy[unit], invQ, \ + twidth[unit], theight[unit] ); \ + ss[unit] += dsdx[unit]; \ + tt[unit] += dtdx[unit]; \ + uu[unit] += dudx[unit]; \ + vv[unit] += dvdx[unit]; \ + } \ + } \ + } \ + } \ + } \ + gl_write_multitexture_span( ctx, n, LEFT, Y, zspan, fogspan, \ + (const GLfloat (*)[MAX_WIDTH]) s, \ + (const GLfloat (*)[MAX_WIDTH]) t, \ + (const GLfloat (*)[MAX_WIDTH]) u, \ + (GLfloat (*)[MAX_WIDTH]) lambda, \ + rgba, NULL, GL_POLYGON ); \ + } \ + } +#include "s_tritemp.h" +} + + +/* + * These wrappers are needed to deal with the 32KB / stack frame limit + * on Mac / PowerPC systems. + */ + +static void general_textured_spec_triangle(GLcontext *ctx, GLuint v0, + GLuint v1, GLuint v2, GLuint pv) +{ + GLdepth zspan[MAX_WIDTH]; + GLfixed fogspan[MAX_WIDTH]; + GLchan rgba[MAX_WIDTH][4], spec[MAX_WIDTH][4]; + general_textured_spec_triangle1(ctx,v0,v1,v2,pv,zspan,fogspan,rgba,spec); +} + +static void lambda_textured_triangle( GLcontext *ctx, GLuint v0, + GLuint v1, GLuint v2, GLuint pv ) +{ + GLfloat s[MAX_WIDTH], t[MAX_WIDTH], u[MAX_WIDTH]; + lambda_textured_triangle1(ctx,v0,v1,v2,pv,s,t,u); +} + +static void lambda_textured_spec_triangle( GLcontext *ctx, GLuint v0, + GLuint v1, GLuint v2, GLuint pv ) +{ + GLfloat s[MAX_WIDTH]; + GLfloat t[MAX_WIDTH]; + GLfloat u[MAX_WIDTH]; + lambda_textured_spec_triangle1(ctx,v0,v1,v2,pv,s,t,u); +} + + +static void lambda_multitextured_triangle( GLcontext *ctx, GLuint v0, + GLuint v1, GLuint v2, GLuint pv) +{ + + GLfloat s[MAX_TEXTURE_UNITS][MAX_WIDTH]; + GLfloat t[MAX_TEXTURE_UNITS][MAX_WIDTH]; + DEFMARRAY(GLfloat,u,MAX_TEXTURE_UNITS,MAX_WIDTH); + CHECKARRAY(u,return); + + lambda_multitextured_triangle1(ctx,v0,v1,v2,pv,s,t,u); + + UNDEFARRAY(u); +} + + + +static void occlusion_zless_triangle( GLcontext *ctx, GLuint v0, GLuint v1, + GLuint v2, GLuint pv ) +{ + (void)pv; + if (ctx->OcclusionResult) { + return; + } + +#define DO_OCCLUSION_TEST +#define INTERP_Z 1 +#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE +#define INNER_LOOP( LEFT, RIGHT, Y ) \ + { \ + GLint i; \ + const GLint len = RIGHT-LEFT; \ + for (i=0;i<len;i++) { \ + GLdepth z = FixedToDepth(ffz); \ + (void) fffog; \ + if (z < zRow[i]) { \ + ctx->OcclusionResult = GL_TRUE; \ + return; \ + } \ + ffz += fdzdx; \ + } \ + } +#include "s_tritemp.h" +} + + + +/* + * Null rasterizer for measuring transformation speed. + */ +static void null_triangle( GLcontext *ctx, GLuint v0, GLuint v1, + GLuint v2, GLuint pv ) +{ + (void) ctx; + (void) v0; + (void) v1; + (void) v2; + (void) pv; +} + + +#if 0 +# define dputs(s) puts(s) +#else +# define dputs(s) +#endif + + + +/* + * Determine which triangle rendering function to use given the current + * rendering context. + * + * Please update the summary flag _SWRAST_NEW_TRIANGLE if you add or + * remove tests to this code. + */ +void +_swrast_set_triangle_function( GLcontext *ctx ) +{ + const GLboolean rgbmode = ctx->Visual.RGBAflag; + + if (ctx->RenderMode==GL_RENDER) { + if (ctx->NoRaster) { + ctx->Driver.TriangleFunc = null_triangle; + return; + } + if (ctx->Driver.TriangleFunc) { + /* Device driver will draw triangles. */ + dputs("Driver triangle"); + return; + } + + if (ctx->Polygon.SmoothFlag) { + _mesa_set_aa_triangle_function(ctx); + ASSERT(ctx->Driver.TriangleFunc); + return; + } + + if (ctx->Depth.OcclusionTest && + ctx->Depth.Test && + ctx->Depth.Mask == GL_FALSE && + ctx->Depth.Func == GL_LESS && + !ctx->Stencil.Enabled) { + if ((rgbmode && + ctx->Color.ColorMask[0] == 0 && + ctx->Color.ColorMask[1] == 0 && + ctx->Color.ColorMask[2] == 0 && + ctx->Color.ColorMask[3] == 0) + || + (!rgbmode && ctx->Color.IndexMask == 0)) { + dputs("occlusion_test_triangle"); + ctx->Driver.TriangleFunc = occlusion_zless_triangle; + return; + } + } + + if (ctx->Texture.ReallyEnabled) { + /* Ugh, we do a _lot_ of tests to pick the best textured tri func */ + GLint format, filter; + const struct gl_texture_object *current2Dtex = ctx->Texture.Unit[0].CurrentD[2]; + const struct gl_texture_image *image; + /* First see if we can used an optimized 2-D texture function */ + if (ctx->Texture.ReallyEnabled==TEXTURE0_2D + && current2Dtex->WrapS==GL_REPEAT + && current2Dtex->WrapT==GL_REPEAT + && ((image = current2Dtex->Image[current2Dtex->BaseLevel]) != 0) /* correct! */ + && image->Border==0 + && ((format = image->Format)==GL_RGB || format==GL_RGBA) + && (filter = current2Dtex->MinFilter)==current2Dtex->MagFilter + && ctx->Light.Model.ColorControl==GL_SINGLE_COLOR + && ctx->Texture.Unit[0].EnvMode!=GL_COMBINE_EXT) { + + if (ctx->Hint.PerspectiveCorrection==GL_FASTEST) { + + if (filter==GL_NEAREST + && format==GL_RGB + && (ctx->Texture.Unit[0].EnvMode==GL_REPLACE + || ctx->Texture.Unit[0].EnvMode==GL_DECAL) + && ((ctx->RasterMask==DEPTH_BIT + && ctx->Depth.Func==GL_LESS + && ctx->Depth.Mask==GL_TRUE) + || ctx->RasterMask==0) + && ctx->Polygon.StippleFlag==GL_FALSE) { + + if (ctx->RasterMask==DEPTH_BIT) { + ctx->Driver.TriangleFunc = simple_z_textured_triangle; + dputs("simple_z_textured_triangle"); + } + else { + ctx->Driver.TriangleFunc = simple_textured_triangle; + dputs("simple_textured_triangle"); + } + } + else { + if (ctx->Texture.Unit[0].EnvMode==GL_ADD) { + ctx->Driver.TriangleFunc = general_textured_triangle; + dputs("general_textured_triangle"); + } + else { + ctx->Driver.TriangleFunc = affine_textured_triangle; + dputs("affine_textured_triangle"); + } + } + } + else { + if (filter==GL_NEAREST) { + ctx->Driver.TriangleFunc = near_persp_textured_triangle; + dputs("near_persp_textured_triangle"); + } + else { + ctx->Driver.TriangleFunc = lin_persp_textured_triangle; + dputs("lin_persp_textured_triangle"); + } + } + } + else { + /* More complicated textures (mipmap, multi-tex, sep specular) */ + GLboolean needLambda; + /* if mag filter != min filter we need to compute lambda */ + const struct gl_texture_object *obj = ctx->Texture.Unit[0].Current; + if (obj && obj->MinFilter != obj->MagFilter) + needLambda = GL_TRUE; + else + needLambda = GL_FALSE; + if (ctx->Texture.MultiTextureEnabled) { + ctx->Driver.TriangleFunc = lambda_multitextured_triangle; + dputs("lambda_multitextured_triangle"); + } + else if ((ctx->Light.Enabled && + ctx->Light.Model.ColorControl==GL_SEPARATE_SPECULAR_COLOR) + || ctx->Fog.ColorSumEnabled) { + /* separate specular color interpolation */ + if (needLambda) { + ctx->Driver.TriangleFunc = lambda_textured_spec_triangle; + dputs("lambda_textured_spec_triangle"); + } + else { + ctx->Driver.TriangleFunc = general_textured_spec_triangle; + dputs("general_textured_spec_triangle"); + } + } + else { + if (needLambda) { + ctx->Driver.TriangleFunc = lambda_textured_triangle; + dputs("lambda_textured_triangle"); + } + else { + ctx->Driver.TriangleFunc = general_textured_triangle; + dputs("general_textured_triangle"); + } + } + } + } + else { + if (ctx->Light.ShadeModel==GL_SMOOTH) { + /* smooth shaded, no texturing, stippled or some raster ops */ + if (rgbmode) { + dputs("smooth_rgba_triangle"); + ctx->Driver.TriangleFunc = smooth_rgba_triangle; + } + else { + dputs("smooth_ci_triangle"); + ctx->Driver.TriangleFunc = smooth_ci_triangle; + } + } + else { + /* flat shaded, no texturing, stippled or some raster ops */ + if (rgbmode) { + dputs("flat_rgba_triangle"); + ctx->Driver.TriangleFunc = flat_rgba_triangle; + } + else { + dputs("flat_ci_triangle"); + ctx->Driver.TriangleFunc = flat_ci_triangle; + } + } + } + } + else if (ctx->RenderMode==GL_FEEDBACK) { + ctx->Driver.TriangleFunc = gl_feedback_triangle; + } + else { + /* GL_SELECT mode */ + ctx->Driver.TriangleFunc = gl_select_triangle; + } +} |