s_triangle.c revision 2a182a98973edc9ecf2936b1288485bb2b3fa722
1/* $Id: s_triangle.c,v 1.49 2002/01/27 18:32:03 brianp Exp $ */
2
3/*
4 * Mesa 3-D graphics library
5 * Version:  4.1
6 *
7 * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28/*
29 * When the device driver doesn't implement triangle rasterization it
30 * can hook in _swrast_Triangle, which eventually calls one of these
31 * functions to draw triangles.
32 */
33
34#include "glheader.h"
35#include "context.h"
36#include "colormac.h"
37#include "macros.h"
38#include "mem.h"
39#include "mmath.h"
40#include "texformat.h"
41#include "teximage.h"
42#include "texstate.h"
43
44#include "s_aatriangle.h"
45#include "s_context.h"
46#include "s_depth.h"
47#include "s_feedback.h"
48#include "s_span.h"
49#include "s_triangle.h"
50
51
52
53GLboolean _mesa_cull_triangle( GLcontext *ctx,
54			    const SWvertex *v0,
55			    const SWvertex *v1,
56			    const SWvertex *v2 )
57{
58   GLfloat ex = v1->win[0] - v0->win[0];
59   GLfloat ey = v1->win[1] - v0->win[1];
60   GLfloat fx = v2->win[0] - v0->win[0];
61   GLfloat fy = v2->win[1] - v0->win[1];
62   GLfloat c = ex*fy-ey*fx;
63
64   if (c * SWRAST_CONTEXT(ctx)->_backface_sign > 0)
65      return 0;
66
67   return 1;
68}
69
70
71
72/*
73 * Render a flat-shaded color index triangle.
74 */
75static void flat_ci_triangle( GLcontext *ctx,
76			      const SWvertex *v0,
77			      const SWvertex *v1,
78			      const SWvertex *v2 )
79{
80#define INTERP_Z 1
81#define INTERP_FOG 1
82
83#define SETUP_CODE					\
84   span.interpMask |= SPAN_INDEX;			\
85   span.index = IntToFixed(v2->index);			\
86   span.indexStep = 0;
87
88#define RENDER_SPAN( span )				\
89   _mesa_write_index_span(ctx, &span, GL_POLYGON );
90
91#include "s_tritemp.h"
92}
93
94
95
96/*
97 * Render a smooth-shaded color index triangle.
98 */
99static void smooth_ci_triangle( GLcontext *ctx,
100				const SWvertex *v0,
101				const SWvertex *v1,
102				const SWvertex *v2 )
103{
104#define INTERP_Z 1
105#define INTERP_FOG 1
106#define INTERP_INDEX 1
107
108#define RENDER_SPAN( span )						\
109   GLuint i;						                \
110   SW_SPAN_SET_FLAG(span.filledColor);			                \
111   for (i = 0; i < span.end; i++) {					\
112      span.color.index[i] = FixedToInt(span.index);			\
113      span.index += span.indexStep;					\
114   }									\
115   _mesa_write_index_span(ctx, &span, GL_POLYGON);
116
117#include "s_tritemp.h"
118}
119
120
121
122/*
123 * Render a flat-shaded RGBA triangle.
124 */
125static void flat_rgba_triangle( GLcontext *ctx,
126				const SWvertex *v0,
127				const SWvertex *v1,
128				const SWvertex *v2 )
129{
130#define INTERP_Z 1
131#define INTERP_FOG 1
132#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
133
134#define RENDER_SPAN( span )						\
135   _mesa_write_monocolor_span(ctx, &span, v2->color, GL_POLYGON );
136
137#include "s_tritemp.h"
138
139   ASSERT(!ctx->Texture._ReallyEnabled);  /* texturing must be off */
140   ASSERT(ctx->Light.ShadeModel==GL_FLAT);
141}
142
143
144
145/*
146 * Render a smooth-shaded RGBA triangle.
147 */
148static void smooth_rgba_triangle( GLcontext *ctx,
149				  const SWvertex *v0,
150				  const SWvertex *v1,
151				  const SWvertex *v2 )
152{
153
154#define INTERP_Z 1
155#define INTERP_FOG 1
156#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
157#define INTERP_RGB 1
158#define INTERP_ALPHA 1
159
160#define RENDER_SPAN( span )					\
161   GLuint i;				        	        \
162   SW_SPAN_SET_FLAG(span.filledColor);			        \
163   SW_SPAN_SET_FLAG(span.filledAlpha);			        \
164   ASSERT(span.interpMask & SPAN_RGBA);				\
165   span.arrayMask |= SPAN_RGBA;					\
166   for (i = 0; i < span.end; i++) {				\
167      span.color.rgba[i][RCOMP] = FixedToChan(span.red);	\
168      span.color.rgba[i][GCOMP] = FixedToChan(span.green);	\
169      span.color.rgba[i][BCOMP] = FixedToChan(span.blue);	\
170      span.color.rgba[i][ACOMP] = FixedToChan(span.alpha);	\
171      span.red += span.redStep;					\
172      span.green += span.greenStep;				\
173      span.blue += span.blueStep;				\
174      span.alpha += span.alphaStep;				\
175   }								\
176   _mesa_write_rgba_span(ctx, &span, GL_POLYGON);
177
178#include "s_tritemp.h"
179
180   ASSERT(!ctx->Texture._ReallyEnabled);  /* texturing must be off */
181   ASSERT(ctx->Light.ShadeModel==GL_SMOOTH);
182}
183
184
185/*
186 * Render an RGB, GL_DECAL, textured triangle.
187 * Interpolate S,T only w/out mipmapping or perspective correction.
188 *
189 * No fog.
190 */
191static void simple_textured_triangle( GLcontext *ctx,
192				      const SWvertex *v0,
193				      const SWvertex *v1,
194				      const SWvertex *v2 )
195{
196#define INTERP_INT_TEX 1
197#define S_SCALE twidth
198#define T_SCALE theight
199
200#define SETUP_CODE							\
201   SWcontext *swrast = SWRAST_CONTEXT(ctx);                             \
202   struct gl_texture_object *obj = ctx->Texture.Unit[0].Current2D;	\
203   const GLint b = obj->BaseLevel;					\
204   const GLfloat twidth = (GLfloat) obj->Image[b]->Width;		\
205   const GLfloat theight = (GLfloat) obj->Image[b]->Height;		\
206   const GLint twidth_log2 = obj->Image[b]->WidthLog2;			\
207   const GLchan *texture = (const GLchan *) obj->Image[b]->Data;	\
208   const GLint smask = obj->Image[b]->Width - 1;			\
209   const GLint tmask = obj->Image[b]->Height - 1;			\
210   if (!texture) {							\
211      /* this shouldn't happen */					\
212      return;								\
213   }
214
215#define RENDER_SPAN( span  )						\
216   GLuint i;								\
217   SW_SPAN_SET_FLAG(span.filledColor);					\
218   span.intTex[0] -= FIXED_HALF; /* off-by-one error? */		\
219   span.intTex[1] -= FIXED_HALF;					\
220   for (i = 0; i < span.end; i++) {					\
221      GLint s = FixedToInt(span.intTex[0]) & smask;			\
222      GLint t = FixedToInt(span.intTex[1]) & tmask;			\
223      GLint pos = (t << twidth_log2) + s;				\
224      pos = pos + pos + pos;  /* multiply by 3 */			\
225      span.color.rgb[i][RCOMP] = texture[pos];				\
226      span.color.rgb[i][GCOMP] = texture[pos+1];			\
227      span.color.rgb[i][BCOMP] = texture[pos+2];			\
228      span.intTex[0] += span.intTexStep[0];				\
229      span.intTex[1] += span.intTexStep[1];				\
230   }									\
231   (*swrast->Driver.WriteRGBSpan)(ctx, span.end, span.x, span.y,	\
232                                  (CONST GLchan (*)[3]) span.color.rgb,	\
233                                  NULL );
234
235#include "s_tritemp.h"
236}
237
238
239/*
240 * Render an RGB, GL_DECAL, textured triangle.
241 * Interpolate S,T, GL_LESS depth test, w/out mipmapping or
242 * perspective correction.
243 *
244 * No fog.
245 */
246static void simple_z_textured_triangle( GLcontext *ctx,
247					const SWvertex *v0,
248					const SWvertex *v1,
249					const SWvertex *v2 )
250{
251#define INTERP_Z 1
252#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
253#define INTERP_INT_TEX 1
254#define S_SCALE twidth
255#define T_SCALE theight
256
257#define SETUP_CODE							\
258   SWcontext *swrast = SWRAST_CONTEXT(ctx);                             \
259   struct gl_texture_object *obj = ctx->Texture.Unit[0].Current2D;	\
260   const GLint b = obj->BaseLevel;					\
261   const GLfloat twidth = (GLfloat) obj->Image[b]->Width;		\
262   const GLfloat theight = (GLfloat) obj->Image[b]->Height;		\
263   const GLint twidth_log2 = obj->Image[b]->WidthLog2;			\
264   const GLchan *texture = (const GLchan *) obj->Image[b]->Data;	\
265   const GLint smask = obj->Image[b]->Width - 1;			\
266   const GLint tmask = obj->Image[b]->Height - 1;			\
267   if (!texture) {							\
268      /* this shouldn't happen */					\
269      return;								\
270   }
271
272#define RENDER_SPAN( span )						\
273   GLuint i;				    				\
274   span.intTex[0] -= FIXED_HALF; /* off-by-one error? */		\
275   span.intTex[1] -= FIXED_HALF;					\
276   SW_SPAN_SET_FLAG(span.filledColor);					\
277   SW_SPAN_SET_FLAG(span.filledDepth);					\
278   for (i = 0; i < span.end; i++) {					\
279      const GLdepth z = FixedToDepth(span.z);				\
280      if (z < zRow[i]) {						\
281         GLint s = FixedToInt(span.intTex[0]) & smask;			\
282         GLint t = FixedToInt(span.intTex[1]) & tmask;			\
283         GLint pos = (t << twidth_log2) + s;				\
284         pos = pos + pos + pos;  /* multiply by 3 */			\
285         span.color.rgb[i][RCOMP] = texture[pos];			\
286         span.color.rgb[i][GCOMP] = texture[pos+1];			\
287         span.color.rgb[i][BCOMP] = texture[pos+2];			\
288         zRow[i] = z;							\
289         span.mask[i] = 1;						\
290      }									\
291      else {								\
292         span.mask[i] = 0;						\
293      }									\
294      span.intTex[0] += span.intTexStep[0];				\
295      span.intTex[1] += span.intTexStep[1];				\
296      span.z += span.zStep;						\
297   }									\
298   (*swrast->Driver.WriteRGBSpan)(ctx, span.end, span.x, span.y,	\
299                                  (CONST GLchan (*)[3]) span.color.rgb,	\
300                                  span.mask );
301
302#include "s_tritemp.h"
303}
304
305
306#if CHAN_TYPE != GL_FLOAT
307
308struct affine_info
309{
310   GLenum filter;
311   GLenum format;
312   GLenum envmode;
313   GLint smask, tmask;
314   GLint twidth_log2;
315   const GLchan *texture;
316   GLfixed er, eg, eb, ea;
317   GLint tbytesline, tsize;
318};
319
320
321/* This function can handle GL_NEAREST or GL_LINEAR sampling of 2D RGB or RGBA
322 * textures with GL_REPLACE, GL_MODULATE, GL_BLEND, GL_DECAL or GL_ADD
323 * texture env modes.
324 */
325static INLINE void
326affine_span(GLcontext *ctx, struct sw_span *span,
327            struct affine_info *info)
328{
329   GLchan sample[4];  /* the filtered texture sample */
330
331   /* Instead of defining a function for each mode, a test is done
332    * between the outer and inner loops. This is to reduce code size
333    * and complexity. Observe that an optimizing compiler kills
334    * unused variables (for instance tf,sf,ti,si in case of GL_NEAREST).
335    */
336
337#define NEAREST_RGB			\
338   sample[RCOMP] = tex00[RCOMP];	\
339   sample[GCOMP] = tex00[GCOMP];	\
340   sample[BCOMP] = tex00[BCOMP];	\
341   sample[ACOMP] = CHAN_MAX
342
343#define LINEAR_RGB							\
344   sample[RCOMP] = (ti * (si * tex00[0] + sf * tex01[0]) +		\
345             tf * (si * tex10[0] + sf * tex11[0])) >> 2 * FIXED_SHIFT;	\
346   sample[GCOMP] = (ti * (si * tex00[1] + sf * tex01[1]) +		\
347             tf * (si * tex10[1] + sf * tex11[1])) >> 2 * FIXED_SHIFT;	\
348   sample[BCOMP] = (ti * (si * tex00[2] + sf * tex01[2]) +		\
349             tf * (si * tex10[2] + sf * tex11[2])) >> 2 * FIXED_SHIFT;	\
350   sample[ACOMP] = CHAN_MAX
351
352#define NEAREST_RGBA  COPY_CHAN4(sample, tex00)
353
354#define LINEAR_RGBA							\
355   sample[RCOMP] = (ti * (si * tex00[0] + sf * tex01[0]) +		\
356               tf * (si * tex10[0] + sf * tex11[0])) >> 2 * FIXED_SHIFT;\
357   sample[GCOMP] = (ti * (si * tex00[1] + sf * tex01[1]) +		\
358               tf * (si * tex10[1] + sf * tex11[1])) >> 2 * FIXED_SHIFT;\
359   sample[BCOMP] = (ti * (si * tex00[2] + sf * tex01[2]) +		\
360               tf * (si * tex10[2] + sf * tex11[2])) >> 2 * FIXED_SHIFT;\
361   sample[ACOMP] = (ti * (si * tex00[3] + sf * tex01[3]) +		\
362               tf * (si * tex10[3] + sf * tex11[3])) >> 2 * FIXED_SHIFT
363
364#define MODULATE							  \
365   dest[RCOMP] = span->red   * (sample[RCOMP] + 1u) >> (FIXED_SHIFT + 8); \
366   dest[GCOMP] = span->green * (sample[GCOMP] + 1u) >> (FIXED_SHIFT + 8); \
367   dest[BCOMP] = span->blue  * (sample[BCOMP] + 1u) >> (FIXED_SHIFT + 8); \
368   dest[ACOMP] = span->alpha * (sample[ACOMP] + 1u) >> (FIXED_SHIFT + 8)
369
370#define DECAL								\
371   dest[RCOMP] = ((CHAN_MAX - sample[ACOMP]) * span->red +		\
372               ((sample[ACOMP] + 1) * sample[RCOMP] << FIXED_SHIFT))	\
373               >> (FIXED_SHIFT + 8);					\
374   dest[GCOMP] = ((CHAN_MAX - sample[ACOMP]) * span->green +		\
375               ((sample[ACOMP] + 1) * sample[GCOMP] << FIXED_SHIFT))	\
376               >> (FIXED_SHIFT + 8);					\
377   dest[BCOMP] = ((CHAN_MAX - sample[ACOMP]) * span->blue +		\
378               ((sample[ACOMP] + 1) * sample[BCOMP] << FIXED_SHIFT))	\
379               >> (FIXED_SHIFT + 8);					\
380   dest[ACOMP] = FixedToInt(span->alpha)
381
382#define BLEND								\
383   dest[RCOMP] = ((CHAN_MAX - sample[RCOMP]) * span->red		\
384               + (sample[RCOMP] + 1) * info->er) >> (FIXED_SHIFT + 8);	\
385   dest[GCOMP] = ((CHAN_MAX - sample[GCOMP]) * span->green		\
386               + (sample[GCOMP] + 1) * info->eg) >> (FIXED_SHIFT + 8);	\
387   dest[BCOMP] = ((CHAN_MAX - sample[BCOMP]) * span->blue		\
388               + (sample[BCOMP] + 1) * info->eb) >> (FIXED_SHIFT + 8);	\
389   dest[ACOMP] = span->alpha * (sample[ACOMP] + 1) >> (FIXED_SHIFT + 8)
390
391#define REPLACE  COPY_CHAN4(dest, sample)
392
393#define ADD								\
394   {									\
395      GLint rSum = FixedToInt(span->red)   + (GLint) sample[RCOMP];	\
396      GLint gSum = FixedToInt(span->green) + (GLint) sample[GCOMP];	\
397      GLint bSum = FixedToInt(span->blue)  + (GLint) sample[BCOMP];	\
398      dest[RCOMP] = MIN2(rSum, CHAN_MAX);				\
399      dest[GCOMP] = MIN2(gSum, CHAN_MAX);				\
400      dest[BCOMP] = MIN2(bSum, CHAN_MAX);				\
401      dest[ACOMP] = span->alpha * (sample[ACOMP] + 1) >> (FIXED_SHIFT + 8); \
402  }
403
404/* shortcuts */
405
406#define NEAREST_RGB_REPLACE		\
407   NEAREST_RGB;				\
408   dest[0] = sample[0];			\
409   dest[1] = sample[1];			\
410   dest[2] = sample[2];			\
411   dest[3] = FixedToInt(span->alpha);
412
413#define NEAREST_RGBA_REPLACE  COPY_CHAN4(dest, tex00)
414
415#define SPAN_NEAREST(DO_TEX,COMP)					\
416	for (i = 0; i < span->end; i++) {				\
417           /* Isn't it necessary to use FixedFloor below?? */		\
418           GLint s = FixedToInt(span->intTex[0]) & info->smask;		\
419           GLint t = FixedToInt(span->intTex[1]) & info->tmask;		\
420           GLint pos = (t << info->twidth_log2) + s;			\
421           const GLchan *tex00 = info->texture + COMP * pos;		\
422           DO_TEX;							\
423           span->red += span->redStep;					\
424	   span->green += span->greenStep;				\
425           span->blue += span->blueStep;				\
426	   span->alpha += span->alphaStep;				\
427	   span->intTex[0] += span->intTexStep[0];			\
428	   span->intTex[1] += span->intTexStep[1];			\
429           dest += 4;							\
430	}
431
432#define SPAN_LINEAR(DO_TEX,COMP)					\
433	for (i = 0; i < span->end; i++) {				\
434           /* Isn't it necessary to use FixedFloor below?? */		\
435           GLint s = FixedToInt(span->intTex[0]) & info->smask;		\
436           GLint t = FixedToInt(span->intTex[1]) & info->tmask;		\
437           GLfixed sf = span->intTex[0] & FIXED_FRAC_MASK;		\
438           GLfixed tf = span->intTex[1] & FIXED_FRAC_MASK;		\
439           GLfixed si = FIXED_FRAC_MASK - sf;				\
440           GLfixed ti = FIXED_FRAC_MASK - tf;				\
441           GLint pos = (t << info->twidth_log2) + s;			\
442           const GLchan *tex00 = info->texture + COMP * pos;		\
443           const GLchan *tex10 = tex00 + info->tbytesline;		\
444           const GLchan *tex01 = tex00 + COMP;				\
445           const GLchan *tex11 = tex10 + COMP;				\
446           (void) ti;							\
447           (void) si;							\
448           if (t == info->tmask) {					\
449              tex10 -= info->tsize;					\
450              tex11 -= info->tsize;					\
451           }								\
452           if (s == info->smask) {					\
453              tex01 -= info->tbytesline;				\
454              tex11 -= info->tbytesline;				\
455           }								\
456           DO_TEX;							\
457           span->red += span->redStep;					\
458	   span->green += span->greenStep;				\
459           span->blue += span->blueStep;				\
460	   span->alpha += span->alphaStep;				\
461	   span->intTex[0] += span->intTexStep[0];			\
462	   span->intTex[1] += span->intTexStep[1];			\
463           dest += 4;							\
464	}
465
466
467   GLuint i;
468   GLchan *dest = span->color.rgba[0];
469
470   SW_SPAN_SET_FLAG(span->filledColor);
471   SW_SPAN_SET_FLAG(span->filledAlpha);
472
473   span->intTex[0] -= FIXED_HALF;
474   span->intTex[1] -= FIXED_HALF;
475   switch (info->filter) {
476   case GL_NEAREST:
477      switch (info->format) {
478      case GL_RGB:
479         switch (info->envmode) {
480         case GL_MODULATE:
481            SPAN_NEAREST(NEAREST_RGB;MODULATE,3);
482            break;
483         case GL_DECAL:
484         case GL_REPLACE:
485            SPAN_NEAREST(NEAREST_RGB_REPLACE,3);
486            break;
487         case GL_BLEND:
488            SPAN_NEAREST(NEAREST_RGB;BLEND,3);
489            break;
490         case GL_ADD:
491            SPAN_NEAREST(NEAREST_RGB;ADD,3);
492            break;
493         default:
494            abort();
495         }
496         break;
497      case GL_RGBA:
498         switch(info->envmode) {
499         case GL_MODULATE:
500            SPAN_NEAREST(NEAREST_RGBA;MODULATE,4);
501            break;
502         case GL_DECAL:
503            SPAN_NEAREST(NEAREST_RGBA;DECAL,4);
504            break;
505         case GL_BLEND:
506            SPAN_NEAREST(NEAREST_RGBA;BLEND,4);
507            break;
508         case GL_ADD:
509            SPAN_NEAREST(NEAREST_RGBA;ADD,4);
510            break;
511         case GL_REPLACE:
512            SPAN_NEAREST(NEAREST_RGBA_REPLACE,4);
513            break;
514         default:
515            abort();
516         }
517         break;
518      }
519      break;
520
521   case GL_LINEAR:
522      span->intTex[0] -= FIXED_HALF;
523      span->intTex[1] -= FIXED_HALF;
524      switch (info->format) {
525      case GL_RGB:
526         switch (info->envmode) {
527         case GL_MODULATE:
528            SPAN_LINEAR(LINEAR_RGB;MODULATE,3);
529            break;
530         case GL_DECAL:
531         case GL_REPLACE:
532            SPAN_LINEAR(LINEAR_RGB;REPLACE,3);
533            break;
534         case GL_BLEND:
535            SPAN_LINEAR(LINEAR_RGB;BLEND,3);
536            break;
537         case GL_ADD:
538            SPAN_LINEAR(LINEAR_RGB;ADD,3);
539            break;
540         default:
541            abort();
542         }
543         break;
544      case GL_RGBA:
545         switch (info->envmode) {
546         case GL_MODULATE:
547            SPAN_LINEAR(LINEAR_RGBA;MODULATE,4);
548            break;
549         case GL_DECAL:
550            SPAN_LINEAR(LINEAR_RGBA;DECAL,4);
551            break;
552         case GL_BLEND:
553            SPAN_LINEAR(LINEAR_RGBA;BLEND,4);
554            break;
555         case GL_ADD:
556            SPAN_LINEAR(LINEAR_RGBA;ADD,4);
557            break;
558         case GL_REPLACE:
559            SPAN_LINEAR(LINEAR_RGBA;REPLACE,4);
560            break;
561         default:
562            abort();
563         }		    break;
564      }
565      break;
566   }
567   ASSERT(span->interpMask & SPAN_RGBA);
568   ASSERT(span->arrayMask & SPAN_RGBA);
569   _mesa_write_rgba_span(ctx, span, GL_POLYGON);
570
571#undef SPAN_NEAREST
572#undef SPAN_LINEAR
573}
574
575
576
577/*
578 * Render an RGB/RGBA textured triangle without perspective correction.
579 */
580static void affine_textured_triangle( GLcontext *ctx,
581				      const SWvertex *v0,
582				      const SWvertex *v1,
583				      const SWvertex *v2 )
584{
585#define INTERP_Z 1
586#define INTERP_FOG 1
587#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
588#define INTERP_RGB 1
589#define INTERP_ALPHA 1
590#define INTERP_INT_TEX 1
591#define S_SCALE twidth
592#define T_SCALE theight
593
594#define SETUP_CODE							\
595   struct affine_info info;						\
596   struct gl_texture_unit *unit = ctx->Texture.Unit+0;			\
597   struct gl_texture_object *obj = unit->Current2D;			\
598   const GLint b = obj->BaseLevel;					\
599   const GLfloat twidth = (GLfloat) obj->Image[b]->Width;		\
600   const GLfloat theight = (GLfloat) obj->Image[b]->Height;		\
601   info.texture = (const GLchan *) obj->Image[b]->Data;			\
602   info.twidth_log2 = obj->Image[b]->WidthLog2;				\
603   info.smask = obj->Image[b]->Width - 1;				\
604   info.tmask = obj->Image[b]->Height - 1;				\
605   info.format = obj->Image[b]->Format;					\
606   info.filter = obj->MinFilter;					\
607   info.envmode = unit->EnvMode;					\
608   span.arrayMask |= SPAN_RGBA;						\
609									\
610   if (info.envmode == GL_BLEND) {					\
611      /* potential off-by-one error here? (1.0f -> 2048 -> 0) */	\
612      info.er = FloatToFixed(unit->EnvColor[RCOMP] * CHAN_MAXF);	\
613      info.eg = FloatToFixed(unit->EnvColor[GCOMP] * CHAN_MAXF);	\
614      info.eb = FloatToFixed(unit->EnvColor[BCOMP] * CHAN_MAXF);	\
615      info.ea = FloatToFixed(unit->EnvColor[ACOMP] * CHAN_MAXF);	\
616   }									\
617   if (!info.texture) {							\
618      /* this shouldn't happen */					\
619      return;								\
620   }									\
621									\
622   switch (info.format) {						\
623   case GL_ALPHA:							\
624   case GL_LUMINANCE:							\
625   case GL_INTENSITY:							\
626      info.tbytesline = obj->Image[b]->Width;				\
627      break;								\
628   case GL_LUMINANCE_ALPHA:						\
629      info.tbytesline = obj->Image[b]->Width * 2;			\
630      break;								\
631   case GL_RGB:								\
632      info.tbytesline = obj->Image[b]->Width * 3;			\
633      break;								\
634   case GL_RGBA:							\
635      info.tbytesline = obj->Image[b]->Width * 4;			\
636      break;								\
637   default:								\
638      _mesa_problem(NULL, "Bad texture format in affine_texture_triangle");\
639      return;								\
640   }									\
641   info.tsize = obj->Image[b]->Height * info.tbytesline;
642
643#define RENDER_SPAN( span )   affine_span(ctx, &span, &info);
644
645#include "s_tritemp.h"
646
647}
648
649
650
651struct persp_info
652{
653   GLenum filter;
654   GLenum format;
655   GLenum envmode;
656   GLint smask, tmask;
657   GLint twidth_log2;
658   const GLchan *texture;
659   GLfixed er, eg, eb, ea;   /* texture env color */
660   GLint tbytesline, tsize;
661};
662
663
664static INLINE void
665fast_persp_span(GLcontext *ctx, struct sw_span *span,
666		struct persp_info *info)
667{
668   GLchan sample[4];  /* the filtered texture sample */
669
670  /* Instead of defining a function for each mode, a test is done
671   * between the outer and inner loops. This is to reduce code size
672   * and complexity. Observe that an optimizing compiler kills
673   * unused variables (for instance tf,sf,ti,si in case of GL_NEAREST).
674   */
675#define SPAN_NEAREST(DO_TEX,COMP)					\
676	for (i = 0; i < span->end; i++) {				\
677           GLdouble invQ = tex_coord[2] ?				\
678                                 (1.0 / tex_coord[2]) : 1.0;            \
679           GLfloat s_tmp = (GLfloat) (tex_coord[0] * invQ);		\
680           GLfloat t_tmp = (GLfloat) (tex_coord[1] * invQ);		\
681           GLint s = IFLOOR(s_tmp) & info->smask;	        	\
682           GLint t = IFLOOR(t_tmp) & info->tmask;	        	\
683           GLint pos = (t << info->twidth_log2) + s;			\
684           const GLchan *tex00 = info->texture + COMP * pos;		\
685           DO_TEX;							\
686           span->red += span->redStep;					\
687	   span->green += span->greenStep;				\
688           span->blue += span->blueStep;				\
689	   span->alpha += span->alphaStep;				\
690	   tex_coord[0] += tex_step[0];					\
691	   tex_coord[1] += tex_step[1];					\
692	   tex_coord[2] += tex_step[2];					\
693           dest += 4;							\
694	}
695
696#define SPAN_LINEAR(DO_TEX,COMP)					\
697	for (i = 0; i < span->end; i++) {				\
698           GLdouble invQ = tex_coord[2] ?				\
699                                 (1.0 / tex_coord[2]) : 1.0;            \
700           GLfloat s_tmp = (GLfloat) (tex_coord[0] * invQ);		\
701           GLfloat t_tmp = (GLfloat) (tex_coord[1] * invQ);		\
702           GLfixed s_fix = FloatToFixed(s_tmp) - FIXED_HALF;		\
703           GLfixed t_fix = FloatToFixed(t_tmp) - FIXED_HALF;        	\
704           GLint s = FixedToInt(FixedFloor(s_fix)) & info->smask;	\
705           GLint t = FixedToInt(FixedFloor(t_fix)) & info->tmask;	\
706           GLfixed sf = s_fix & FIXED_FRAC_MASK;			\
707           GLfixed tf = t_fix & FIXED_FRAC_MASK;			\
708           GLfixed si = FIXED_FRAC_MASK - sf;				\
709           GLfixed ti = FIXED_FRAC_MASK - tf;				\
710           GLint pos = (t << info->twidth_log2) + s;			\
711           const GLchan *tex00 = info->texture + COMP * pos;		\
712           const GLchan *tex10 = tex00 + info->tbytesline;		\
713           const GLchan *tex01 = tex00 + COMP;				\
714           const GLchan *tex11 = tex10 + COMP;				\
715           (void) ti;							\
716           (void) si;							\
717           if (t == info->tmask) {					\
718              tex10 -= info->tsize;					\
719              tex11 -= info->tsize;					\
720           }								\
721           if (s == info->smask) {					\
722              tex01 -= info->tbytesline;				\
723              tex11 -= info->tbytesline;				\
724           }								\
725           DO_TEX;							\
726           span->red   += span->redStep;				\
727	   span->green += span->greenStep;				\
728           span->blue  += span->blueStep;				\
729	   span->alpha += span->alphaStep;				\
730	   tex_coord[0] += tex_step[0];					\
731	   tex_coord[1] += tex_step[1];					\
732	   tex_coord[2] += tex_step[2];					\
733           dest += 4;							\
734	}
735
736   GLuint i;
737   GLfloat tex_coord[3], tex_step[3];
738   GLchan *dest = span->color.rgba[0];
739
740   SW_SPAN_SET_FLAG(span->filledColor);
741   SW_SPAN_SET_FLAG(span->filledAlpha);
742
743   tex_coord[0] = span->tex[0][0]  * (info->smask + 1),
744     tex_step[0] = span->texStep[0][0] * (info->smask + 1);
745   tex_coord[1] = span->tex[0][1] * (info->tmask + 1),
746     tex_step[1] = span->texStep[0][1] * (info->tmask + 1);
747   /* span->tex[0][2] only if 3D-texturing, here only 2D */
748   tex_coord[2] = span->tex[0][3],
749     tex_step[2] = span->texStep[0][3];
750
751   switch (info->filter) {
752   case GL_NEAREST:
753      switch (info->format) {
754      case GL_RGB:
755         switch (info->envmode) {
756         case GL_MODULATE:
757            SPAN_NEAREST(NEAREST_RGB;MODULATE,3);
758            break;
759         case GL_DECAL:
760         case GL_REPLACE:
761            SPAN_NEAREST(NEAREST_RGB_REPLACE,3);
762            break;
763         case GL_BLEND:
764            SPAN_NEAREST(NEAREST_RGB;BLEND,3);
765            break;
766         case GL_ADD:
767            SPAN_NEAREST(NEAREST_RGB;ADD,3);
768            break;
769         default:
770            abort();
771         }
772         break;
773      case GL_RGBA:
774         switch(info->envmode) {
775         case GL_MODULATE:
776            SPAN_NEAREST(NEAREST_RGBA;MODULATE,4);
777            break;
778         case GL_DECAL:
779            SPAN_NEAREST(NEAREST_RGBA;DECAL,4);
780            break;
781         case GL_BLEND:
782            SPAN_NEAREST(NEAREST_RGBA;BLEND,4);
783            break;
784         case GL_ADD:
785            SPAN_NEAREST(NEAREST_RGBA;ADD,4);
786            break;
787         case GL_REPLACE:
788            SPAN_NEAREST(NEAREST_RGBA_REPLACE,4);
789            break;
790         default:
791            abort();
792         }
793         break;
794      }
795      break;
796
797   case GL_LINEAR:
798      switch (info->format) {
799      case GL_RGB:
800         switch (info->envmode) {
801         case GL_MODULATE:
802            SPAN_LINEAR(LINEAR_RGB;MODULATE,3);
803            break;
804         case GL_DECAL:
805         case GL_REPLACE:
806            SPAN_LINEAR(LINEAR_RGB;REPLACE,3);
807            break;
808         case GL_BLEND:
809            SPAN_LINEAR(LINEAR_RGB;BLEND,3);
810            break;
811         case GL_ADD:
812            SPAN_LINEAR(LINEAR_RGB;ADD,3);
813            break;
814         default:
815            abort();
816         }
817         break;
818      case GL_RGBA:
819         switch (info->envmode) {
820         case GL_MODULATE:
821            SPAN_LINEAR(LINEAR_RGBA;MODULATE,4);
822            break;
823         case GL_DECAL:
824            SPAN_LINEAR(LINEAR_RGBA;DECAL,4);
825            break;
826         case GL_BLEND:
827            SPAN_LINEAR(LINEAR_RGBA;BLEND,4);
828            break;
829         case GL_ADD:
830            SPAN_LINEAR(LINEAR_RGBA;ADD,4);
831            break;
832         case GL_REPLACE:
833            SPAN_LINEAR(LINEAR_RGBA;REPLACE,4);
834            break;
835         default:
836            abort();
837         }
838         break;
839      }
840      break;
841   }
842
843   ASSERT(span->interpMask & SPAN_RGBA);
844   ASSERT(span->arrayMask & SPAN_RGBA);
845   _mesa_write_rgba_span(ctx, span, GL_POLYGON);
846
847
848#undef SPAN_NEAREST
849#undef SPAN_LINEAR
850}
851
852
853/*
854 * Render an perspective corrected RGB/RGBA textured triangle.
855 * The Q (aka V in Mesa) coordinate must be zero such that the divide
856 * by interpolated Q/W comes out right.
857 *
858 */
859static void persp_textured_triangle( GLcontext *ctx,
860				     const SWvertex *v0,
861				     const SWvertex *v1,
862				     const SWvertex *v2 )
863{
864#define INTERP_Z 1
865#define INTERP_FOG 1
866#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
867#define INTERP_RGB 1
868#define INTERP_ALPHA 1
869#define INTERP_TEX 1
870
871#define SETUP_CODE							\
872   struct persp_info info;						\
873   const struct gl_texture_unit *unit = ctx->Texture.Unit+0;		\
874   const struct gl_texture_object *obj = unit->Current2D;		\
875   const GLint b = obj->BaseLevel;					\
876   info.texture = (const GLchan *) obj->Image[b]->Data;			\
877   info.twidth_log2 = obj->Image[b]->WidthLog2;				\
878   info.smask = obj->Image[b]->Width - 1;				\
879   info.tmask = obj->Image[b]->Height - 1;				\
880   info.format = obj->Image[b]->Format;					\
881   info.filter = obj->MinFilter;					\
882   info.envmode = unit->EnvMode;					\
883   span.arrayMask |= SPAN_RGBA;						\
884									\
885   if (info.envmode == GL_BLEND) {					\
886      /* potential off-by-one error here? (1.0f -> 2048 -> 0) */	\
887      info.er = FloatToFixed(unit->EnvColor[RCOMP] * CHAN_MAXF);	\
888      info.eg = FloatToFixed(unit->EnvColor[GCOMP] * CHAN_MAXF);	\
889      info.eb = FloatToFixed(unit->EnvColor[BCOMP] * CHAN_MAXF);	\
890      info.ea = FloatToFixed(unit->EnvColor[ACOMP] * CHAN_MAXF);	\
891   }									\
892   if (!info.texture) {							\
893      /* this shouldn't happen */					\
894      return;								\
895   }									\
896									\
897   switch (info.format) {						\
898   case GL_ALPHA:							\
899   case GL_LUMINANCE:							\
900   case GL_INTENSITY:							\
901      info.tbytesline = obj->Image[b]->Width;				\
902      break;								\
903   case GL_LUMINANCE_ALPHA:						\
904      info.tbytesline = obj->Image[b]->Width * 2;			\
905      break;								\
906   case GL_RGB:								\
907      info.tbytesline = obj->Image[b]->Width * 3;			\
908      break;								\
909   case GL_RGBA:							\
910      info.tbytesline = obj->Image[b]->Width * 4;			\
911      break;								\
912   default:								\
913      _mesa_problem(NULL, "Bad texture format in persp_textured_triangle");\
914      return;								\
915   }									\
916   info.tsize = obj->Image[b]->Height * info.tbytesline;
917
918#define RENDER_SPAN( span )   fast_persp_span(ctx, &span, &info);
919
920#include "s_tritemp.h"
921
922}
923
924
925#endif /* CHAN_BITS != GL_FLOAT */
926
927
928
929
930/*
931 * Render a smooth-shaded, textured, RGBA triangle.
932 * Interpolate S,T,R with perspective correction, w/out mipmapping.
933 */
934static void general_textured_triangle( GLcontext *ctx,
935				       const SWvertex *v0,
936				       const SWvertex *v1,
937				       const SWvertex *v2 )
938{
939#define INTERP_Z 1
940#define INTERP_FOG 1
941#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
942#define INTERP_RGB 1
943#define INTERP_ALPHA 1
944#define INTERP_TEX 1
945
946#define SETUP_CODE							\
947   const struct gl_texture_object *obj = ctx->Texture.Unit[0]._Current;	\
948   const struct gl_texture_image *texImage = obj->Image[obj->BaseLevel];\
949   span.texWidth[0] = (GLfloat) texImage->Width;			\
950   span.texHeight[0] = (GLfloat) texImage->Height;			\
951   (void) fixedToDepthShift;
952
953#define RENDER_SPAN( span )						\
954   GLuint i;								\
955   SW_SPAN_SET_FLAG(span.filledColor);					\
956   SW_SPAN_SET_FLAG(span.filledAlpha);					\
957   SW_SPAN_SET_FLAG(span.filledTex[0]);					\
958   SW_SPAN_SET_FLAG(span.filledDepth);					\
959   /* NOTE: we could just call rasterize_span() here instead */		\
960   for (i = 0; i < span.end; i++) {					\
961      GLdouble invQ = span.tex[0][3] ? (1.0 / span.tex[0][3]) : 1.0;	\
962      span.zArray[i] = FixedToDepth(span.z);				\
963      span.z += span.zStep;						\
964      span.color.rgba[i][RCOMP] = FixedToChan(span.red);		\
965      span.color.rgba[i][GCOMP] = FixedToChan(span.green);		\
966      span.color.rgba[i][BCOMP] = FixedToChan(span.blue);		\
967      span.color.rgba[i][ACOMP] = FixedToChan(span.alpha);		\
968      span.red += span.redStep;						\
969      span.green += span.greenStep;					\
970      span.blue += span.blueStep;					\
971      span.alpha += span.alphaStep;					\
972      span.texcoords[0][i][0] = (GLfloat) (span.tex[0][0] * invQ);	\
973      span.texcoords[0][i][1] = (GLfloat) (span.tex[0][1] * invQ);	\
974      span.texcoords[0][i][2] = (GLfloat) (span.tex[0][2] * invQ);	\
975      span.tex[0][0] += span.texStep[0][0];				\
976      span.tex[0][1] += span.texStep[0][1];				\
977      span.tex[0][2] += span.texStep[0][2];				\
978      span.tex[0][3] += span.texStep[0][3];				\
979   }									\
980   _mesa_write_texture_span( ctx, &span, GL_POLYGON );
981
982#include "s_tritemp.h"
983}
984
985
986/*
987 * Render a smooth-shaded, textured, RGBA triangle with separate specular
988 * color interpolation.
989 * Interpolate texcoords with perspective correction, w/out mipmapping.
990 */
991static void general_textured_spec_triangle( GLcontext *ctx,
992					    const SWvertex *v0,
993					    const SWvertex *v1,
994					    const SWvertex *v2 )
995{
996#define INTERP_Z 1
997#define INTERP_FOG 1
998#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
999#define INTERP_RGB 1
1000#define INTERP_SPEC 1
1001#define INTERP_ALPHA 1
1002#define INTERP_TEX 1
1003
1004#define SETUP_CODE							\
1005   const struct gl_texture_object *obj = ctx->Texture.Unit[0]._Current;	\
1006   const struct gl_texture_image *texImage = obj->Image[obj->BaseLevel];\
1007   span.texWidth[0] = (GLfloat) texImage->Width;			\
1008   span.texHeight[0] = (GLfloat) texImage->Height;			\
1009   (void) fixedToDepthShift;
1010
1011#define RENDER_SPAN( span )   _mesa_rasterize_span(ctx, &span);
1012
1013#include "s_tritemp.h"
1014}
1015
1016
1017/*
1018 * Render a smooth-shaded, textured, RGBA triangle.
1019 * Interpolate S,T,R with perspective correction and compute lambda for
1020 * each fragment.  Lambda is used to determine whether to use the
1021 * minification or magnification filter.  If minification and using
1022 * mipmaps, lambda is also used to select the texture level of detail.
1023 */
1024static void lambda_textured_triangle( GLcontext *ctx,
1025				      const SWvertex *v0,
1026				      const SWvertex *v1,
1027				      const SWvertex *v2 )
1028{
1029#define INTERP_Z 1
1030#define INTERP_FOG 1
1031#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
1032#define INTERP_RGB 1
1033#define INTERP_ALPHA 1
1034#define INTERP_TEX 1
1035#define INTERP_LAMBDA 1
1036
1037#define SETUP_CODE							\
1038   const struct gl_texture_object *obj = ctx->Texture.Unit[0]._Current;	\
1039   const struct gl_texture_image *texImage = obj->Image[obj->BaseLevel];\
1040   span.texWidth[0] = (GLfloat) texImage->Width;			\
1041   span.texHeight[0] = (GLfloat) texImage->Height;			\
1042   (void) fixedToDepthShift;
1043
1044#define RENDER_SPAN( span )   _mesa_rasterize_span(ctx, &span);
1045
1046#include "s_tritemp.h"
1047}
1048
1049
1050/*
1051 * Render a smooth-shaded, textured, RGBA triangle with separate specular
1052 * interpolation.
1053 * Interpolate S,T,R with perspective correction and compute lambda for
1054 * each fragment.  Lambda is used to determine whether to use the
1055 * minification or magnification filter.  If minification and using
1056 * mipmaps, lambda is also used to select the texture level of detail.
1057 */
1058static void lambda_textured_spec_triangle( GLcontext *ctx,
1059					   const SWvertex *v0,
1060					   const SWvertex *v1,
1061					   const SWvertex *v2 )
1062{
1063#define INTERP_Z 1
1064#define INTERP_FOG 1
1065#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
1066#define INTERP_RGB 1
1067#define INTERP_SPEC 1
1068#define INTERP_ALPHA 1
1069#define INTERP_TEX 1
1070#define INTERP_LAMBDA 1
1071
1072#define SETUP_CODE							\
1073   const struct gl_texture_object *obj = ctx->Texture.Unit[0]._Current;	\
1074   const struct gl_texture_image *texImage = obj->Image[obj->BaseLevel];\
1075   span.texWidth[0] = (GLfloat) texImage->Width;			\
1076   span.texHeight[0] = (GLfloat) texImage->Height;			\
1077   (void) fixedToDepthShift;
1078
1079#define RENDER_SPAN( span )   _mesa_rasterize_span(ctx, &span);
1080
1081#include "s_tritemp.h"
1082}
1083
1084
1085/*
1086 * This is the big one!
1087 * Interpolate Z, RGB, Alpha, specular, fog, and N sets of texture coordinates
1088 * with lambda (LOD).
1089 * Yup, it's slow.
1090 */
1091static void
1092lambda_multitextured_triangle( GLcontext *ctx,
1093                               const SWvertex *v0,
1094                               const SWvertex *v1,
1095                               const SWvertex *v2 )
1096{
1097
1098#define INTERP_Z 1
1099#define INTERP_FOG 1
1100#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
1101#define INTERP_RGB 1
1102#define INTERP_ALPHA 1
1103#define INTERP_SPEC 1
1104#define INTERP_MULTITEX 1
1105#define INTERP_LAMBDA 1
1106
1107#define SETUP_CODE							\
1108   GLuint u;								\
1109   for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {			\
1110      if (ctx->Texture.Unit[u]._ReallyEnabled) {			\
1111         const struct gl_texture_object *texObj;			\
1112         const struct gl_texture_image *texImage;			\
1113         texObj = ctx->Texture.Unit[u]._Current;			\
1114         texImage = texObj->Image[texObj->BaseLevel];			\
1115         span.texWidth[u] = (GLfloat) texImage->Width;			\
1116         span.texHeight[u] = (GLfloat) texImage->Height;		\
1117      }									\
1118   }									\
1119   (void) fixedToDepthShift;
1120
1121#define RENDER_SPAN( span )   _mesa_rasterize_span(ctx, &span);
1122
1123#include "s_tritemp.h"
1124
1125}
1126
1127
1128static void occlusion_zless_triangle( GLcontext *ctx,
1129				      const SWvertex *v0,
1130				      const SWvertex *v1,
1131				      const SWvertex *v2 )
1132{
1133   if (ctx->OcclusionResult) {
1134      return;
1135   }
1136
1137#define DO_OCCLUSION_TEST
1138#define INTERP_Z 1
1139#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
1140
1141#define RENDER_SPAN( span )				\
1142   GLuint i;						\
1143   for (i = 0; i < span.end; i++) {			\
1144      GLdepth z = FixedToDepth(span.z);			\
1145      if (z < zRow[i]) {				\
1146         ctx->OcclusionResult = GL_TRUE;		\
1147         return;					\
1148      }							\
1149      span.z += span.zStep;				\
1150   }
1151
1152#include "s_tritemp.h"
1153}
1154
1155static void nodraw_triangle( GLcontext *ctx,
1156			     const SWvertex *v0,
1157			     const SWvertex *v1,
1158			     const SWvertex *v2 )
1159{
1160   (void) (ctx && v0 && v1 && v2);
1161}
1162
1163
1164/*
1165 * This is used when separate specular color is enabled, but not
1166 * texturing.  We add the specular color to the primary color,
1167 * draw the triangle, then restore the original primary color.
1168 * Inefficient, but seldom needed.
1169 */
1170void _swrast_add_spec_terms_triangle( GLcontext *ctx,
1171				      const SWvertex *v0,
1172				      const SWvertex *v1,
1173				      const SWvertex *v2 )
1174{
1175   SWvertex *ncv0 = (SWvertex *)v0; /* drop const qualifier */
1176   SWvertex *ncv1 = (SWvertex *)v1;
1177   SWvertex *ncv2 = (SWvertex *)v2;
1178#if CHAN_TYPE == GL_FLOAT
1179   GLfloat rSum, gSum, bSum;
1180#else
1181   GLint rSum, gSum, bSum;
1182#endif
1183   GLchan c[3][4];
1184   /* save original colors */
1185   COPY_CHAN4( c[0], ncv0->color );
1186   COPY_CHAN4( c[1], ncv1->color );
1187   COPY_CHAN4( c[2], ncv2->color );
1188   /* sum v0 */
1189   rSum = ncv0->color[0] + ncv0->specular[0];
1190   gSum = ncv0->color[1] + ncv0->specular[1];
1191   bSum = ncv0->color[2] + ncv0->specular[2];
1192   ncv0->color[0] = MIN2(rSum, CHAN_MAX);
1193   ncv0->color[1] = MIN2(gSum, CHAN_MAX);
1194   ncv0->color[2] = MIN2(bSum, CHAN_MAX);
1195   /* sum v1 */
1196   rSum = ncv1->color[0] + ncv1->specular[0];
1197   gSum = ncv1->color[1] + ncv1->specular[1];
1198   bSum = ncv1->color[2] + ncv1->specular[2];
1199   ncv1->color[0] = MIN2(rSum, CHAN_MAX);
1200   ncv1->color[1] = MIN2(gSum, CHAN_MAX);
1201   ncv1->color[2] = MIN2(bSum, CHAN_MAX);
1202   /* sum v2 */
1203   rSum = ncv2->color[0] + ncv2->specular[0];
1204   gSum = ncv2->color[1] + ncv2->specular[1];
1205   bSum = ncv2->color[2] + ncv2->specular[2];
1206   ncv2->color[0] = MIN2(rSum, CHAN_MAX);
1207   ncv2->color[1] = MIN2(gSum, CHAN_MAX);
1208   ncv2->color[2] = MIN2(bSum, CHAN_MAX);
1209   /* draw */
1210   SWRAST_CONTEXT(ctx)->SpecTriangle( ctx, ncv0, ncv1, ncv2 );
1211   /* restore original colors */
1212   COPY_CHAN4( ncv0->color, c[0] );
1213   COPY_CHAN4( ncv1->color, c[1] );
1214   COPY_CHAN4( ncv2->color, c[2] );
1215}
1216
1217
1218
1219#ifdef DEBUG
1220
1221/* record the current triangle function name */
1222const char *_mesa_triFuncName = NULL;
1223
1224#define USE(triFunc)				\
1225do {						\
1226    _mesa_triFuncName = #triFunc;		\
1227    /*printf("%s\n", _mesa_triFuncName);*/	\
1228    swrast->Triangle = triFunc;			\
1229} while (0)
1230
1231#else
1232
1233#define USE(triFunc)  swrast->Triangle = triFunc;
1234
1235#endif
1236
1237
1238
1239
1240/*
1241 * Determine which triangle rendering function to use given the current
1242 * rendering context.
1243 *
1244 * Please update the summary flag _SWRAST_NEW_TRIANGLE if you add or
1245 * remove tests to this code.
1246 */
1247void
1248_swrast_choose_triangle( GLcontext *ctx )
1249{
1250   SWcontext *swrast = SWRAST_CONTEXT(ctx);
1251   const GLboolean rgbmode = ctx->Visual.rgbMode;
1252
1253   if (ctx->Polygon.CullFlag &&
1254       ctx->Polygon.CullFaceMode == GL_FRONT_AND_BACK) {
1255      USE(nodraw_triangle);
1256      return;
1257   }
1258
1259   if (ctx->RenderMode==GL_RENDER) {
1260
1261      if (ctx->Polygon.SmoothFlag) {
1262         _mesa_set_aa_triangle_function(ctx);
1263         ASSERT(swrast->Triangle);
1264         return;
1265      }
1266
1267      if (ctx->Depth.OcclusionTest &&
1268          ctx->Depth.Test &&
1269          ctx->Depth.Mask == GL_FALSE &&
1270          ctx->Depth.Func == GL_LESS &&
1271          !ctx->Stencil.Enabled) {
1272         if ((rgbmode &&
1273              ctx->Color.ColorMask[0] == 0 &&
1274              ctx->Color.ColorMask[1] == 0 &&
1275              ctx->Color.ColorMask[2] == 0 &&
1276              ctx->Color.ColorMask[3] == 0)
1277             ||
1278             (!rgbmode && ctx->Color.IndexMask == 0)) {
1279            USE(occlusion_zless_triangle);
1280            return;
1281         }
1282      }
1283
1284      if (ctx->Texture._ReallyEnabled) {
1285         /* Ugh, we do a _lot_ of tests to pick the best textured tri func */
1286	 const struct gl_texture_object *texObj2D;
1287         const struct gl_texture_image *texImg;
1288         GLenum minFilter, magFilter, envMode;
1289         GLint format;
1290         texObj2D = ctx->Texture.Unit[0].Current2D;
1291         texImg = texObj2D ? texObj2D->Image[texObj2D->BaseLevel] : NULL;
1292         format = texImg ? texImg->TexFormat->MesaFormat : -1;
1293         minFilter = texObj2D ? texObj2D->MinFilter : (GLenum) 0;
1294         magFilter = texObj2D ? texObj2D->MagFilter : (GLenum) 0;
1295         envMode = ctx->Texture.Unit[0].EnvMode;
1296
1297         /* First see if we can used an optimized 2-D texture function */
1298         if (ctx->Texture._ReallyEnabled==TEXTURE0_2D
1299             && texObj2D->WrapS==GL_REPEAT
1300	     && texObj2D->WrapT==GL_REPEAT
1301             && texImg->Border==0
1302             && (format == MESA_FORMAT_RGB || format == MESA_FORMAT_RGBA)
1303	     && minFilter == magFilter
1304	     && ctx->Light.Model.ColorControl == GL_SINGLE_COLOR
1305	     && ctx->Texture.Unit[0].EnvMode != GL_COMBINE_EXT) {
1306	    if (ctx->Hint.PerspectiveCorrection==GL_FASTEST) {
1307	       if (minFilter == GL_NEAREST
1308		   && format == MESA_FORMAT_RGB
1309		   && (envMode == GL_REPLACE || envMode == GL_DECAL)
1310		   && ((swrast->_RasterMask == (DEPTH_BIT | TEXTURE_BIT)
1311			&& ctx->Depth.Func == GL_LESS
1312			&& ctx->Depth.Mask == GL_TRUE)
1313		       || swrast->_RasterMask == TEXTURE_BIT)
1314		   && ctx->Polygon.StippleFlag == GL_FALSE) {
1315		  if (swrast->_RasterMask == (DEPTH_BIT | TEXTURE_BIT)) {
1316		     USE(simple_z_textured_triangle);
1317		  }
1318		  else {
1319		     USE(simple_textured_triangle);
1320		  }
1321	       }
1322	       else {
1323#if CHAN_TYPE == GL_FLOAT
1324                  USE(general_textured_triangle);
1325#else
1326                  USE(affine_textured_triangle);
1327#endif
1328	       }
1329	    }
1330	    else {
1331#if CHAN_TYPE == GL_FLOAT
1332               USE(general_textured_triangle);
1333#else
1334               USE(persp_textured_triangle);
1335#endif
1336	    }
1337	 }
1338         else {
1339            /* More complicated textures (mipmap, multi-tex, sep specular) */
1340            GLboolean needLambda;
1341            /* if mag filter != min filter we need to compute lambda */
1342            const struct gl_texture_object *obj = ctx->Texture.Unit[0]._Current;
1343            if (obj && obj->MinFilter != obj->MagFilter)
1344               needLambda = GL_TRUE;
1345            else
1346               needLambda = GL_FALSE;
1347            if (ctx->Texture._ReallyEnabled > TEXTURE0_ANY) {
1348               USE(lambda_multitextured_triangle);
1349            }
1350            else if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) {
1351               /* separate specular color interpolation */
1352               if (needLambda) {
1353                  USE(lambda_textured_spec_triangle);
1354	       }
1355               else {
1356                  USE(general_textured_spec_triangle);
1357	       }
1358            }
1359            else {
1360               if (needLambda) {
1361		  USE(lambda_textured_triangle);
1362	       }
1363               else {
1364                  USE(general_textured_triangle);
1365	       }
1366            }
1367         }
1368      }
1369      else {
1370         ASSERT(!ctx->Texture._ReallyEnabled);
1371	 if (ctx->Light.ShadeModel==GL_SMOOTH) {
1372	    /* smooth shaded, no texturing, stippled or some raster ops */
1373            if (rgbmode) {
1374	       USE(smooth_rgba_triangle);
1375            }
1376            else {
1377               USE(smooth_ci_triangle);
1378            }
1379	 }
1380	 else {
1381	    /* flat shaded, no texturing, stippled or some raster ops */
1382            if (rgbmode) {
1383	       USE(flat_rgba_triangle);
1384            }
1385            else {
1386               USE(flat_ci_triangle);
1387            }
1388	 }
1389      }
1390   }
1391   else if (ctx->RenderMode==GL_FEEDBACK) {
1392      USE(_mesa_feedback_triangle);
1393   }
1394   else {
1395      /* GL_SELECT mode */
1396      USE(_mesa_select_triangle);
1397   }
1398}
1399