1383 lines
36 KiB
C
1383 lines
36 KiB
C
/*
|
|
* $XFree86: xc/programs/Xserver/fb/fbtrap.c,v 1.9 2002/09/26 02:56:48 keithp Exp $
|
|
*
|
|
* Copyright © 2000 University of Southern California
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software
|
|
* and its documentation for any purpose is hereby granted without
|
|
* fee, provided that the above copyright notice appear in all copies
|
|
* and that both that copyright notice and this permission notice
|
|
* appear in supporting documentation, and that the name of University
|
|
* of Southern California not be used in advertising or publicity
|
|
* pertaining to distribution of the software without specific,
|
|
* written prior permission. University of Southern California makes
|
|
* no representations about the suitability of this software for any
|
|
* purpose. It is provided "as is" without express or implied
|
|
* warranty.
|
|
*
|
|
* University of Southern California DISCLAIMS ALL WARRANTIES WITH
|
|
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE BE LIABLE FOR
|
|
* ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
|
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
|
* SOFTWARE.
|
|
*
|
|
* Author: Carl Worth, USC, Information Sciences Institute */
|
|
|
|
#include "fb.h"
|
|
|
|
#ifdef RENDER
|
|
|
|
#include "picturestr.h"
|
|
#include "mipict.h"
|
|
#include "fbpict.h"
|
|
|
|
#ifdef DEBUG
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
|
|
#define ASSERT(e) assert(e)
|
|
|
|
#endif
|
|
|
|
#ifndef ASSERT
|
|
#define ASSERT(e)
|
|
#endif
|
|
|
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
|
|
|
#define MAX_AREA 0x80000000
|
|
|
|
/*
|
|
* A RationalPoint is an exact position along one of the trapezoid
|
|
* edges represented by an approximate position (x,y) and two error
|
|
* terms (ex_dy, ey_dx). The error in X is multiplied by the Y
|
|
* dimension of the line while the error in Y is multiplied by the
|
|
* X dimension of the line, allowing an exact measurement of the
|
|
* distance from (x,y) to the line.
|
|
*
|
|
* Generally, while walking an edge, one of ex_dy/ey_dx will be zero
|
|
* indicating that the position error is held in the other.
|
|
*/
|
|
typedef struct {
|
|
xFixed x;
|
|
xFixed ex_dy;
|
|
xFixed y;
|
|
xFixed ey_dx;
|
|
} RationalPoint;
|
|
|
|
/*
|
|
* Edges are walked both horizontally and vertically
|
|
* They are walked vertically to get to a particular row
|
|
* of pixels, and then walked horizontally within that row
|
|
* to compute pixel coverage.
|
|
*
|
|
* Edges are always walked from top to bottom and from
|
|
* left to right. This means that for lines moving leftwards
|
|
* from top to bottom, the left to right walking actually moves
|
|
* backwards along the line with respect to the top to bottom
|
|
* walking.
|
|
*/
|
|
|
|
/*
|
|
* A RationalRow represents the two positions where
|
|
* an edge intersects a row of pixels. This is used
|
|
* to walk an edge vertically
|
|
*/
|
|
|
|
typedef struct {
|
|
RationalPoint top; /* intersection at top of row */
|
|
RationalPoint bottom; /* intersection at bottom of row */
|
|
RationalPoint pixel_top; /* intersection at top of pixel */
|
|
} RationalRow;
|
|
|
|
/*
|
|
* A RationalCol represents the two positions where
|
|
* an edge intersects a column of pixels
|
|
*/
|
|
|
|
typedef struct {
|
|
RationalPoint left; /* intersection at left of column */
|
|
RationalPoint right; /* intersection at right of column */
|
|
} RationalCol;
|
|
|
|
/*
|
|
Here are some thoughts on line walking:
|
|
|
|
Conditions: c2.x - c1.x = 1
|
|
r2.y - r1.y = 1
|
|
|
|
A B C D E F G H
|
|
c1\ c1 c2 /c2
|
|
r1 r1 |\ \ r1 r1 / r1/| r1 r1
|
|
\-+---+ \-+---+ +-\-+ +\--+ +--/+ +-/-+ +---+-/ +---+-/
|
|
\| | `.c1 | |r1\| | \ | | / | |/ | | .' | |/
|
|
c1\ | |`-.|c2 | \c2 | | | | | | c1/ | c1|,_/|c2 | /c2
|
|
|\ | | `. | |\ | \ | | / | /| | ./ | | /|
|
|
+-\-+ +---+-\ +---+-\ +--\+ +/--+ /-+---+ /-+---+ +-/-+
|
|
r2\| r2 r2 r2\ /r2 r2 r2 |/r2
|
|
\c2 c2 c1 c1/
|
|
|
|
Bottom Right Right Bottom Top Top Right Right
|
|
|
|
State transitions:
|
|
|
|
A -> C, D E -> E, F
|
|
B -> A, B F -> G, H
|
|
C -> A, B G -> G, H
|
|
D -> C, D H -> E, F
|
|
|
|
*/
|
|
|
|
/*
|
|
* Values for PixelWalk.depart. Top and Bottom can have the same value
|
|
* as only one mode is possible given a line of either positive or
|
|
* negative slope. These mark the departure edge while walking
|
|
* rightwards across columns.
|
|
*/
|
|
|
|
typedef enum _departure {
|
|
DepartTop = 0, /* edge exits top of pixel */
|
|
DepartBottom = 0, /* edge exits bottom of pixel */
|
|
DepartRight = 1 /* edge exits right edge of pixel */
|
|
} Departure;
|
|
|
|
/*
|
|
* PixelWalk
|
|
*
|
|
* This structure holds state to walk a single edge down the trapezoid.
|
|
*
|
|
* The edge is walked twice -- once by rows and once by columns.
|
|
* The two intersections of the pixel by the edge are then set
|
|
* from either the row or column position, depending on which edge
|
|
* is intersected.
|
|
*
|
|
* Note that for lines moving left, walking by rows moves down the
|
|
* line (increasing y) while walking by columns moves up the line
|
|
* (decreasing y).
|
|
*/
|
|
typedef struct {
|
|
xFixed dx;
|
|
xFixed ey_thresh;
|
|
xFixed dy;
|
|
xFixed ex_thresh;
|
|
|
|
Departure depart;
|
|
|
|
/* slope */
|
|
xFixed m;
|
|
xFixed em_dx;
|
|
xFixed y_correct;
|
|
xFixed ey_correct;
|
|
|
|
/* Inverse slope. Does this have a standard symbol? */
|
|
xFixed p;
|
|
xFixed ep_dy;
|
|
xFixed x_correct;
|
|
xFixed ex_correct;
|
|
|
|
/* Trapezoid bottom, used to limit walking to the last row */
|
|
xFixed bottom;
|
|
|
|
/*
|
|
* Current edge positions along pixel rows and columns
|
|
*/
|
|
RationalRow row;
|
|
RationalCol col;
|
|
|
|
/*
|
|
* The three pixel intersection points, copied from the appropriate
|
|
* row or column position above
|
|
*/
|
|
RationalPoint p_pixel_top;
|
|
RationalPoint p_trap_top;
|
|
RationalPoint p_trap_bottom;
|
|
} PixelWalk;
|
|
|
|
#if 0
|
|
#ifdef GCC
|
|
#define INLINE inline
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef INLINE
|
|
#define INLINE
|
|
#endif
|
|
|
|
/*
|
|
* Step 'pt' vertically to 'newy'.
|
|
*/
|
|
static INLINE void
|
|
pixelWalkMovePointToRow (PixelWalk *pw, RationalPoint *pt, xFixed newy)
|
|
{
|
|
xFixed_32_32 oex;
|
|
xFixed xoff;
|
|
|
|
/* X error of old X position and new Y position */
|
|
oex = (xFixed_32_32) pw->dx * (newy - pt->y) - pt->ey_dx + pt->ex_dy;
|
|
|
|
/* amount to step X by */
|
|
xoff = oex / pw->dy;
|
|
|
|
/* step X */
|
|
pt->x = pt->x + xoff;
|
|
|
|
/* set new X error value for new X position and new Y positition */
|
|
pt->ex_dy = oex - (xFixed_32_32) pw->dy * xoff;
|
|
|
|
/* set new Y position, set Y error to zero */
|
|
pt->y = newy;
|
|
pt->ey_dx = 0;
|
|
}
|
|
|
|
/*
|
|
* Step 'pt' horizontally to 'newx'
|
|
*/
|
|
static INLINE void
|
|
pixelWalkMovePointToCol (PixelWalk *pw, RationalPoint *pt, xFixed newx)
|
|
{
|
|
xFixed_32_32 oey;
|
|
xFixed yoff;
|
|
|
|
/* Special case vertical lines to arbitrary y */
|
|
if (pw->dx == 0)
|
|
{
|
|
pt->x = newx;
|
|
pt->ex_dy = 0;
|
|
pt->y = 0;
|
|
pt->ey_dx = 0;
|
|
}
|
|
else
|
|
{
|
|
/* Y error of old Y position and new X position */
|
|
oey = (xFixed_32_32) pw->dy * (newx - pt->x) - pt->ex_dy + pt->ey_dx;
|
|
|
|
/* amount to step Y by */
|
|
yoff = oey / pw->dx;
|
|
|
|
/* step Y */
|
|
pt->y = pt->y + yoff;
|
|
|
|
/* set new Y error value for new Y position and new X position */
|
|
pt->ey_dx = oey - (xFixed_32_32) pw->dx * yoff;
|
|
|
|
/* set new X position, set X error to zero */
|
|
pt->x = newx;
|
|
pt->ex_dy = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Step the 'row' element of 'pw' vertically
|
|
* (increasing y) by one whole pixel
|
|
*/
|
|
static INLINE void
|
|
pixelWalkStepRow (PixelWalk *pw)
|
|
{
|
|
xFixed y_next = xFixedFloor (pw->row.bottom.y) + xFixed1;
|
|
|
|
if (y_next > pw->bottom)
|
|
y_next = pw->bottom;
|
|
|
|
/* pw.row.top.y < pw.row.bottom.y */
|
|
pw->row.top = pw->row.bottom;
|
|
|
|
if (y_next - pw->row.bottom.y == xFixed1)
|
|
{
|
|
pw->row.pixel_top = pw->row.bottom;
|
|
pw->row.bottom.y += xFixed1;
|
|
pw->row.bottom.x += pw->p;
|
|
pw->row.bottom.ex_dy += pw->ep_dy;
|
|
if (abs (pw->row.bottom.ex_dy) > pw->ex_thresh)
|
|
{
|
|
pw->row.bottom.x += pw->x_correct;
|
|
pw->row.bottom.ex_dy += pw->ex_correct;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pixelWalkMovePointToRow (pw, &pw->row.pixel_top,
|
|
xFixedCeil (y_next) - xFixed1);
|
|
pixelWalkMovePointToRow (pw, &pw->row.bottom, y_next);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Step the 'col' element of 'pw' horizontally
|
|
* (increasing x) by one whole pixel
|
|
*/
|
|
static INLINE void
|
|
pixelWalkStepCol (PixelWalk *pw)
|
|
{
|
|
/* pw.col.p1.x < pw.col.p2.x */
|
|
/*
|
|
* Copy the current right point into the left point
|
|
*/
|
|
pw->col.left = pw->col.right;
|
|
|
|
/*
|
|
* Now incrementally walk across the pixel
|
|
*/
|
|
pw->col.right.x += xFixed1;
|
|
pw->col.right.y += pw->m;
|
|
pw->col.right.ey_dx += pw->em_dx;
|
|
if (pw->col.right.ey_dx > pw->ey_thresh)
|
|
{
|
|
pw->col.right.y += pw->y_correct;
|
|
pw->col.right.ey_dx += pw->ey_correct;
|
|
}
|
|
}
|
|
/*
|
|
* Walk to the nearest edge of the next pixel, filling in both p1 and
|
|
* p2 as necessary from either the row or col intersections.
|
|
*
|
|
* The "next" pixel is defined to be the next pixel intersected by the
|
|
* line with pixels visited in raster scan order, (for the benefit of
|
|
* cache performance). For lines with positive slope it is easy to
|
|
* achieve raster scan order by simply calling StepCol for each pixel
|
|
* in a given scanline, then calling StepRow once at the end of each
|
|
* scanline.
|
|
*
|
|
* However, for lines of negative slope where the magnitude of dx is
|
|
* greater than dy, a little more work needs to be done. The pixels of
|
|
* a particular scanline will be visited by succesive calls to StepCol
|
|
* as before. This will effectively step "up" the line as we scan from
|
|
* left to right. But, the call to StepRow at the end of the scan line
|
|
* will step "down" the line and the column information will be
|
|
* invalid at that point.
|
|
*
|
|
* For now, I fix up the column of all negative slope lines by calling
|
|
* MovePointToCol at the end of each scanline. However, this is an
|
|
* extremely expensive operation since it involves a 64-bit multiply
|
|
* and a 64-bit divide. It would be much better, (at least as long as
|
|
* abs(dx) is not much greater than dy), to instead step the col
|
|
* backwards as many times as necessary. Or even better, we could
|
|
* simply restore col to the position it began at when we started the
|
|
* scanline, then simply step it backwards once. That would give a
|
|
* performance benefit for lines with slope of any magnitude.
|
|
*/
|
|
|
|
static INLINE void
|
|
pixelWalkNextPixel (PixelWalk *pw)
|
|
{
|
|
if (pw->dx < 0)
|
|
{
|
|
/*
|
|
* left moving lines
|
|
*
|
|
* Check which pixel edge we're departing from
|
|
*
|
|
* Remember that in this case (dx < 0), the 'row' element of 'pw'
|
|
* walks down the line while 'col' walks up
|
|
*/
|
|
if (pw->depart == DepartTop)
|
|
{
|
|
/*
|
|
* The edge departs the row at this pixel, the
|
|
* next time it gets used will be for the next row
|
|
*
|
|
* Step down one row and then recompute the
|
|
* column values to start the next row of
|
|
* pixels
|
|
*/
|
|
pixelWalkStepRow(pw);
|
|
/*
|
|
* Set column exit pixel
|
|
*/
|
|
pixelWalkMovePointToCol(pw, &pw->col.right, xFixedFloor(pw->row.bottom.x));
|
|
/*
|
|
* This moves the exit pixel to the entry pixel
|
|
* and computes the next exit pixel
|
|
*/
|
|
pixelWalkStepCol(pw);
|
|
/*
|
|
* The first pixel on the next row will always
|
|
* be entered from below, set the lower
|
|
* intersection of this edge with that pixel
|
|
*/
|
|
pw->p_trap_bottom = pw->row.bottom;
|
|
}
|
|
else /* pw->depart == DepartRight */
|
|
{
|
|
/*
|
|
* easy case -- just move right one pixel
|
|
*/
|
|
pixelWalkStepCol(pw);
|
|
/*
|
|
* Set the lower intersection of the edge with the
|
|
* pixel -- that's just where the edge entered
|
|
* the pixel from the left
|
|
*/
|
|
pw->p_trap_bottom = pw->col.left;
|
|
}
|
|
/*
|
|
* Now compute which edge the pixel
|
|
* is departing from
|
|
*/
|
|
if (pw->row.top.x <= pw->col.right.x)
|
|
{
|
|
/*
|
|
* row intersection is left of column intersection,
|
|
* that means the edge hits the top of the pixel
|
|
* before it hits the right edge
|
|
*/
|
|
pw->p_trap_top = pw->row.top;
|
|
pw->depart = DepartTop;
|
|
/*
|
|
* Further check to see whether the edge
|
|
* leaves the right or top edge of the
|
|
* whole pixel
|
|
*/
|
|
if (pw->row.pixel_top.x <= pw->col.right.x)
|
|
pw->p_pixel_top = pw->row.pixel_top;
|
|
else
|
|
pw->p_pixel_top = pw->col.right;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Row intersection is right of colum intersection,
|
|
* that means the edge hits the right edge of the
|
|
* pixel first
|
|
*/
|
|
pw->p_trap_top = pw->col.right;
|
|
pw->p_pixel_top = pw->col.right;
|
|
pw->depart = DepartRight;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* right moving lines
|
|
*
|
|
* Check which edge we're departing from
|
|
*
|
|
* In the dx >= 0 case, the row and col elements both
|
|
* walk downwards
|
|
*/
|
|
if (pw->depart == DepartBottom)
|
|
{
|
|
/*
|
|
* The edge departs the row at this pixel,
|
|
* the next time it gets used will be for the
|
|
* next row
|
|
*
|
|
* Step down one row and (maybe) over one
|
|
* column to prepare for the next row
|
|
*/
|
|
if (pw->row.bottom.x == pw->col.right.x)
|
|
{
|
|
/*
|
|
* right through the corner of the pixel,
|
|
* adjust the column
|
|
*/
|
|
pixelWalkStepCol(pw);
|
|
}
|
|
pixelWalkStepRow(pw);
|
|
/*
|
|
* Set the upper intersection of the edge with
|
|
* the pixel, the first pixel on the next
|
|
* row is always entered from the top
|
|
*/
|
|
pw->p_trap_top = pw->row.top;
|
|
pw->p_pixel_top = pw->row.pixel_top;
|
|
}
|
|
else /* pw->depart == DepartRight */
|
|
{
|
|
/*
|
|
* Easy case -- move right one
|
|
* pixel
|
|
*/
|
|
pixelWalkStepCol(pw);
|
|
/*
|
|
* Set the upper intersection of the edge
|
|
* with the pixel, that's along the left
|
|
* edge of the pixel
|
|
*/
|
|
pw->p_trap_top = pw->col.left;
|
|
pw->p_pixel_top = pw->col.left;
|
|
}
|
|
/*
|
|
* Now compute the exit edge and the
|
|
* lower intersection of the edge with the pixel
|
|
*/
|
|
if (pw->row.bottom.x <= pw->col.right.x)
|
|
{
|
|
/*
|
|
* Hit the place where the edge leaves
|
|
* the pixel, the lower intersection is
|
|
* where the edge hits the bottom
|
|
*/
|
|
pw->p_trap_bottom = pw->row.bottom;
|
|
pw->depart = DepartBottom;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The edge goes through the
|
|
* next pixel on the row,
|
|
* the lower intersection is where the
|
|
* edge hits the right side of the pixel
|
|
*/
|
|
pw->p_trap_bottom = pw->col.right;
|
|
pw->depart = DepartRight;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Compute the first pixel intersection points
|
|
* and the departure type from that pixel
|
|
*/
|
|
static void
|
|
pixelWalkFirstPixel (PixelWalk *pw)
|
|
{
|
|
if (pw->dx < 0)
|
|
{
|
|
if (pw->row.top.x <= pw->col.right.x)
|
|
{
|
|
/*
|
|
* leaving through the top.
|
|
* upper position is the upper point of
|
|
* the 'row' element
|
|
*/
|
|
pw->depart = DepartTop;
|
|
pw->p_trap_top = pw->row.top;
|
|
/*
|
|
* further check for pixel top
|
|
*/
|
|
if (pw->row.pixel_top.x <= pw->col.right.x)
|
|
pw->p_pixel_top = pw->row.pixel_top;
|
|
else
|
|
pw->p_pixel_top = pw->col.right;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* leaving through the right side
|
|
* upper position is the right point of
|
|
* the 'col' element
|
|
*/
|
|
pw->depart = DepartRight;
|
|
pw->p_trap_top = pw->col.right;
|
|
pw->p_pixel_top = pw->col.right;
|
|
}
|
|
/*
|
|
* Now find the lower pixel intersection point
|
|
*/
|
|
if (pw->row.bottom.x >= pw->col.left.x)
|
|
/*
|
|
* entering through bottom,
|
|
* lower position is the bottom point of
|
|
* the 'row' element
|
|
*/
|
|
pw->p_trap_bottom = pw->row.bottom;
|
|
else
|
|
/*
|
|
* entering through left side,
|
|
* lower position is the left point of
|
|
* the 'col' element
|
|
*/
|
|
pw->p_trap_bottom = pw->col.left;
|
|
}
|
|
else
|
|
{
|
|
if (pw->row.bottom.x <= pw->col.right.x)
|
|
{
|
|
/*
|
|
* leaving through the bottom (or corner).
|
|
* lower position is the lower point of
|
|
* the 'row' element
|
|
*/
|
|
pw->depart = DepartBottom;
|
|
pw->p_trap_bottom = pw->row.bottom;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* leaving through the right side
|
|
* lower position is the right point of
|
|
* the 'col' element
|
|
*/
|
|
pw->depart = DepartRight;
|
|
pw->p_trap_bottom = pw->col.right;
|
|
}
|
|
/*
|
|
* Now find the upper pixel intersection point
|
|
*/
|
|
if (pw->row.top.x >= pw->col.left.x)
|
|
{
|
|
/*
|
|
* entering through the top (or corner),
|
|
* upper position is the top point
|
|
* of the 'row' element
|
|
*/
|
|
pw->p_trap_top = pw->row.top;
|
|
/*
|
|
* further check for pixel entry
|
|
*/
|
|
if (pw->row.pixel_top.x >= pw->col.left.x)
|
|
pw->p_pixel_top = pw->row.pixel_top;
|
|
else
|
|
pw->p_pixel_top = pw->col.left;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* entering through the left side,
|
|
* upper position is the left point of
|
|
* the 'col' element
|
|
*/
|
|
pw->p_trap_top = pw->col.left;
|
|
pw->p_pixel_top = pw->col.left;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
pixelWalkInit (PixelWalk *pw, xLineFixed *line, xFixed top_y, xFixed bottom_y)
|
|
{
|
|
xFixed_32_32 dy_inc, dx_inc;
|
|
xFixed next_y;
|
|
xFixed left_x;
|
|
xPointFixed *top, *bot;
|
|
|
|
next_y = xFixedFloor (top_y) + xFixed1;
|
|
if (next_y > bottom_y)
|
|
next_y = bottom_y;
|
|
|
|
/*
|
|
* Orient lines top down
|
|
*/
|
|
if (line->p1.y < line->p2.y)
|
|
{
|
|
top = &line->p1;
|
|
bot = &line->p2;
|
|
}
|
|
else
|
|
{
|
|
top = &line->p2;
|
|
bot = &line->p1;
|
|
}
|
|
|
|
pw->dx = bot->x - top->x;
|
|
pw->ey_thresh = abs(pw->dx >> 1);
|
|
pw->dy = bot->y - top->y;
|
|
pw->ex_thresh = pw->dy >> 1;
|
|
|
|
/*
|
|
* Set step values for walking lines
|
|
*/
|
|
if (pw->dx < 0)
|
|
{
|
|
pw->x_correct = -1;
|
|
pw->ex_correct = pw->dy;
|
|
pw->y_correct = -1;
|
|
pw->ey_correct = pw->dx;
|
|
}
|
|
else
|
|
{
|
|
pw->x_correct = 1;
|
|
pw->ex_correct = -pw->dy;
|
|
pw->y_correct = 1;
|
|
pw->ey_correct = -pw->dx;
|
|
}
|
|
|
|
pw->bottom = bottom_y;
|
|
|
|
/*
|
|
* Compute Bresenham values for walking edges incrementally
|
|
*/
|
|
dy_inc = (xFixed_32_32) xFixed1 * pw->dy; /* > 0 */
|
|
if (pw->dx != 0)
|
|
{
|
|
pw->m = dy_inc / pw->dx; /* sign(dx) */
|
|
pw->em_dx = dy_inc - (xFixed_32_32) pw->m * pw->dx; /* > 0 */
|
|
}
|
|
else
|
|
{
|
|
/* Vertical line. Setting these to zero prevents us from
|
|
having to put any conditions in pixelWalkStepCol. */
|
|
pw->m = 0;
|
|
pw->em_dx = 0;
|
|
}
|
|
|
|
dx_inc = (xFixed_32_32) xFixed1 * (xFixed_32_32) pw->dx; /* sign(dx) */
|
|
pw->p = dx_inc / pw->dy; /* sign(dx) */
|
|
pw->ep_dy = dx_inc - (xFixed_32_32) pw->p * pw->dy; /* sign(dx) */
|
|
|
|
/*
|
|
* Initialize 'row' for walking down rows
|
|
*/
|
|
pw->row.bottom.x = top->x;
|
|
pw->row.bottom.ex_dy = 0;
|
|
pw->row.bottom.y = top->y;
|
|
pw->row.bottom.ey_dx = 0;
|
|
|
|
/*
|
|
* Initialize 'pixel_top' to be on the line for
|
|
* the first step
|
|
*/
|
|
pw->row.pixel_top = pw->row.bottom;
|
|
/*
|
|
* Move to the pixel above the 'top_y' coordinate,
|
|
* first setting 'bottom' and then using StepRow
|
|
* which moves that to 'top' and computes the next 'bottom'
|
|
*/
|
|
pixelWalkMovePointToRow(pw, &pw->row.bottom, top_y);
|
|
pixelWalkStepRow(pw);
|
|
|
|
/*
|
|
* Initialize 'col' for walking across columns
|
|
*/
|
|
pw->col.right.x = top->x;
|
|
pw->col.right.ex_dy = 0;
|
|
pw->col.right.y = top->y;
|
|
pw->col.right.ey_dx = 0;
|
|
|
|
/*
|
|
* First set the column to the left most
|
|
* pixel hit by the row
|
|
*/
|
|
if (pw->dx < 0)
|
|
left_x = pw->row.bottom.x;
|
|
else
|
|
left_x = pw->row.top.x;
|
|
|
|
pixelWalkMovePointToCol(pw, &pw->col.right, xFixedFloor (left_x));
|
|
pixelWalkStepCol(pw);
|
|
|
|
/*
|
|
* Compute first pixel intersections and the
|
|
* first departure state
|
|
*/
|
|
pixelWalkFirstPixel (pw);
|
|
}
|
|
|
|
#define RoundShift(a,b) (((a) + (1 << ((b) - 1))) >> (b))
|
|
#define MaxAlpha(depth) ((1 << (depth)) - 1)
|
|
|
|
#define AreaAlpha(area, depth) (RoundShift (RoundShift (area, depth) * \
|
|
MaxAlpha (depth), \
|
|
(31 - depth)))
|
|
|
|
/*
|
|
Pixel coverage from the upper-left corner bounded by one horizontal
|
|
bottom line (bottom) and one line defined by two points, (x1,y1) and
|
|
(x2,y2), which intersect the pixel. y1 must be less than y2. There
|
|
are 8 cases yielding the following area calculations:
|
|
|
|
A B C D E F G H
|
|
+---+ +---+ +-1-+ +1--+ +--1+ +-1-+ +---+ +---+
|
|
| | 1 | | \| | \ | | / | |/ | | 1 | |
|
|
1 | |`-.| | 2 | | | | | | 2 | |,_/| | 1
|
|
|\ | | 2 | | | \ | | / | | | 2 | | /|
|
|
+-2-+ +---+ +---+ +--2+ +2--+ +---+ +---+ +-2-+
|
|
|
|
A: (1/2 * x2 * (y2 - y1))
|
|
B: (1/2 * x2 * (y2 - y1)) + (bottom - y2) * x2
|
|
C: (1/2 * (x1 + x2) * y2 ) + (bottom - y2) * x2
|
|
D: (1/2 * (x1 + x2) * y2 )
|
|
E: (1/2 * (x1 + x2) * y2 )
|
|
F: (1/2 * x1 * y2 )
|
|
G: (1/2 * x1 * (y2 - y1)) + x1 * y1
|
|
H: (1/2 * (x1 + x2) * (y2 - y1)) + x1 * y1
|
|
|
|
The union of these calculations is valid for all cases. Namely:
|
|
|
|
(1/2 * (x1 + x2) * (y2 - y1)) + (bottom - y2) * x2 + x1 * y1
|
|
|
|
An exercise for later would perhaps be to optimize the calculations
|
|
for some of the cases above. Specifically, it's possible to eliminate
|
|
multiplications by zero in several cases, leaving a maximum of two
|
|
multiplies per pixel calculation. (This is even more promising now
|
|
that the higher level code actually computes the exact same 8 cases
|
|
as part of its pixel walking).
|
|
|
|
But, for now, I just want to get something working correctly even if
|
|
slower. So, we'll use the non-optimized general equation.
|
|
|
|
*/
|
|
|
|
/* 1.16 * 1.16 -> 1.31 */
|
|
#define AREA_MULT(w, h) ( (xFixed_1_31) (((((xFixed_1_16)w)*((xFixed_1_16)h) + 1) >> 1) | (((xFixed_1_16)w)&((xFixed_1_16)h)&0x10000) << 15))
|
|
|
|
/* (1.16 + 1.16) / 2 -> 1.16 */
|
|
#define WIDTH_AVG(x1,x2) (((x1) + (x2) + 1) >> 1)
|
|
|
|
#define SubPixelArea(x1, y1, x2, y2, bottom) \
|
|
(xFixed_1_31) ( \
|
|
AREA_MULT((x1), (y1)) \
|
|
+ AREA_MULT(WIDTH_AVG((x1), (x2)), (y2) - (y1))\
|
|
+ AREA_MULT((x2), (bottom) - (y2)) \
|
|
)
|
|
|
|
/*
|
|
static xFixed_1_31
|
|
SubPixelArea (xFixed_1_16 x1,
|
|
xFixed_1_16 y1,
|
|
xFixed_1_16 x2,
|
|
xFixed_1_16 y2,
|
|
xFixed_1_16 bottom)
|
|
{
|
|
xFixed_1_16 x_trap;
|
|
xFixed_1_16 h_top, h_trap, h_bot;
|
|
xFixed_1_31 area;
|
|
|
|
x_trap = WIDTH_AVG(x1,x2);
|
|
h_top = y1;
|
|
h_trap = (y2 - y1);
|
|
h_bot = (bottom - y2);
|
|
|
|
area = AREA_MULT(x1, h_top) +
|
|
AREA_MULT(x_trap, h_trap) +
|
|
AREA_MULT(x2, h_bot);
|
|
|
|
return area;
|
|
}
|
|
*/
|
|
|
|
#define SubPixelAlpha(x1, y1, x2, y2, bottom, depth) \
|
|
( \
|
|
AreaAlpha( \
|
|
SubPixelArea((x1), (y1), (x2), (y2), (bottom)), \
|
|
(depth) \
|
|
) \
|
|
)
|
|
|
|
/*
|
|
static int
|
|
SubPixelAlpha (xFixed_1_16 x1,
|
|
xFixed_1_16 y1,
|
|
xFixed_1_16 x2,
|
|
xFixed_1_16 y2,
|
|
xFixed_1_16 bottom,
|
|
int depth)
|
|
{
|
|
xFixed_1_31 area;
|
|
|
|
area = SubPixelArea(x1, y1, x2, y2, bottom);
|
|
|
|
return AreaAlpha(area, depth);
|
|
}
|
|
*/
|
|
|
|
/* Alpha of a pixel above a given horizontal line */
|
|
#define AlphaAbove(pixel_y, line_y, depth) \
|
|
( \
|
|
AreaAlpha(AREA_MULT((line_y) - (pixel_y), xFixed1), depth) \
|
|
)
|
|
|
|
static int
|
|
RectAlpha(xFixed pixel_y, xFixed top, xFixed bottom, int depth)
|
|
{
|
|
if (depth == 1)
|
|
return top == pixel_y ? 1 : 0;
|
|
else
|
|
return (AlphaAbove (pixel_y, bottom, depth) -
|
|
AlphaAbove (pixel_y, top, depth));
|
|
}
|
|
|
|
|
|
/*
|
|
* Pixel coverage from the left edge bounded by one horizontal lines,
|
|
* (top and bottom), as well as one PixelWalk line.
|
|
*/
|
|
static int
|
|
AlphaAboveLeft(RationalPoint *upper,
|
|
RationalPoint *lower,
|
|
xFixed bottom,
|
|
xFixed pixel_x,
|
|
xFixed pixel_y,
|
|
int depth)
|
|
{
|
|
return SubPixelAlpha(upper->x - pixel_x,
|
|
upper->y - pixel_y,
|
|
lower->x - pixel_x,
|
|
lower->y - pixel_y,
|
|
bottom - pixel_y,
|
|
depth);
|
|
}
|
|
|
|
/*
|
|
Pixel coverage from the left edge bounded by two horizontal lines,
|
|
(top and bottom), as well as one line two points, p1 and p2, which
|
|
intersect the pixel. The following condition must be true:
|
|
|
|
p2.y > p1.y
|
|
*/
|
|
|
|
/*
|
|
lr
|
|
|\
|
|
+--|-\-------+
|
|
| a| b\ |
|
|
=======|===\========== top
|
|
| c| d \ |
|
|
=======|=====\======== bot
|
|
| | \ |
|
|
+--|-------\-+
|
|
|
|
alpha(d) = alpha(cd) - alpha(c) = alpha(abcd) - alpha(ab) - (alpha(ac) - alpha(c))
|
|
|
|
alpha(d) = pixelalpha(top, bot, right) - pixelalpha(top, bot, left)
|
|
|
|
pixelalpha(top, bot, line) = subpixelalpha(bot, line) - subpixelalpha(top, line)
|
|
*/
|
|
|
|
static int
|
|
PixelAlpha(xFixed pixel_x,
|
|
xFixed pixel_y,
|
|
xFixed top,
|
|
xFixed bottom,
|
|
PixelWalk *pw,
|
|
int depth)
|
|
{
|
|
int alpha;
|
|
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "alpha (%f, %f) - (%f, %f) = ",
|
|
(double) pw->p1.x / (1 << 16),
|
|
(double) pw->p1.y / (1 << 16),
|
|
(double) pw->p2.x / (1 << 16),
|
|
(double) pw->p2.y / (1 << 16));
|
|
fflush(stderr);
|
|
#endif
|
|
|
|
/*
|
|
* Sharp polygons are different, alpha is 1 if the
|
|
* area includes the pixel origin, else zero, in
|
|
* the above figure, only 'a' has alpha 1
|
|
*/
|
|
if (depth == 1)
|
|
{
|
|
alpha = 0;
|
|
if (top == pixel_y && pw->p_pixel_top.x != pixel_x)
|
|
alpha = 1;
|
|
}
|
|
else
|
|
{
|
|
alpha = (AlphaAboveLeft(&pw->p_pixel_top, &pw->p_trap_bottom,
|
|
bottom, pixel_x, pixel_y, depth)
|
|
- AlphaAboveLeft(&pw->p_pixel_top, &pw->p_trap_top,
|
|
top, pixel_x, pixel_y, depth));
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "0x%x => %f\n",
|
|
alpha,
|
|
(double) alpha / ((1 << depth) -1 ));
|
|
fflush(stderr);
|
|
#endif
|
|
|
|
return alpha;
|
|
}
|
|
|
|
#define INCREMENT_X_AND_PIXEL \
|
|
{ \
|
|
pixel_x += xFixed1; \
|
|
(*mask.over) (&mask); \
|
|
}
|
|
|
|
/* XXX: What do we really want this prototype to look like? Do we want
|
|
separate versions for 1, 4, 8, and 16-bit alpha? */
|
|
|
|
#define saturateAdd(t, a, b) (((t) = (a) + (b)), \
|
|
((CARD8) ((t) | (0 - ((t) >> 8)))))
|
|
|
|
#define addAlpha(mask, depth, alpha, temp) (\
|
|
(*(mask)->store) ((mask), (alpha == (1 << depth) - 1) ? \
|
|
0xff000000 : \
|
|
(saturateAdd (temp, \
|
|
alpha << (8 - depth), \
|
|
(*(mask)->fetch) (mask) >> 24) << 24)) \
|
|
)
|
|
|
|
void
|
|
fbRasterizeTrapezoid (PicturePtr pMask,
|
|
xTrapezoid *pTrap,
|
|
int x_off,
|
|
int y_off)
|
|
{
|
|
xTrapezoid trap = *pTrap;
|
|
int alpha, temp;
|
|
|
|
FbCompositeOperand mask;
|
|
|
|
int depth = pMask->pDrawable->depth;
|
|
int max_alpha = (1 << depth) - 1;
|
|
int buf_width = pMask->pDrawable->width;
|
|
|
|
xFixed x_off_fixed = IntToxFixed(x_off);
|
|
xFixed y_off_fixed = IntToxFixed(y_off);
|
|
xFixed buf_width_fixed = IntToxFixed(buf_width);
|
|
|
|
PixelWalk left, right;
|
|
xFixed pixel_x, pixel_y;
|
|
xFixed first_right_x;
|
|
xFixed y, y_next;
|
|
|
|
/* trap.left and trap.right must be non-horizontal */
|
|
if (trap.left.p1.y == trap.left.p2.y
|
|
|| trap.right.p1.y == trap.right.p2.y) {
|
|
return;
|
|
}
|
|
|
|
trap.top += y_off_fixed;
|
|
trap.bottom += y_off_fixed;
|
|
trap.left.p1.x += x_off_fixed;
|
|
trap.left.p1.y += y_off_fixed;
|
|
trap.left.p2.x += x_off_fixed;
|
|
trap.left.p2.y += y_off_fixed;
|
|
trap.right.p1.x += x_off_fixed;
|
|
trap.right.p1.y += y_off_fixed;
|
|
trap.right.p2.x += x_off_fixed;
|
|
trap.right.p2.y += y_off_fixed;
|
|
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "(top, bottom) = (%f, %f)\n",
|
|
(double) trap.top / (1 << 16),
|
|
(double) trap.bottom / (1 << 16));
|
|
#endif
|
|
|
|
pixelWalkInit(&left, &trap.left, trap.top, trap.bottom);
|
|
pixelWalkInit(&right, &trap.right, trap.top, trap.bottom);
|
|
|
|
/* XXX: I'd still like to optimize this loop for top and
|
|
bottom. Only the first row intersects top and only the last
|
|
row, (which could also be the first row), intersects bottom. So
|
|
we could eliminate some unnecessary calculations from all other
|
|
rows. Unfortunately, I haven't found an easy way to do it
|
|
without bloating the text, (eg. unrolling a couple iterations
|
|
of the loop). So, for sake of maintenance, I'm putting off this
|
|
optimization at least until this code is more stable.. */
|
|
|
|
if (!fbBuildCompositeOperand (pMask, &mask, 0, xFixedToInt (trap.top), FALSE, FALSE))
|
|
return;
|
|
|
|
for (y = trap.top; y < trap.bottom; y = y_next)
|
|
{
|
|
pixel_y = xFixedFloor (y);
|
|
y_next = pixel_y + xFixed1;
|
|
if (y_next > trap.bottom)
|
|
y_next = trap.bottom;
|
|
|
|
ASSERT (left.row.top.y == y);
|
|
ASSERT (left.row.bottom.y == y_next);
|
|
ASSERT (right.row.top.y == y);
|
|
ASSERT (right.row.bottom.y == y_next);
|
|
|
|
pixel_x = xFixedFloor(left.col.left.x);
|
|
|
|
/*
|
|
* Walk pixels on this row that are left of the
|
|
* first possibly lit pixel
|
|
*
|
|
* pixelWalkNextPixel will change .row.top.y
|
|
* when the last pixel covered by the edge
|
|
* is passed
|
|
*/
|
|
|
|
first_right_x = xFixedFloor(right.col.left.x);
|
|
while (right.row.top.y == y && first_right_x < pixel_x)
|
|
{
|
|
/* these are empty */
|
|
pixelWalkNextPixel (&right);
|
|
/* step over */
|
|
first_right_x += xFixed1;
|
|
}
|
|
|
|
(*mask.set) (&mask, xFixedToInt (pixel_x), xFixedToInt (y));
|
|
|
|
/*
|
|
* Walk pixels on this row intersected by only trap.left
|
|
*
|
|
*/
|
|
while (left.row.top.y == y && pixel_x < first_right_x)
|
|
{
|
|
alpha = (RectAlpha (pixel_y, y, y_next, depth)
|
|
- PixelAlpha(pixel_x, pixel_y, y, y_next, &left, depth));
|
|
|
|
if (alpha > 0)
|
|
{
|
|
if (0 <= pixel_x && pixel_x < buf_width_fixed)
|
|
addAlpha (&mask, depth, alpha, temp);
|
|
}
|
|
|
|
/*
|
|
* Step right
|
|
*/
|
|
pixelWalkNextPixel(&left);
|
|
INCREMENT_X_AND_PIXEL;
|
|
}
|
|
|
|
/*
|
|
* Either pixels are covered by both edges or
|
|
* there are fully covered pixels on this row
|
|
*/
|
|
if (pixel_x == first_right_x)
|
|
{
|
|
/*
|
|
* Now walk the pixels on this row intersected
|
|
* by both edges
|
|
*/
|
|
while (left.row.top.y == y && right.row.top.y == y)
|
|
{
|
|
alpha = (PixelAlpha(pixel_x, pixel_y, y, y_next, &right, depth)
|
|
- PixelAlpha(pixel_x, pixel_y, y, y_next, &left, depth));
|
|
if (alpha > 0)
|
|
{
|
|
ASSERT (0 <= alpha && alpha <= max_alpha);
|
|
if (0 <= pixel_x && pixel_x < buf_width_fixed)
|
|
addAlpha (&mask, depth, alpha, temp);
|
|
}
|
|
pixelWalkNextPixel(&left);
|
|
pixelWalkNextPixel(&right);
|
|
INCREMENT_X_AND_PIXEL;
|
|
}
|
|
/*
|
|
* If the right edge is now left of the left edge,
|
|
* the left edge will end up only partially walked,
|
|
* walk it the rest of the way
|
|
*/
|
|
while (left.row.top.y == y)
|
|
pixelWalkNextPixel(&left);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Fully covered pixels simply saturate
|
|
*/
|
|
alpha = RectAlpha (pixel_y, y, y_next, depth);
|
|
if (alpha == max_alpha)
|
|
{
|
|
while (pixel_x < first_right_x)
|
|
{
|
|
if (0 <= pixel_x && pixel_x < buf_width_fixed)
|
|
(*mask.store) (&mask, 0xff000000);
|
|
INCREMENT_X_AND_PIXEL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (pixel_x < first_right_x)
|
|
{
|
|
ASSERT (0 <= alpha && alpha <= max_alpha);
|
|
if (0 <= pixel_x && pixel_x < buf_width_fixed)
|
|
addAlpha (&mask, depth, alpha, temp);
|
|
INCREMENT_X_AND_PIXEL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Finally, pixels intersected only by trap.right
|
|
*/
|
|
while (right.row.top.y == y)
|
|
{
|
|
alpha = PixelAlpha(pixel_x, pixel_y, y, y_next, &right, depth);
|
|
if (alpha > 0)
|
|
{
|
|
if (0 <= pixel_x && pixel_x < buf_width_fixed)
|
|
addAlpha (&mask, depth, alpha, temp);
|
|
}
|
|
pixelWalkNextPixel(&right);
|
|
INCREMENT_X_AND_PIXEL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Some notes on walking while keeping track of errors in both dimensions:
|
|
|
|
That's really pretty easy. Your bresenham should be walking sub-pixel
|
|
coordinates rather than pixel coordinates. Now you can calculate the
|
|
sub-pixel Y coordinate for any arbitrary sub-pixel X coordinate (or vice
|
|
versa).
|
|
|
|
ey: y error term (distance from current Y sub-pixel to line) * dx
|
|
ex: x error term (distance from current X sub-pixel to line) * dy
|
|
dx: difference of X coordinates for line endpoints
|
|
dy: difference of Y coordinates for line endpoints
|
|
x: current fixed-point X coordinate
|
|
y: current fixed-point Y coordinate
|
|
|
|
One of ey or ex will always be zero, depending on whether the distance to
|
|
the line was measured horizontally or vertically.
|
|
|
|
In moving from x, y to x1, y1:
|
|
|
|
(x1 + e1x/dy) - (x + ex/dy) dx
|
|
--------------------------- = --
|
|
(y1 + e1y/dx) - (y + ey/dx) dy
|
|
|
|
(x1dy + e1x) - (xdy + ex) = (y1dx + e1y) - (ydx + ey)
|
|
|
|
dy(x1 - x) + (e1x - ex) = dx(y1-y) + (e1y - ey)
|
|
|
|
So, if you know y1 and want to know x1:
|
|
|
|
Set e1y to zero and compute the error from x:
|
|
|
|
oex = dx(y1 - y) - ey + ex
|
|
|
|
Compute the number of whole pixels to get close to the line:
|
|
|
|
wx = oex / dy
|
|
|
|
Set x1:
|
|
|
|
Now compute the e1x:
|
|
|
|
e1x = oex - wx * dy
|
|
|
|
A similar operation moves to a known y1. Note that this computation (in
|
|
general) requires 64 bit arithmetic. I suggest just using the available
|
|
64 bit datatype for now, we can optimize the common cases with a few
|
|
conditionals. There's some cpp code in fb/fb.h that selects a 64 bit type
|
|
for machines that XFree86 builds on; there aren't any machines missing a
|
|
64 bit datatype that I know of.
|
|
*/
|
|
|
|
/* Here's a large-step Bresenham for jogging my memory.
|
|
|
|
void large_bresenham_x_major(x1, y1, x2, y2, x_inc)
|
|
{
|
|
int x, y, dx, dy, m;
|
|
int em_dx, ey_dx;
|
|
|
|
dx = x2 - x1;
|
|
dy = y2 - y1;
|
|
|
|
m = (x_inc * dy) / dx;
|
|
em_dx = (x_inc * dy) - m * dx;
|
|
|
|
x = x1;
|
|
y = y1;
|
|
ey = 0;
|
|
|
|
set(x,y);
|
|
|
|
while (x < x2) {
|
|
x += x_inc;
|
|
y += m;
|
|
ey_dx += em_dx;
|
|
if (ey_dx > dx_2) {
|
|
y++;
|
|
ey_dx -= dx;
|
|
}
|
|
set(x,y);
|
|
}
|
|
}
|
|
|
|
*/
|
|
|
|
/* Here are the latest, simplified equations for computing trapezoid
|
|
coverage of a pixel:
|
|
|
|
alpha_from_area(A) = round(2**depth-1 * A)
|
|
|
|
alpha(o) = 2**depth-1
|
|
|
|
alpha(a) = alpha_from_area(area(a))
|
|
|
|
alpha(ab) = alpha_from_area(area(ab))
|
|
|
|
alpha(b) = alpha(ab) - alpha (a)
|
|
|
|
alpha(abc) = alpha_from_area(area(abc))
|
|
|
|
alpha(c) = alpha(abc) - alpha(ab)
|
|
|
|
alpha(ad) = alpha_from_area(area(ad))
|
|
|
|
alpha (d) = alpha(ad) - alpha (a)
|
|
|
|
alpha (abde) = alpha_from_area(area(abde))
|
|
|
|
alpha (de) = alpha (abde) - alpha (ab)
|
|
|
|
alpha (e) = alpha (de) - alpha (d)
|
|
|
|
alpha (abcdef) = alpha_from_area(area(abcdef))
|
|
|
|
alpha (def) = alpha (abcdef) - alpha (abc)
|
|
|
|
alpha (f) = alpha (def) - alpha (de)
|
|
|
|
alpha (adg) = alpha_from_area(area(adg))
|
|
|
|
alpha (g) = alpha (adg) - alpha (ad)
|
|
|
|
alpha (abdegh) = alpha_from_area(area(abdegh))
|
|
|
|
alpha (gh) = alpha (abdegh) - alpha (abde)
|
|
|
|
alpha (h) = alpha (gh) - alpha (g)
|
|
|
|
alpha (abcdefghi) = alpha_from_area(area(abcdefghi)) =
|
|
alpha_from_area(area(o)) = alpha_from_area(1) = alpha(o)
|
|
|
|
alpha (ghi) = alpha (abcdefghi) - alpha (abcdef)
|
|
|
|
alpha (i) = alpha (ghi) - alpha (gh)
|
|
*/
|
|
|
|
/* Latest thoughts from Keith on implementing area/alpha computations:
|
|
|
|
*** 1.16 * 1.16 -> 1.31 ***
|
|
#define AREA_MULT(w,h) ((w)&(h) == 0x10000 ? 0x80000000 : (((w)*(h) + 1) >> 1)
|
|
|
|
*** (1.16 + 1.16) / 2 -> 1.16 ***
|
|
#define WIDTH_AVG(x1,x2) (((x1) + (x2) + 1) >> 1)
|
|
|
|
xFixed_1_31
|
|
SubpixelArea (xFixed_1_16 x1,
|
|
xFixed_1_16 x2,
|
|
xFixed_1_16 y1,
|
|
xFixed_1_16 y2,
|
|
xFixed_1_16 bottom)
|
|
{
|
|
xFixed_1_16 x_trap;
|
|
xFixed_1_16 h_top, h_trap, h_bot;
|
|
xFixed_1_31 area;
|
|
|
|
x_trap = WIDTH_AVG(x1,x2);
|
|
h_top = y1;
|
|
h_trap = (y2 - y1);
|
|
h_bot = (bottom - y2);
|
|
|
|
area = AREA_MULT(x1, h_top) +
|
|
AREA_MULT(x_trap, h_trap) +
|
|
AREA_MULT(x2, h_bot);
|
|
|
|
return area;
|
|
}
|
|
|
|
To convert this xFixed_1_31 value to alpha using 32 bit arithmetic:
|
|
|
|
int
|
|
AreaAlpha (xFixed_1_31 area, int depth)
|
|
{
|
|
return ((area >> bits) * ((1 << depth) - 1)) >> (31 - depth);
|
|
}
|
|
|
|
Avoiding the branch bubble in the AREA_MULT could be done with either:
|
|
|
|
area = (w * h + 1) >> 1;
|
|
area |= ((area - 1) & 0x80000000);
|
|
|
|
or
|
|
#define AREA_MULT(w,h) ((((w)*(h) + 1) >> 1) | ((w)&(h)&0x10000) << 15)
|
|
|
|
depending on your preference, the first takes one less operation but
|
|
can't be expressed as a macro; the second takes a large constant which may
|
|
require an additional instruction on some processors. The differences
|
|
will be swamped by the cost of the multiply.
|
|
|
|
*/
|
|
|
|
#endif /* RENDER */
|