diff options
Diffstat (limited to 'src/blitter/common.hpp')
-rw-r--r-- | src/blitter/common.hpp | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/src/blitter/common.hpp b/src/blitter/common.hpp new file mode 100644 index 000000000..0e255ca9a --- /dev/null +++ b/src/blitter/common.hpp @@ -0,0 +1,141 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>. + */ + +/** @file common.hpp Common functionality for all blitter implementations. */ + +#ifndef BLITTER_COMMON_HPP +#define BLITTER_COMMON_HPP + +#include "base.hpp" +#include "../core/math_func.hpp" + +template <typename SetPixelT> +void Blitter::DrawLineGeneric(int x, int y, int x2, int y2, int screen_width, int screen_height, int width, int dash, SetPixelT set_pixel) +{ + int dy; + int dx; + int stepx; + int stepy; + + dy = (y2 - y) * 2; + if (dy < 0) { + dy = -dy; + stepy = -1; + } else { + stepy = 1; + } + + dx = (x2 - x) * 2; + if (dx < 0) { + dx = -dx; + stepx = -1; + } else { + stepx = 1; + } + + if (dx == 0 && dy == 0) { + /* The algorithm below cannot handle this special case; make it work at least for line width 1 */ + if (x >= 0 && x < screen_width && y >= 0 && y < screen_height) set_pixel(x, y); + return; + } + + int frac_diff = width * max(dx, dy); + if (width > 1) { + /* compute frac_diff = width * sqrt(dx*dx + dy*dy) + * Start interval: + * max(dx, dy) <= sqrt(dx*dx + dy*dy) <= sqrt(2) * max(dx, dy) <= 3/2 * max(dx, dy) */ + int frac_sq = width * width * (dx * dx + dy * dy); + int frac_max = 3 * frac_diff / 2; + while (frac_diff < frac_max) { + int frac_test = (frac_diff + frac_max) / 2; + if (frac_test * frac_test < frac_sq) { + frac_diff = frac_test + 1; + } else { + frac_max = frac_test - 1; + } + } + } + + int gap = dash; + if (dash == 0) dash = 1; + int dash_count = 0; + if (dx > dy) { + int y_low = y; + int y_high = y; + int frac_low = dy - frac_diff / 2; + int frac_high = dy + frac_diff / 2; + + while (frac_low + dx / 2 < 0) { + frac_low += dx; + y_low -= stepy; + } + while (frac_high - dx / 2 >= 0) { + frac_high -= dx; + y_high += stepy; + } + x2 += stepx; + + while (x != x2) { + if (dash_count < dash && x >= 0 && x < screen_width) { + for (int y = y_low; y != y_high; y += stepy) { + if (y >= 0 && y < screen_height) set_pixel(x, y); + } + } + if (frac_low >= 0) { + y_low += stepy; + frac_low -= dx; + } + if (frac_high >= 0) { + y_high += stepy; + frac_high -= dx; + } + x += stepx; + frac_low += dy; + frac_high += dy; + if (++dash_count >= dash + gap) dash_count = 0; + } + } else { + int x_low = x; + int x_high = x; + int frac_low = dx - frac_diff / 2; + int frac_high = dx + frac_diff / 2; + + while (frac_low + dy / 2 < 0) { + frac_low += dy; + x_low -= stepx; + } + while (frac_high - dy / 2 >= 0) { + frac_high -= dy; + x_high += stepx; + } + y2 += stepy; + + while (y != y2) { + if (dash_count < dash && y >= 0 && y < screen_height) { + for (int x = x_low; x != x_high; x += stepx) { + if (x >= 0 && x < screen_width) set_pixel(x, y); + } + } + if (frac_low >= 0) { + x_low += stepx; + frac_low -= dy; + } + if (frac_high >= 0) { + x_high += stepx; + frac_high -= dy; + } + y += stepy; + frac_low += dx; + frac_high += dx; + if (++dash_count >= dash + gap) dash_count = 0; + } + } +} + +#endif /* BLITTER_COMMON_HPP */ |