summaryrefslogtreecommitdiff
path: root/src/mesa/swrast/s_triangle.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/swrast/s_triangle.c')
-rw-r--r--src/mesa/swrast/s_triangle.c2448
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;
+ }
+}