1 /*
2  * Mesa 3-D graphics library
3  *
4  * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * OTHER DEALINGS IN THE SOFTWARE.
23  */
24 
25 
26 #include "main/glheader.h"
27 #include "main/context.h"
28 #include "main/macros.h"
29 #include "s_aaline.h"
30 #include "s_context.h"
31 #include "s_feedback.h"
32 #include "s_lines.h"
33 #include "s_span.h"
34 
35 
36 /*
37  * Init the mask[] array to implement a line stipple.
38  */
39 static void
compute_stipple_mask(struct gl_context * ctx,GLuint len,GLubyte mask[])40 compute_stipple_mask( struct gl_context *ctx, GLuint len, GLubyte mask[] )
41 {
42    SWcontext *swrast = SWRAST_CONTEXT(ctx);
43    GLuint i;
44 
45    for (i = 0; i < len; i++) {
46       GLuint bit = (swrast->StippleCounter / ctx->Line.StippleFactor) & 0xf;
47       if ((1 << bit) & ctx->Line.StipplePattern) {
48          mask[i] = GL_TRUE;
49       }
50       else {
51          mask[i] = GL_FALSE;
52       }
53       swrast->StippleCounter++;
54    }
55 }
56 
57 
58 /*
59  * To draw a wide line we can simply redraw the span N times, side by side.
60  */
61 static void
draw_wide_line(struct gl_context * ctx,SWspan * span,GLboolean xMajor)62 draw_wide_line( struct gl_context *ctx, SWspan *span, GLboolean xMajor )
63 {
64    const GLint width = (GLint) CLAMP(ctx->Line.Width,
65                                      ctx->Const.MinLineWidth,
66                                      ctx->Const.MaxLineWidth);
67    GLint start;
68 
69    assert(span->end < SWRAST_MAX_WIDTH);
70 
71    if (width & 1)
72       start = width / 2;
73    else
74       start = width / 2 - 1;
75 
76    if (xMajor) {
77       GLint *y = span->array->y;
78       GLuint i;
79       GLint w;
80       for (w = 0; w < width; w++) {
81          if (w == 0) {
82             for (i = 0; i < span->end; i++)
83                y[i] -= start;
84          }
85          else {
86             for (i = 0; i < span->end; i++)
87                y[i]++;
88          }
89 	 _swrast_write_rgba_span(ctx, span);
90       }
91    }
92    else {
93       GLint *x = span->array->x;
94       GLuint i;
95       GLint w;
96       for (w = 0; w < width; w++) {
97          if (w == 0) {
98             for (i = 0; i < span->end; i++)
99                x[i] -= start;
100          }
101          else {
102             for (i = 0; i < span->end; i++)
103                x[i]++;
104          }
105 	 _swrast_write_rgba_span(ctx, span);
106       }
107    }
108 }
109 
110 
111 
112 /**********************************************************************/
113 /*****                    Rasterization                           *****/
114 /**********************************************************************/
115 
116 /* Simple RGBA index line (no stipple, width=1, no Z, no fog, no tex)*/
117 #define NAME simple_no_z_rgba_line
118 #define INTERP_RGBA
119 #define RENDER_SPAN(span) _swrast_write_rgba_span(ctx, &span);
120 #include "s_linetemp.h"
121 
122 
123 /* Z, fog, wide, stipple RGBA line */
124 #define NAME rgba_line
125 #define INTERP_RGBA
126 #define INTERP_Z
127 #define RENDER_SPAN(span)					\
128    if (ctx->Line.StippleFlag) {					\
129       span.arrayMask |= SPAN_MASK;				\
130       compute_stipple_mask(ctx, span.end, span.array->mask);	\
131    }								\
132    if (ctx->Line.Width > 1.0) {					\
133       draw_wide_line(ctx, &span, (GLboolean)(dx > dy));		\
134    }								\
135    else {							\
136       _swrast_write_rgba_span(ctx, &span);			\
137    }
138 #include "s_linetemp.h"
139 
140 
141 /* General-purpose line (any/all features). */
142 #define NAME general_line
143 #define INTERP_RGBA
144 #define INTERP_Z
145 #define INTERP_ATTRIBS
146 #define RENDER_SPAN(span)					\
147    if (ctx->Line.StippleFlag) {					\
148       span.arrayMask |= SPAN_MASK;				\
149       compute_stipple_mask(ctx, span.end, span.array->mask);	\
150    }								\
151    if (ctx->Line.Width > 1.0) {					\
152       draw_wide_line(ctx, &span, (GLboolean)(dx > dy));		\
153    }								\
154    else {							\
155       _swrast_write_rgba_span(ctx, &span);			\
156    }
157 #include "s_linetemp.h"
158 
159 
160 
161 void
_swrast_add_spec_terms_line(struct gl_context * ctx,const SWvertex * v0,const SWvertex * v1)162 _swrast_add_spec_terms_line(struct gl_context *ctx,
163                             const SWvertex *v0, const SWvertex *v1)
164 {
165    SWvertex *ncv0 = (SWvertex *)v0;
166    SWvertex *ncv1 = (SWvertex *)v1;
167    GLfloat rSum, gSum, bSum;
168    GLchan cSave[2][4];
169 
170    /* save original colors */
171    COPY_CHAN4(cSave[0], ncv0->color);
172    COPY_CHAN4(cSave[1], ncv1->color);
173    /* sum v0 */
174    rSum = CHAN_TO_FLOAT(ncv0->color[0]) + ncv0->attrib[VARYING_SLOT_COL1][0];
175    gSum = CHAN_TO_FLOAT(ncv0->color[1]) + ncv0->attrib[VARYING_SLOT_COL1][1];
176    bSum = CHAN_TO_FLOAT(ncv0->color[2]) + ncv0->attrib[VARYING_SLOT_COL1][2];
177    UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[0], rSum);
178    UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[1], gSum);
179    UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[2], bSum);
180    /* sum v1 */
181    rSum = CHAN_TO_FLOAT(ncv1->color[0]) + ncv1->attrib[VARYING_SLOT_COL1][0];
182    gSum = CHAN_TO_FLOAT(ncv1->color[1]) + ncv1->attrib[VARYING_SLOT_COL1][1];
183    bSum = CHAN_TO_FLOAT(ncv1->color[2]) + ncv1->attrib[VARYING_SLOT_COL1][2];
184    UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[0], rSum);
185    UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[1], gSum);
186    UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[2], bSum);
187    /* draw */
188    SWRAST_CONTEXT(ctx)->SpecLine( ctx, ncv0, ncv1 );
189    /* restore original colors */
190    COPY_CHAN4(ncv0->color, cSave[0]);
191    COPY_CHAN4(ncv1->color, cSave[1]);
192 }
193 
194 
195 
196 #ifdef DEBUG
197 
198 /* record the current line function name */
199 static const char *lineFuncName = NULL;
200 
201 #define USE(lineFunc)                   \
202 do {                                    \
203     lineFuncName = #lineFunc;           \
204     /*printf("%s\n", lineFuncName);*/   \
205     swrast->Line = lineFunc;            \
206 } while (0)
207 
208 #else
209 
210 #define USE(lineFunc)  swrast->Line = lineFunc
211 
212 #endif
213 
214 
215 
216 /**
217  * Determine which line drawing function to use given the current
218  * rendering context.
219  *
220  * Please update the summary flag _SWRAST_NEW_LINE if you add or remove
221  * tests to this code.
222  */
223 void
_swrast_choose_line(struct gl_context * ctx)224 _swrast_choose_line( struct gl_context *ctx )
225 {
226    SWcontext *swrast = SWRAST_CONTEXT(ctx);
227    GLboolean specular = (ctx->Fog.ColorSumEnabled ||
228                          (ctx->Light.Enabled &&
229                           ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR));
230 
231    if (ctx->RenderMode == GL_RENDER) {
232       if (ctx->Line.SmoothFlag) {
233          /* antialiased lines */
234          _swrast_choose_aa_line_function(ctx);
235          assert(swrast->Line);
236       }
237       else if (ctx->Texture._EnabledCoordUnits
238                || _swrast_use_fragment_program(ctx)
239                || swrast->_FogEnabled
240                || specular) {
241          USE(general_line);
242       }
243       else if (ctx->Depth.Test
244                || ctx->Line.Width != 1.0F
245                || ctx->Line.StippleFlag) {
246          /* no texture, but Z, fog, width>1, stipple, etc. */
247 #if CHAN_BITS == 32
248          USE(general_line);
249 #else
250          USE(rgba_line);
251 #endif
252       }
253       else {
254          assert(!ctx->Depth.Test);
255          assert(ctx->Line.Width == 1.0F);
256          /* simple lines */
257          USE(simple_no_z_rgba_line);
258       }
259    }
260    else if (ctx->RenderMode == GL_FEEDBACK) {
261       USE(_swrast_feedback_line);
262    }
263    else {
264       assert(ctx->RenderMode == GL_SELECT);
265       USE(_swrast_select_line);
266    }
267 }
268