1 //---------------------------------------------------------------------------- 2 // Anti-Grain Geometry - Version 2.4 3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) 4 // 5 // Permission to copy, use, modify, sell and distribute this software 6 // is granted provided this copyright notice appears in all copies. 7 // This software is provided "as is" without express or implied 8 // warranty, and with no claim as to its suitability for any purpose. 9 // 10 //---------------------------------------------------------------------------- 11 // Contact: mcseem@antigrain.com 12 // mcseemagg@yahoo.com 13 // http://www.antigrain.com 14 //---------------------------------------------------------------------------- 15 #ifndef AGG_RASTERIZER_SL_CLIP_INCLUDED 16 #define AGG_RASTERIZER_SL_CLIP_INCLUDED 17 18 #include "agg_clip_liang_barsky.h" 19 20 namespace agg 21 { 22 //--------------------------------------------------------poly_max_coord_e 23 enum poly_max_coord_e 24 { 25 poly_max_coord = (1 << 30) - 1 //----poly_max_coord 26 }; 27 28 //------------------------------------------------------------ras_conv_int 29 struct ras_conv_int 30 { 31 typedef int coord_type; mul_divras_conv_int32 static AGG_INLINE int mul_div(double a, double b, double c) 33 { 34 return iround(a * b / c); 35 } xiras_conv_int36 static int xi(int v) { return v; } yiras_conv_int37 static int yi(int v) { return v; } upscaleras_conv_int38 static int upscale(double v) { return iround(v * poly_subpixel_scale); } downscaleras_conv_int39 static int downscale(int v) { return v; } 40 }; 41 42 //--------------------------------------------------------ras_conv_int_sat 43 struct ras_conv_int_sat 44 { 45 typedef int coord_type; mul_divras_conv_int_sat46 static AGG_INLINE int mul_div(double a, double b, double c) 47 { 48 return saturation<poly_max_coord>::iround(a * b / c); 49 } xiras_conv_int_sat50 static int xi(int v) { return v; } yiras_conv_int_sat51 static int yi(int v) { return v; } upscaleras_conv_int_sat52 static int upscale(double v) 53 { 54 return saturation<poly_max_coord>::iround(v * poly_subpixel_scale); 55 } downscaleras_conv_int_sat56 static int downscale(int v) { return v; } 57 }; 58 59 //---------------------------------------------------------ras_conv_int_3x 60 struct ras_conv_int_3x 61 { 62 typedef int coord_type; mul_divras_conv_int_3x63 static AGG_INLINE int mul_div(double a, double b, double c) 64 { 65 return iround(a * b / c); 66 } xiras_conv_int_3x67 static int xi(int v) { return v * 3; } yiras_conv_int_3x68 static int yi(int v) { return v; } upscaleras_conv_int_3x69 static int upscale(double v) { return iround(v * poly_subpixel_scale); } downscaleras_conv_int_3x70 static int downscale(int v) { return v; } 71 }; 72 73 //-----------------------------------------------------------ras_conv_dbl 74 struct ras_conv_dbl 75 { 76 typedef double coord_type; mul_divras_conv_dbl77 static AGG_INLINE double mul_div(double a, double b, double c) 78 { 79 return a * b / c; 80 } xiras_conv_dbl81 static int xi(double v) { return iround(v * poly_subpixel_scale); } yiras_conv_dbl82 static int yi(double v) { return iround(v * poly_subpixel_scale); } upscaleras_conv_dbl83 static double upscale(double v) { return v; } downscaleras_conv_dbl84 static double downscale(int v) { return v / double(poly_subpixel_scale); } 85 }; 86 87 //--------------------------------------------------------ras_conv_dbl_3x 88 struct ras_conv_dbl_3x 89 { 90 typedef double coord_type; mul_divras_conv_dbl_3x91 static AGG_INLINE double mul_div(double a, double b, double c) 92 { 93 return a * b / c; 94 } xiras_conv_dbl_3x95 static int xi(double v) { return iround(v * poly_subpixel_scale * 3); } yiras_conv_dbl_3x96 static int yi(double v) { return iround(v * poly_subpixel_scale); } upscaleras_conv_dbl_3x97 static double upscale(double v) { return v; } downscaleras_conv_dbl_3x98 static double downscale(int v) { return v / double(poly_subpixel_scale); } 99 }; 100 101 102 103 104 105 //------------------------------------------------------rasterizer_sl_clip 106 template<class Conv> class rasterizer_sl_clip 107 { 108 public: 109 typedef Conv conv_type; 110 typedef typename Conv::coord_type coord_type; 111 typedef rect_base<coord_type> rect_type; 112 113 //-------------------------------------------------------------------- rasterizer_sl_clip()114 rasterizer_sl_clip() : 115 m_clip_box(0,0,0,0), 116 m_x1(0), 117 m_y1(0), 118 m_f1(0), 119 m_clipping(false) 120 {} 121 122 //-------------------------------------------------------------------- reset_clipping()123 void reset_clipping() 124 { 125 m_clipping = false; 126 } 127 128 //-------------------------------------------------------------------- clip_box(coord_type x1,coord_type y1,coord_type x2,coord_type y2)129 void clip_box(coord_type x1, coord_type y1, coord_type x2, coord_type y2) 130 { 131 m_clip_box = rect_type(x1, y1, x2, y2); 132 m_clip_box.normalize(); 133 m_clipping = true; 134 } 135 136 //-------------------------------------------------------------------- move_to(coord_type x1,coord_type y1)137 void move_to(coord_type x1, coord_type y1) 138 { 139 m_x1 = x1; 140 m_y1 = y1; 141 if(m_clipping) m_f1 = clipping_flags(x1, y1, m_clip_box); 142 } 143 144 private: 145 //------------------------------------------------------------------------ 146 template<class Rasterizer> line_clip_y(Rasterizer & ras,coord_type x1,coord_type y1,coord_type x2,coord_type y2,unsigned f1,unsigned f2)147 AGG_INLINE void line_clip_y(Rasterizer& ras, 148 coord_type x1, coord_type y1, 149 coord_type x2, coord_type y2, 150 unsigned f1, unsigned f2) const 151 { 152 f1 &= 10; 153 f2 &= 10; 154 if((f1 | f2) == 0) 155 { 156 // Fully visible 157 ras.line(Conv::xi(x1), Conv::yi(y1), Conv::xi(x2), Conv::yi(y2)); 158 } 159 else 160 { 161 if(f1 == f2) 162 { 163 // Invisible by Y 164 return; 165 } 166 167 coord_type tx1 = x1; 168 coord_type ty1 = y1; 169 coord_type tx2 = x2; 170 coord_type ty2 = y2; 171 172 if(f1 & 8) // y1 < clip.y1 173 { 174 tx1 = x1 + Conv::mul_div(m_clip_box.y1-y1, x2-x1, y2-y1); 175 ty1 = m_clip_box.y1; 176 } 177 178 if(f1 & 2) // y1 > clip.y2 179 { 180 tx1 = x1 + Conv::mul_div(m_clip_box.y2-y1, x2-x1, y2-y1); 181 ty1 = m_clip_box.y2; 182 } 183 184 if(f2 & 8) // y2 < clip.y1 185 { 186 tx2 = x1 + Conv::mul_div(m_clip_box.y1-y1, x2-x1, y2-y1); 187 ty2 = m_clip_box.y1; 188 } 189 190 if(f2 & 2) // y2 > clip.y2 191 { 192 tx2 = x1 + Conv::mul_div(m_clip_box.y2-y1, x2-x1, y2-y1); 193 ty2 = m_clip_box.y2; 194 } 195 ras.line(Conv::xi(tx1), Conv::yi(ty1), 196 Conv::xi(tx2), Conv::yi(ty2)); 197 } 198 } 199 200 201 public: 202 //-------------------------------------------------------------------- 203 template<class Rasterizer> line_to(Rasterizer & ras,coord_type x2,coord_type y2)204 void line_to(Rasterizer& ras, coord_type x2, coord_type y2) 205 { 206 if(m_clipping) 207 { 208 unsigned f2 = clipping_flags(x2, y2, m_clip_box); 209 210 if((m_f1 & 10) == (f2 & 10) && (m_f1 & 10) != 0) 211 { 212 // Invisible by Y 213 m_x1 = x2; 214 m_y1 = y2; 215 m_f1 = f2; 216 return; 217 } 218 219 coord_type x1 = m_x1; 220 coord_type y1 = m_y1; 221 unsigned f1 = m_f1; 222 coord_type y3, y4; 223 unsigned f3, f4; 224 225 switch(((f1 & 5) << 1) | (f2 & 5)) 226 { 227 case 0: // Visible by X 228 line_clip_y(ras, x1, y1, x2, y2, f1, f2); 229 break; 230 231 case 1: // x2 > clip.x2 232 y3 = y1 + Conv::mul_div(m_clip_box.x2-x1, y2-y1, x2-x1); 233 f3 = clipping_flags_y(y3, m_clip_box); 234 line_clip_y(ras, x1, y1, m_clip_box.x2, y3, f1, f3); 235 line_clip_y(ras, m_clip_box.x2, y3, m_clip_box.x2, y2, f3, f2); 236 break; 237 238 case 2: // x1 > clip.x2 239 y3 = y1 + Conv::mul_div(m_clip_box.x2-x1, y2-y1, x2-x1); 240 f3 = clipping_flags_y(y3, m_clip_box); 241 line_clip_y(ras, m_clip_box.x2, y1, m_clip_box.x2, y3, f1, f3); 242 line_clip_y(ras, m_clip_box.x2, y3, x2, y2, f3, f2); 243 break; 244 245 case 3: // x1 > clip.x2 && x2 > clip.x2 246 line_clip_y(ras, m_clip_box.x2, y1, m_clip_box.x2, y2, f1, f2); 247 break; 248 249 case 4: // x2 < clip.x1 250 y3 = y1 + Conv::mul_div(m_clip_box.x1-x1, y2-y1, x2-x1); 251 f3 = clipping_flags_y(y3, m_clip_box); 252 line_clip_y(ras, x1, y1, m_clip_box.x1, y3, f1, f3); 253 line_clip_y(ras, m_clip_box.x1, y3, m_clip_box.x1, y2, f3, f2); 254 break; 255 256 case 6: // x1 > clip.x2 && x2 < clip.x1 257 y3 = y1 + Conv::mul_div(m_clip_box.x2-x1, y2-y1, x2-x1); 258 y4 = y1 + Conv::mul_div(m_clip_box.x1-x1, y2-y1, x2-x1); 259 f3 = clipping_flags_y(y3, m_clip_box); 260 f4 = clipping_flags_y(y4, m_clip_box); 261 line_clip_y(ras, m_clip_box.x2, y1, m_clip_box.x2, y3, f1, f3); 262 line_clip_y(ras, m_clip_box.x2, y3, m_clip_box.x1, y4, f3, f4); 263 line_clip_y(ras, m_clip_box.x1, y4, m_clip_box.x1, y2, f4, f2); 264 break; 265 266 case 8: // x1 < clip.x1 267 y3 = y1 + Conv::mul_div(m_clip_box.x1-x1, y2-y1, x2-x1); 268 f3 = clipping_flags_y(y3, m_clip_box); 269 line_clip_y(ras, m_clip_box.x1, y1, m_clip_box.x1, y3, f1, f3); 270 line_clip_y(ras, m_clip_box.x1, y3, x2, y2, f3, f2); 271 break; 272 273 case 9: // x1 < clip.x1 && x2 > clip.x2 274 y3 = y1 + Conv::mul_div(m_clip_box.x1-x1, y2-y1, x2-x1); 275 y4 = y1 + Conv::mul_div(m_clip_box.x2-x1, y2-y1, x2-x1); 276 f3 = clipping_flags_y(y3, m_clip_box); 277 f4 = clipping_flags_y(y4, m_clip_box); 278 line_clip_y(ras, m_clip_box.x1, y1, m_clip_box.x1, y3, f1, f3); 279 line_clip_y(ras, m_clip_box.x1, y3, m_clip_box.x2, y4, f3, f4); 280 line_clip_y(ras, m_clip_box.x2, y4, m_clip_box.x2, y2, f4, f2); 281 break; 282 283 case 12: // x1 < clip.x1 && x2 < clip.x1 284 line_clip_y(ras, m_clip_box.x1, y1, m_clip_box.x1, y2, f1, f2); 285 break; 286 } 287 m_f1 = f2; 288 } 289 else 290 { 291 ras.line(Conv::xi(m_x1), Conv::yi(m_y1), 292 Conv::xi(x2), Conv::yi(y2)); 293 } 294 m_x1 = x2; 295 m_y1 = y2; 296 } 297 298 299 private: 300 rect_type m_clip_box; 301 coord_type m_x1; 302 coord_type m_y1; 303 unsigned m_f1; 304 bool m_clipping; 305 }; 306 307 308 309 310 //---------------------------------------------------rasterizer_sl_no_clip 311 class rasterizer_sl_no_clip 312 { 313 public: 314 typedef ras_conv_int conv_type; 315 typedef int coord_type; 316 rasterizer_sl_no_clip()317 rasterizer_sl_no_clip() : m_x1(0), m_y1(0) {} 318 reset_clipping()319 void reset_clipping() {} clip_box(coord_type x1,coord_type y1,coord_type x2,coord_type y2)320 void clip_box(coord_type x1, coord_type y1, coord_type x2, coord_type y2) {} move_to(coord_type x1,coord_type y1)321 void move_to(coord_type x1, coord_type y1) { m_x1 = x1; m_y1 = y1; } 322 323 template<class Rasterizer> line_to(Rasterizer & ras,coord_type x2,coord_type y2)324 void line_to(Rasterizer& ras, coord_type x2, coord_type y2) 325 { 326 ras.line(m_x1, m_y1, x2, y2); 327 m_x1 = x2; 328 m_y1 = y2; 329 } 330 331 private: 332 int m_x1, m_y1; 333 }; 334 335 336 // -----rasterizer_sl_clip_int 337 // -----rasterizer_sl_clip_int_sat 338 // -----rasterizer_sl_clip_int_3x 339 // -----rasterizer_sl_clip_dbl 340 // -----rasterizer_sl_clip_dbl_3x 341 //------------------------------------------------------------------------ 342 typedef rasterizer_sl_clip<ras_conv_int> rasterizer_sl_clip_int; 343 typedef rasterizer_sl_clip<ras_conv_int_sat> rasterizer_sl_clip_int_sat; 344 typedef rasterizer_sl_clip<ras_conv_int_3x> rasterizer_sl_clip_int_3x; 345 typedef rasterizer_sl_clip<ras_conv_dbl> rasterizer_sl_clip_dbl; 346 typedef rasterizer_sl_clip<ras_conv_dbl_3x> rasterizer_sl_clip_dbl_3x; 347 348 349 } 350 351 #endif 352