1/*
2 * Mesa 3-D graphics library
3 * Version:  7.1
4 *
5 * Copyright (C) 1999-2007  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 * Authors:
25 *    Keith Whitwell <keith@tungstengraphics.com>
26 */
27
28#include "main/glheader.h"
29#include "main/colormac.h"
30#include "main/macros.h"
31#include "main/mtypes.h"
32
33#include "tnl/t_context.h"
34
35#include "ss_triangle.h"
36#include "ss_context.h"
37
38#define SS_OFFSET_BIT	    0x1
39#define SS_TWOSIDE_BIT	    0x2
40#define SS_UNFILLED_BIT	    0x4
41#define SS_MAX_TRIFUNC      0x8
42
43static tnl_triangle_func tri_tab[SS_MAX_TRIFUNC];
44static tnl_quad_func     quad_tab[SS_MAX_TRIFUNC];
45
46
47/*
48 * Render a triangle respecting edge flags.
49 */
50typedef void (* swsetup_edge_render_prim_tri)(struct gl_context *ctx,
51                                              const GLubyte *ef,
52                                              GLuint e0,
53                                              GLuint e1,
54                                              GLuint e2,
55                                              const SWvertex *v0,
56                                              const SWvertex *v1,
57                                              const SWvertex *v2);
58
59/*
60 * Render a triangle using lines and respecting edge flags.
61 */
62static void
63_swsetup_edge_render_line_tri(struct gl_context *ctx,
64                              const GLubyte *ef,
65                              GLuint e0,
66                              GLuint e1,
67                              GLuint e2,
68                              const SWvertex *v0,
69                              const SWvertex *v1,
70                              const SWvertex *v2)
71{
72   SScontext *swsetup = SWSETUP_CONTEXT(ctx);
73
74   if (swsetup->render_prim == GL_POLYGON) {
75      if (ef[e2]) _swrast_Line( ctx, v2, v0 );
76      if (ef[e0]) _swrast_Line( ctx, v0, v1 );
77      if (ef[e1]) _swrast_Line( ctx, v1, v2 );
78   } else {
79      if (ef[e0]) _swrast_Line( ctx, v0, v1 );
80      if (ef[e1]) _swrast_Line( ctx, v1, v2 );
81      if (ef[e2]) _swrast_Line( ctx, v2, v0 );
82   }
83}
84
85/*
86 * Render a triangle using points and respecting edge flags.
87 */
88static void
89_swsetup_edge_render_point_tri(struct gl_context *ctx,
90                               const GLubyte *ef,
91                               GLuint e0,
92                               GLuint e1,
93                               GLuint e2,
94                               const SWvertex *v0,
95                               const SWvertex *v1,
96                               const SWvertex *v2)
97{
98   if (ef[e0]) _swrast_Point( ctx, v0 );
99   if (ef[e1]) _swrast_Point( ctx, v1 );
100   if (ef[e2]) _swrast_Point( ctx, v2 );
101
102   _swrast_flush(ctx);
103}
104
105/*
106 * Render a triangle respecting cull and shade model.
107 */
108static void _swsetup_render_tri(struct gl_context *ctx,
109                                GLuint e0,
110                                GLuint e1,
111                                GLuint e2,
112                                GLuint facing,
113                                swsetup_edge_render_prim_tri render)
114{
115   SScontext *swsetup = SWSETUP_CONTEXT(ctx);
116   struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
117   GLubyte *ef = VB->EdgeFlag;
118   SWvertex *verts = swsetup->verts;
119   SWvertex *v0 = &verts[e0];
120   SWvertex *v1 = &verts[e1];
121   SWvertex *v2 = &verts[e2];
122
123   /* cull testing */
124   if (ctx->Polygon.CullFlag) {
125      if (facing == 1 && ctx->Polygon.CullFaceMode != GL_FRONT)
126         return;
127      if (facing == 0 && ctx->Polygon.CullFaceMode != GL_BACK)
128         return;
129   }
130
131   _swrast_SetFacing(ctx, facing);
132
133   if (ctx->Light.ShadeModel == GL_FLAT) {
134      GLchan c[2][4];
135      GLfloat s[2][4];
136
137      /* save colors/indexes for v0, v1 vertices */
138      COPY_CHAN4(c[0], v0->color);
139      COPY_CHAN4(c[1], v1->color);
140      COPY_4V(s[0], v0->attrib[FRAG_ATTRIB_COL1]);
141      COPY_4V(s[1], v1->attrib[FRAG_ATTRIB_COL1]);
142
143      /* copy v2 color/indexes to v0, v1 indexes */
144      COPY_CHAN4(v0->color, v2->color);
145      COPY_CHAN4(v1->color, v2->color);
146      COPY_4V(v0->attrib[FRAG_ATTRIB_COL1], v2->attrib[FRAG_ATTRIB_COL1]);
147      COPY_4V(v1->attrib[FRAG_ATTRIB_COL1], v2->attrib[FRAG_ATTRIB_COL1]);
148
149      render(ctx, ef, e0, e1, e2, v0, v1, v2);
150
151      COPY_CHAN4(v0->color, c[0]);
152      COPY_CHAN4(v1->color, c[1]);
153      COPY_4V(v0->attrib[FRAG_ATTRIB_COL1], s[0]);
154      COPY_4V(v1->attrib[FRAG_ATTRIB_COL1], s[1]);
155   }
156   else {
157      render(ctx, ef, e0, e1, e2, v0, v1, v2);
158   }
159}
160
161#define SS_COLOR(a,b) UNCLAMPED_FLOAT_TO_RGBA_CHAN(a,b)
162#define SS_SPEC(a,b) COPY_4V(a,b)
163#define SS_IND(a,b) (a = b)
164
165#define IND (0)
166#define TAG(x) x##_rgba
167#include "ss_tritmp.h"
168
169#define IND (SS_OFFSET_BIT)
170#define TAG(x) x##_offset_rgba
171#include "ss_tritmp.h"
172
173#define IND (SS_TWOSIDE_BIT)
174#define TAG(x) x##_twoside_rgba
175#include "ss_tritmp.h"
176
177#define IND (SS_OFFSET_BIT|SS_TWOSIDE_BIT)
178#define TAG(x) x##_offset_twoside_rgba
179#include "ss_tritmp.h"
180
181#define IND (SS_UNFILLED_BIT)
182#define TAG(x) x##_unfilled_rgba
183#include "ss_tritmp.h"
184
185#define IND (SS_OFFSET_BIT|SS_UNFILLED_BIT)
186#define TAG(x) x##_offset_unfilled_rgba
187#include "ss_tritmp.h"
188
189#define IND (SS_TWOSIDE_BIT|SS_UNFILLED_BIT)
190#define TAG(x) x##_twoside_unfilled_rgba
191#include "ss_tritmp.h"
192
193#define IND (SS_OFFSET_BIT|SS_TWOSIDE_BIT|SS_UNFILLED_BIT)
194#define TAG(x) x##_offset_twoside_unfilled_rgba
195#include "ss_tritmp.h"
196
197
198void _swsetup_trifuncs_init( struct gl_context *ctx )
199{
200   (void) ctx;
201
202   init_rgba();
203   init_offset_rgba();
204   init_twoside_rgba();
205   init_offset_twoside_rgba();
206   init_unfilled_rgba();
207   init_offset_unfilled_rgba();
208   init_twoside_unfilled_rgba();
209   init_offset_twoside_unfilled_rgba();
210}
211
212
213static void swsetup_points( struct gl_context *ctx, GLuint first, GLuint last )
214{
215   struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
216   SWvertex *verts = SWSETUP_CONTEXT(ctx)->verts;
217   GLuint i;
218
219   if (VB->Elts) {
220      for (i = first; i < last; i++)
221	 if (VB->ClipMask[VB->Elts[i]] == 0)
222	    _swrast_Point( ctx, &verts[VB->Elts[i]] );
223   }
224   else {
225      for (i = first; i < last; i++)
226	 if (VB->ClipMask[i] == 0)
227	    _swrast_Point( ctx, &verts[i] );
228   }
229}
230
231static void swsetup_line( struct gl_context *ctx, GLuint v0, GLuint v1 )
232{
233   SWvertex *verts = SWSETUP_CONTEXT(ctx)->verts;
234   _swrast_Line( ctx, &verts[v0], &verts[v1] );
235}
236
237
238
239void _swsetup_choose_trifuncs( struct gl_context *ctx )
240{
241   TNLcontext *tnl = TNL_CONTEXT(ctx);
242   GLuint ind = 0;
243
244   if (ctx->Polygon.OffsetPoint ||
245       ctx->Polygon.OffsetLine ||
246       ctx->Polygon.OffsetFill)
247      ind |= SS_OFFSET_BIT;
248
249   if ((ctx->Light.Enabled && ctx->Light.Model.TwoSide) ||
250       (ctx->VertexProgram._Current && ctx->VertexProgram.TwoSideEnabled))
251      ind |= SS_TWOSIDE_BIT;
252
253   /* We piggyback the two-sided stencil front/back determination on the
254    * unfilled triangle path.
255    */
256   if (ctx->Polygon.FrontMode != GL_FILL ||
257       ctx->Polygon.BackMode != GL_FILL ||
258       (ctx->Stencil.Enabled && ctx->Stencil._TestTwoSide))
259      ind |= SS_UNFILLED_BIT;
260
261   tnl->Driver.Render.Triangle = tri_tab[ind];
262   tnl->Driver.Render.Quad = quad_tab[ind];
263   tnl->Driver.Render.Line = swsetup_line;
264   tnl->Driver.Render.Points = swsetup_points;
265}
266