s_triangle.c revision 767ffdcc9f5d15c88fc4c2f1c5592b7739bd31dd
1/*
2 * Mesa 3-D graphics library
3 * Version:  6.5
4 *
5 * Copyright (C) 1999-2006  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_feedback.h"
42#include "s_span.h"
43#include "s_triangle.h"
44
45
46/*
47 * Just used for feedback mode.
48 */
49GLboolean
50_swrast_culltriangle( GLcontext *ctx,
51                      const SWvertex *v0,
52                      const SWvertex *v1,
53                      const SWvertex *v2 )
54{
55   GLfloat ex = v1->win[0] - v0->win[0];
56   GLfloat ey = v1->win[1] - v0->win[1];
57   GLfloat fx = v2->win[0] - v0->win[0];
58   GLfloat fy = v2->win[1] - v0->win[1];
59   GLfloat c = ex*fy-ey*fx;
60
61   if (c * SWRAST_CONTEXT(ctx)->_BackfaceSign > 0)
62      return 0;
63
64   return 1;
65}
66
67
68
69/*
70 * Render a flat-shaded color index triangle.
71 */
72#define NAME flat_ci_triangle
73#define INTERP_Z 1
74#define INTERP_FOG 1
75#define SETUP_CODE			\
76   span.interpMask |= SPAN_INDEX;	\
77   span.index = FloatToFixed(v2->index);\
78   span.indexStep = 0;
79#define RENDER_SPAN( span )  _swrast_write_index_span(ctx, &span);
80#include "s_tritemp.h"
81
82
83
84/*
85 * Render a smooth-shaded color index triangle.
86 */
87#define NAME smooth_ci_triangle
88#define INTERP_Z 1
89#define INTERP_FOG 1
90#define INTERP_INDEX 1
91#define RENDER_SPAN( span )  _swrast_write_index_span(ctx, &span);
92#include "s_tritemp.h"
93
94
95
96/*
97 * Render a flat-shaded RGBA triangle.
98 */
99#define NAME flat_rgba_triangle
100#define INTERP_Z 1
101#define INTERP_FOG 1
102#define SETUP_CODE				\
103   ASSERT(ctx->Texture._EnabledCoordUnits == 0);\
104   ASSERT(ctx->Light.ShadeModel==GL_FLAT);	\
105   span.interpMask |= SPAN_RGBA;		\
106   span.red = ChanToFixed(v2->color[0]);	\
107   span.green = ChanToFixed(v2->color[1]);	\
108   span.blue = ChanToFixed(v2->color[2]);	\
109   span.alpha = ChanToFixed(v2->color[3]);	\
110   span.redStep = 0;				\
111   span.greenStep = 0;				\
112   span.blueStep = 0;				\
113   span.alphaStep = 0;
114#define RENDER_SPAN( span )  _swrast_write_rgba_span(ctx, &span);
115#include "s_tritemp.h"
116
117
118
119/*
120 * Render a smooth-shaded RGBA triangle.
121 */
122#define NAME smooth_rgba_triangle
123#define INTERP_Z 1
124#define INTERP_FOG 1
125#define INTERP_RGB 1
126#define INTERP_ALPHA 1
127#define SETUP_CODE				\
128   {						\
129      /* texturing must be off */		\
130      ASSERT(ctx->Texture._EnabledCoordUnits == 0);	\
131      ASSERT(ctx->Light.ShadeModel==GL_SMOOTH);	\
132   }
133#define RENDER_SPAN( span )  _swrast_write_rgba_span(ctx, &span);
134#include "s_tritemp.h"
135
136
137
138/*
139 * Render an RGB, GL_DECAL, textured triangle.
140 * Interpolate S,T only w/out mipmapping or perspective correction.
141 *
142 * No fog.
143 */
144#define NAME simple_textured_triangle
145#define INTERP_INT_TEX 1
146#define S_SCALE twidth
147#define T_SCALE theight
148
149#define SETUP_CODE							\
150   struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0][0];\
151   struct gl_texture_object *obj = ctx->Texture.Unit[0].Current2D;	\
152   const GLint b = obj->BaseLevel;					\
153   const GLfloat twidth = (GLfloat) obj->Image[0][b]->Width;		\
154   const GLfloat theight = (GLfloat) obj->Image[0][b]->Height;		\
155   const GLint twidth_log2 = obj->Image[0][b]->WidthLog2;		\
156   const GLchan *texture = (const GLchan *) obj->Image[0][b]->Data;	\
157   const GLint smask = obj->Image[0][b]->Width - 1;			\
158   const GLint tmask = obj->Image[0][b]->Height - 1;			\
159   if (!texture) {							\
160      /* this shouldn't happen */					\
161      return;								\
162   }
163
164#define RENDER_SPAN( span )						\
165   GLuint i;								\
166   span.intTex[0] -= FIXED_HALF; /* off-by-one error? */		\
167   span.intTex[1] -= FIXED_HALF;					\
168   for (i = 0; i < span.end; i++) {					\
169      GLint s = FixedToInt(span.intTex[0]) & smask;			\
170      GLint t = FixedToInt(span.intTex[1]) & tmask;			\
171      GLint pos = (t << twidth_log2) + s;				\
172      pos = pos + pos + pos;  /* multiply by 3 */			\
173      span.array->rgb[i][RCOMP] = texture[pos];				\
174      span.array->rgb[i][GCOMP] = texture[pos+1];			\
175      span.array->rgb[i][BCOMP] = texture[pos+2];			\
176      span.intTex[0] += span.intTexStep[0];				\
177      span.intTex[1] += span.intTexStep[1];				\
178   }									\
179   rb->PutRowRGB(ctx, rb, span.end, span.x, span.y, span.array->rgb, NULL);
180
181#include "s_tritemp.h"
182
183
184
185/*
186 * Render an RGB, GL_DECAL, textured triangle.
187 * Interpolate S,T, GL_LESS depth test, w/out mipmapping or
188 * perspective correction.
189 * Depth buffer bits must be <= sizeof(DEFAULT_SOFTWARE_DEPTH_TYPE)
190 *
191 * No fog.
192 */
193#define NAME simple_z_textured_triangle
194#define INTERP_Z 1
195#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
196#define INTERP_INT_TEX 1
197#define S_SCALE twidth
198#define T_SCALE theight
199
200#define SETUP_CODE							\
201   struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0][0];\
202   struct gl_texture_object *obj = ctx->Texture.Unit[0].Current2D;	\
203   const GLint b = obj->BaseLevel;					\
204   const GLfloat twidth = (GLfloat) obj->Image[0][b]->Width;		\
205   const GLfloat theight = (GLfloat) obj->Image[0][b]->Height;		\
206   const GLint twidth_log2 = obj->Image[0][b]->WidthLog2;		\
207   const GLchan *texture = (const GLchan *) obj->Image[0][b]->Data;	\
208   const GLint smask = obj->Image[0][b]->Width - 1;			\
209   const GLint tmask = obj->Image[0][b]->Height - 1;			\
210   if (!texture) {							\
211      /* this shouldn't happen */					\
212      return;								\
213   }
214
215#define RENDER_SPAN( span )						\
216   GLuint i;				    				\
217   span.intTex[0] -= FIXED_HALF; /* off-by-one error? */		\
218   span.intTex[1] -= FIXED_HALF;					\
219   for (i = 0; i < span.end; i++) {					\
220      const GLuint z = FixedToDepth(span.z);				\
221      if (z < zRow[i]) {						\
222         GLint s = FixedToInt(span.intTex[0]) & smask;			\
223         GLint t = FixedToInt(span.intTex[1]) & tmask;			\
224         GLint pos = (t << twidth_log2) + s;				\
225         pos = pos + pos + pos;  /* multiply by 3 */			\
226         span.array->rgb[i][RCOMP] = texture[pos];			\
227         span.array->rgb[i][GCOMP] = texture[pos+1];			\
228         span.array->rgb[i][BCOMP] = texture[pos+2];			\
229         zRow[i] = z;							\
230         span.array->mask[i] = 1;					\
231      }									\
232      else {								\
233         span.array->mask[i] = 0;					\
234      }									\
235      span.intTex[0] += span.intTexStep[0];				\
236      span.intTex[1] += span.intTexStep[1];				\
237      span.z += span.zStep;						\
238   }									\
239   rb->PutRowRGB(ctx, rb, span.end, span.x, span.y,			\
240                 span.array->rgb, span.array->mask);
241
242#include "s_tritemp.h"
243
244
245
246#if CHAN_TYPE != GL_FLOAT
247
248struct affine_info
249{
250   GLenum filter;
251   GLenum format;
252   GLenum envmode;
253   GLint smask, tmask;
254   GLint twidth_log2;
255   const GLchan *texture;
256   GLfixed er, eg, eb, ea;
257   GLint tbytesline, tsize;
258};
259
260
261static INLINE GLint
262ilerp(GLint t, GLint a, GLint b)
263{
264   return a + ((t * (b - a)) >> FIXED_SHIFT);
265}
266
267static INLINE GLint
268ilerp_2d(GLint ia, GLint ib, GLint v00, GLint v10, GLint v01, GLint v11)
269{
270   const GLint temp0 = ilerp(ia, v00, v10);
271   const GLint temp1 = ilerp(ia, v01, v11);
272   return ilerp(ib, temp0, temp1);
273}
274
275
276/* This function can handle GL_NEAREST or GL_LINEAR sampling of 2D RGB or RGBA
277 * textures with GL_REPLACE, GL_MODULATE, GL_BLEND, GL_DECAL or GL_ADD
278 * texture env modes.
279 */
280static INLINE void
281affine_span(GLcontext *ctx, struct sw_span *span,
282            struct affine_info *info)
283{
284   GLchan sample[4];  /* the filtered texture sample */
285
286   /* Instead of defining a function for each mode, a test is done
287    * between the outer and inner loops. This is to reduce code size
288    * and complexity. Observe that an optimizing compiler kills
289    * unused variables (for instance tf,sf,ti,si in case of GL_NEAREST).
290    */
291
292#define NEAREST_RGB			\
293   sample[RCOMP] = tex00[RCOMP];	\
294   sample[GCOMP] = tex00[GCOMP];	\
295   sample[BCOMP] = tex00[BCOMP];	\
296   sample[ACOMP] = CHAN_MAX
297
298#define LINEAR_RGB							\
299   sample[RCOMP] = ilerp_2d(sf, tf, tex00[0], tex01[0], tex10[0], tex11[0]);\
300   sample[GCOMP] = ilerp_2d(sf, tf, tex00[1], tex01[1], tex10[1], tex11[1]);\
301   sample[BCOMP] = ilerp_2d(sf, tf, tex00[2], tex01[2], tex10[2], tex11[2]);\
302   sample[ACOMP] = CHAN_MAX;
303
304#define NEAREST_RGBA  COPY_CHAN4(sample, tex00)
305
306#define LINEAR_RGBA							\
307   sample[RCOMP] = ilerp_2d(sf, tf, tex00[0], tex01[0], tex10[0], tex11[0]);\
308   sample[GCOMP] = ilerp_2d(sf, tf, tex00[1], tex01[1], tex10[1], tex11[1]);\
309   sample[BCOMP] = ilerp_2d(sf, tf, tex00[2], tex01[2], tex10[2], tex11[2]);\
310   sample[ACOMP] = ilerp_2d(sf, tf, tex00[3], tex01[3], tex10[3], tex11[3])
311
312#define MODULATE							  \
313   dest[RCOMP] = span->red   * (sample[RCOMP] + 1u) >> (FIXED_SHIFT + 8); \
314   dest[GCOMP] = span->green * (sample[GCOMP] + 1u) >> (FIXED_SHIFT + 8); \
315   dest[BCOMP] = span->blue  * (sample[BCOMP] + 1u) >> (FIXED_SHIFT + 8); \
316   dest[ACOMP] = span->alpha * (sample[ACOMP] + 1u) >> (FIXED_SHIFT + 8)
317
318#define DECAL								\
319   dest[RCOMP] = ((CHAN_MAX - sample[ACOMP]) * span->red +		\
320               ((sample[ACOMP] + 1) * sample[RCOMP] << FIXED_SHIFT))	\
321               >> (FIXED_SHIFT + 8);					\
322   dest[GCOMP] = ((CHAN_MAX - sample[ACOMP]) * span->green +		\
323               ((sample[ACOMP] + 1) * sample[GCOMP] << FIXED_SHIFT))	\
324               >> (FIXED_SHIFT + 8);					\
325   dest[BCOMP] = ((CHAN_MAX - sample[ACOMP]) * span->blue +		\
326               ((sample[ACOMP] + 1) * sample[BCOMP] << FIXED_SHIFT))	\
327               >> (FIXED_SHIFT + 8);					\
328   dest[ACOMP] = FixedToInt(span->alpha)
329
330#define BLEND								\
331   dest[RCOMP] = ((CHAN_MAX - sample[RCOMP]) * span->red		\
332               + (sample[RCOMP] + 1) * info->er) >> (FIXED_SHIFT + 8);	\
333   dest[GCOMP] = ((CHAN_MAX - sample[GCOMP]) * span->green		\
334               + (sample[GCOMP] + 1) * info->eg) >> (FIXED_SHIFT + 8);	\
335   dest[BCOMP] = ((CHAN_MAX - sample[BCOMP]) * span->blue		\
336               + (sample[BCOMP] + 1) * info->eb) >> (FIXED_SHIFT + 8);	\
337   dest[ACOMP] = span->alpha * (sample[ACOMP] + 1) >> (FIXED_SHIFT + 8)
338
339#define REPLACE  COPY_CHAN4(dest, sample)
340
341#define ADD								\
342   {									\
343      GLint rSum = FixedToInt(span->red)   + (GLint) sample[RCOMP];	\
344      GLint gSum = FixedToInt(span->green) + (GLint) sample[GCOMP];	\
345      GLint bSum = FixedToInt(span->blue)  + (GLint) sample[BCOMP];	\
346      dest[RCOMP] = MIN2(rSum, CHAN_MAX);				\
347      dest[GCOMP] = MIN2(gSum, CHAN_MAX);				\
348      dest[BCOMP] = MIN2(bSum, CHAN_MAX);				\
349      dest[ACOMP] = span->alpha * (sample[ACOMP] + 1) >> (FIXED_SHIFT + 8); \
350  }
351
352/* shortcuts */
353
354#define NEAREST_RGB_REPLACE		\
355   NEAREST_RGB;				\
356   dest[0] = sample[0];			\
357   dest[1] = sample[1];			\
358   dest[2] = sample[2];			\
359   dest[3] = FixedToInt(span->alpha);
360
361#define NEAREST_RGBA_REPLACE  COPY_CHAN4(dest, tex00)
362
363#define SPAN_NEAREST(DO_TEX, COMPS)					\
364	for (i = 0; i < span->end; i++) {				\
365           /* Isn't it necessary to use FixedFloor below?? */		\
366           GLint s = FixedToInt(span->intTex[0]) & info->smask;		\
367           GLint t = FixedToInt(span->intTex[1]) & info->tmask;		\
368           GLint pos = (t << info->twidth_log2) + s;			\
369           const GLchan *tex00 = info->texture + COMPS * pos;		\
370           DO_TEX;							\
371           span->red += span->redStep;					\
372	   span->green += span->greenStep;				\
373           span->blue += span->blueStep;				\
374	   span->alpha += span->alphaStep;				\
375	   span->intTex[0] += span->intTexStep[0];			\
376	   span->intTex[1] += span->intTexStep[1];			\
377           dest += 4;							\
378	}
379
380#define SPAN_LINEAR(DO_TEX, COMPS)					\
381	for (i = 0; i < span->end; i++) {				\
382           /* Isn't it necessary to use FixedFloor below?? */		\
383           const GLint s = FixedToInt(span->intTex[0]) & info->smask;	\
384           const GLint t = FixedToInt(span->intTex[1]) & info->tmask;	\
385           const GLfixed sf = span->intTex[0] & FIXED_FRAC_MASK;	\
386           const GLfixed tf = span->intTex[1] & FIXED_FRAC_MASK;	\
387           const GLint pos = (t << info->twidth_log2) + s;		\
388           const GLchan *tex00 = info->texture + COMPS * pos;		\
389           const GLchan *tex10 = tex00 + info->tbytesline;		\
390           const GLchan *tex01 = tex00 + COMPS;				\
391           const GLchan *tex11 = tex10 + COMPS;				\
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]->_BaseFormat;				\
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           const GLfloat s_tmp = (GLfloat) (tex_coord[0] * invQ);	\
640           const GLfloat t_tmp = (GLfloat) (tex_coord[1] * invQ);	\
641           const GLfixed s_fix = FloatToFixed(s_tmp) - FIXED_HALF;	\
642           const GLfixed t_fix = FloatToFixed(t_tmp) - FIXED_HALF;      \
643           const GLint s = FixedToInt(FixedFloor(s_fix)) & info->smask;	\
644           const GLint t = FixedToInt(FixedFloor(t_fix)) & info->tmask;	\
645           const GLfixed sf = s_fix & FIXED_FRAC_MASK;			\
646           const GLfixed tf = t_fix & FIXED_FRAC_MASK;			\
647           const GLint pos = (t << info->twidth_log2) + s;		\
648           const GLchan *tex00 = info->texture + COMP * pos;		\
649           const GLchan *tex10 = tex00 + info->tbytesline;		\
650           const GLchan *tex01 = tex00 + COMP;				\
651           const GLchan *tex11 = tex10 + COMP;				\
652           if (t == info->tmask) {					\
653              tex10 -= info->tsize;					\
654              tex11 -= info->tsize;					\
655           }								\
656           if (s == info->smask) {					\
657              tex01 -= info->tbytesline;				\
658              tex11 -= info->tbytesline;				\
659           }								\
660           DO_TEX;							\
661           span->red   += span->redStep;				\
662	   span->green += span->greenStep;				\
663           span->blue  += span->blueStep;				\
664	   span->alpha += span->alphaStep;				\
665	   tex_coord[0] += tex_step[0];					\
666	   tex_coord[1] += tex_step[1];					\
667	   tex_coord[2] += tex_step[2];					\
668           dest += 4;							\
669	}
670
671   GLuint i;
672   GLfloat tex_coord[3], tex_step[3];
673   GLchan *dest = span->array->rgba[0];
674
675   const GLuint savedTexEnable = ctx->Texture._EnabledUnits;
676   ctx->Texture._EnabledUnits = 0;
677
678   tex_coord[0] = span->tex[0][0]  * (info->smask + 1);
679   tex_step[0] = span->texStepX[0][0] * (info->smask + 1);
680   tex_coord[1] = span->tex[0][1] * (info->tmask + 1);
681   tex_step[1] = span->texStepX[0][1] * (info->tmask + 1);
682   /* span->tex[0][2] only if 3D-texturing, here only 2D */
683   tex_coord[2] = span->tex[0][3];
684   tex_step[2] = span->texStepX[0][3];
685
686   switch (info->filter) {
687   case GL_NEAREST:
688      switch (info->format) {
689      case GL_RGB:
690         switch (info->envmode) {
691         case GL_MODULATE:
692            SPAN_NEAREST(NEAREST_RGB;MODULATE,3);
693            break;
694         case GL_DECAL:
695         case GL_REPLACE:
696            SPAN_NEAREST(NEAREST_RGB_REPLACE,3);
697            break;
698         case GL_BLEND:
699            SPAN_NEAREST(NEAREST_RGB;BLEND,3);
700            break;
701         case GL_ADD:
702            SPAN_NEAREST(NEAREST_RGB;ADD,3);
703            break;
704         default:
705            _mesa_problem(ctx, "bad tex env mode (5) in SPAN_LINEAR");
706            return;
707         }
708         break;
709      case GL_RGBA:
710         switch(info->envmode) {
711         case GL_MODULATE:
712            SPAN_NEAREST(NEAREST_RGBA;MODULATE,4);
713            break;
714         case GL_DECAL:
715            SPAN_NEAREST(NEAREST_RGBA;DECAL,4);
716            break;
717         case GL_BLEND:
718            SPAN_NEAREST(NEAREST_RGBA;BLEND,4);
719            break;
720         case GL_ADD:
721            SPAN_NEAREST(NEAREST_RGBA;ADD,4);
722            break;
723         case GL_REPLACE:
724            SPAN_NEAREST(NEAREST_RGBA_REPLACE,4);
725            break;
726         default:
727            _mesa_problem(ctx, "bad tex env mode (6) in SPAN_LINEAR");
728            return;
729         }
730         break;
731      }
732      break;
733
734   case GL_LINEAR:
735      switch (info->format) {
736      case GL_RGB:
737         switch (info->envmode) {
738         case GL_MODULATE:
739            SPAN_LINEAR(LINEAR_RGB;MODULATE,3);
740            break;
741         case GL_DECAL:
742         case GL_REPLACE:
743            SPAN_LINEAR(LINEAR_RGB;REPLACE,3);
744            break;
745         case GL_BLEND:
746            SPAN_LINEAR(LINEAR_RGB;BLEND,3);
747            break;
748         case GL_ADD:
749            SPAN_LINEAR(LINEAR_RGB;ADD,3);
750            break;
751         default:
752            _mesa_problem(ctx, "bad tex env mode (7) in SPAN_LINEAR");
753            return;
754         }
755         break;
756      case GL_RGBA:
757         switch (info->envmode) {
758         case GL_MODULATE:
759            SPAN_LINEAR(LINEAR_RGBA;MODULATE,4);
760            break;
761         case GL_DECAL:
762            SPAN_LINEAR(LINEAR_RGBA;DECAL,4);
763            break;
764         case GL_BLEND:
765            SPAN_LINEAR(LINEAR_RGBA;BLEND,4);
766            break;
767         case GL_ADD:
768            SPAN_LINEAR(LINEAR_RGBA;ADD,4);
769            break;
770         case GL_REPLACE:
771            SPAN_LINEAR(LINEAR_RGBA;REPLACE,4);
772            break;
773         default:
774            _mesa_problem(ctx, "bad tex env mode (8) in SPAN_LINEAR");
775            return;
776         }
777         break;
778      }
779      break;
780   }
781
782   ASSERT(span->arrayMask & SPAN_RGBA);
783   _swrast_write_rgba_span(ctx, span);
784
785#undef SPAN_NEAREST
786#undef SPAN_LINEAR
787
788   /* restore state */
789   ctx->Texture._EnabledUnits = savedTexEnable;
790}
791
792
793/*
794 * Render an perspective corrected RGB/RGBA textured triangle.
795 * The Q (aka V in Mesa) coordinate must be zero such that the divide
796 * by interpolated Q/W comes out right.
797 *
798 */
799#define NAME persp_textured_triangle
800#define INTERP_Z 1
801#define INTERP_W 1
802#define INTERP_FOG 1
803#define INTERP_RGB 1
804#define INTERP_ALPHA 1
805#define INTERP_TEX 1
806
807#define SETUP_CODE							\
808   struct persp_info info;						\
809   const struct gl_texture_unit *unit = ctx->Texture.Unit+0;		\
810   const struct gl_texture_object *obj = unit->Current2D;		\
811   const GLint b = obj->BaseLevel;					\
812   info.texture = (const GLchan *) obj->Image[0][b]->Data;		\
813   info.twidth_log2 = obj->Image[0][b]->WidthLog2;			\
814   info.smask = obj->Image[0][b]->Width - 1;				\
815   info.tmask = obj->Image[0][b]->Height - 1;				\
816   info.format = obj->Image[0][b]->_BaseFormat;				\
817   info.filter = obj->MinFilter;					\
818   info.envmode = unit->EnvMode;					\
819									\
820   if (info.envmode == GL_BLEND) {					\
821      /* potential off-by-one error here? (1.0f -> 2048 -> 0) */	\
822      info.er = FloatToFixed(unit->EnvColor[RCOMP] * CHAN_MAXF);	\
823      info.eg = FloatToFixed(unit->EnvColor[GCOMP] * CHAN_MAXF);	\
824      info.eb = FloatToFixed(unit->EnvColor[BCOMP] * CHAN_MAXF);	\
825      info.ea = FloatToFixed(unit->EnvColor[ACOMP] * CHAN_MAXF);	\
826   }									\
827   if (!info.texture) {							\
828      /* this shouldn't happen */					\
829      return;								\
830   }									\
831									\
832   switch (info.format) {						\
833   case GL_ALPHA:							\
834   case GL_LUMINANCE:							\
835   case GL_INTENSITY:							\
836      info.tbytesline = obj->Image[0][b]->Width;			\
837      break;								\
838   case GL_LUMINANCE_ALPHA:						\
839      info.tbytesline = obj->Image[0][b]->Width * 2;			\
840      break;								\
841   case GL_RGB:								\
842      info.tbytesline = obj->Image[0][b]->Width * 3;			\
843      break;								\
844   case GL_RGBA:							\
845      info.tbytesline = obj->Image[0][b]->Width * 4;			\
846      break;								\
847   default:								\
848      _mesa_problem(NULL, "Bad texture format in persp_textured_triangle");\
849      return;								\
850   }									\
851   info.tsize = obj->Image[0][b]->Height * info.tbytesline;
852
853#define RENDER_SPAN( span )			\
854   span.interpMask &= ~SPAN_RGBA;		\
855   span.arrayMask |= SPAN_RGBA;			\
856   fast_persp_span(ctx, &span, &info);
857
858#include "s_tritemp.h"
859
860
861#endif /* CHAN_BITS != GL_FLOAT */
862
863
864
865
866/*
867 * Render a smooth-shaded, textured, RGBA triangle.
868 * Interpolate S,T,R with perspective correction, w/out mipmapping.
869 */
870#define NAME general_textured_triangle
871#define INTERP_Z 1
872#define INTERP_W 1
873#define INTERP_FOG 1
874#define INTERP_RGB 1
875#define INTERP_SPEC 1
876#define INTERP_ALPHA 1
877#define INTERP_TEX 1
878#define RENDER_SPAN( span )   _swrast_write_rgba_span(ctx, &span);
879#include "s_tritemp.h"
880
881
882
883/*
884 * This is the big one!
885 * Interpolate Z, RGB, Alpha, specular, fog, N sets of texture coordinates, and varying floats.
886 * Yup, it's slow.
887 */
888#define NAME multitextured_triangle
889#define INTERP_Z 1
890#define INTERP_W 1
891#define INTERP_FOG 1
892#define INTERP_RGB 1
893#define INTERP_ALPHA 1
894#define INTERP_SPEC 1
895#define INTERP_MULTITEX 1
896#define INTERP_VARYING 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 = ctx->DrawBuffer->_DepthBuffer;		\
909   struct gl_query_object *q = ctx->Query.CurrentOcclusionObject;	\
910   ASSERT(ctx->Depth.Test);						\
911   ASSERT(!ctx->Depth.Mask);						\
912   ASSERT(ctx->Depth.Func == GL_LESS);					\
913   if (!q) {								\
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         GLuint z = FixedToDepth(span.z);				\
923         if (z < zRow[i]) {						\
924            q->Result++;						\
925         }								\
926         span.z += span.zStep;						\
927      }									\
928   }									\
929   else {								\
930      GLuint i;								\
931      const GLuint *zRow = (const GLuint *)				\
932         rb->GetPointer(ctx, rb, span.x, span.y);			\
933      for (i = 0; i < span.end; i++) {					\
934         if ((GLuint)span.z < zRow[i]) {				\
935            q->Result++;						\
936         }								\
937         span.z += span.zStep;						\
938      }									\
939   }
940#include "s_tritemp.h"
941
942
943
944static void
945nodraw_triangle( GLcontext *ctx,
946                 const SWvertex *v0,
947                 const SWvertex *v1,
948                 const SWvertex *v2 )
949{
950   (void) (ctx && v0 && v1 && v2);
951}
952
953
954/*
955 * This is used when separate specular color is enabled, but not
956 * texturing.  We add the specular color to the primary color,
957 * draw the triangle, then restore the original primary color.
958 * Inefficient, but seldom needed.
959 */
960void _swrast_add_spec_terms_triangle( GLcontext *ctx,
961				      const SWvertex *v0,
962				      const SWvertex *v1,
963				      const SWvertex *v2 )
964{
965   SWvertex *ncv0 = (SWvertex *)v0; /* drop const qualifier */
966   SWvertex *ncv1 = (SWvertex *)v1;
967   SWvertex *ncv2 = (SWvertex *)v2;
968#if CHAN_TYPE == GL_FLOAT
969   GLfloat rSum, gSum, bSum;
970#else
971   GLint rSum, gSum, bSum;
972#endif
973   GLchan c[3][4];
974   /* save original colors */
975   COPY_CHAN4( c[0], ncv0->color );
976   COPY_CHAN4( c[1], ncv1->color );
977   COPY_CHAN4( c[2], ncv2->color );
978   /* sum v0 */
979   rSum = ncv0->color[0] + ncv0->specular[0];
980   gSum = ncv0->color[1] + ncv0->specular[1];
981   bSum = ncv0->color[2] + ncv0->specular[2];
982   ncv0->color[0] = MIN2(rSum, CHAN_MAX);
983   ncv0->color[1] = MIN2(gSum, CHAN_MAX);
984   ncv0->color[2] = MIN2(bSum, CHAN_MAX);
985   /* sum v1 */
986   rSum = ncv1->color[0] + ncv1->specular[0];
987   gSum = ncv1->color[1] + ncv1->specular[1];
988   bSum = ncv1->color[2] + ncv1->specular[2];
989   ncv1->color[0] = MIN2(rSum, CHAN_MAX);
990   ncv1->color[1] = MIN2(gSum, CHAN_MAX);
991   ncv1->color[2] = MIN2(bSum, CHAN_MAX);
992   /* sum v2 */
993   rSum = ncv2->color[0] + ncv2->specular[0];
994   gSum = ncv2->color[1] + ncv2->specular[1];
995   bSum = ncv2->color[2] + ncv2->specular[2];
996   ncv2->color[0] = MIN2(rSum, CHAN_MAX);
997   ncv2->color[1] = MIN2(gSum, CHAN_MAX);
998   ncv2->color[2] = MIN2(bSum, CHAN_MAX);
999   /* draw */
1000   SWRAST_CONTEXT(ctx)->SpecTriangle( ctx, ncv0, ncv1, ncv2 );
1001   /* restore original colors */
1002   COPY_CHAN4( ncv0->color, c[0] );
1003   COPY_CHAN4( ncv1->color, c[1] );
1004   COPY_CHAN4( ncv2->color, c[2] );
1005}
1006
1007
1008
1009#ifdef DEBUG
1010
1011/* record the current triangle function name */
1012const char *_mesa_triFuncName = NULL;
1013
1014#define USE(triFunc)				\
1015do {						\
1016    _mesa_triFuncName = #triFunc;		\
1017    /*printf("%s\n", _mesa_triFuncName);*/	\
1018    swrast->Triangle = triFunc;			\
1019} while (0)
1020
1021#else
1022
1023#define USE(triFunc)  swrast->Triangle = triFunc;
1024
1025#endif
1026
1027
1028
1029
1030/*
1031 * Determine which triangle rendering function to use given the current
1032 * rendering context.
1033 *
1034 * Please update the summary flag _SWRAST_NEW_TRIANGLE if you add or
1035 * remove tests to this code.
1036 */
1037void
1038_swrast_choose_triangle( GLcontext *ctx )
1039{
1040   SWcontext *swrast = SWRAST_CONTEXT(ctx);
1041   const GLboolean rgbmode = ctx->Visual.rgbMode;
1042
1043   if (ctx->Polygon.CullFlag &&
1044       ctx->Polygon.CullFaceMode == GL_FRONT_AND_BACK) {
1045      USE(nodraw_triangle);
1046      return;
1047   }
1048
1049   if (ctx->RenderMode==GL_RENDER) {
1050
1051      if (ctx->Polygon.SmoothFlag) {
1052         _swrast_set_aa_triangle_function(ctx);
1053         ASSERT(swrast->Triangle);
1054         return;
1055      }
1056
1057      /* special case for occlusion testing */
1058      if (ctx->Query.CurrentOcclusionObject &&
1059          ctx->Depth.Test &&
1060          ctx->Depth.Mask == GL_FALSE &&
1061          ctx->Depth.Func == GL_LESS &&
1062          !ctx->Stencil.Enabled) {
1063         if ((rgbmode &&
1064              ctx->Color.ColorMask[0] == 0 &&
1065              ctx->Color.ColorMask[1] == 0 &&
1066              ctx->Color.ColorMask[2] == 0 &&
1067              ctx->Color.ColorMask[3] == 0)
1068             ||
1069             (!rgbmode && ctx->Color.IndexMask == 0)) {
1070            USE(occlusion_zless_triangle);
1071            return;
1072         }
1073      }
1074
1075      if (ctx->Texture._EnabledCoordUnits || ctx->FragmentProgram._Active ||
1076          ctx->ATIFragmentShader._Enabled || ctx->ShaderObjects._FragmentShaderPresent) {
1077         /* Ugh, we do a _lot_ of tests to pick the best textured tri func */
1078         const struct gl_texture_object *texObj2D;
1079         const struct gl_texture_image *texImg;
1080         GLenum minFilter, magFilter, envMode;
1081         GLint format;
1082         texObj2D = ctx->Texture.Unit[0].Current2D;
1083         texImg = texObj2D ? texObj2D->Image[0][texObj2D->BaseLevel] : NULL;
1084         format = texImg ? texImg->TexFormat->MesaFormat : -1;
1085         minFilter = texObj2D ? texObj2D->MinFilter : (GLenum) 0;
1086         magFilter = texObj2D ? texObj2D->MagFilter : (GLenum) 0;
1087         envMode = ctx->Texture.Unit[0].EnvMode;
1088
1089         /* First see if we can use an optimized 2-D texture function */
1090         if (ctx->Texture._EnabledCoordUnits == 0x1
1091             && !ctx->FragmentProgram._Active
1092             && !ctx->ATIFragmentShader._Enabled
1093             && !ctx->ShaderObjects._FragmentShaderPresent
1094             && ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT
1095             && texObj2D->WrapS == GL_REPEAT
1096             && texObj2D->WrapT == GL_REPEAT
1097             && texImg->_IsPowerOfTwo
1098             && texImg->Border == 0
1099             && texImg->Width == texImg->RowStride
1100             && (format == MESA_FORMAT_RGB || format == MESA_FORMAT_RGBA)
1101             && minFilter == magFilter
1102             && ctx->Light.Model.ColorControl == GL_SINGLE_COLOR
1103             && ctx->Texture.Unit[0].EnvMode != GL_COMBINE_EXT) {
1104	    if (ctx->Hint.PerspectiveCorrection==GL_FASTEST) {
1105	       if (minFilter == GL_NEAREST
1106		   && format == MESA_FORMAT_RGB
1107		   && (envMode == GL_REPLACE || envMode == GL_DECAL)
1108		   && ((swrast->_RasterMask == (DEPTH_BIT | TEXTURE_BIT)
1109			&& ctx->Depth.Func == GL_LESS
1110			&& ctx->Depth.Mask == GL_TRUE)
1111		       || swrast->_RasterMask == TEXTURE_BIT)
1112		   && ctx->Polygon.StippleFlag == GL_FALSE
1113                   && ctx->Visual.depthBits <= 16) {
1114		  if (swrast->_RasterMask == (DEPTH_BIT | TEXTURE_BIT)) {
1115		     USE(simple_z_textured_triangle);
1116		  }
1117		  else {
1118		     USE(simple_textured_triangle);
1119		  }
1120	       }
1121	       else {
1122#if (CHAN_BITS == 16 || CHAN_BITS == 32)
1123                  USE(general_textured_triangle);
1124#else
1125                  USE(affine_textured_triangle);
1126#endif
1127	       }
1128	    }
1129	    else {
1130#if (CHAN_BITS == 16 || CHAN_BITS == 32)
1131               USE(general_textured_triangle);
1132#else
1133               USE(persp_textured_triangle);
1134#endif
1135	    }
1136	 }
1137         else {
1138            /* general case textured triangles */
1139            if (ctx->Texture._EnabledCoordUnits > 1) {
1140               USE(multitextured_triangle);
1141            }
1142            else {
1143               USE(general_textured_triangle);
1144            }
1145         }
1146      }
1147      else {
1148         ASSERT(!ctx->Texture._EnabledCoordUnits);
1149	 if (ctx->Light.ShadeModel==GL_SMOOTH) {
1150	    /* smooth shaded, no texturing, stippled or some raster ops */
1151            if (rgbmode) {
1152	       USE(smooth_rgba_triangle);
1153            }
1154            else {
1155               USE(smooth_ci_triangle);
1156            }
1157	 }
1158	 else {
1159	    /* flat shaded, no texturing, stippled or some raster ops */
1160            if (rgbmode) {
1161	       USE(flat_rgba_triangle);
1162            }
1163            else {
1164               USE(flat_ci_triangle);
1165            }
1166	 }
1167      }
1168   }
1169   else if (ctx->RenderMode==GL_FEEDBACK) {
1170      USE(_swrast_feedback_triangle);
1171   }
1172   else {
1173      /* GL_SELECT mode */
1174      USE(_swrast_select_triangle);
1175   }
1176}
1177