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