draw_pipe_stipple.c revision 26831bdac594a11e51b6c4b09df78bb11444f5dd
1/**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * 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
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28/* Authors:  Keith Whitwell <keith@tungstengraphics.com>
29 */
30
31/* Implement line stipple by cutting lines up into smaller lines.
32 * There are hundreds of ways to implement line stipple, this is one
33 * choice that should work in all situations, requires no state
34 * manipulations, but with a penalty in terms of large amounts of
35 * generated geometry.
36 */
37
38
39#include "pipe/p_util.h"
40#include "pipe/p_defines.h"
41#include "pipe/p_shader_tokens.h"
42#include "draw_private.h"
43
44
45/** Subclass of draw_stage */
46struct stipple_stage {
47   struct draw_stage stage;
48   float counter;
49   uint pattern;
50   uint factor;
51};
52
53
54static INLINE struct stipple_stage *
55stipple_stage(struct draw_stage *stage)
56{
57   return (struct stipple_stage *) stage;
58}
59
60
61/**
62 * Compute interpolated vertex attributes for 'dst' at position 't'
63 * between 'v0' and 'v1'.
64 * XXX using linear interpolation for all attribs at this time.
65 */
66static void
67screen_interp( struct draw_context *draw,
68               struct vertex_header *dst,
69               float t,
70               const struct vertex_header *v0,
71               const struct vertex_header *v1 )
72{
73   uint attr;
74   for (attr = 0; attr < draw->num_vs_outputs; attr++) {
75      const float *val0 = v0->data[attr];
76      const float *val1 = v1->data[attr];
77      float *newv = dst->data[attr];
78      uint i;
79      for (i = 0; i < 4; i++) {
80         newv[i] = val0[i] + t * (val1[i] - val0[i]);
81      }
82   }
83}
84
85
86static void
87emit_segment(struct draw_stage *stage, struct prim_header *header,
88             float t0, float t1)
89{
90   struct vertex_header *v0new = dup_vert(stage, header->v[0], 0);
91   struct vertex_header *v1new = dup_vert(stage, header->v[1], 1);
92   struct prim_header newprim = *header;
93
94   if (t0 > 0.0) {
95      screen_interp( stage->draw, v0new, t0, header->v[0], header->v[1] );
96      newprim.v[0] = v0new;
97   }
98
99   if (t1 < 1.0) {
100      screen_interp( stage->draw, v1new, t1, header->v[0], header->v[1] );
101      newprim.v[1] = v1new;
102   }
103
104   stage->next->line( stage->next, &newprim );
105}
106
107
108static INLINE unsigned
109stipple_test(int counter, ushort pattern, int factor)
110{
111   int b = (counter / factor) & 0xf;
112   return (1 << b) & pattern;
113}
114
115
116static void
117stipple_line(struct draw_stage *stage, struct prim_header *header)
118{
119   struct stipple_stage *stipple = stipple_stage(stage);
120   struct vertex_header *v0 = header->v[0];
121   struct vertex_header *v1 = header->v[1];
122   const float *pos0 = v0->data[0];
123   const float *pos1 = v1->data[0];
124   float start = 0;
125   int state = 0;
126
127   float x0 = pos0[0];
128   float x1 = pos1[0];
129   float y0 = pos0[1];
130   float y1 = pos1[1];
131
132   float dx = x0 > x1 ? x0 - x1 : x1 - x0;
133   float dy = y0 > y1 ? y0 - y1 : y1 - y0;
134
135   float length = MAX2(dx, dy);
136   int i;
137
138   /* XXX ToDo: intead of iterating pixel-by-pixel, use a look-up table.
139    */
140   for (i = 0; i < length; i++) {
141      int result = stipple_test( (int) stipple->counter+i,
142                                 (ushort) stipple->pattern, stipple->factor );
143      if (result != state) {
144         /* changing from "off" to "on" or vice versa */
145	 if (state) {
146	    if (start != i) {
147               /* finishing an "on" segment */
148	       emit_segment( stage, header, start / length, i / length );
149            }
150	 }
151	 else {
152            /* starting an "on" segment */
153	    start = (float) i;
154	 }
155	 state = result;
156      }
157   }
158
159   if (state && start < length)
160      emit_segment( stage, header, start / length, 1.0 );
161
162   stipple->counter += length;
163}
164
165
166static void
167reset_stipple_counter(struct draw_stage *stage)
168{
169   struct stipple_stage *stipple = stipple_stage(stage);
170   stipple->counter = 0;
171   stage->next->reset_stipple_counter( stage->next );
172}
173
174
175static void
176stipple_first_line(struct draw_stage *stage,
177		   struct prim_header *header)
178{
179   struct stipple_stage *stipple = stipple_stage(stage);
180   struct draw_context *draw = stage->draw;
181
182   stipple->pattern = draw->rasterizer->line_stipple_pattern;
183   stipple->factor = draw->rasterizer->line_stipple_factor + 1;
184
185   stage->line = stipple_line;
186   stage->line( stage, header );
187}
188
189
190static void
191stipple_flush(struct draw_stage *stage, unsigned flags)
192{
193   stage->line = stipple_first_line;
194   stage->next->flush( stage->next, flags );
195}
196
197
198static void
199passthrough_point(struct draw_stage *stage, struct prim_header *header)
200{
201   stage->next->point( stage->next, header );
202}
203
204
205static void
206passthrough_tri(struct draw_stage *stage, struct prim_header *header)
207{
208   stage->next->tri(stage->next, header);
209}
210
211
212static void
213stipple_destroy( struct draw_stage *stage )
214{
215   draw_free_temp_verts( stage );
216   FREE( stage );
217}
218
219
220/**
221 * Create line stippler stage
222 */
223struct draw_stage *draw_stipple_stage( struct draw_context *draw )
224{
225   struct stipple_stage *stipple = CALLOC_STRUCT(stipple_stage);
226
227   draw_alloc_temp_verts( &stipple->stage, 2 );
228
229   stipple->stage.draw = draw;
230   stipple->stage.next = NULL;
231   stipple->stage.point = passthrough_point;
232   stipple->stage.line = stipple_first_line;
233   stipple->stage.tri = passthrough_tri;
234   stipple->stage.reset_stipple_counter = reset_stipple_counter;
235   stipple->stage.flush = stipple_flush;
236   stipple->stage.destroy = stipple_destroy;
237
238   return &stipple->stage;
239}
240