mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-03-09 23:50:25 +00:00
(svn r25119) -Codechange [FS#5512]: Improve the clipping/visiblity check before sending lines to blitter for drawing. (fonsinchen)
This commit is contained in:
parent
166513bbd4
commit
79185e7a2b
75
src/gfx.cpp
75
src/gfx.cpp
@ -191,6 +191,71 @@ void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectM
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check line clipping by using a linear equation and draw the visible part of
|
||||
* the line given by x/y and x2/y2.
|
||||
* @param video Destination pointer to draw into.
|
||||
* @param x X coordinate of first point.
|
||||
* @param y Y coordinate of first point.
|
||||
* @param x2 X coordinate of second point.
|
||||
* @param y2 Y coordinate of second point.
|
||||
* @param screen_width With of the screen to check clipping against.
|
||||
* @param screen_height Height of the screen to check clipping against.
|
||||
* @param colour Colour of the line.
|
||||
* @param width Width of the line.
|
||||
*/
|
||||
static inline void GfxDoDrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width)
|
||||
{
|
||||
Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
|
||||
|
||||
assert(width > 0);
|
||||
|
||||
if (y2 == y) {
|
||||
/* Special case: horizontal line. */
|
||||
blitter->DrawLine(video,
|
||||
Clamp(x, 0, screen_width), y,
|
||||
Clamp(x2, 0, screen_width), y2,
|
||||
screen_width, screen_height, colour, width);
|
||||
return;
|
||||
}
|
||||
if (x2 == x) {
|
||||
/* Special case: vertical line. */
|
||||
blitter->DrawLine(video,
|
||||
x, Clamp(y, 0, screen_height),
|
||||
x2, Clamp(y2, 0, screen_height),
|
||||
screen_width, screen_height, colour, width);
|
||||
return;
|
||||
}
|
||||
|
||||
int grade_y = y2 - y;
|
||||
int grade_x = x2 - x;
|
||||
|
||||
/* prevent integer overflows. */
|
||||
int margin = 1;
|
||||
while (INT_MAX / abs(grade_y) < max(abs(x), abs(screen_width - x))) {
|
||||
grade_y /= 2;
|
||||
grade_x /= 2;
|
||||
margin *= 2; // account for rounding errors
|
||||
}
|
||||
|
||||
/* If the line is outside the screen on the same side at X positions 0
|
||||
* and screen_width, we don't need to draw anything. */
|
||||
int offset_0 = y - x * grade_y / grade_x;
|
||||
int offset_width = y + (screen_width - x) * grade_y / grade_x;
|
||||
if ((offset_0 > screen_height + width / 2 + margin && offset_width > screen_height + width / 2 + margin) ||
|
||||
(offset_0 < -width / 2 - margin && offset_width < -width / 2 - margin)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* It is possible to use the line equation to further reduce the amount of
|
||||
* work the blitter has to do by shortening the effective line segment.
|
||||
* However, in order to get that right and prevent the flickering effects
|
||||
* of rounding errors so much additional code has to be run here that in
|
||||
* the general case the effect is not noticable. */
|
||||
|
||||
blitter->DrawLine(video, x, y, x2, y2, screen_width, screen_height, colour, width);
|
||||
}
|
||||
|
||||
/**
|
||||
* Align parameters of a line to the given DPI and check simple clipping.
|
||||
* @param dpi Screen parameters to align with.
|
||||
@ -219,23 +284,17 @@ static inline bool GfxPreprocessLine(DrawPixelInfo *dpi, int &x, int &y, int &x2
|
||||
|
||||
void GfxDrawLine(int x, int y, int x2, int y2, int colour, int width)
|
||||
{
|
||||
Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
|
||||
DrawPixelInfo *dpi = _cur_dpi;
|
||||
|
||||
assert(width > 0);
|
||||
|
||||
if (GfxPreprocessLine(dpi, x, y, x2, y2, width)) {
|
||||
blitter->DrawLine(dpi->dst_ptr, x, y, x2, y2, dpi->width, dpi->height, colour, width);
|
||||
GfxDoDrawLine(dpi->dst_ptr, x, y, x2, y2, dpi->width, dpi->height, colour, width);
|
||||
}
|
||||
}
|
||||
|
||||
void GfxDrawLineUnscaled(int x, int y, int x2, int y2, int colour)
|
||||
{
|
||||
Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
|
||||
DrawPixelInfo *dpi = _cur_dpi;
|
||||
|
||||
if (GfxPreprocessLine(dpi, x, y, x2, y2, 1)) {
|
||||
blitter->DrawLine(dpi->dst_ptr,
|
||||
GfxDoDrawLine(dpi->dst_ptr,
|
||||
UnScaleByZoom(x, dpi->zoom), UnScaleByZoom(y, dpi->zoom),
|
||||
UnScaleByZoom(x2, dpi->zoom), UnScaleByZoom(y2, dpi->zoom),
|
||||
UnScaleByZoom(dpi->width, dpi->zoom), UnScaleByZoom(dpi->height, dpi->zoom), colour, 1);
|
||||
|
Loading…
Reference in New Issue
Block a user