1 /* $Id: triangle.c,v 1.31 1998/02/03 23:46:00 brianp Exp $ */
4 * Mesa 3-D graphics library
6 * Copyright (C) 1995-1997 Brian Paul
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the Free
20 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 * $Log: triangle.c,v $
26 * Revision 1.31 1998/02/03 23:46:00 brianp
27 * fixed a few problems with condition expressions for Amiga StormC compiler
29 * Revision 1.30 1997/08/27 01:20:05 brianp
30 * moved texture completeness test out one level (Karl Anders Oygard)
32 * Revision 1.29 1997/07/24 01:26:05 brianp
33 * changed precompiled header symbol from PCH to PC_HEADER
35 * Revision 1.28 1997/07/21 22:18:10 brianp
36 * fixed bug in compute_lambda() thanks to Magnus Lundin
38 * Revision 1.27 1997/06/23 00:40:03 brianp
39 * added a DEFARRAY/UNDEFARRAY for the Mac
41 * Revision 1.26 1997/06/20 02:51:38 brianp
42 * changed color components from GLfixed to GLubyte
44 * Revision 1.25 1997/06/03 01:38:22 brianp
45 * fixed divide by zero problem in feedback function (William Mitchell)
47 * Revision 1.24 1997/05/28 03:26:49 brianp
48 * added precompiled header (PCH) support
50 * Revision 1.23 1997/05/17 03:40:55 brianp
51 * refined textured triangle selection code (Mats Lofkvist)
53 * Revision 1.22 1997/05/03 00:51:02 brianp
54 * removed calls to gl_texturing_enabled()
56 * Revision 1.21 1997/04/14 21:38:15 brianp
57 * fixed a typo (dtdx instead of dudx) in lambda_textured_triangle()
59 * Revision 1.20 1997/04/14 02:00:39 brianp
60 * #include "texstate.h" instead of "texture.h"
62 * Revision 1.19 1997/04/12 12:27:16 brianp
63 * replaced ctx->TriangleFunc with ctx->Driver.TriangleFunc
65 * Revision 1.18 1997/04/02 03:12:06 brianp
66 * replaced ctx->IdentityTexMat with ctx->TextureMatrixType
68 * Revision 1.17 1997/03/13 03:05:31 brianp
69 * removed unused shift variable in feedback_triangle()
71 * Revision 1.16 1997/03/08 02:04:27 brianp
72 * better implementation of feedback function
74 * Revision 1.15 1997/03/04 18:54:13 brianp
75 * renamed mipmap_textured_triangle() to lambda_textured_triangle()
76 * better comments about lambda and mipmapping
78 * Revision 1.14 1997/02/20 23:47:35 brianp
79 * triangle feedback colors were wrong when using smooth shading
81 * Revision 1.13 1997/02/19 10:24:26 brianp
82 * use a GLdouble instead of a GLfloat for wwvvInv (perspective correction)
84 * Revision 1.12 1997/02/09 19:53:43 brianp
85 * now use TEXTURE_xD enable constants
87 * Revision 1.11 1997/02/09 18:51:02 brianp
88 * added GL_EXT_texture3D support
90 * Revision 1.10 1997/01/16 03:36:43 brianp
91 * added #include "texture.h"
93 * Revision 1.9 1997/01/09 19:50:49 brianp
94 * now call gl_texturing_enabled()
96 * Revision 1.8 1996/12/20 20:23:30 brianp
97 * the test for using general_textured_triangle() was wrong
99 * Revision 1.7 1996/12/12 22:37:30 brianp
100 * projective textures didn't work right
102 * Revision 1.6 1996/11/08 02:21:21 brianp
103 * added null drawing function for GL_NO_RASTER
105 * Revision 1.4 1996/09/27 01:30:37 brianp
106 * removed unneeded INTERP_ALPHA from flat_rgba_triangle()
108 * Revision 1.3 1996/09/15 14:19:16 brianp
109 * now use GLframebuffer and GLvisual
111 * Revision 1.2 1996/09/15 01:48:58 brianp
112 * removed #define NULL 0
114 * Revision 1.1 1996/09/13 01:38:16 brianp
121 * Triangle rasterizers
132 #include "feedback.h"
135 #include "texstate.h"
136 #include "triangle.h"
143 * Put triangle in feedback buffer.
145 static void feedback_triangle( GLcontext
*ctx
,
146 GLuint v0
, GLuint v1
, GLuint v2
, GLuint pv
)
148 struct vertex_buffer
*VB
= ctx
->VB
;
151 GLfloat invRedScale
= ctx
->Visual
->InvRedScale
;
152 GLfloat invGreenScale
= ctx
->Visual
->InvGreenScale
;
153 GLfloat invBlueScale
= ctx
->Visual
->InvBlueScale
;
154 GLfloat invAlphaScale
= ctx
->Visual
->InvAlphaScale
;
156 FEEDBACK_TOKEN( ctx
, (GLfloat
) (GLint
) GL_POLYGON_TOKEN
);
157 FEEDBACK_TOKEN( ctx
, (GLfloat
) 3 ); /* three vertices */
159 if (ctx
->Light
.ShadeModel
==GL_FLAT
) {
160 /* flat shading - same color for each vertex */
161 color
[0] = (GLfloat
) VB
->Color
[pv
][0] * invRedScale
;
162 color
[1] = (GLfloat
) VB
->Color
[pv
][1] * invGreenScale
;
163 color
[2] = (GLfloat
) VB
->Color
[pv
][2] * invBlueScale
;
164 color
[3] = (GLfloat
) VB
->Color
[pv
][3] * invAlphaScale
;
174 else if (i
==1) v
= v1
;
179 z
= VB
->Win
[v
][2] / DEPTH_SCALE
;
182 if (ctx
->Light
.ShadeModel
==GL_SMOOTH
) {
183 /* smooth shading - different color for each vertex */
184 color
[0] = VB
->Color
[v
][0] * invRedScale
;
185 color
[1] = VB
->Color
[v
][1] * invGreenScale
;
186 color
[2] = VB
->Color
[v
][2] * invBlueScale
;
187 color
[3] = VB
->Color
[v
][3] * invAlphaScale
;
190 invq
= (VB
->TexCoord
[v
][3]==0.0) ? 1.0 : (1.0F
/ VB
->TexCoord
[v
][3]);
191 tc
[0] = VB
->TexCoord
[v
][0] * invq
;
192 tc
[1] = VB
->TexCoord
[v
][1] * invq
;
193 tc
[2] = VB
->TexCoord
[v
][2] * invq
;
194 tc
[3] = VB
->TexCoord
[v
][3];
196 gl_feedback_vertex( ctx
, x
, y
, z
, w
, color
, (GLfloat
) VB
->Index
[v
], tc
);
203 * Put triangle in selection buffer.
205 static void select_triangle( GLcontext
*ctx
,
206 GLuint v0
, GLuint v1
, GLuint v2
, GLuint pv
)
208 struct vertex_buffer
*VB
= ctx
->VB
;
210 gl_update_hitflag( ctx
, VB
->Win
[v0
][2] / DEPTH_SCALE
);
211 gl_update_hitflag( ctx
, VB
->Win
[v1
][2] / DEPTH_SCALE
);
212 gl_update_hitflag( ctx
, VB
->Win
[v2
][2] / DEPTH_SCALE
);
218 * Render a flat-shaded color index triangle.
220 static void flat_ci_triangle( GLcontext
*ctx
,
221 GLuint v0
, GLuint v1
, GLuint v2
, GLuint pv
)
226 GLuint index = VB->Index[pv]; \
227 if (!VB->MonoColor) { \
228 /* set the color index */ \
229 (*ctx->Driver.Index)( ctx, index ); \
232 #define INNER_LOOP( LEFT, RIGHT, Y ) \
234 GLint i, n = RIGHT-LEFT; \
235 GLdepth zspan[MAX_WIDTH]; \
237 for (i=0;i<n;i++) { \
241 gl_write_monoindex_span( ctx, n, LEFT, Y, \
242 zspan, index, GL_POLYGON ); \
252 * Render a smooth-shaded color index triangle.
254 static void smooth_ci_triangle( GLcontext
*ctx
,
255 GLuint v0
, GLuint v1
, GLuint v2
, GLuint pv
)
258 #define INTERP_INDEX 1
260 #define INNER_LOOP( LEFT, RIGHT, Y ) \
262 GLint i, n = RIGHT-LEFT; \
263 GLdepth zspan[MAX_WIDTH]; \
264 GLuint index[MAX_WIDTH]; \
266 for (i=0;i<n;i++) { \
268 index[i] = FixedToInt(ffi); \
272 gl_write_index_span( ctx, n, LEFT, Y, zspan, \
273 index, GL_POLYGON ); \
283 * Render a flat-shaded RGBA triangle.
285 static void flat_rgba_triangle( GLcontext
*ctx
,
286 GLuint v0
, GLuint v1
, GLuint v2
, GLuint pv
)
291 if (!VB->MonoColor) { \
292 /* set the color */ \
293 GLubyte r = VB->Color[pv][0]; \
294 GLubyte g = VB->Color[pv][1]; \
295 GLubyte b = VB->Color[pv][2]; \
296 GLubyte a = VB->Color[pv][3]; \
297 (*ctx->Driver.Color)( ctx, r, g, b, a ); \
300 #define INNER_LOOP( LEFT, RIGHT, Y ) \
302 GLint i, n = RIGHT-LEFT; \
303 GLdepth zspan[MAX_WIDTH]; \
305 for (i=0;i<n;i++) { \
309 gl_write_monocolor_span( ctx, n, LEFT, Y, zspan, \
310 VB->Color[pv][0], VB->Color[pv][1],\
311 VB->Color[pv][2], VB->Color[pv][3],\
322 * Render a smooth-shaded RGBA triangle.
324 static void smooth_rgba_triangle( GLcontext
*ctx
,
325 GLuint v0
, GLuint v1
, GLuint v2
, GLuint pv
)
329 #define INTERP_ALPHA 1
331 #define INNER_LOOP( LEFT, RIGHT, Y ) \
333 GLint i, n = RIGHT-LEFT; \
334 GLdepth zspan[MAX_WIDTH]; \
335 GLubyte red[MAX_WIDTH], green[MAX_WIDTH]; \
336 GLubyte blue[MAX_WIDTH], alpha[MAX_WIDTH]; \
338 for (i=0;i<n;i++) { \
340 red[i] = FixedToInt(ffr); \
341 green[i] = FixedToInt(ffg); \
342 blue[i] = FixedToInt(ffb); \
343 alpha[i] = FixedToInt(ffa); \
350 gl_write_color_span( ctx, n, LEFT, Y, zspan, \
351 red, green, blue, alpha, \
362 * Render an RGB, GL_DECAL, textured triangle.
363 * Interpolate S,T only w/out mipmapping or perspective correction.
365 static void simple_textured_triangle( GLcontext
*ctx
, GLuint v0
, GLuint v1
,
366 GLuint v2
, GLuint pv
)
369 #define S_SCALE twidth
370 #define T_SCALE theight
372 GLfloat twidth = (GLfloat) ctx->Texture.Current2D->Image[0]->Width; \
373 GLfloat theight = (GLfloat) ctx->Texture.Current2D->Image[0]->Height;\
374 GLint twidth_log2 = ctx->Texture.Current2D->Image[0]->WidthLog2; \
375 GLubyte *texture = ctx->Texture.Current2D->Image[0]->Data; \
376 GLint smask = ctx->Texture.Current2D->Image[0]->Width - 1; \
377 GLint tmask = ctx->Texture.Current2D->Image[0]->Height - 1;
379 #define INNER_LOOP( LEFT, RIGHT, Y ) \
381 GLint i, n = RIGHT-LEFT; \
382 GLubyte red[MAX_WIDTH], green[MAX_WIDTH]; \
383 GLubyte blue[MAX_WIDTH], alpha[MAX_WIDTH]; \
385 for (i=0;i<n;i++) { \
386 GLint s = FixedToInt(ffs) & smask; \
387 GLint t = FixedToInt(fft) & tmask; \
388 GLint pos = (t << twidth_log2) + s; \
389 pos = pos + pos + pos; /* multiply by 3 */ \
390 red[i] = texture[pos]; \
391 green[i] = texture[pos+1]; \
392 blue[i] = texture[pos+2]; \
397 (*ctx->Driver.WriteColorSpan)( ctx, n, LEFT, Y, \
398 red, green, blue, alpha, NULL ); \
408 * Render an RGB, GL_DECAL, textured triangle.
409 * Interpolate S,T, GL_LESS depth test, w/out mipmapping or
410 * perspective correction.
412 static void simple_z_textured_triangle( GLcontext
*ctx
, GLuint v0
, GLuint v1
,
413 GLuint v2
, GLuint pv
)
417 #define S_SCALE twidth
418 #define T_SCALE theight
420 GLfloat twidth = (GLfloat) ctx->Texture.Current2D->Image[0]->Width; \
421 GLfloat theight = (GLfloat) ctx->Texture.Current2D->Image[0]->Height;\
422 GLint twidth_log2 = ctx->Texture.Current2D->Image[0]->WidthLog2; \
423 GLubyte *texture = ctx->Texture.Current2D->Image[0]->Data; \
424 GLint smask = ctx->Texture.Current2D->Image[0]->Width - 1; \
425 GLint tmask = ctx->Texture.Current2D->Image[0]->Height - 1;
427 #define INNER_LOOP( LEFT, RIGHT, Y ) \
429 GLint i, n = RIGHT-LEFT; \
430 GLubyte red[MAX_WIDTH], green[MAX_WIDTH]; \
431 GLubyte blue[MAX_WIDTH], alpha[MAX_WIDTH]; \
432 GLubyte mask[MAX_WIDTH]; \
434 for (i=0;i<n;i++) { \
437 GLint s = FixedToInt(ffs) & smask; \
438 GLint t = FixedToInt(fft) & tmask; \
439 GLint pos = (t << twidth_log2) + s; \
440 pos = pos + pos + pos; /* multiply by 3 */\
441 red[i] = texture[pos]; \
442 green[i] = texture[pos+1]; \
443 blue[i] = texture[pos+2]; \
455 (*ctx->Driver.WriteColorSpan)( ctx, n, LEFT, Y, \
456 red, green, blue, alpha, mask ); \
466 * Render a smooth-shaded, textured, RGBA triangle.
467 * Interpolate S,T,U with perspective correction, w/out mipmapping.
468 * Note: we use texture coordinates S,T,U,V instead of S,T,R,Q because
469 * R is already used for red.
471 static void general_textured_triangle( GLcontext
*ctx
, GLuint v0
, GLuint v1
,
472 GLuint v2
, GLuint pv
)
476 #define INTERP_ALPHA 1
480 GLboolean flat_shade = (ctx->Light.ShadeModel==GL_FLAT); \
483 r = VB->Color[pv][0]; \
484 g = VB->Color[pv][1]; \
485 b = VB->Color[pv][2]; \
486 a = VB->Color[pv][3]; \
488 #define INNER_LOOP( LEFT, RIGHT, Y ) \
490 GLint i, n = RIGHT-LEFT; \
491 GLdepth zspan[MAX_WIDTH]; \
492 GLubyte red[MAX_WIDTH], green[MAX_WIDTH]; \
493 GLubyte blue[MAX_WIDTH], alpha[MAX_WIDTH]; \
494 GLfloat s[MAX_WIDTH], t[MAX_WIDTH], u[MAX_WIDTH]; \
497 for (i=0;i<n;i++) { \
498 GLdouble wwvvInv = 1.0 / (ww*vv); \
516 for (i=0;i<n;i++) { \
517 GLdouble wwvvInv = 1.0 / (ww*vv); \
519 red[i] = FixedToInt(ffr); \
520 green[i] = FixedToInt(ffg); \
521 blue[i] = FixedToInt(ffb); \
522 alpha[i] = FixedToInt(ffa); \
538 gl_write_texture_span( ctx, n, LEFT, Y, zspan, \
540 red, green, blue, alpha, \
551 * Compute the lambda value (texture level value) for a fragment.
553 static GLfloat
compute_lambda( GLfloat s
, GLfloat t
,
554 GLfloat dsdx
, GLfloat dsdy
,
555 GLfloat dtdx
, GLfloat dtdy
,
556 GLfloat w
, GLfloat dwdx
, GLfloat dwdy
,
557 GLfloat width
, GLfloat height
)
559 /* TODO: this function can probably be optimized a bit */
560 GLfloat invw
= 1.0 / w
;
561 GLfloat dudx
, dudy
, dvdx
, dvdy
;
562 GLfloat r1
, r2
, rho2
;
564 dudx
= (dsdx
- s
*dwdx
) * invw
* width
;
565 dudy
= (dsdy
- s
*dwdy
) * invw
* width
;
566 dvdx
= (dtdx
- t
*dwdx
) * invw
* height
;
567 dvdy
= (dtdy
- t
*dwdy
) * invw
* height
;
569 r1
= dudx
* dudx
+ dudy
* dudy
;
570 r2
= dvdx
* dvdx
+ dvdy
* dvdy
;
572 /* rho2 = MAX2(r1,r2); */
578 /* return log base 2 of rho */
579 return log(rho2
) * 1.442695 * 0.5; /* 1.442695 = 1/log(2) */
586 * Render a smooth-shaded, textured, RGBA triangle.
587 * Interpolate S,T,U with perspective correction and compute lambda for
588 * each fragment. Lambda is used to determine whether to use the
589 * minification or magnification filter. If minification and using
590 * mipmaps, lambda is also used to select the texture level of detail.
592 static void lambda_textured_triangle( GLcontext
*ctx
, GLuint v0
, GLuint v1
,
593 GLuint v2
, GLuint pv
)
597 #define INTERP_ALPHA 1
602 GLboolean flat_shade = (ctx->Light.ShadeModel==GL_FLAT); \
604 GLfloat twidth, theight; \
605 if (ctx->Texture.Enabled & TEXTURE_2D) { \
606 twidth = (GLfloat) ctx->Texture.Current2D->Image[0]->Width; \
607 theight = (GLfloat) ctx->Texture.Current2D->Image[0]->Height; \
610 twidth = (GLfloat) ctx->Texture.Current1D->Image[0]->Width; \
614 r = VB->Color[pv][0]; \
615 g = VB->Color[pv][1]; \
616 b = VB->Color[pv][2]; \
617 a = VB->Color[pv][3]; \
620 #define INNER_LOOP( LEFT, RIGHT, Y ) \
622 GLint i, n = RIGHT-LEFT; \
623 GLdepth zspan[MAX_WIDTH]; \
624 GLubyte red[MAX_WIDTH], green[MAX_WIDTH]; \
625 GLubyte blue[MAX_WIDTH], alpha[MAX_WIDTH]; \
626 GLfloat s[MAX_WIDTH], t[MAX_WIDTH], u[MAX_WIDTH]; \
627 DEFARRAY(GLfloat,lambda,MAX_WIDTH); \
630 for (i=0;i<n;i++) { \
631 GLdouble wwvvInv = 1.0 / (ww*vv); \
640 lambda[i] = compute_lambda( s[i], t[i], \
654 for (i=0;i<n;i++) { \
655 GLdouble wwvvInv = 1.0 / (ww*vv); \
657 red[i] = FixedToInt(ffr); \
658 green[i] = FixedToInt(ffg); \
659 blue[i] = FixedToInt(ffb); \
660 alpha[i] = FixedToInt(ffa); \
664 lambda[i] = compute_lambda( s[i], t[i], \
681 gl_write_texture_span( ctx, n, LEFT, Y, zspan, \
683 red, green, blue, alpha, \
686 UNDEFARRAY(lambda); \
695 * Null rasterizer for measuring transformation speed.
697 static void null_triangle( GLcontext
*ctx
, GLuint v0
, GLuint v1
,
698 GLuint v2
, GLuint pv
)
705 * Determine which triangle rendering function to use given the current
708 void gl_set_triangle_function( GLcontext
*ctx
)
710 GLboolean rgbmode
= ctx
->Visual
->RGBAflag
;
712 if (ctx
->RenderMode
==GL_RENDER
) {
714 ctx
->Driver
.TriangleFunc
= null_triangle
;
717 if (ctx
->Driver
.TriangleFunc
) {
718 /* Device driver will draw triangles. */
720 else if (ctx
->Texture
.Enabled
721 && ctx
->Texture
.Current
722 && ctx
->Texture
.Current
->Complete
) {
723 if ( (ctx
->Texture
.Enabled
==TEXTURE_2D
)
724 && ctx
->Texture
.Current2D
->MinFilter
==GL_NEAREST
725 && ctx
->Texture
.Current2D
->MagFilter
==GL_NEAREST
726 && ctx
->Texture
.Current2D
->WrapS
==GL_REPEAT
727 && ctx
->Texture
.Current2D
->WrapT
==GL_REPEAT
728 && ctx
->Texture
.Current2D
->Image
[0]->Format
==GL_RGB
729 && ctx
->Texture
.Current2D
->Image
[0]->Border
==0
730 && (ctx
->Texture
.EnvMode
==GL_DECAL
731 || ctx
->Texture
.EnvMode
==GL_REPLACE
)
732 && ctx
->Hint
.PerspectiveCorrection
==GL_FASTEST
733 && ctx
->TextureMatrixType
==MATRIX_IDENTITY
734 && ((ctx
->RasterMask
==DEPTH_BIT
735 && ctx
->Depth
.Func
==GL_LESS
736 && ctx
->Depth
.Mask
==GL_TRUE
)
737 || ctx
->RasterMask
==0)
738 && ctx
->Polygon
.StippleFlag
==GL_FALSE
739 && ctx
->Visual
->EightBitColor
) {
740 if (ctx
->RasterMask
==DEPTH_BIT
) {
741 ctx
->Driver
.TriangleFunc
= simple_z_textured_triangle
;
744 ctx
->Driver
.TriangleFunc
= simple_textured_triangle
;
748 GLboolean needLambda
= GL_TRUE
;
749 /* if mag filter == min filter we're not mipmapping */
750 if (ctx
->Texture
.Enabled
& TEXTURE_2D
) {
751 if (ctx
->Texture
.Current2D
->MinFilter
==
752 ctx
->Texture
.Current2D
->MagFilter
) {
753 needLambda
= GL_FALSE
;
756 else if (ctx
->Texture
.Enabled
& TEXTURE_1D
) {
757 if (ctx
->Texture
.Current1D
->MinFilter
==
758 ctx
->Texture
.Current1D
->MagFilter
) {
759 needLambda
= GL_FALSE
;
763 ctx
->Driver
.TriangleFunc
= lambda_textured_triangle
;
765 ctx
->Driver
.TriangleFunc
= general_textured_triangle
;
769 if (ctx
->Light
.ShadeModel
==GL_SMOOTH
) {
770 /* smooth shaded, no texturing, stippled or some raster ops */
772 ctx
->Driver
.TriangleFunc
= smooth_rgba_triangle
;
774 ctx
->Driver
.TriangleFunc
= smooth_ci_triangle
;
777 /* flat shaded, no texturing, stippled or some raster ops */
779 ctx
->Driver
.TriangleFunc
= flat_rgba_triangle
;
781 ctx
->Driver
.TriangleFunc
= flat_ci_triangle
;
785 else if (ctx
->RenderMode
==GL_FEEDBACK
) {
786 ctx
->Driver
.TriangleFunc
= feedback_triangle
;
790 ctx
->Driver
.TriangleFunc
= select_triangle
;