* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-#include "ao_draw.h"
-#include "ao_draw_int.h"
+#include <ao_draw.h>
+#include <ao_draw_int.h>
#include <stdio.h>
+#include <math.h>
+#include <float.h>
+
+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.
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;
* 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;
};
* 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;
*/
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);
}
/*
* 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
*/
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
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;