added stipple_destroy()
[mesa.git] / src / mesa / pipe / draw / draw_stipple.c
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 */
46 struct stipple_stage {
47 struct draw_stage stage;
48 float counter;
49 uint pattern;
50 uint factor;
51 };
52
53
54 static INLINE struct stipple_stage *
55 stipple_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 */
65 static void
66 screen_interp( struct draw_context *draw,
67 struct vertex_header *dst,
68 float t,
69 const struct vertex_header *v0,
70 const struct vertex_header *v1 )
71 {
72 uint attr;
73 for (attr = 0; attr < draw->vertex_info.num_attribs; attr++) {
74 switch (draw->vertex_info.interp_mode[attr]) {
75 case INTERP_NONE:
76 case INTERP_CONSTANT:
77 COPY_4FV(dst->data[attr], v0->data[attr]);
78 break;
79 case INTERP_PERSPECTIVE:
80 /* Fall-through */
81 /* XXX special-case perspective? */
82 case INTERP_LINEAR:
83 {
84 const float *val0 = v0->data[attr];
85 const float *val1 = v1->data[attr];
86 float *newv = dst->data[attr];
87 uint i;
88 for (i = 0; i < 4; i++) {
89 newv[i] = val0[i] + t * (val1[i] - val0[i]);
90 }
91 }
92 break;
93 default:
94 abort();
95 }
96 }
97 }
98
99
100 static void
101 emit_segment(struct draw_stage *stage, struct prim_header *header,
102 float t0, float t1)
103 {
104 struct vertex_header *v0new = dup_vert(stage, header->v[0], 0);
105 struct vertex_header *v1new = dup_vert(stage, header->v[1], 1);
106 struct prim_header newprim = *header;
107
108 if (t0 > 0.0) {
109 screen_interp( stage->draw, v0new, t0, header->v[0], header->v[1] );
110 newprim.v[0] = v0new;
111 }
112
113 if (t1 < 1.0) {
114 screen_interp( stage->draw, v1new, t1, header->v[0], header->v[1] );
115 newprim.v[1] = v1new;
116 }
117
118 stage->next->line( stage->next, &newprim );
119 }
120
121
122 static INLINE unsigned
123 stipple_test(int counter, ushort pattern, int factor)
124 {
125 int b = (counter / factor) & 0xf;
126 return (1 << b) & pattern;
127 }
128
129
130 static void
131 stipple_line(struct draw_stage *stage, struct prim_header *header)
132 {
133 struct stipple_stage *stipple = stipple_stage(stage);
134 struct vertex_header *v0 = header->v[0];
135 struct vertex_header *v1 = header->v[1];
136 const float *pos0 = v0->data[0];
137 const float *pos1 = v1->data[0];
138 float start = 0;
139 int state = 0;
140
141 float x0 = pos0[0];
142 float x1 = pos1[0];
143 float y0 = pos0[1];
144 float y1 = pos1[1];
145
146 float dx = x0 > x1 ? x0 - x1 : x1 - x0;
147 float dy = y0 > y1 ? y0 - y1 : y1 - y0;
148
149 float length = MAX2(dx, dy);
150 int i;
151
152 /* XXX ToDo: intead of iterating pixel-by-pixel, use a look-up table.
153 */
154 for (i = 0; i < length; i++) {
155 int result = stipple_test( (int) stipple->counter+i,
156 (ushort) stipple->pattern, stipple->factor );
157 if (result != state) {
158 /* changing from "off" to "on" or vice versa */
159 if (state) {
160 if (start != i) {
161 /* finishing an "on" segment */
162 emit_segment( stage, header, start / length, i / length );
163 }
164 }
165 else {
166 /* starting an "on" segment */
167 start = (float) i;
168 }
169 state = result;
170 }
171 }
172
173 if (state && start < length)
174 emit_segment( stage, header, start / length, 1.0 );
175
176 stipple->counter += length;
177 }
178
179
180 static void
181 reset_stipple_counter(struct draw_stage *stage)
182 {
183 struct stipple_stage *stipple = stipple_stage(stage);
184 stipple->counter = 0;
185 stage->next->reset_stipple_counter( stage->next );
186 }
187
188
189 static void
190 stipple_begin(struct draw_stage *stage)
191 {
192 struct stipple_stage *stipple = stipple_stage(stage);
193 struct draw_context *draw = stage->draw;
194
195 stipple->pattern = draw->rasterizer->line_stipple_pattern;
196 stipple->factor = draw->rasterizer->line_stipple_factor + 1;
197
198 stage->next->begin( stage->next );
199 }
200
201
202 static void
203 stipple_end(struct draw_stage *stage)
204 {
205 stage->next->end( stage->next );
206 }
207
208
209 static void
210 passthrough_point(struct draw_stage *stage, struct prim_header *header)
211 {
212 stage->next->point( stage->next, header );
213 }
214
215
216 static void
217 passthrough_tri(struct draw_stage *stage, struct prim_header *header)
218 {
219 stage->next->tri(stage->next, header);
220 }
221
222
223 static void
224 stipple_destroy( struct draw_stage *stage )
225 {
226 FREE( stage );
227 }
228
229
230 /**
231 * Create line stippler stage
232 */
233 struct draw_stage *draw_stipple_stage( struct draw_context *draw )
234 {
235 struct stipple_stage *stipple = CALLOC_STRUCT(stipple_stage);
236
237 draw_alloc_tmps( &stipple->stage, 2 );
238
239 stipple->stage.draw = draw;
240 stipple->stage.next = NULL;
241 stipple->stage.begin = stipple_begin;
242 stipple->stage.point = passthrough_point;
243 stipple->stage.line = stipple_line;
244 stipple->stage.tri = passthrough_tri;
245 stipple->stage.reset_stipple_counter = reset_stipple_counter;
246 stipple->stage.end = stipple_end;
247 stipple->stage.destroy = stipple_destroy;
248
249 return &stipple->stage;
250 }