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( struct gl_context *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( struct gl_context *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 < SWRAST_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	 _swrast_write_rgba_span(ctx, span);
91      }
92   }
93   else {
94      GLint *x = span->array->x;
95      GLuint i;
96      GLint w;
97      for (w = 0; w < width; w++) {
98         if (w == 0) {
99            for (i = 0; i < span->end; i++)
100               x[i] -= start;
101         }
102         else {
103            for (i = 0; i < span->end; i++)
104               x[i]++;
105         }
106	 _swrast_write_rgba_span(ctx, span);
107      }
108   }
109}
110
111
112
113/**********************************************************************/
114/*****                    Rasterization                           *****/
115/**********************************************************************/
116
117/* Simple RGBA index line (no stipple, width=1, no Z, no fog, no tex)*/
118#define NAME simple_no_z_rgba_line
119#define INTERP_RGBA
120#define RENDER_SPAN(span) _swrast_write_rgba_span(ctx, &span);
121#include "s_linetemp.h"
122
123
124/* Z, fog, wide, stipple RGBA line */
125#define NAME rgba_line
126#define INTERP_RGBA
127#define INTERP_Z
128#define RENDER_SPAN(span)					\
129   if (ctx->Line.StippleFlag) {					\
130      span.arrayMask |= SPAN_MASK;				\
131      compute_stipple_mask(ctx, span.end, span.array->mask);	\
132   }								\
133   if (ctx->Line.Width > 1.0) {					\
134      draw_wide_line(ctx, &span, (GLboolean)(dx > dy));		\
135   }								\
136   else {							\
137      _swrast_write_rgba_span(ctx, &span);			\
138   }
139#include "s_linetemp.h"
140
141
142/* General-purpose line (any/all features). */
143#define NAME general_line
144#define INTERP_RGBA
145#define INTERP_Z
146#define INTERP_ATTRIBS
147#define RENDER_SPAN(span)					\
148   if (ctx->Line.StippleFlag) {					\
149      span.arrayMask |= SPAN_MASK;				\
150      compute_stipple_mask(ctx, span.end, span.array->mask);	\
151   }								\
152   if (ctx->Line.Width > 1.0) {					\
153      draw_wide_line(ctx, &span, (GLboolean)(dx > dy));		\
154   }								\
155   else {							\
156      _swrast_write_rgba_span(ctx, &span);			\
157   }
158#include "s_linetemp.h"
159
160
161
162void
163_swrast_add_spec_terms_line(struct gl_context *ctx,
164                            const SWvertex *v0, const SWvertex *v1)
165{
166   SWvertex *ncv0 = (SWvertex *)v0;
167   SWvertex *ncv1 = (SWvertex *)v1;
168   GLfloat rSum, gSum, bSum;
169   GLchan cSave[2][4];
170
171   /* save original colors */
172   COPY_CHAN4(cSave[0], ncv0->color);
173   COPY_CHAN4(cSave[1], ncv1->color);
174   /* sum v0 */
175   rSum = CHAN_TO_FLOAT(ncv0->color[0]) + ncv0->attrib[FRAG_ATTRIB_COL1][0];
176   gSum = CHAN_TO_FLOAT(ncv0->color[1]) + ncv0->attrib[FRAG_ATTRIB_COL1][1];
177   bSum = CHAN_TO_FLOAT(ncv0->color[2]) + ncv0->attrib[FRAG_ATTRIB_COL1][2];
178   UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[0], rSum);
179   UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[1], gSum);
180   UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[2], bSum);
181   /* sum v1 */
182   rSum = CHAN_TO_FLOAT(ncv1->color[0]) + ncv1->attrib[FRAG_ATTRIB_COL1][0];
183   gSum = CHAN_TO_FLOAT(ncv1->color[1]) + ncv1->attrib[FRAG_ATTRIB_COL1][1];
184   bSum = CHAN_TO_FLOAT(ncv1->color[2]) + ncv1->attrib[FRAG_ATTRIB_COL1][2];
185   UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[0], rSum);
186   UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[1], gSum);
187   UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[2], bSum);
188   /* draw */
189   SWRAST_CONTEXT(ctx)->SpecLine( ctx, ncv0, ncv1 );
190   /* restore original colors */
191   COPY_CHAN4(ncv0->color, cSave[0]);
192   COPY_CHAN4(ncv1->color, cSave[1]);
193}
194
195
196
197#ifdef DEBUG
198
199/* record the current line function name */
200static const char *lineFuncName = NULL;
201
202#define USE(lineFunc)                   \
203do {                                    \
204    lineFuncName = #lineFunc;           \
205    /*printf("%s\n", lineFuncName);*/   \
206    swrast->Line = lineFunc;            \
207} while (0)
208
209#else
210
211#define USE(lineFunc)  swrast->Line = lineFunc
212
213#endif
214
215
216
217/**
218 * Determine which line drawing function to use given the current
219 * rendering context.
220 *
221 * Please update the summary flag _SWRAST_NEW_LINE if you add or remove
222 * tests to this code.
223 */
224void
225_swrast_choose_line( struct gl_context *ctx )
226{
227   SWcontext *swrast = SWRAST_CONTEXT(ctx);
228   GLboolean specular = (ctx->Fog.ColorSumEnabled ||
229                         (ctx->Light.Enabled &&
230                          ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR));
231
232   if (ctx->RenderMode == GL_RENDER) {
233      if (ctx->Line.SmoothFlag) {
234         /* antialiased lines */
235         _swrast_choose_aa_line_function(ctx);
236         ASSERT(swrast->Line);
237      }
238      else if (ctx->Texture._EnabledCoordUnits
239               || _swrast_use_fragment_program(ctx)
240               || swrast->_FogEnabled
241               || specular) {
242         USE(general_line);
243      }
244      else if (ctx->Depth.Test
245               || ctx->Line.Width != 1.0
246               || ctx->Line.StippleFlag) {
247         /* no texture, but Z, fog, width>1, stipple, etc. */
248#if CHAN_BITS == 32
249         USE(general_line);
250#else
251         USE(rgba_line);
252#endif
253      }
254      else {
255         ASSERT(!ctx->Depth.Test);
256         ASSERT(ctx->Line.Width == 1.0);
257         /* simple lines */
258         USE(simple_no_z_rgba_line);
259      }
260   }
261   else if (ctx->RenderMode == GL_FEEDBACK) {
262      USE(_swrast_feedback_line);
263   }
264   else {
265      ASSERT(ctx->RenderMode == GL_SELECT);
266      USE(_swrast_select_line);
267   }
268}
269