From cd8587243ca353d579e8737d196fd36919d00503 Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Sun, 11 May 2014 13:14:43 +0100 Subject: [PATCH 1/3] Initial rewrite of gfx_draw_line --- src/gfx.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 115 insertions(+), 1 deletion(-) diff --git a/src/gfx.c b/src/gfx.c index 022b35e1a2..41d464030a 100644 --- a/src/gfx.c +++ b/src/gfx.c @@ -98,6 +98,48 @@ void gfx_draw_pixel(rct_drawpixelinfo *dpi, int x, int y, int colour) gfx_fill_rect(dpi, x, y, x, y, colour); } +/* +* rct2: 0x68474C +*/ +void gfx_draw_line_on_buffer(int edi, int ebp, int esi) +{ + //edi ebp + //int edi, ebp, esi; + edi -= RCT2_GLOBAL(0x9ABDBE, sint16); + + if (edi < 0)return; + if (edi >= RCT2_GLOBAL(0x9ABDC2, sint16))return; + + if (!ebp) return; + + ebp++; + esi -= RCT2_GLOBAL(0x9ABDBC, sint16); + if (esi < 0){ + ebp += esi; + if (ebp <= 0)return; + esi = 0; + } + + int eax = esi; + eax += ebp; + eax -= RCT2_GLOBAL(0x9ABDC0, sint16); + if (eax > 0){ + ebp -= eax; + return; + } + eax = RCT2_GLOBAL(0x9ABDC4, sint16); + eax += RCT2_GLOBAL(0x9ABDC0, sint16); + edi *= eax; + edi += esi; + edi += RCT2_GLOBAL(0x9ABDB8, sint32); + eax = RCT2_GLOBAL(0xEDF84A,uint16); + for (int i = 0; i < ebp; ++i){ + *((uint8*)edi) = eax; + edi++; + } +} + + /** * * rct2: 0x00684466 @@ -110,7 +152,79 @@ void gfx_draw_pixel(rct_drawpixelinfo *dpi, int x, int y, int colour) */ void gfx_draw_line(rct_drawpixelinfo *dpi, int x1, int y1, int x2, int y2, int colour) { - RCT2_CALLPROC_X(0x00684466, x1, y1, x2, y2, 0, dpi, colour); + //RCT2_CALLPROC_X(0x00684466, x1, y1, x2, y2, 0, dpi, colour); + + if ((x1 < dpi->x) && (x2 < dpi->x)){ + return;//jump to 0x68474B + } + + if ((y1 < dpi->y) && (y2 < dpi->y)){ + return;//jump to 0x68474B + } + + if ((x1 <= (dpi->x + dpi->width)) && (x2 <= (dpi->x + dpi->width))){ + return;//jump to 0x68474B + } + + if ((y1 <= (dpi->y + dpi->height)) && (y2 <= (dpi->y + dpi->height))){ + return;//jump to 0x68474B + } + + RCT2_GLOBAL(0xEDF84A, uint16) = (uint16)(0xFFFF & colour); + + int bits_pointer; + bits_pointer = dpi->bits; + RCT2_GLOBAL(0x9ABDB8, uint32) = bits_pointer; + RCT2_GLOBAL(0x9ABDBC, uint16) = dpi->x; + RCT2_GLOBAL(0x9ABDBE, uint16) = dpi->y; + RCT2_GLOBAL(0x9ABDC0, uint16) = dpi->width; + RCT2_GLOBAL(0x9ABDC2, uint16) = dpi->height; + RCT2_GLOBAL(0x9ABDC4, uint16) = dpi->pitch; + + int edi = y1; + int esi = x1; + int ebp = colour & 0xFFFF; + int cx = x2 - x1; + if (cx < 0){ + //jump 0x684633 + } + int ax = cx; + int dx = y2 - y1; + if (dx < 0){ + //jump 0x6845AB + } + RCT2_GLOBAL(0xEDF846, uint16) = cx; + RCT2_GLOBAL(0xEDF848, uint16) = dx; + if (dx > cx){ + //jump 0x68456A + } + ax--; + if (ax < 0){ + return;//jump 0x684568 + } + cx /= 2; + cx = -cx; + ebp = 0; + + for (int i = ax; i >= 0; i--){ + ebp++; + cx += RCT2_GLOBAL(0xEDF848, sint16); + if (cx <= 0){ + i--; + if (i < 0){ + gfx_draw_line_on_buffer(edi, ebp, esi); + return; + } + continue; + } + cx -= RCT2_GLOBAL(0xEDF846, sint16); + gfx_draw_line_on_buffer(edi, ebp, esi); + esi += ebp; + edi++; + ebp = 0; + } + return; + } /** From 45532da9c6bca80698190e6651cbae6895ffad3b Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Sun, 11 May 2014 20:10:32 +0100 Subject: [PATCH 2/3] Rewrote gfx_draw_line_on_buffer after realising how it works --- src/gfx.c | 126 ++++++++++++++++++++++++++++------------------ src/window_park.c | 1 - 2 files changed, 78 insertions(+), 49 deletions(-) diff --git a/src/gfx.c b/src/gfx.c index 41d464030a..7beb9bb6a7 100644 --- a/src/gfx.c +++ b/src/gfx.c @@ -99,43 +99,46 @@ void gfx_draw_pixel(rct_drawpixelinfo *dpi, int x, int y, int colour) } /* +* Draws a horizontal line of specified colour to a buffer. * rct2: 0x68474C */ -void gfx_draw_line_on_buffer(int edi, int ebp, int esi) +void gfx_draw_line_on_buffer(rct_drawpixelinfo *dpi, char colour, int y, int x, int no_pixels) { - //edi ebp - //int edi, ebp, esi; - edi -= RCT2_GLOBAL(0x9ABDBE, sint16); + y -= dpi->y; - if (edi < 0)return; - if (edi >= RCT2_GLOBAL(0x9ABDC2, sint16))return; + //Check to make sure point is in the y range + if (y < 0)return; + if (y >= dpi->height)return; + //Check to make sure we are drawing at least a pixel + if (!no_pixels) return; - if (!ebp) return; + no_pixels++; + x -= dpi->x; - ebp++; - esi -= RCT2_GLOBAL(0x9ABDBC, sint16); - if (esi < 0){ - ebp += esi; - if (ebp <= 0)return; - esi = 0; + //If x coord outside range leave + if (x < 0){ + //Unless the number of pixels is enough to be in range + no_pixels += x; + if (no_pixels <= 0)return; + //Resets starting point to 0 as we don't draw outside the range + x = 0; } - int eax = esi; - eax += ebp; - eax -= RCT2_GLOBAL(0x9ABDC0, sint16); - if (eax > 0){ - ebp -= eax; - return; + //Ensure that the end point of the line is within range + if (x + no_pixels - dpi->width > 0){ + //If the end point has any pixels outside range + //cut them off. If there are now no pixels return. + no_pixels -= x + no_pixels - dpi->width; + if (no_pixels <= 0)return; } - eax = RCT2_GLOBAL(0x9ABDC4, sint16); - eax += RCT2_GLOBAL(0x9ABDC0, sint16); - edi *= eax; - edi += esi; - edi += RCT2_GLOBAL(0x9ABDB8, sint32); - eax = RCT2_GLOBAL(0xEDF84A,uint16); - for (int i = 0; i < ebp; ++i){ - *((uint8*)edi) = eax; - edi++; + + char* bits_pointer; + //Get the buffer we are drawing to and move to the first coordinate. + bits_pointer = dpi->bits + y*(dpi->pitch + dpi->width) + x; + + //Draw the line to the specified colour + for (; no_pixels > 0; --no_pixels, ++bits_pointer){ + *((uint8*)bits_pointer) = colour; } } @@ -153,6 +156,7 @@ void gfx_draw_line_on_buffer(int edi, int ebp, int esi) void gfx_draw_line(rct_drawpixelinfo *dpi, int x1, int y1, int x2, int y2, int colour) { //RCT2_CALLPROC_X(0x00684466, x1, y1, x2, y2, 0, dpi, colour); + //return; if ((x1 < dpi->x) && (x2 < dpi->x)){ return;//jump to 0x68474B @@ -162,11 +166,11 @@ void gfx_draw_line(rct_drawpixelinfo *dpi, int x1, int y1, int x2, int y2, int c return;//jump to 0x68474B } - if ((x1 <= (dpi->x + dpi->width)) && (x2 <= (dpi->x + dpi->width))){ + if ((x1 > (dpi->x + dpi->width)) && (x2 > (dpi->x + dpi->width))){ return;//jump to 0x68474B } - if ((y1 <= (dpi->y + dpi->height)) && (y2 <= (dpi->y + dpi->height))){ + if ((y1 > (dpi->y + dpi->height)) && (y2 > (dpi->y + dpi->height))){ return;//jump to 0x68474B } @@ -184,41 +188,67 @@ void gfx_draw_line(rct_drawpixelinfo *dpi, int x1, int y1, int x2, int y2, int c int edi = y1; int esi = x1; int ebp = colour & 0xFFFF; - int cx = x2 - x1; - if (cx < 0){ - //jump 0x684633 + int x_diff, y_diff; + x_diff = x2 - x1; + + if (x1 > x2){ + x_diff = -x_diff; + int ax = x_diff; + int dx = y2 - y1; + if (dx < 0){ + RCT2_CALLPROC_X(0x6846C5, ax, x2, x_diff, dx, esi, edi, ebp); + return; + //jump 0x6846C5 + } + RCT2_GLOBAL(0xEDF846, uint16) = x_diff; + RCT2_GLOBAL(0xEDF848, uint16) = y2 - y1; + if (dx > x_diff){ + RCT2_CALLPROC_X(0x684691, ax, x2, x_diff, dx, esi, edi, ebp); + return; + //jump 0x684691 + } + ax--; + if (ax < 0)return; + x_diff /= 2; + x_diff = -x_diff; + ebp = 0; + return;//not finished } - int ax = cx; - int dx = y2 - y1; - if (dx < 0){ + int ax = x_diff; + y_diff = y2 - y1; + if (y1 > y2){ + RCT2_CALLPROC_X(0x6845AB, ax, x2, x_diff, y_diff, esi, edi, ebp); + return; //jump 0x6845AB } - RCT2_GLOBAL(0xEDF846, uint16) = cx; - RCT2_GLOBAL(0xEDF848, uint16) = dx; - if (dx > cx){ + RCT2_GLOBAL(0xEDF846, uint16) = x_diff; + RCT2_GLOBAL(0xEDF848, uint16) = y_diff; + if ((y2 - y1) > (x2 - x1)){ + RCT2_CALLPROC_X(0x68456A, ax, x2, x_diff, y_diff, esi, edi, ebp); + return; //jump 0x68456A } ax--; if (ax < 0){ + RCT2_CALLPROC_X(0x684568, ax, x2, x_diff, y_diff, esi, edi, ebp); return;//jump 0x684568 } - cx /= 2; - cx = -cx; + x_diff /= 2; + x_diff = -x_diff; ebp = 0; for (int i = ax; i >= 0; i--){ ebp++; - cx += RCT2_GLOBAL(0xEDF848, sint16); - if (cx <= 0){ - i--; - if (i < 0){ - gfx_draw_line_on_buffer(edi, ebp, esi); + x_diff += y_diff; + if (x_diff <= 0){ + if (i-1 < 0){ + gfx_draw_line_on_buffer(dpi, (uint16)(0xFFFF & colour), edi, ebp, esi); return; } continue; } - cx -= RCT2_GLOBAL(0xEDF846, sint16); - gfx_draw_line_on_buffer(edi, ebp, esi); + x_diff -= x2 - x1; + gfx_draw_line_on_buffer(dpi, (uint16)(0xFFFF & colour), edi, ebp, esi); esi += ebp; edi++; ebp = 0; diff --git a/src/window_park.c b/src/window_park.c index e01ca4550a..6e3911f424 100644 --- a/src/window_park.c +++ b/src/window_park.c @@ -2139,7 +2139,6 @@ static void window_park_graph_draw_months(rct_drawpixelinfo *dpi, uint8 *history static void window_park_graph_draw_line_a(rct_drawpixelinfo *dpi, uint8 *history, int baseX, int baseY) { int i, x, y, lastX, lastY; - lastX = -1; x = baseX; for (i = 31; i >= 0; i--) { From 84342b07d20354a94ea5597be29c864640077a79 Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Sun, 11 May 2014 21:25:18 +0100 Subject: [PATCH 3/3] Replaced decompiled code with bresenhams algorithm. Gfx_draw_line finished. --- src/gfx.c | 136 ++++++++++++++++++++++-------------------------------- 1 file changed, 54 insertions(+), 82 deletions(-) diff --git a/src/gfx.c b/src/gfx.c index 7beb9bb6a7..b2ba5158aa 100644 --- a/src/gfx.c +++ b/src/gfx.c @@ -144,7 +144,7 @@ void gfx_draw_line_on_buffer(rct_drawpixelinfo *dpi, char colour, int y, int x, /** - * + * Draws a line on dpi if within dpi boundaries * rct2: 0x00684466 * dpi (edi) * x1 (ax) @@ -155,106 +155,78 @@ void gfx_draw_line_on_buffer(rct_drawpixelinfo *dpi, char colour, int y, int x, */ void gfx_draw_line(rct_drawpixelinfo *dpi, int x1, int y1, int x2, int y2, int colour) { - //RCT2_CALLPROC_X(0x00684466, x1, y1, x2, y2, 0, dpi, colour); - //return; - + // Check to make sure the line is within the drawing area if ((x1 < dpi->x) && (x2 < dpi->x)){ - return;//jump to 0x68474B + return; } if ((y1 < dpi->y) && (y2 < dpi->y)){ - return;//jump to 0x68474B + return; } - if ((x1 > (dpi->x + dpi->width)) && (x2 > (dpi->x + dpi->width))){ - return;//jump to 0x68474B + if ((x1 >(dpi->x + dpi->width)) && (x2 >(dpi->x + dpi->width))){ + return; } if ((y1 > (dpi->y + dpi->height)) && (y2 > (dpi->y + dpi->height))){ - return;//jump to 0x68474B + return; } - RCT2_GLOBAL(0xEDF84A, uint16) = (uint16)(0xFFFF & colour); + //Bresenhams algorithm - int bits_pointer; - bits_pointer = dpi->bits; - RCT2_GLOBAL(0x9ABDB8, uint32) = bits_pointer; - RCT2_GLOBAL(0x9ABDBC, uint16) = dpi->x; - RCT2_GLOBAL(0x9ABDBE, uint16) = dpi->y; - RCT2_GLOBAL(0x9ABDC0, uint16) = dpi->width; - RCT2_GLOBAL(0x9ABDC2, uint16) = dpi->height; - RCT2_GLOBAL(0x9ABDC4, uint16) = dpi->pitch; - - int edi = y1; - int esi = x1; - int ebp = colour & 0xFFFF; - int x_diff, y_diff; - x_diff = x2 - x1; + //If vertical plot points upwards + int steep = abs(y2 - y1) > abs(x2 - x1); + if (steep){ + int temp_y2 = y2; + int temp_x2 = x2; + y2 = x1; + x2 = y1; + y1 = temp_x2; + x1 = temp_y2; + } + //If line is right to left swap direction if (x1 > x2){ - x_diff = -x_diff; - int ax = x_diff; - int dx = y2 - y1; - if (dx < 0){ - RCT2_CALLPROC_X(0x6846C5, ax, x2, x_diff, dx, esi, edi, ebp); - return; - //jump 0x6846C5 - } - RCT2_GLOBAL(0xEDF846, uint16) = x_diff; - RCT2_GLOBAL(0xEDF848, uint16) = y2 - y1; - if (dx > x_diff){ - RCT2_CALLPROC_X(0x684691, ax, x2, x_diff, dx, esi, edi, ebp); - return; - //jump 0x684691 - } - ax--; - if (ax < 0)return; - x_diff /= 2; - x_diff = -x_diff; - ebp = 0; - return;//not finished + int temp_y2 = y2; + int temp_x2 = x2; + y2 = y1; + x2 = x1; + y1 = temp_y2; + x1 = temp_x2; } - int ax = x_diff; - y_diff = y2 - y1; - if (y1 > y2){ - RCT2_CALLPROC_X(0x6845AB, ax, x2, x_diff, y_diff, esi, edi, ebp); - return; - //jump 0x6845AB - } - RCT2_GLOBAL(0xEDF846, uint16) = x_diff; - RCT2_GLOBAL(0xEDF848, uint16) = y_diff; - if ((y2 - y1) > (x2 - x1)){ - RCT2_CALLPROC_X(0x68456A, ax, x2, x_diff, y_diff, esi, edi, ebp); - return; - //jump 0x68456A - } - ax--; - if (ax < 0){ - RCT2_CALLPROC_X(0x684568, ax, x2, x_diff, y_diff, esi, edi, ebp); - return;//jump 0x684568 - } - x_diff /= 2; - x_diff = -x_diff; - ebp = 0; - for (int i = ax; i >= 0; i--){ - ebp++; - x_diff += y_diff; - if (x_diff <= 0){ - if (i-1 < 0){ - gfx_draw_line_on_buffer(dpi, (uint16)(0xFFFF & colour), edi, ebp, esi); - return; - } - continue; + int delta_x = x2 - x1; + int delta_y = abs(y2 - y1); + int error = delta_x / 2; + int y_step; + int y = y1; + + //Direction of step + if (y1 < y2)y_step = 1; + else y_step = -1; + + for (int x = x1, x_start = x1, no_pixels = 1; x < x2; ++x,++no_pixels){ + //Vertical lines are drawn 1 pixel at a time + if (steep)gfx_draw_line_on_buffer(dpi, colour, x, y, 1); + + error -= delta_y; + if (error < 0){ + //Non vertical lines are drawn with as many pixels in a horizontal line as possible + if (!steep)gfx_draw_line_on_buffer(dpi, colour, y, x_start, no_pixels); + + //Reset non vertical line vars + x_start = x + 1; + no_pixels = 1; + y += y_step; + error += delta_x; + } + + //Catch the case of the last line + if (x + 1 == x2 && !steep){ + gfx_draw_line_on_buffer(dpi, colour, y, x_start, no_pixels); } - x_diff -= x2 - x1; - gfx_draw_line_on_buffer(dpi, (uint16)(0xFFFF & colour), edi, ebp, esi); - esi += ebp; - edi++; - ebp = 0; } return; - } /**