X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fdraw%2Fao_poly.c;h=546f0db5ab71685d25490673862f15c0879d38fc;hb=3f31012645918097dc426cd6ba8763b30e78bab1;hp=d60d73344588121d688c4e6bf79bcd15c89698fe;hpb=38ff7005463ae83bd662ad06434840327bde729d;p=fw%2Faltos diff --git a/src/draw/ao_poly.c b/src/draw/ao_poly.c index d60d7334..546f0db5 100644 --- a/src/draw/ao_poly.c +++ b/src/draw/ao_poly.c @@ -16,9 +16,38 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include "ao_draw.h" -#include "ao_draw_int.h" +#include +#include #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,25 @@ 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_clip(ix1, 0, dst->width); + ao_clip(ix2, 0, dst->width); + ao_solid(ao_and(rop, fill), + ao_xor(rop, fill), + dst->base + iy * dst->stride, + dst->stride, + ix1, + ix2 - ix1, + 1); } /* @@ -119,43 +162,67 @@ 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; } /* * Fill the specified polygon with non-zero winding rule */ void -ao_poly(const struct ao_bitmap *dst, - const struct ao_coord *coords, - uint16_t ncoords, - uint32_t fill, +ao_poly(struct ao_bitmap *dst, + 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; + float x_min, x_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 + * Find the limits of the polygon */ - y_min = y_max = coords[0].y; + x_min = x_max = _x(coords, transform, 0); + y_min = y_max = _y(coords, transform, 0); for (edge = 1; edge < ncoords; edge++) { - y = coords[edge].y; + x = _x(coords, transform, edge); + if (x < x_min) + x_min = x; + else if (x > x_max) + x_max = x; + y = _y(coords, transform, edge); if (y < y_min) y_min = y; else if (y > y_max) y_max = y; } + x_min = floorf(x_min); + x_max = ceilf(x_max); + ao_clip(x_min, 0, dst->width); + ao_clip(x_max, 0, dst->width); + + y_min = floorf(y_min); + y_max = ceilf(y_max); + ao_clip(y_min, 0, dst->height); + ao_clip(y_max, 0, dst->height); + + ao_damage(dst, (int16_t) x_min, (int16_t) y_min, (int16_t) x_max, (int16_t) y_max); + /* * Walk each scanline in the range and fill included spans */ @@ -164,7 +231,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 +241,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;