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