| 16 | |
| 17 | template <typename SetPixelT> |
| 18 | void Blitter::DrawLineGeneric(int x1, int y1, int x2, int y2, int screen_width, int screen_height, int width, int dash, SetPixelT set_pixel) |
| 19 | { |
| 20 | int dy; |
| 21 | int dx; |
| 22 | int stepx; |
| 23 | int stepy; |
| 24 | |
| 25 | dy = (y2 - y1) * 2; |
| 26 | if (dy < 0) { |
| 27 | dy = -dy; |
| 28 | stepy = -1; |
| 29 | } else { |
| 30 | stepy = 1; |
| 31 | } |
| 32 | |
| 33 | dx = (x2 - x1) * 2; |
| 34 | if (dx < 0) { |
| 35 | dx = -dx; |
| 36 | stepx = -1; |
| 37 | } else { |
| 38 | stepx = 1; |
| 39 | } |
| 40 | |
| 41 | if (dx == 0 && dy == 0) { |
| 42 | /* The algorithm below cannot handle this special case; make it work at least for line width 1 */ |
| 43 | if (x1 >= 0 && x1 < screen_width && y1 >= 0 && y1 < screen_height) set_pixel(x1, y1); |
| 44 | return; |
| 45 | } |
| 46 | |
| 47 | int frac_diff = width * std::max(dx, dy); |
| 48 | if (width > 1) { |
| 49 | /* compute frac_diff = width * sqrt(dx*dx + dy*dy) |
| 50 | * Start interval: |
| 51 | * max(dx, dy) <= sqrt(dx*dx + dy*dy) <= sqrt(2) * max(dx, dy) <= 3/2 * max(dx, dy) */ |
| 52 | int64_t frac_sq = ((int64_t) width) * ((int64_t) width) * (((int64_t) dx) * ((int64_t) dx) + ((int64_t) dy) * ((int64_t) dy)); |
| 53 | int frac_max = 3 * frac_diff / 2; |
| 54 | while (frac_diff < frac_max) { |
| 55 | int frac_test = (frac_diff + frac_max) / 2; |
| 56 | if (((int64_t) frac_test) * ((int64_t) frac_test) < frac_sq) { |
| 57 | frac_diff = frac_test + 1; |
| 58 | } else { |
| 59 | frac_max = frac_test - 1; |
| 60 | } |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | int gap = dash; |
| 65 | if (dash == 0) dash = 1; |
| 66 | int dash_count = 0; |
| 67 | if (dx > dy) { |
| 68 | if (stepx < 0) { |
| 69 | std::swap(x1, x2); |
| 70 | std::swap(y1, y2); |
| 71 | stepy = -stepy; |
| 72 | } |
| 73 | if (x2 < 0 || x1 >= screen_width) return; |
| 74 | |
| 75 | int y_low = y1; |