1 /************************************************************************** 2 * 3 * Copyright 2007 VMware, Inc. 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 VMWARE 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 <keithw (at) vmware.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_defines.h" 40 #include "pipe/p_shader_tokens.h" 41 #include "util/u_math.h" 42 #include "util/u_memory.h" 43 44 #include "draw/draw_pipe.h" 45 46 47 /** Subclass of draw_stage */ 48 struct stipple_stage { 49 struct draw_stage stage; 50 float counter; 51 uint pattern; 52 uint factor; 53 }; 54 55 56 static inline struct stipple_stage * 57 stipple_stage(struct draw_stage *stage) 58 { 59 return (struct stipple_stage *) stage; 60 } 61 62 63 /** 64 * Compute interpolated vertex attributes for 'dst' at position 't' 65 * between 'v0' and 'v1'. 66 * XXX using linear interpolation for all attribs at this time. 67 */ 68 static void 69 screen_interp(struct draw_context *draw, 70 struct vertex_header *dst, 71 float t, 72 const struct vertex_header *v0, 73 const struct vertex_header *v1) 74 { 75 uint attr; 76 uint num_outputs = draw_current_shader_outputs(draw); 77 for (attr = 0; attr < num_outputs; attr++) { 78 const float *val0 = v0->data[attr]; 79 const float *val1 = v1->data[attr]; 80 float *newv = dst->data[attr]; 81 uint i; 82 for (i = 0; i < 4; i++) { 83 newv[i] = val0[i] + t * (val1[i] - val0[i]); 84 } 85 } 86 } 87 88 89 static void 90 emit_segment(struct draw_stage *stage, struct prim_header *header, 91 float t0, float t1) 92 { 93 struct vertex_header *v0new = dup_vert(stage, header->v[0], 0); 94 struct vertex_header *v1new = dup_vert(stage, header->v[1], 1); 95 struct prim_header newprim = *header; 96 97 if (t0 > 0.0) { 98 screen_interp(stage->draw, v0new, t0, header->v[0], header->v[1]); 99 newprim.v[0] = v0new; 100 } 101 102 if (t1 < 1.0) { 103 screen_interp(stage->draw, v1new, t1, header->v[0], header->v[1]); 104 newprim.v[1] = v1new; 105 } 106 107 stage->next->line(stage->next, &newprim); 108 } 109 110 111 static inline bool 112 stipple_test(int counter, ushort pattern, int factor) 113 { 114 int b = (counter / factor) & 0xf; 115 return !!((1 << b) & pattern); 116 } 117 118 119 static void 120 stipple_line(struct draw_stage *stage, struct prim_header *header) 121 { 122 struct stipple_stage *stipple = stipple_stage(stage); 123 struct vertex_header *v0 = header->v[0]; 124 struct vertex_header *v1 = header->v[1]; 125 const unsigned pos = draw_current_shader_position_output(stage->draw); 126 const float *pos0 = v0->data[pos]; 127 const float *pos1 = v1->data[pos]; 128 float start = 0; 129 bool state = 0; 130 131 float x0 = pos0[0]; 132 float x1 = pos1[0]; 133 float y0 = pos0[1]; 134 float y1 = pos1[1]; 135 136 float dx = x0 > x1 ? x0 - x1 : x1 - x0; 137 float dy = y0 > y1 ? y0 - y1 : y1 - y0; 138 139 float length = MAX2(dx, dy); 140 int i; 141 142 if (header->flags & DRAW_PIPE_RESET_STIPPLE) 143 stipple->counter = 0; 144 145 146 /* XXX ToDo: instead of iterating pixel-by-pixel, use a look-up table. 147 */ 148 for (i = 0; i < length; i++) { 149 bool result = stipple_test((int)stipple->counter + i, 150 (ushort)stipple->pattern, stipple->factor); 151 if (result != state) { 152 /* changing from "off" to "on" or vice versa */ 153 if (state) { 154 if (start != i) { 155 /* finishing an "on" segment */ 156 emit_segment(stage, header, start / length, i / length); 157 } 158 } 159 else { 160 /* starting an "on" segment */ 161 start = (float)i; 162 } 163 state = result; 164 } 165 } 166 167 if (state && start < length) 168 emit_segment(stage, header, start / length, 1.0); 169 170 stipple->counter += length; 171 } 172 173 174 static void 175 reset_stipple_counter(struct draw_stage *stage) 176 { 177 struct stipple_stage *stipple = stipple_stage(stage); 178 stipple->counter = 0; 179 stage->next->reset_stipple_counter(stage->next); 180 } 181 182 static void 183 stipple_reset_point(struct draw_stage *stage, struct prim_header *header) 184 { 185 struct stipple_stage *stipple = stipple_stage(stage); 186 stipple->counter = 0; 187 stage->next->point(stage->next, header); 188 } 189 190 static void 191 stipple_reset_tri(struct draw_stage *stage, struct prim_header *header) 192 { 193 struct stipple_stage *stipple = stipple_stage(stage); 194 stipple->counter = 0; 195 stage->next->tri(stage->next, header); 196 } 197 198 199 static void 200 stipple_first_line(struct draw_stage *stage, 201 struct prim_header *header) 202 { 203 struct stipple_stage *stipple = stipple_stage(stage); 204 struct draw_context *draw = stage->draw; 205 206 stipple->pattern = draw->rasterizer->line_stipple_pattern; 207 stipple->factor = draw->rasterizer->line_stipple_factor + 1; 208 209 stage->line = stipple_line; 210 stage->line(stage, header); 211 } 212 213 214 static void 215 stipple_flush(struct draw_stage *stage, unsigned flags) 216 { 217 stage->line = stipple_first_line; 218 stage->next->flush(stage->next, flags); 219 } 220 221 222 static void 223 stipple_destroy(struct draw_stage *stage) 224 { 225 draw_free_temp_verts(stage); 226 FREE(stage); 227 } 228 229 230 /** 231 * Create line stippler stage 232 */ 233 struct draw_stage * 234 draw_stipple_stage(struct draw_context *draw) 235 { 236 struct stipple_stage *stipple = CALLOC_STRUCT(stipple_stage); 237 if (!stipple) 238 goto fail; 239 240 stipple->stage.draw = draw; 241 stipple->stage.name = "stipple"; 242 stipple->stage.next = NULL; 243 stipple->stage.point = stipple_reset_point; 244 stipple->stage.line = stipple_first_line; 245 stipple->stage.tri = stipple_reset_tri; 246 stipple->stage.reset_stipple_counter = reset_stipple_counter; 247 stipple->stage.flush = stipple_flush; 248 stipple->stage.destroy = stipple_destroy; 249 250 if (!draw_alloc_temp_verts(&stipple->stage, 2)) 251 goto fail; 252 253 return &stipple->stage; 254 255 fail: 256 if (stipple) 257 stipple->stage.destroy(&stipple->stage); 258 259 return NULL; 260 } 261