4 XCSoar Glide Computer - http://www.xcsoar.org/
5 Copyright (C) 2000-2013 The XCSoar Project
6 A detailed list of copyright holders can be found in the file "AUTHORS".
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include "Terrain/RasterBuffer.hpp"
25 #include "Math/FastMath.h"
31 RasterBuffer::Resize(unsigned _width
, unsigned _height
)
33 assert(_width
> 0 && _height
> 0);
35 data
.GrowDiscard(_width
, _height
);
39 RasterBuffer::GetInterpolated(unsigned lx
, unsigned ly
,
40 unsigned ix
, unsigned iy
) const
43 assert(lx
< GetWidth());
44 assert(ly
< GetHeight());
48 // perform piecewise linear interpolation
49 const unsigned int dx
= (lx
== GetWidth() - 1) ? 0 : 1;
50 const unsigned int dy
= (ly
== GetHeight() - 1) ? 0 : GetWidth();
51 const short *tm
= GetDataAt(lx
, ly
);
53 if (IsSpecial(*tm
) || IsSpecial(tm
[dx
]) ||
54 IsSpecial(tm
[dy
]) || IsSpecial(tm
[dx
+ dy
]))
57 unsigned kx
= 0x100 - ix
;
58 unsigned ky
= 0x100 - iy
;
60 return (*tm
* kx
* ky
+ tm
[dx
] * ix
* ky
+ tm
[dy
] * kx
* iy
+ tm
[dx
+ dy
] * ix
* iy
) >> 16;
64 RasterBuffer::GetInterpolated(unsigned lx
, unsigned ly
) const
66 // check x in range, and decompose fraction part
67 const unsigned int ix
= CombinedDivAndMod(lx
);
69 return TERRAIN_INVALID
;
71 // check y in range, and decompose fraction part
72 const unsigned int iy
= CombinedDivAndMod(ly
);
73 if (ly
>= GetHeight())
74 return TERRAIN_INVALID
;
76 return GetInterpolated(lx
, ly
, ix
, iy
);
80 * This class implements an algorithm to traverse pixels quickly with
81 * only integer addition, no multiplication and division.
85 unsigned src_increment
, src_counter
;
86 unsigned dest_increment
, dest_counter
;
89 PixelIterator(unsigned src_size
, unsigned dest_size
)
90 :src_increment(dest_size
), src_counter(0),
91 dest_increment(src_size
), dest_counter(0) {}
94 * @return the number of source pixels to skip
97 if (dest_counter
< src_counter
) {
98 dest_counter
+= dest_increment
;
102 dest_counter
+= dest_increment
;
106 /* this loop is inefficient with large dest_increment values */
107 while (src_counter
+ src_increment
<= dest_counter
) {
108 src_counter
+= src_increment
;
117 RasterBuffer::ScanHorizontalLine(unsigned ax
, unsigned bx
, unsigned y
,
118 short *gcc_restrict buffer
, unsigned size
,
119 bool interpolate
) const
121 assert(ax
< GetFineWidth());
122 assert(bx
< GetFineWidth());
123 assert(y
< GetFineHeight());
124 assert(buffer
!= NULL
);
128 *buffer
= Get(ax
>> 8, y
>> 8);
132 const int dx
= bx
- ax
;
133 /* disable interpolation when an output pixel is larger than two
134 pixels in our buffer; the factor of two should account for the Y
135 axis, which can have a different scale, making the factor some
136 sort of ugly kludge to avoid horizontal shading stripes */
137 if (interpolate
&& (unsigned)abs(dx
) < (2 * size
<< 8u)) {
141 const unsigned int iy
= CombinedDivAndMod(cy
);
144 for (int i
= 0; (unsigned)i
<= size
; ++i
) {
145 unsigned cx
= ax
+ (i
* dx
) / (int)size
;
146 const unsigned int ix
= CombinedDivAndMod(cx
);
148 *buffer
++ = GetInterpolated(cx
, cy
, ix
, iy
);
150 } else if (gcc_likely(dx
> 0)) {
151 /* no interpolation needed, forward scan */
153 const short *gcc_restrict src
= GetDataAt(ax
>> 8, y
>> 8);
155 PixelIterator
iterator(dx
>> 8, size
);
156 short *gcc_restrict end
= buffer
+ size
;
161 src
+= iterator
.Next();
164 /* no interpolation needed */
166 const short *gcc_restrict src
= GetDataAt(0, y
>> 8);
169 for (int i
= 0; (unsigned)i
<= size
; ++i
) {
170 unsigned cx
= ax
+ (i
* dx
) / (int)size
;
172 *buffer
++ = src
[cx
>> 8];
178 RasterBuffer::ScanLine(unsigned ax
, unsigned ay
, unsigned bx
, unsigned by
,
179 short *gcc_restrict buffer
,
180 unsigned size
, bool interpolate
) const
182 assert(ax
< GetFineWidth());
183 assert(ay
< GetFineHeight());
184 assert(bx
< GetFineWidth());
185 assert(by
< GetFineHeight());
186 assert(buffer
!= NULL
);
190 ScanHorizontalLine(ax
, bx
, ay
, buffer
, size
, interpolate
);
195 *buffer
= Get(ax
>> 8, ay
>> 8);
200 const int dx
= bx
- ax
, dy
= by
- ay
;
201 /* disable interpolation when an output pixel is larger than two
202 pixels in our buffer; the factor of two should account for the Y
203 axis, which can have a different scale, making the factor some
204 sort of ugly kludge to avoid horizontal shading stripes */
205 if (interpolate
&& (unsigned)(abs(dx
) + abs(dy
)) < (2 * size
<< 8u)) {
208 for (int i
= 0; (unsigned)i
<= size
; ++i
) {
209 unsigned cx
= ax
+ (i
* dx
) / (int)size
;
210 unsigned cy
= ay
+ (i
* dy
) / (int)size
;
212 const unsigned int ix
= CombinedDivAndMod(cx
);
213 const unsigned int iy
= CombinedDivAndMod(cy
);
215 *buffer
++ = GetInterpolated(cx
, cy
, ix
, iy
);
218 /* no interpolation needed */
220 for (int i
= 0; (unsigned)i
<= size
; ++i
) {
221 unsigned cx
= ax
+ (i
* dx
) / (int)size
;
222 unsigned cy
= ay
+ (i
* dy
) / (int)size
;
224 *buffer
++ = Get(cx
>> 8, cy
>> 8);
230 RasterBuffer::ScanLineChecked(unsigned ax
, unsigned ay
,
231 unsigned bx
, unsigned by
,
232 short *buffer
, unsigned size
,
233 bool interpolate
) const
235 if (ax
>= GetFineWidth())
236 ax
= GetFineWidth() - 1;
238 if (ay
>= GetFineHeight())
239 ay
= GetFineHeight() - 1;
241 if (bx
>= GetFineWidth())
242 bx
= GetFineWidth() - 1;
244 if (by
>= GetFineHeight())
245 by
= GetFineHeight() - 1;
247 ScanLine(ax
, ay
, bx
, by
, buffer
, size
, interpolate
);
251 RasterBuffer::GetMaximum() const
253 return IsDefined() ? *std::max_element(data
.begin(), data
.end()) : 0;