315 lines
8.6 KiB
C
315 lines
8.6 KiB
C
/*
|
|
* $Id: fbedge.c,v 1.1.1.1 2006/11/26 18:15:37 matthieu Exp $
|
|
*
|
|
* Copyright © 2004 Keith Packard
|
|
*
|
|
* 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 Keith Packard not be used in
|
|
* advertising or publicity pertaining to distribution of the software without
|
|
* specific, written prior permission. Keith Packard makes no
|
|
* representations about the suitability of this software for any purpose. It
|
|
* is provided "as is" without express or implied warranty.
|
|
*
|
|
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
|
* EVENT SHALL KEITH PACKARD 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.
|
|
*/
|
|
|
|
#include <string.h>
|
|
|
|
#ifdef HAVE_DIX_CONFIG_H
|
|
#include <dix-config.h>
|
|
#endif
|
|
|
|
#include "fb.h"
|
|
|
|
#ifdef RENDER
|
|
|
|
#include "picturestr.h"
|
|
#include "mipict.h"
|
|
#include "renderedge.h"
|
|
#include "fbpict.h"
|
|
|
|
/*
|
|
* 4 bit alpha
|
|
*/
|
|
|
|
#define N_BITS 4
|
|
#define rasterizeEdges fbRasterizeEdges4
|
|
|
|
#if BITMAP_BIT_ORDER == LSBFirst
|
|
#define Shift4(o) ((o) << 2)
|
|
#else
|
|
#define Shift4(o) ((1-(o)) << 2)
|
|
#endif
|
|
|
|
#define Get4(x,o) (((x) >> Shift4(o)) & 0xf)
|
|
#define Put4(x,o,v) (((x) & ~(0xf << Shift4(o))) | (((v) & 0xf) << Shift4(o)))
|
|
|
|
#define DefineAlpha(line,x) \
|
|
CARD8 *__ap = (CARD8 *) line + ((x) >> 1); \
|
|
int __ao = (x) & 1
|
|
|
|
#define StepAlpha ((__ap += __ao), (__ao ^= 1))
|
|
|
|
#define AddAlpha(a) { \
|
|
CARD8 __o = *__ap; \
|
|
CARD8 __a = (a) + Get4(__o, __ao); \
|
|
*__ap = Put4 (__o, __ao, __a | (0 - ((__a) >> 4))); \
|
|
}
|
|
|
|
#include "fbedgeimp.h"
|
|
|
|
#undef AddAlpha
|
|
#undef StepAlpha
|
|
#undef DefineAlpha
|
|
#undef rasterizeEdges
|
|
#undef N_BITS
|
|
|
|
|
|
/*
|
|
* 1 bit alpha
|
|
*/
|
|
|
|
#define N_BITS 1
|
|
#define rasterizeEdges fbRasterizeEdges1
|
|
|
|
#include "fbedgeimp.h"
|
|
|
|
#undef rasterizeEdges
|
|
#undef N_BITS
|
|
|
|
/*
|
|
* 8 bit alpha
|
|
*/
|
|
|
|
static INLINE CARD8
|
|
clip255 (int x)
|
|
{
|
|
if (x > 255) return 255;
|
|
return x;
|
|
}
|
|
|
|
static INLINE void
|
|
add_saturate_8 (CARD8 *buf, int value, int length)
|
|
{
|
|
while (length--)
|
|
{
|
|
*buf = clip255 (*buf + value);
|
|
buf++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* We want to detect the case where we add the same value to a long
|
|
* span of pixels. The triangles on the end are filled in while we
|
|
* count how many sub-pixel scanlines contribute to the middle section.
|
|
*
|
|
* +--------------------------+
|
|
* fill_height =| \ /
|
|
* +------------------+
|
|
* |================|
|
|
* fill_start fill_end
|
|
*/
|
|
static void
|
|
fbRasterizeEdges8 (FbBits *buf,
|
|
int width,
|
|
int stride,
|
|
RenderEdge *l,
|
|
RenderEdge *r,
|
|
xFixed t,
|
|
xFixed b)
|
|
{
|
|
xFixed y = t;
|
|
FbBits *line;
|
|
int fill_start = -1, fill_end = -1;
|
|
int fill_size = 0;
|
|
|
|
line = buf + xFixedToInt (y) * stride;
|
|
|
|
for (;;)
|
|
{
|
|
CARD8 *ap = (CARD8 *) line;
|
|
xFixed lx, rx;
|
|
int lxi, rxi;
|
|
|
|
/* clip X */
|
|
lx = l->x;
|
|
if (lx < 0)
|
|
lx = 0;
|
|
rx = r->x;
|
|
if (xFixedToInt (rx) >= width)
|
|
rx = IntToxFixed (width);
|
|
|
|
/* Skip empty (or backwards) sections */
|
|
if (rx > lx)
|
|
{
|
|
int lxs, rxs;
|
|
|
|
/* Find pixel bounds for span. */
|
|
lxi = xFixedToInt (lx);
|
|
rxi = xFixedToInt (rx);
|
|
|
|
/* Sample coverage for edge pixels */
|
|
lxs = RenderSamplesX (lx, 8);
|
|
rxs = RenderSamplesX (rx, 8);
|
|
|
|
/* Add coverage across row */
|
|
if (lxi == rxi)
|
|
{
|
|
ap[lxi] = clip255 (ap[lxi] + rxs - lxs);
|
|
}
|
|
else
|
|
{
|
|
ap[lxi] = clip255 (ap[lxi] + N_X_FRAC(8) - lxs);
|
|
|
|
/* Move forward so that lxi/rxi is the pixel span */
|
|
lxi++;
|
|
|
|
/* Don't bother trying to optimize the fill unless
|
|
* the span is longer than 4 pixels. */
|
|
if (rxi - lxi > 4)
|
|
{
|
|
if (fill_start < 0)
|
|
{
|
|
fill_start = lxi;
|
|
fill_end = rxi;
|
|
fill_size++;
|
|
}
|
|
else
|
|
{
|
|
if (lxi >= fill_end || rxi < fill_start)
|
|
{
|
|
/* We're beyond what we saved, just fill it */
|
|
add_saturate_8 (ap + fill_start,
|
|
fill_size * N_X_FRAC(8),
|
|
fill_end - fill_start);
|
|
fill_start = lxi;
|
|
fill_end = rxi;
|
|
fill_size = 1;
|
|
}
|
|
else
|
|
{
|
|
/* Update fill_start */
|
|
if (lxi > fill_start)
|
|
{
|
|
add_saturate_8 (ap + fill_start,
|
|
fill_size * N_X_FRAC(8),
|
|
lxi - fill_start);
|
|
fill_start = lxi;
|
|
}
|
|
else if (lxi < fill_start)
|
|
{
|
|
add_saturate_8 (ap + lxi, N_X_FRAC(8),
|
|
fill_start - lxi);
|
|
}
|
|
|
|
/* Update fill_end */
|
|
if (rxi < fill_end)
|
|
{
|
|
add_saturate_8 (ap + rxi,
|
|
fill_size * N_X_FRAC(8),
|
|
fill_end - rxi);
|
|
fill_end = rxi;
|
|
}
|
|
else if (fill_end < rxi)
|
|
{
|
|
add_saturate_8 (ap + fill_end,
|
|
N_X_FRAC(8),
|
|
rxi - fill_end);
|
|
}
|
|
fill_size++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
add_saturate_8 (ap + lxi, N_X_FRAC(8), rxi - lxi);
|
|
}
|
|
|
|
/* Do not add in a 0 alpha here. This check is
|
|
* necessary to avoid a buffer overrun, (when rx
|
|
* is exactly on a pixel boundary). */
|
|
if (rxs)
|
|
ap[rxi] = clip255 (ap[rxi] + rxs);
|
|
}
|
|
}
|
|
|
|
if (y == b) {
|
|
/* We're done, make sure we clean up any remaining fill. */
|
|
if (fill_start != fill_end) {
|
|
if (fill_size == N_Y_FRAC(8))
|
|
{
|
|
memset (ap + fill_start, 0xff, fill_end - fill_start);
|
|
}
|
|
else
|
|
{
|
|
add_saturate_8 (ap + fill_start, fill_size * N_X_FRAC(8),
|
|
fill_end - fill_start);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (xFixedFrac (y) != Y_FRAC_LAST(8))
|
|
{
|
|
RenderEdgeStepSmall (l);
|
|
RenderEdgeStepSmall (r);
|
|
y += STEP_Y_SMALL(8);
|
|
}
|
|
else
|
|
{
|
|
RenderEdgeStepBig (l);
|
|
RenderEdgeStepBig (r);
|
|
y += STEP_Y_BIG(8);
|
|
if (fill_start != fill_end)
|
|
{
|
|
if (fill_size == N_Y_FRAC(8))
|
|
{
|
|
memset (ap + fill_start, 0xff, fill_end - fill_start);
|
|
}
|
|
else
|
|
{
|
|
add_saturate_8 (ap + fill_start, fill_size * N_X_FRAC(8),
|
|
fill_end - fill_start);
|
|
}
|
|
fill_start = fill_end = -1;
|
|
fill_size = 0;
|
|
}
|
|
line += stride;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
fbRasterizeEdges (FbBits *buf,
|
|
int bpp,
|
|
int width,
|
|
int stride,
|
|
RenderEdge *l,
|
|
RenderEdge *r,
|
|
xFixed t,
|
|
xFixed b)
|
|
{
|
|
switch (bpp) {
|
|
case 1:
|
|
fbRasterizeEdges1 (buf, width, stride, l, r, t, b);
|
|
break;
|
|
case 4:
|
|
fbRasterizeEdges4 (buf, width, stride, l, r, t, b);
|
|
break;
|
|
case 8:
|
|
fbRasterizeEdges8 (buf, width, stride, l, r, t, b);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endif /* RENDER */
|