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