s_lines.c revision 45bc887da226403f2c41077e40ca38b6f60f1359
1/* $Id: s_lines.c,v 1.36 2003/03/25 02:23:46 brianp Exp $ */
2
3/*
4 * Mesa 3-D graphics library
5 * Version:  5.1
6 *
7 * Copyright (C) 1999-2003  Brian Paul   All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28#include "glheader.h"
29#include "colormac.h"
30#include "macros.h"
31#include "s_aaline.h"
32#include "s_context.h"
33#include "s_depth.h"
34#include "s_feedback.h"
35#include "s_lines.h"
36#include "s_span.h"
37
38
39/*
40 * Init the mask[] array to implement a line stipple.
41 */
42static void
43compute_stipple_mask( GLcontext *ctx, GLuint len, GLubyte mask[] )
44{
45   SWcontext *swrast = SWRAST_CONTEXT(ctx);
46   GLuint i;
47
48   for (i = 0; i < len; i++) {
49      GLuint bit = (swrast->StippleCounter / ctx->Line.StippleFactor) & 0xf;
50      if ((1 << bit) & ctx->Line.StipplePattern) {
51         mask[i] = GL_TRUE;
52      }
53      else {
54         mask[i] = GL_FALSE;
55      }
56      swrast->StippleCounter++;
57   }
58}
59
60
61/*
62 * To draw a wide line we can simply redraw the span N times, side by side.
63 */
64static void
65draw_wide_line( GLcontext *ctx, struct sw_span *span, GLboolean xMajor )
66{
67   GLint width, start;
68
69   ASSERT(span->end < MAX_WIDTH);
70
71   width = (GLint) CLAMP( ctx->Line.Width, MIN_LINE_WIDTH, MAX_LINE_WIDTH );
72
73   if (width & 1)
74      start = width / 2;
75   else
76      start = width / 2 - 1;
77
78   if (xMajor) {
79      GLint *y = span->array->y;
80      GLuint i;
81      GLint w;
82      for (w = 0; w < width; w++) {
83         if (w == 0) {
84            for (i = 0; i < span->end; i++)
85               y[i] -= start;
86         }
87         else {
88            for (i = 0; i < span->end; i++)
89               y[i]++;
90         }
91         if ((span->interpMask | span->arrayMask) & SPAN_TEXTURE)
92            _swrast_write_texture_span(ctx, span);
93         else if ((span->interpMask | span->arrayMask) & SPAN_RGBA)
94            _swrast_write_rgba_span(ctx, span);
95         else
96            _swrast_write_index_span(ctx, span);
97      }
98   }
99   else {
100      GLint *x = span->array->x;
101      GLuint i;
102      GLint w;
103      for (w = 0; w < width; w++) {
104         if (w == 0) {
105            for (i = 0; i < span->end; i++)
106               x[i] -= start;
107         }
108         else {
109            for (i = 0; i < span->end; i++)
110               x[i]++;
111         }
112         if ((span->interpMask | span->arrayMask) & SPAN_TEXTURE)
113            _swrast_write_texture_span(ctx, span);
114         else if ((span->interpMask | span->arrayMask) & SPAN_RGBA)
115            _swrast_write_rgba_span(ctx, span);
116         else
117            _swrast_write_index_span(ctx, span);
118      }
119   }
120}
121
122
123
124/**********************************************************************/
125/*****                    Rasterization                           *****/
126/**********************************************************************/
127
128
129/* Simple color index line (no stipple, width=1, no Z, no fog, no tex)*/
130#define NAME simple_ci_line
131#define INTERP_INDEX
132#define RENDER_SPAN(span) _swrast_write_index_span(ctx, &span)
133#include "s_linetemp.h"
134
135
136/* Simple RGBA index line (no stipple, width=1, no Z, no fog, no tex)*/
137#define NAME simple_rgba_line
138#define INTERP_RGBA
139#define RENDER_SPAN(span) _swrast_write_rgba_span(ctx, &span);
140#include "s_linetemp.h"
141
142
143/* Z, fog, wide, stipple color index line */
144#define NAME general_ci_line
145#define INTERP_INDEX
146#define INTERP_Z
147#define INTERP_FOG
148#define RENDER_SPAN(span)					\
149   if (ctx->Line.StippleFlag) {					\
150      span.arrayMask |= SPAN_MASK;				\
151      compute_stipple_mask(ctx, span.end, span.array->mask);	\
152   }								\
153   if (ctx->Line.Width > 1.0) {					\
154      draw_wide_line(ctx, &span, dx > dy);			\
155   }								\
156   else {							\
157      _swrast_write_index_span(ctx, &span);			\
158   }
159#include "s_linetemp.h"
160
161
162/* Z, fog, wide, stipple RGBA line */
163#define NAME general_rgba_line
164#define INTERP_RGBA
165#define INTERP_Z
166#define INTERP_FOG
167#define RENDER_SPAN(span)					\
168   if (ctx->Line.StippleFlag) {					\
169      span.arrayMask |= SPAN_MASK;				\
170      compute_stipple_mask(ctx, span.end, span.array->mask);	\
171   }								\
172   if (ctx->Line.Width > 1.0) {					\
173      draw_wide_line(ctx, &span, dx > dy);			\
174   }								\
175   else {							\
176      _swrast_write_rgba_span(ctx, &span);			\
177   }
178#include "s_linetemp.h"
179
180
181/* Single-texture line, w/ fog, Z, specular, etc. */
182#define NAME textured_line
183#define INTERP_RGBA
184#define INTERP_Z
185#define INTERP_FOG
186#define INTERP_TEX
187#define RENDER_SPAN(span)					\
188   if (ctx->Line.StippleFlag) {					\
189      span.arrayMask |= SPAN_MASK;				\
190      compute_stipple_mask(ctx, span.end, span.array->mask);	\
191   }								\
192   if (ctx->Line.Width > 1.0) {					\
193      draw_wide_line(ctx, &span, dx > dy);			\
194   }								\
195   else {							\
196      _swrast_write_texture_span(ctx, &span);			\
197   }
198#include "s_linetemp.h"
199
200
201/* Multi-texture or separate specular line, w/ fog, Z, specular, etc. */
202#define NAME multitextured_line
203#define INTERP_RGBA
204#define INTERP_SPEC
205#define INTERP_Z
206#define INTERP_FOG
207#define INTERP_MULTITEX
208#define RENDER_SPAN(span)					\
209   if (ctx->Line.StippleFlag) {					\
210      span.arrayMask |= SPAN_MASK;				\
211      compute_stipple_mask(ctx, span.end, span.array->mask);	\
212   }								\
213   if (ctx->Line.Width > 1.0) {					\
214      draw_wide_line(ctx, &span, dx > dy);			\
215   }								\
216   else {							\
217      _swrast_write_texture_span(ctx, &span);			\
218   }
219#include "s_linetemp.h"
220
221
222
223void
224_swrast_add_spec_terms_line( GLcontext *ctx,
225                             const SWvertex *v0,
226                             const SWvertex *v1 )
227{
228   SWvertex *ncv0 = (SWvertex *)v0;
229   SWvertex *ncv1 = (SWvertex *)v1;
230   GLchan c[2][4];
231   COPY_CHAN4( c[0], ncv0->color );
232   COPY_CHAN4( c[1], ncv1->color );
233   ACC_3V( ncv0->color, ncv0->specular );
234   ACC_3V( ncv1->color, ncv1->specular );
235   SWRAST_CONTEXT(ctx)->SpecLine( ctx, ncv0, ncv1 );
236   COPY_CHAN4( ncv0->color, c[0] );
237   COPY_CHAN4( ncv1->color, c[1] );
238}
239
240
241#ifdef DEBUG
242extern void
243_mesa_print_line_function(GLcontext *ctx);  /* silence compiler warning */
244void
245_mesa_print_line_function(GLcontext *ctx)
246{
247   SWcontext *swrast = SWRAST_CONTEXT(ctx);
248
249   _mesa_printf("Line Func == ");
250   if (swrast->Line == simple_ci_line)
251      _mesa_printf("simple_ci_line\n");
252   else if (swrast->Line == simple_rgba_line)
253      _mesa_printf("simple_rgba_line\n");
254   else if (swrast->Line == general_ci_line)
255      _mesa_printf("general_ci_line\n");
256   else if (swrast->Line == general_rgba_line)
257      _mesa_printf("general_rgba_line\n");
258   else if (swrast->Line == textured_line)
259      _mesa_printf("textured_line\n");
260   else if (swrast->Line == multitextured_line)
261      _mesa_printf("multitextured_line\n");
262   else
263      _mesa_printf("Driver func %p\n", (void *) swrast->Line);
264}
265#endif
266
267
268
269#ifdef DEBUG
270
271/* record the current line function name */
272static const char *lineFuncName = NULL;
273
274#define USE(lineFunc)                   \
275do {                                    \
276    lineFuncName = #lineFunc;           \
277    /*_mesa_printf("%s\n", lineFuncName);*/   \
278    swrast->Line = lineFunc;            \
279} while (0)
280
281#else
282
283#define USE(lineFunc)  swrast->Line = lineFunc
284
285#endif
286
287
288
289/*
290 * Determine which line drawing function to use given the current
291 * rendering context.
292 *
293 * Please update the summary flag _SWRAST_NEW_LINE if you add or remove
294 * tests to this code.
295 */
296void
297_swrast_choose_line( GLcontext *ctx )
298{
299   SWcontext *swrast = SWRAST_CONTEXT(ctx);
300   const GLboolean rgbmode = ctx->Visual.rgbMode;
301
302   if (ctx->RenderMode == GL_RENDER) {
303      if (ctx->Line.SmoothFlag) {
304         /* antialiased lines */
305         _swrast_choose_aa_line_function(ctx);
306         ASSERT(swrast->Line);
307      }
308      else if (ctx->Texture._EnabledUnits) {
309         /* textured lines */
310         if (ctx->Texture._EnabledUnits > 0x1 || (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR)) {
311            /* multi-texture and/or separate specular color */
312            USE(multitextured_line);
313         }
314         else {
315            USE(textured_line);
316         }
317      }
318      else if (ctx->Depth.Test || ctx->Fog.Enabled || ctx->Line.Width != 1.0
319               || ctx->Line.StippleFlag) {
320         /* no texture, but Z, fog, width>1, stipple, etc. */
321         if (rgbmode)
322            USE(general_rgba_line);
323         else
324            USE(general_ci_line);
325      }
326      else {
327         /* simplest lines */
328         if (rgbmode)
329            USE(simple_rgba_line);
330         else
331            USE(simple_ci_line);
332      }
333   }
334   else if (ctx->RenderMode == GL_FEEDBACK) {
335      USE(_swrast_feedback_line);
336   }
337   else {
338      ASSERT(ctx->RenderMode == GL_SELECT);
339      USE(_swrast_select_line);
340   }
341
342   /*_mesa_print_line_function(ctx);*/
343}
344