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