s_lines.c revision 4a49301e
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
25
26#include "main/glheader.h"
27#include "main/context.h"
28#include "main/colormac.h"
29#include "main/macros.h"
30#include "s_aaline.h"
31#include "s_context.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 */
40static void
41compute_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 */
62static void
63draw_wide_line( GLcontext *ctx, SWspan *span, GLboolean xMajor )
64{
65   const GLint width = (GLint) CLAMP(ctx->Line.Width,
66                                     ctx->Const.MinLineWidth,
67                                     ctx->Const.MaxLineWidth);
68   GLint start;
69
70   ASSERT(span->end < MAX_WIDTH);
71
72   if (width & 1)
73      start = width / 2;
74   else
75      start = width / 2 - 1;
76
77   if (xMajor) {
78      GLint *y = span->array->y;
79      GLuint i;
80      GLint w;
81      for (w = 0; w < width; w++) {
82         if (w == 0) {
83            for (i = 0; i < span->end; i++)
84               y[i] -= start;
85         }
86         else {
87            for (i = 0; i < span->end; i++)
88               y[i]++;
89         }
90         if (ctx->Visual.rgbMode)
91            _swrast_write_rgba_span(ctx, span);
92         else
93            _swrast_write_index_span(ctx, span);
94      }
95   }
96   else {
97      GLint *x = span->array->x;
98      GLuint i;
99      GLint w;
100      for (w = 0; w < width; w++) {
101         if (w == 0) {
102            for (i = 0; i < span->end; i++)
103               x[i] -= start;
104         }
105         else {
106            for (i = 0; i < span->end; i++)
107               x[i]++;
108         }
109         if (ctx->Visual.rgbMode)
110            _swrast_write_rgba_span(ctx, span);
111         else
112            _swrast_write_index_span(ctx, span);
113      }
114   }
115}
116
117
118
119/**********************************************************************/
120/*****                    Rasterization                           *****/
121/**********************************************************************/
122
123/* Simple color index line (no stipple, width=1, no Z, no fog, no tex)*/
124#define NAME simple_no_z_ci_line
125#define INTERP_INDEX
126#define RENDER_SPAN(span) _swrast_write_index_span(ctx, &span)
127#include "s_linetemp.h"
128
129/* Simple RGBA index line (no stipple, width=1, no Z, no fog, no tex)*/
130#define NAME simple_no_z_rgba_line
131#define INTERP_RGBA
132#define RENDER_SPAN(span) _swrast_write_rgba_span(ctx, &span);
133#include "s_linetemp.h"
134
135
136/* Z, fog, wide, stipple color index line */
137#define NAME ci_line
138#define INTERP_INDEX
139#define INTERP_Z
140#define INTERP_ATTRIBS /* for fog */
141#define RENDER_SPAN(span)					\
142   if (ctx->Line.StippleFlag) {					\
143      span.arrayMask |= SPAN_MASK;				\
144      compute_stipple_mask(ctx, span.end, span.array->mask);    \
145   }								\
146   if (ctx->Line.Width > 1.0) {					\
147      draw_wide_line(ctx, &span, (GLboolean)(dx > dy));		\
148   }								\
149   else {							\
150      _swrast_write_index_span(ctx, &span);			\
151   }
152#include "s_linetemp.h"
153
154
155/* Z, fog, wide, stipple RGBA line */
156#define NAME rgba_line
157#define INTERP_RGBA
158#define INTERP_Z
159#define RENDER_SPAN(span)					\
160   if (ctx->Line.StippleFlag) {					\
161      span.arrayMask |= SPAN_MASK;				\
162      compute_stipple_mask(ctx, span.end, span.array->mask);	\
163   }								\
164   if (ctx->Line.Width > 1.0) {					\
165      draw_wide_line(ctx, &span, (GLboolean)(dx > dy));		\
166   }								\
167   else {							\
168      _swrast_write_rgba_span(ctx, &span);			\
169   }
170#include "s_linetemp.h"
171
172
173/* General-purpose line (any/all features). */
174#define NAME general_line
175#define INTERP_RGBA
176#define INTERP_Z
177#define INTERP_ATTRIBS
178#define RENDER_SPAN(span)					\
179   if (ctx->Line.StippleFlag) {					\
180      span.arrayMask |= SPAN_MASK;				\
181      compute_stipple_mask(ctx, span.end, span.array->mask);	\
182   }								\
183   if (ctx->Line.Width > 1.0) {					\
184      draw_wide_line(ctx, &span, (GLboolean)(dx > dy));		\
185   }								\
186   else {							\
187      _swrast_write_rgba_span(ctx, &span);			\
188   }
189#include "s_linetemp.h"
190
191
192
193void
194_swrast_add_spec_terms_line(GLcontext *ctx,
195                            const SWvertex *v0, const SWvertex *v1)
196{
197   SWvertex *ncv0 = (SWvertex *)v0;
198   SWvertex *ncv1 = (SWvertex *)v1;
199   GLfloat rSum, gSum, bSum;
200   GLchan cSave[2][4];
201
202   /* save original colors */
203   COPY_CHAN4(cSave[0], ncv0->color);
204   COPY_CHAN4(cSave[1], ncv1->color);
205   /* sum v0 */
206   rSum = CHAN_TO_FLOAT(ncv0->color[0]) + ncv0->attrib[FRAG_ATTRIB_COL1][0];
207   gSum = CHAN_TO_FLOAT(ncv0->color[1]) + ncv0->attrib[FRAG_ATTRIB_COL1][1];
208   bSum = CHAN_TO_FLOAT(ncv0->color[2]) + ncv0->attrib[FRAG_ATTRIB_COL1][2];
209   UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[0], rSum);
210   UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[1], gSum);
211   UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[2], bSum);
212   /* sum v1 */
213   rSum = CHAN_TO_FLOAT(ncv1->color[0]) + ncv1->attrib[FRAG_ATTRIB_COL1][0];
214   gSum = CHAN_TO_FLOAT(ncv1->color[1]) + ncv1->attrib[FRAG_ATTRIB_COL1][1];
215   bSum = CHAN_TO_FLOAT(ncv1->color[2]) + ncv1->attrib[FRAG_ATTRIB_COL1][2];
216   UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[0], rSum);
217   UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[1], gSum);
218   UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[2], bSum);
219   /* draw */
220   SWRAST_CONTEXT(ctx)->SpecLine( ctx, ncv0, ncv1 );
221   /* restore original colors */
222   COPY_CHAN4( ncv0->attrib[FRAG_ATTRIB_COL0], cSave[0] );
223   COPY_CHAN4( ncv1->attrib[FRAG_ATTRIB_COL0], cSave[1] );
224}
225
226
227
228#ifdef DEBUG
229
230/* record the current line function name */
231static const char *lineFuncName = NULL;
232
233#define USE(lineFunc)                   \
234do {                                    \
235    lineFuncName = #lineFunc;           \
236    /*_mesa_printf("%s\n", lineFuncName);*/   \
237    swrast->Line = lineFunc;            \
238} while (0)
239
240#else
241
242#define USE(lineFunc)  swrast->Line = lineFunc
243
244#endif
245
246
247
248/**
249 * Determine which line drawing function to use given the current
250 * rendering context.
251 *
252 * Please update the summary flag _SWRAST_NEW_LINE if you add or remove
253 * tests to this code.
254 */
255void
256_swrast_choose_line( GLcontext *ctx )
257{
258   SWcontext *swrast = SWRAST_CONTEXT(ctx);
259   const GLboolean rgbmode = ctx->Visual.rgbMode;
260   GLboolean specular = (ctx->Fog.ColorSumEnabled ||
261                         (ctx->Light.Enabled &&
262                          ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR));
263
264   if (ctx->RenderMode == GL_RENDER) {
265      if (ctx->Line.SmoothFlag) {
266         /* antialiased lines */
267         _swrast_choose_aa_line_function(ctx);
268         ASSERT(swrast->Line);
269      }
270      else if (ctx->Texture._EnabledCoordUnits
271               || ctx->FragmentProgram._Current
272               || swrast->_FogEnabled
273               || specular) {
274         USE(general_line);
275      }
276      else if (ctx->Depth.Test
277               || ctx->Line.Width != 1.0
278               || ctx->Line.StippleFlag) {
279         /* no texture, but Z, fog, width>1, stipple, etc. */
280         if (rgbmode)
281#if CHAN_BITS == 32
282            USE(general_line);
283#else
284            USE(rgba_line);
285#endif
286         else
287            USE(ci_line);
288      }
289      else {
290         ASSERT(!ctx->Depth.Test);
291         ASSERT(ctx->Line.Width == 1.0);
292         /* simple lines */
293         if (rgbmode)
294            USE(simple_no_z_rgba_line);
295         else
296            USE(simple_no_z_ci_line);
297      }
298   }
299   else if (ctx->RenderMode == GL_FEEDBACK) {
300      USE(_swrast_feedback_line);
301   }
302   else {
303      ASSERT(ctx->RenderMode == GL_SELECT);
304      USE(_swrast_select_line);
305   }
306}
307