97143a2f4b715ffbd6f673b2a5273bf265366746
[mesa.git] / src / mesa / swrast / s_lines.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 5.1
4 *
5 * Copyright (C) 1999-2003 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
25
26 #include "glheader.h"
27 #include "colormac.h"
28 #include "macros.h"
29 #include "s_aaline.h"
30 #include "s_context.h"
31 #include "s_depth.h"
32 #include "s_feedback.h"
33 #include "s_lines.h"
34 #include "s_span.h"
35
36
37 /*
38 * Init the mask[] array to implement a line stipple.
39 */
40 static void
41 compute_stipple_mask( GLcontext *ctx, GLuint len, GLubyte mask[] )
42 {
43 SWcontext *swrast = SWRAST_CONTEXT(ctx);
44 GLuint i;
45
46 for (i = 0; i < len; i++) {
47 GLuint bit = (swrast->StippleCounter / ctx->Line.StippleFactor) & 0xf;
48 if ((1 << bit) & ctx->Line.StipplePattern) {
49 mask[i] = GL_TRUE;
50 }
51 else {
52 mask[i] = GL_FALSE;
53 }
54 swrast->StippleCounter++;
55 }
56 }
57
58
59 /*
60 * To draw a wide line we can simply redraw the span N times, side by side.
61 */
62 static void
63 draw_wide_line( GLcontext *ctx, struct sw_span *span, GLboolean xMajor )
64 {
65 GLint width, start;
66
67 ASSERT(span->end < MAX_WIDTH);
68
69 width = (GLint) CLAMP( ctx->Line.Width, MIN_LINE_WIDTH, MAX_LINE_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 if ((span->interpMask | span->arrayMask) & SPAN_TEXTURE)
90 _swrast_write_texture_span(ctx, span);
91 else if ((span->interpMask | span->arrayMask) & SPAN_RGBA)
92 _swrast_write_rgba_span(ctx, span);
93 else
94 _swrast_write_index_span(ctx, span);
95 }
96 }
97 else {
98 GLint *x = span->array->x;
99 GLuint i;
100 GLint w;
101 for (w = 0; w < width; w++) {
102 if (w == 0) {
103 for (i = 0; i < span->end; i++)
104 x[i] -= start;
105 }
106 else {
107 for (i = 0; i < span->end; i++)
108 x[i]++;
109 }
110 if ((span->interpMask | span->arrayMask) & SPAN_TEXTURE)
111 _swrast_write_texture_span(ctx, span);
112 else if ((span->interpMask | span->arrayMask) & SPAN_RGBA)
113 _swrast_write_rgba_span(ctx, span);
114 else
115 _swrast_write_index_span(ctx, span);
116 }
117 }
118 }
119
120
121
122 /**********************************************************************/
123 /***** Rasterization *****/
124 /**********************************************************************/
125
126 /* Simple color index line (no stipple, width=1, no Z, no fog, no tex)*/
127 #define NAME simple_ci_line
128 #define INTERP_INDEX
129 #define RENDER_SPAN(span) _swrast_write_index_span(ctx, &span)
130 #include "s_linetemp.h"
131
132 /* Simple RGBA index line (no stipple, width=1, no Z, no fog, no tex)*/
133 #define NAME simple_rgba_line
134 #define INTERP_RGBA
135 #define RENDER_SPAN(span) _swrast_write_rgba_span(ctx, &span);
136 #include "s_linetemp.h"
137
138
139 /* Z, fog, wide, stipple color index line */
140 #define NAME general_ci_line
141 #define INTERP_INDEX
142 #define INTERP_Z
143 #define INTERP_FOG
144 #define RENDER_SPAN(span) \
145 if (ctx->Line.StippleFlag) { \
146 span.arrayMask |= SPAN_MASK; \
147 compute_stipple_mask(ctx, span.end, span.array->mask); \
148 } \
149 if (ctx->Line.Width > 1.0) { \
150 draw_wide_line(ctx, &span, (GLboolean)(dx > dy)); \
151 } \
152 else { \
153 _swrast_write_index_span(ctx, &span); \
154 }
155 #include "s_linetemp.h"
156
157
158 /* Z, fog, wide, stipple RGBA line */
159 #define NAME general_rgba_line
160 #define INTERP_RGBA
161 #define INTERP_Z
162 #define INTERP_FOG
163 #define RENDER_SPAN(span) \
164 if (ctx->Line.StippleFlag) { \
165 span.arrayMask |= SPAN_MASK; \
166 compute_stipple_mask(ctx, span.end, span.array->mask); \
167 } \
168 if (ctx->Line.Width > 1.0) { \
169 draw_wide_line(ctx, &span, (GLboolean)(dx > dy)); \
170 } \
171 else { \
172 _swrast_write_rgba_span(ctx, &span); \
173 }
174 #include "s_linetemp.h"
175
176
177 /* Single-texture line, w/ fog, Z, specular, etc. */
178 #define NAME textured_line
179 #define INTERP_RGBA
180 #define INTERP_Z
181 #define INTERP_FOG
182 #define INTERP_TEX
183 #define RENDER_SPAN(span) \
184 if (ctx->Line.StippleFlag) { \
185 span.arrayMask |= SPAN_MASK; \
186 compute_stipple_mask(ctx, span.end, span.array->mask); \
187 } \
188 if (ctx->Line.Width > 1.0) { \
189 draw_wide_line(ctx, &span, (GLboolean)(dx > dy)); \
190 } \
191 else { \
192 _swrast_write_texture_span(ctx, &span); \
193 }
194 #include "s_linetemp.h"
195
196
197 /* Multi-texture or separate specular line, w/ fog, Z, specular, etc. */
198 #define NAME multitextured_line
199 #define INTERP_RGBA
200 #define INTERP_SPEC
201 #define INTERP_Z
202 #define INTERP_FOG
203 #define INTERP_MULTITEX
204 #define RENDER_SPAN(span) \
205 if (ctx->Line.StippleFlag) { \
206 span.arrayMask |= SPAN_MASK; \
207 compute_stipple_mask(ctx, span.end, span.array->mask); \
208 } \
209 if (ctx->Line.Width > 1.0) { \
210 draw_wide_line(ctx, &span, (GLboolean)(dx > dy)); \
211 } \
212 else { \
213 _swrast_write_texture_span(ctx, &span); \
214 }
215 #include "s_linetemp.h"
216
217
218
219 void
220 _swrast_add_spec_terms_line( GLcontext *ctx,
221 const SWvertex *v0,
222 const SWvertex *v1 )
223 {
224 SWvertex *ncv0 = (SWvertex *)v0;
225 SWvertex *ncv1 = (SWvertex *)v1;
226 GLchan c[2][4];
227 COPY_CHAN4( c[0], ncv0->color );
228 COPY_CHAN4( c[1], ncv1->color );
229 ACC_3V( ncv0->color, ncv0->specular );
230 ACC_3V( ncv1->color, ncv1->specular );
231 SWRAST_CONTEXT(ctx)->SpecLine( ctx, ncv0, ncv1 );
232 COPY_CHAN4( ncv0->color, c[0] );
233 COPY_CHAN4( ncv1->color, c[1] );
234 }
235
236
237 #ifdef DEBUG
238 extern void
239 _mesa_print_line_function(GLcontext *ctx); /* silence compiler warning */
240 void
241 _mesa_print_line_function(GLcontext *ctx)
242 {
243 SWcontext *swrast = SWRAST_CONTEXT(ctx);
244
245 _mesa_printf("Line Func == ");
246 if (swrast->Line == simple_ci_line)
247 _mesa_printf("simple_ci_line\n");
248 else if (swrast->Line == simple_rgba_line)
249 _mesa_printf("simple_rgba_line\n");
250 else if (swrast->Line == general_ci_line)
251 _mesa_printf("general_ci_line\n");
252 else if (swrast->Line == general_rgba_line)
253 _mesa_printf("general_rgba_line\n");
254 else if (swrast->Line == textured_line)
255 _mesa_printf("textured_line\n");
256 else if (swrast->Line == multitextured_line)
257 _mesa_printf("multitextured_line\n");
258 else
259 _mesa_printf("Driver func %p\n", (void *) swrast->Line);
260 }
261 #endif
262
263
264
265 #ifdef DEBUG
266
267 /* record the current line function name */
268 static const char *lineFuncName = NULL;
269
270 #define USE(lineFunc) \
271 do { \
272 lineFuncName = #lineFunc; \
273 /*_mesa_printf("%s\n", lineFuncName);*/ \
274 swrast->Line = lineFunc; \
275 } while (0)
276
277 #else
278
279 #define USE(lineFunc) swrast->Line = lineFunc
280
281 #endif
282
283
284
285 /*
286 * Determine which line drawing function to use given the current
287 * rendering context.
288 *
289 * Please update the summary flag _SWRAST_NEW_LINE if you add or remove
290 * tests to this code.
291 */
292 void
293 _swrast_choose_line( GLcontext *ctx )
294 {
295 SWcontext *swrast = SWRAST_CONTEXT(ctx);
296 const GLboolean rgbmode = ctx->Visual.rgbMode;
297
298 if (ctx->RenderMode == GL_RENDER) {
299 if (ctx->Line.SmoothFlag) {
300 /* antialiased lines */
301 _swrast_choose_aa_line_function(ctx);
302 ASSERT(swrast->Line);
303 }
304 else if (ctx->Texture._EnabledCoordUnits) {
305 /* textured lines */
306 if (ctx->Texture._EnabledCoordUnits > 0x1
307 || (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR)) {
308 /* multi-texture and/or separate specular color */
309 USE(multitextured_line);
310 }
311 else {
312 USE(textured_line);
313 }
314 }
315 else if (ctx->Depth.Test || ctx->Fog.Enabled || ctx->Line.Width != 1.0
316 || ctx->Line.StippleFlag) {
317 /* no texture, but Z, fog, width>1, stipple, etc. */
318 if (rgbmode)
319 USE(general_rgba_line);
320 else
321 USE(general_ci_line);
322 }
323 else {
324 /* simplest lines */
325 if (rgbmode)
326 USE(simple_rgba_line);
327 else
328 USE(simple_ci_line);
329 }
330 }
331 else if (ctx->RenderMode == GL_FEEDBACK) {
332 USE(_swrast_feedback_line);
333 }
334 else {
335 ASSERT(ctx->RenderMode == GL_SELECT);
336 USE(_swrast_select_line);
337 }
338
339 /*_mesa_print_line_function(ctx);*/
340 }