315 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			315 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * $Id$
 | |
|  *
 | |
|  * 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 */
 |