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 */
39static void
40compute_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 */
61static void
62draw_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
161void
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 */
199static const char *lineFuncName = NULL;
200
201#define USE(lineFunc)                   \
202do {                                    \
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 */
223void
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