Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blitter line drawing improvements #7082

Merged
merged 3 commits into from Jan 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion projects/openttd_vs140.vcxproj
Expand Up @@ -1201,8 +1201,8 @@
<ClInclude Include="..\src\blitter\8bpp_optimized.hpp" />
<ClCompile Include="..\src\blitter\8bpp_simple.cpp" />
<ClInclude Include="..\src\blitter\8bpp_simple.hpp" />
<ClCompile Include="..\src\blitter\base.cpp" />
<ClInclude Include="..\src\blitter\base.hpp" />
<ClInclude Include="..\src\blitter\common.hpp" />
<ClInclude Include="..\src\blitter\factory.hpp" />
<ClCompile Include="..\src\blitter\null.cpp" />
<ClInclude Include="..\src\blitter\null.hpp" />
Expand Down
6 changes: 3 additions & 3 deletions projects/openttd_vs140.vcxproj.filters
Expand Up @@ -2691,12 +2691,12 @@
<ClInclude Include="..\src\blitter\8bpp_simple.hpp">
<Filter>Blitters</Filter>
</ClInclude>
<ClCompile Include="..\src\blitter\base.cpp">
<Filter>Blitters</Filter>
</ClCompile>
<ClInclude Include="..\src\blitter\base.hpp">
<Filter>Blitters</Filter>
</ClInclude>
<ClInclude Include="..\src\blitter\common.hpp">
<Filter>Blitters</Filter>
</ClInclude>
<ClInclude Include="..\src\blitter\factory.hpp">
<Filter>Blitters</Filter>
</ClInclude>
Expand Down
2 changes: 1 addition & 1 deletion projects/openttd_vs141.vcxproj
Expand Up @@ -1201,8 +1201,8 @@
<ClInclude Include="..\src\blitter\8bpp_optimized.hpp" />
<ClCompile Include="..\src\blitter\8bpp_simple.cpp" />
<ClInclude Include="..\src\blitter\8bpp_simple.hpp" />
<ClCompile Include="..\src\blitter\base.cpp" />
<ClInclude Include="..\src\blitter\base.hpp" />
<ClInclude Include="..\src\blitter\common.hpp" />
<ClInclude Include="..\src\blitter\factory.hpp" />
<ClCompile Include="..\src\blitter\null.cpp" />
<ClInclude Include="..\src\blitter\null.hpp" />
Expand Down
6 changes: 3 additions & 3 deletions projects/openttd_vs141.vcxproj.filters
Expand Up @@ -2691,12 +2691,12 @@
<ClInclude Include="..\src\blitter\8bpp_simple.hpp">
<Filter>Blitters</Filter>
</ClInclude>
<ClCompile Include="..\src\blitter\base.cpp">
<Filter>Blitters</Filter>
</ClCompile>
<ClInclude Include="..\src\blitter\base.hpp">
<Filter>Blitters</Filter>
</ClInclude>
<ClInclude Include="..\src\blitter\common.hpp">
<Filter>Blitters</Filter>
</ClInclude>
<ClInclude Include="..\src\blitter\factory.hpp">
<Filter>Blitters</Filter>
</ClInclude>
Expand Down
2 changes: 1 addition & 1 deletion source.list
Expand Up @@ -948,8 +948,8 @@ blitter/8bpp_optimized.hpp
blitter/8bpp_simple.cpp
blitter/8bpp_simple.hpp
#end
blitter/base.cpp
blitter/base.hpp
blitter/common.hpp
blitter/factory.hpp
blitter/null.cpp
blitter/null.hpp
Expand Down
19 changes: 19 additions & 0 deletions src/blitter/32bpp_anim.cpp
Expand Up @@ -12,6 +12,7 @@
#include "../stdafx.h"
#include "../video/video_driver.hpp"
#include "32bpp_anim.hpp"
#include "common.hpp"

#include "../table/sprites.h"

Expand Down Expand Up @@ -321,6 +322,24 @@ void Blitter_32bppAnim::SetPixel(void *video, int x, int y, uint8 colour)
this->anim_buf[this->ScreenToAnimOffset((uint32 *)video) + x + y * this->anim_buf_pitch] = colour | (DEFAULT_BRIGHTNESS << 8);
}

void Blitter_32bppAnim::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash)
{
const Colour c = LookupColourInPalette(colour);

if (_screen_disable_anim) {
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [&](int x, int y) {
*((Colour *)video + x + y * _screen.pitch) = c;
});
} else {
uint16 * const offset_anim_buf = this->anim_buf + this->ScreenToAnimOffset((uint32 *)video);
const uint16 anim_colour = colour | (DEFAULT_BRIGHTNESS << 8);
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [&](int x, int y) {
*((Colour *)video + x + y * _screen.pitch) = c;
offset_anim_buf[x + y * this->anim_buf_pitch] = anim_colour;
});
}
}

void Blitter_32bppAnim::DrawRect(void *video, int width, int height, uint8 colour)
{
if (_screen_disable_anim) {
Expand Down
1 change: 1 addition & 0 deletions src/blitter/32bpp_anim.hpp
Expand Up @@ -40,6 +40,7 @@ class Blitter_32bppAnim : public Blitter_32bppOptimized {
/* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom);
/* virtual */ void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal);
/* virtual */ void SetPixel(void *video, int x, int y, uint8 colour);
/* virtual */ void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash);
/* virtual */ void DrawRect(void *video, int width, int height, uint8 colour);
/* virtual */ void CopyFromBuffer(void *video, const void *src, int width, int height);
/* virtual */ void CopyToBuffer(const void *video, void *dst, int width, int height);
Expand Down
9 changes: 9 additions & 0 deletions src/blitter/32bpp_base.cpp
Expand Up @@ -11,6 +11,7 @@

#include "../stdafx.h"
#include "32bpp_base.hpp"
#include "common.hpp"

#include "../safeguards.h"

Expand All @@ -24,6 +25,14 @@ void Blitter_32bppBase::SetPixel(void *video, int x, int y, uint8 colour)
*((Colour *)video + x + y * _screen.pitch) = LookupColourInPalette(colour);
}

void Blitter_32bppBase::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash)
{
const Colour c = LookupColourInPalette(colour);
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [=](int x, int y) {
*((Colour *)video + x + y * _screen.pitch) = c;
});
}

void Blitter_32bppBase::DrawRect(void *video, int width, int height, uint8 colour)
{
Colour colour32 = LookupColourInPalette(colour);
Expand Down
1 change: 1 addition & 0 deletions src/blitter/32bpp_base.hpp
Expand Up @@ -23,6 +23,7 @@ class Blitter_32bppBase : public Blitter {
/* virtual */ uint8 GetScreenDepth() { return 32; }
/* virtual */ void *MoveTo(void *video, int x, int y);
/* virtual */ void SetPixel(void *video, int x, int y, uint8 colour);
/* virtual */ void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash);
/* virtual */ void DrawRect(void *video, int width, int height, uint8 colour);
/* virtual */ void CopyFromBuffer(void *video, const void *src, int width, int height);
/* virtual */ void CopyToBuffer(const void *video, void *dst, int width, int height);
Expand Down
8 changes: 8 additions & 0 deletions src/blitter/8bpp_base.cpp
Expand Up @@ -12,6 +12,7 @@
#include "../stdafx.h"
#include "../gfx_func.h"
#include "8bpp_base.hpp"
#include "common.hpp"

#include "../safeguards.h"

Expand All @@ -35,6 +36,13 @@ void Blitter_8bppBase::SetPixel(void *video, int x, int y, uint8 colour)
*((uint8 *)video + x + y * _screen.pitch) = colour;
}

void Blitter_8bppBase::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash)
{
this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [=](int x, int y) {
*((uint8 *)video + x + y * _screen.pitch) = colour;
});
}

void Blitter_8bppBase::DrawRect(void *video, int width, int height, uint8 colour)
{
do {
Expand Down
1 change: 1 addition & 0 deletions src/blitter/8bpp_base.hpp
Expand Up @@ -21,6 +21,7 @@ class Blitter_8bppBase : public Blitter {
/* virtual */ void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal);
/* virtual */ void *MoveTo(void *video, int x, int y);
/* virtual */ void SetPixel(void *video, int x, int y, uint8 colour);
/* virtual */ void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash);
/* virtual */ void DrawRect(void *video, int width, int height, uint8 colour);
/* virtual */ void CopyFromBuffer(void *video, const void *src, int width, int height);
/* virtual */ void CopyToBuffer(const void *video, void *dst, int width, int height);
Expand Down
4 changes: 3 additions & 1 deletion src/blitter/base.hpp
Expand Up @@ -122,7 +122,7 @@ class Blitter {
* @param width Line width.
* @param dash Length of dashes for dashed lines. 0 means solid line.
*/
virtual void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash = 0);
virtual void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash = 0) = 0;

/**
* Copy from a buffer to the screen.
Expand Down Expand Up @@ -203,6 +203,8 @@ class Blitter {
virtual void PostResize() { };

virtual ~Blitter() { }

template <typename SetPixelT> void DrawLineGeneric(int x, int y, int x2, int y2, int screen_width, int screen_height, int width, int dash, SetPixelT set_pixel);
};

#endif /* BLITTER_BASE_HPP */
97 changes: 78 additions & 19 deletions src/blitter/base.cpp → src/blitter/common.hpp
Expand Up @@ -7,15 +7,18 @@
* 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 base.cpp Implementation of the base for all blitters. */
/** @file common.hpp Common functionality for all blitter implementations. */

#ifndef BLITTER_COMMON_HPP
#define BLITTER_COMMON_HPP

#include "../stdafx.h"
#include "base.hpp"
#include "../core/math_func.hpp"

#include "../safeguards.h"
#include <utility>

void Blitter::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash)
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;
Expand All @@ -40,7 +43,7 @@ void Blitter::DrawLine(void *video, int x, int y, int x2, int y2, int screen_wid

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) this->SetPixel(video, x, y, colour);
if (x >= 0 && x < screen_width && y >= 0 && y < screen_height) set_pixel(x, y);
return;
}

Expand All @@ -49,11 +52,11 @@ void Blitter::DrawLine(void *video, int x, int y, int x2, int y2, int screen_wid
/* 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);
int64 frac_sq = ((int64) width) * ((int64) width) * (((int64) dx) * ((int64) dx) + ((int64) dy) * ((int64) 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) {
if (((int64) frac_test) * ((int64) frac_test) < frac_sq) {
frac_diff = frac_test + 1;
} else {
frac_max = frac_test - 1;
Expand All @@ -65,25 +68,52 @@ void Blitter::DrawLine(void *video, int x, int y, int x2, int y2, int screen_wid
if (dash == 0) dash = 1;
int dash_count = 0;
if (dx > dy) {
if (stepx < 0) {
std::swap(x, x2);
std::swap(y, y2);
stepy = -stepy;
}
if (x2 < 0 || x >= screen_width) return;

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) {
while (frac_low < -(dx / 2)) {
frac_low += dx;
y_low -= stepy;
}
while (frac_high - dx / 2 >= 0) {
while (frac_high >= dx / 2) {
frac_high -= dx;
y_high += stepy;
}
x2 += stepx;

if (x < 0) {
dash_count = (-x) % (dash + gap);
auto adjust_frac = [&](int64 frac, int &y_bound) -> int {
frac -= ((int64) dy) * ((int64) x);
if (frac >= 0) {
int quotient = frac / dx;
int remainder = frac % dx;
y_bound += (1 + quotient) * stepy;
frac = remainder - dx;
}
return frac;
};
frac_low = adjust_frac(frac_low, y_low);
frac_high = adjust_frac(frac_high, y_high);
x = 0;
}
x2++;
if (x2 > screen_width) {
x2 = screen_width;
}

while (x != x2) {
if (dash_count < dash && x >= 0 && x < screen_width) {
if (dash_count < dash) {
for (int y = y_low; y != y_high; y += stepy) {
if (y >= 0 && y < screen_height) this->SetPixel(video, x, y, colour);
if (y >= 0 && y < screen_height) set_pixel(x, y);
}
}
if (frac_low >= 0) {
Expand All @@ -94,31 +124,58 @@ void Blitter::DrawLine(void *video, int x, int y, int x2, int y2, int screen_wid
y_high += stepy;
frac_high -= dx;
}
x += stepx;
x++;
frac_low += dy;
frac_high += dy;
if (++dash_count >= dash + gap) dash_count = 0;
}
} else {
if (stepy < 0) {
std::swap(x, x2);
std::swap(y, y2);
stepx = -stepx;
}
if (y2 < 0 || y >= screen_height) return;

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) {
while (frac_low < -(dy / 2)) {
frac_low += dy;
x_low -= stepx;
}
while (frac_high - dy / 2 >= 0) {
while (frac_high >= dy / 2) {
frac_high -= dy;
x_high += stepx;
}
y2 += stepy;

if (y < 0) {
dash_count = (-y) % (dash + gap);
auto adjust_frac = [&](int64 frac, int &x_bound) -> int {
frac -= ((int64) dx) * ((int64) y);
if (frac >= 0) {
int quotient = frac / dy;
int remainder = frac % dy;
x_bound += (1 + quotient) * stepx;
frac = remainder - dy;
}
return frac;
};
frac_low = adjust_frac(frac_low, x_low);
frac_high = adjust_frac(frac_high, x_high);
y = 0;
}
y2++;
if (y2 > screen_height) {
y2 = screen_height;
}

while (y != y2) {
if (dash_count < dash && y >= 0 && y < screen_height) {
if (dash_count < dash) {
for (int x = x_low; x != x_high; x += stepx) {
if (x >= 0 && x < screen_width) this->SetPixel(video, x, y, colour);
if (x >= 0 && x < screen_width) set_pixel(x, y);
}
}
if (frac_low >= 0) {
Expand All @@ -129,10 +186,12 @@ void Blitter::DrawLine(void *video, int x, int y, int x2, int y2, int screen_wid
x_high += stepx;
frac_high -= dy;
}
y += stepy;
y++;
frac_low += dx;
frac_high += dx;
if (++dash_count >= dash + gap) dash_count = 0;
}
}
}

#endif /* BLITTER_COMMON_HPP */