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