2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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/>.
8 /** @file common.hpp Common functionality for all blitter implementations. */
10 #ifndef BLITTER_COMMON_HPP
11 #define BLITTER_COMMON_HPP
14 #include "../core/math_func.hpp"
18 template <typename SetPixelT
>
19 void Blitter::DrawLineGeneric(int x1
, int y1
, int x2
, int y2
, int screen_width
, int screen_height
, int width
, int dash
, SetPixelT set_pixel
)
42 if (dx
== 0 && dy
== 0) {
43 /* The algorithm below cannot handle this special case; make it work at least for line width 1 */
44 if (x1
>= 0 && x1
< screen_width
&& y1
>= 0 && y1
< screen_height
) set_pixel(x1
, y1
);
48 int frac_diff
= width
* std::max(dx
, dy
);
50 /* compute frac_diff = width * sqrt(dx*dx + dy*dy)
52 * max(dx, dy) <= sqrt(dx*dx + dy*dy) <= sqrt(2) * max(dx, dy) <= 3/2 * max(dx, dy) */
53 int64_t frac_sq
= ((int64_t) width
) * ((int64_t) width
) * (((int64_t) dx
) * ((int64_t) dx
) + ((int64_t) dy
) * ((int64_t) dy
));
54 int frac_max
= 3 * frac_diff
/ 2;
55 while (frac_diff
< frac_max
) {
56 int frac_test
= (frac_diff
+ frac_max
) / 2;
57 if (((int64_t) frac_test
) * ((int64_t) frac_test
) < frac_sq
) {
58 frac_diff
= frac_test
+ 1;
60 frac_max
= frac_test
- 1;
66 if (dash
== 0) dash
= 1;
74 if (x2
< 0 || x1
>= screen_width
) return;
78 int frac_low
= dy
- frac_diff
/ 2;
79 int frac_high
= dy
+ frac_diff
/ 2;
81 while (frac_low
< -(dx
/ 2)) {
85 while (frac_high
>= dx
/ 2) {
91 dash_count
= (-x1
) % (dash
+ gap
);
92 auto adjust_frac
= [&](int64_t frac
, int &y_bound
) -> int {
93 frac
-= ((int64_t) dy
) * ((int64_t) x1
);
95 int quotient
= frac
/ dx
;
96 int remainder
= frac
% dx
;
97 y_bound
+= (1 + quotient
) * stepy
;
98 frac
= remainder
- dx
;
102 frac_low
= adjust_frac(frac_low
, y_low
);
103 frac_high
= adjust_frac(frac_high
, y_high
);
107 if (x2
> screen_width
) {
112 if (dash_count
< dash
) {
113 for (int y
= y_low
; y
!= y_high
; y
+= stepy
) {
114 if (y
>= 0 && y
< screen_height
) set_pixel(x1
, y
);
121 if (frac_high
>= 0) {
128 if (++dash_count
>= dash
+ gap
) dash_count
= 0;
136 if (y2
< 0 || y1
>= screen_height
) return;
140 int frac_low
= dx
- frac_diff
/ 2;
141 int frac_high
= dx
+ frac_diff
/ 2;
143 while (frac_low
< -(dy
/ 2)) {
147 while (frac_high
>= dy
/ 2) {
153 dash_count
= (-y1
) % (dash
+ gap
);
154 auto adjust_frac
= [&](int64_t frac
, int &x_bound
) -> int {
155 frac
-= ((int64_t) dx
) * ((int64_t) y1
);
157 int quotient
= frac
/ dy
;
158 int remainder
= frac
% dy
;
159 x_bound
+= (1 + quotient
) * stepx
;
160 frac
= remainder
- dy
;
164 frac_low
= adjust_frac(frac_low
, x_low
);
165 frac_high
= adjust_frac(frac_high
, x_high
);
169 if (y2
> screen_height
) {
174 if (dash_count
< dash
) {
175 for (int x
= x_low
; x
!= x_high
; x
+= stepx
) {
176 if (x
>= 0 && x
< screen_width
) set_pixel(x
, y1
);
183 if (frac_high
>= 0) {
190 if (++dash_count
>= dash
+ gap
) dash_count
= 0;
195 #endif /* BLITTER_COMMON_HPP */