X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fdraw%2Fao_poly.c;h=994f0a366811da18eecd7bbc64c1f40b701309ba;hb=0c6b7a34f8f52dafe7f75d790f74d4dd63fd53d3;hp=d60d73344588121d688c4e6bf79bcd15c89698fe;hpb=38ff7005463ae83bd662ad06434840327bde729d;p=fw%2Faltos diff --git a/src/draw/ao_poly.c b/src/draw/ao_poly.c index d60d7334..994f0a36 100644 --- a/src/draw/ao_poly.c +++ b/src/draw/ao_poly.c @@ -19,6 +19,35 @@ #include "ao_draw.h" #include "ao_draw_int.h" #include +#include +#include + +const struct ao_transform ao_identity = { + .x_scale = 1.0f, .x_off = 0.0f, + .y_scale = 1.0f, .y_off = 0.0f +}; + +static float +_x(const struct ao_coord *coords, + const struct ao_transform *transform, + uint16_t coord) +{ + return ao_t_x_c(&coords[coord], transform); +} + +static float +_y(const struct ao_coord *coords, + const struct ao_transform *transform, + uint16_t coord) +{ + return ao_t_y_c(&coords[coord], transform); +} + +static uint16_t +_next(uint16_t ncoords, uint16_t edge) +{ + return edge == ncoords - 1 ? 0 : edge + 1; +} /* * Return if the given edge is 'live' at the specified y coordinate. @@ -28,12 +57,12 @@ static bool ao_edge_live(const struct ao_coord *coords, uint16_t ncoords, + const struct ao_transform *transform, uint16_t edge, - int16_t y) + float y) { - int next_edge = (edge == ncoords - 1) ? 0 : edge + 1; - int16_t y1 = coords[edge].y; - int16_t y2 = coords[next_edge].y; + float y1 = _y(coords, transform, edge); + float y2 = _y(coords, transform, _next(ncoords, edge)); if (y1 > y2) return y2 <= y && y < y1; @@ -45,25 +74,26 @@ ao_edge_live(const struct ao_coord *coords, * Compute the X coordinate for a given edge at a specified y value */ static int16_t -ao_edge_x(const struct ao_coord *coords, - uint16_t ncoords, - uint16_t edge, - int16_t y) +ao_edge_x(const struct ao_coord *coords, + uint16_t ncoords, + const struct ao_transform *transform, + uint16_t edge, + float y) { - int next_edge = (edge == ncoords - 1) ? 0 : edge + 1; - int16_t x1 = coords[edge].x; - int16_t x2 = coords[next_edge].x; - int16_t y1 = coords[edge].y; - int16_t y2 = coords[next_edge].y; - int16_t dx = x2 - x1; - int16_t dy = y2 - y1; - int16_t off_y = y - y1; - - return x1 + (off_y * dx) / dy; + uint16_t next_edge = _next(ncoords, edge); + float x1 = _x(coords, transform, edge); + float x2 = _x(coords, transform, next_edge); + float y1 = _y(coords, transform, edge); + float y2 = _y(coords, transform, next_edge); + float dx = x2 - x1; + float dy = y2 - y1; + float off_y = y - y1; + + return (int16_t) (x1 + (off_y * dx) / dy + 0.5f); } struct next_x { - int16_t x; + float x; uint16_t edge; }; @@ -73,19 +103,20 @@ struct next_x { * if there are no more edges. */ static bool -ao_next_x(const struct ao_coord *coords, - uint16_t ncoords, - struct next_x *this_x, - int16_t y) +ao_next_x(const struct ao_coord *coords, + uint16_t ncoords, + const struct ao_transform *transform, + struct next_x *this_x, + float y) { uint16_t edge; - int16_t next_x = INT16_MAX; + float next_x = FLT_MAX; uint16_t next_edge = UINT16_MAX; bool ret = false; for (edge = 0; edge < ncoords; edge++) { - if (ao_edge_live(coords, ncoords, edge, y)) { - int16_t nx = ao_edge_x(coords, ncoords, edge, y); + if (ao_edge_live(coords, ncoords, transform, edge, y)) { + float nx = ao_edge_x(coords, ncoords, transform, edge, y); if (this_x->x < nx || (this_x->x == nx && this_x->edge < edge)) { if (nx < next_x) { next_x = nx; @@ -105,13 +136,16 @@ ao_next_x(const struct ao_coord *coords, */ static void ao_span(const struct ao_bitmap *dst, - int16_t x1, - int16_t x2, - int16_t y, + float x1, + float x2, + float y, uint32_t fill, uint8_t rop) { - ao_rect(dst, x1, y, x2 - x1, 1, fill, rop); + int16_t ix1 = (int16_t) floorf(x1 + 0.5f); + int16_t ix2 = (int16_t) floorf(x2 + 0.5f); + int16_t iy = (int16_t) y; + ao_rect(dst, ix1, iy, ix2 - ix1, 1, fill, rop); } /* @@ -119,12 +153,13 @@ ao_span(const struct ao_bitmap *dst, * indication of whether the edge goes upwards or downwards */ static int -ao_wind(const struct ao_coord *coords, - uint16_t ncoords, - uint16_t edge) +ao_wind(const struct ao_coord *coords, + uint16_t ncoords, + const struct ao_transform *transform, + uint16_t edge) { - uint16_t next_edge = (edge == ncoords - 1) ? 0 : edge + 1; - return coords[edge].y > coords[next_edge].y ? 1 : -1; + uint16_t next_edge = _next(ncoords, edge); + return _y(coords, transform, edge) > _y(coords, transform, next_edge) ? 1 : -1; } /* @@ -132,30 +167,37 @@ ao_wind(const struct ao_coord *coords, */ void ao_poly(const struct ao_bitmap *dst, - const struct ao_coord *coords, - uint16_t ncoords, - uint32_t fill, + const struct ao_coord *coords, + uint16_t ncoords, + const struct ao_transform *transform, + uint32_t fill, uint8_t rop) { - int16_t y_min, y_max; + float y_min, y_max; uint16_t edge; - int16_t y; - int16_t x; + float y; + float x; struct next_x next_x; int wind; + if (!transform) + transform = &ao_identity; + /* * Find the y limits of the polygon */ - y_min = y_max = coords[0].y; + y_min = y_max = _y(coords, transform, 0); for (edge = 1; edge < ncoords; edge++) { - y = coords[edge].y; + y = _y(coords, transform, edge); if (y < y_min) y_min = y; else if (y > y_max) y_max = y; } + y_min = floorf(y_min); + y_max = ceilf(y_max); + /* * Walk each scanline in the range and fill included spans */ @@ -164,7 +206,7 @@ ao_poly(const struct ao_bitmap *dst, next_x.x = INT16_MIN; next_x.edge = 0; wind = 0; - while (ao_next_x(coords, ncoords, &next_x, y)) { + while (ao_next_x(coords, ncoords, transform, &next_x, y)) { /* * Fill the previous span if winding is @@ -174,7 +216,7 @@ ao_poly(const struct ao_bitmap *dst, ao_span(dst, x, next_x.x, y, fill, rop); /* Adjust winding for the current span */ - wind += ao_wind(coords, ncoords, next_x.edge); + wind += ao_wind(coords, ncoords, transform, next_x.edge); /* Step to next span start x value */ x = next_x.x;