shithub: candycrisis

ref: e67675bc2c457a0bc3bd4b7883d82d0ec7746c10
dir: /src/blitter.c/

View raw version
// blitter.c

#include "SDLU.h"

#include "main.h"
#include "gworld.h"
#include "blitter.h"
#include "font.h"
#include "level.h"
#include "graphics.h"

MBoolean update[2][kGridAcross][kGridDown];
MBoolean refresh[2];

void InitBlitter( void )
{
	int player, x, y;

	for( player=0; player<=1; player++ )
	{
		refresh[player] = false;
		
		for( x=0; x<kGridAcross; x++ )
		{
			for( y=0; y<kGridDown; y++ )
			{
				update[player][x][y] = false;
			}
		}
	}
}

void UpdatePlayerWindow( int player )
{
	SDL_Rect fullSDLRect, offsetSDLRect;
	int      x, y;
	
	if( control[player] == kNobodyControl ) return;
	
	if( playerWindowVisible[player] && refresh[player] )
	{
		MRect updateRect = {0, 0, 0, 0}, fullRect, offsetRect;
		MBoolean first = true;
		
		for( x=0; x<kGridAcross; x++ )
		{
			for( y=1; y<kGridDown; y++ )
			{
				if( update[player][x][y] )
				{
					updateRect.top  = y * kBlobVertSize;
					updateRect.left = x * kBlobHorizSize;
					updateRect.bottom = updateRect.top + kBlobVertSize;
					updateRect.right = updateRect.left + kBlobHorizSize;
					if( first )
					{
						fullRect = updateRect;
						first = false;
					}
					else
					{
						UnionMRect( &fullRect, &updateRect, &fullRect );
					}

					update[player][x][y] = false;
				}
			}
		}

		if( !first )
		{
			offsetRect = fullRect;
			OffsetMRect( &offsetRect, playerWindowRect[player].left, playerWindowRect[player].top - kBlobVertSize );
			
			SDLU_BlitFrontSurface( playerSpriteSurface[player], 
								   SDLU_MRectToSDLRect( &fullRect, &fullSDLRect ),
								   SDLU_MRectToSDLRect( &offsetRect, &offsetSDLRect ) );
		}
	}
}

void SetUpdateRect( int player, MRect *where )
{
	int x,y;
	int xMin, xMax, yMin, yMax;
	
	xMin = where->left / kBlobHorizSize;
	xMax = ( where->right + kBlobHorizSize - 1 ) / kBlobHorizSize;
	
	if( xMin < 0 ) xMin = 0;
	if( xMin > (kGridAcross-1) ) xMin = kGridAcross-1;
	if( xMax < 0 ) xMax = 0;
	if( xMax > kGridAcross ) xMax = kGridAcross;
	
	yMin = where->top / kBlobVertSize;
	yMax = ( where->bottom + kBlobVertSize - 1 ) / kBlobVertSize;

	if( yMin < 0 ) yMin = 0;
	if( yMin > (kGridDown-1) ) yMin = kGridDown-1;
	if( yMax < 0 ) yMax = 0;
	if( yMax > kGridDown ) yMax = kGridDown;
	
	for( x=xMin; x<xMax; x++ )
	{
		for( y=yMin; y<yMax; y++ )
		{
			update[player][x][y] = true;
		}
	}
	
	refresh[player] = true;
}


void SurfaceBlitMask( SDL_Surface* object,     SDL_Surface* mask,     SDL_Surface* dest,
                      const MRect*  objectRect, const MRect*  maskRect, const MRect*  destRect )
{
	int            startX = 0, startY = 0, endX, endY, x, y, srcRowBytes, mskRowBytes, dstRowBytes;
	unsigned char *src, *msk, *dst;
	MRect          destBounds;

	SDLU_SDLRectToMRect( &dest->clip_rect, &destBounds );
	
	endX = objectRect->right - objectRect->left;
	endY = objectRect->bottom - objectRect->top;

	if( destRect->left   > destBounds.right  ||			// completely clipped?
		destRect->right  < destBounds.left   ||
		destRect->top    > destBounds.bottom ||
		destRect->bottom < destBounds.top )
	{
		return; 												// do nothing
	}
	
	src         = (unsigned char*) object->pixels;
	msk         = (unsigned char*) mask->pixels;
	dst         = (unsigned char*) dest->pixels;
	srcRowBytes = object->pitch;
	mskRowBytes = mask->pitch;
	dstRowBytes = dest->pitch;
	
	src += (objectRect->top * srcRowBytes) + (objectRect->left * BYTES_PER_PIXEL);
	msk += (maskRect->top   * mskRowBytes) + (maskRect->left   * BYTES_PER_MASK_PIXEL);
	dst += (destRect->top   * dstRowBytes) + (destRect->left   * BYTES_PER_PIXEL);
	
	if( destRect->left   < destBounds.left   ) startX -= destRect->left - destBounds.left;
	if( destRect->right  > destBounds.right  ) endX   -= destRect->right - destBounds.right;
	if( destRect->top    < destBounds.top    ) startY -= destRect->top - destBounds.top;
	if( destRect->bottom > destBounds.bottom ) endY   -= destRect->bottom - destBounds.bottom;
	
	msk += (mskRowBytes * startY) + (startX * BYTES_PER_MASK_PIXEL);
	src += (srcRowBytes * startY) + (startX * BYTES_PER_PIXEL);
	dst += (dstRowBytes * startY) + (startX * BYTES_PER_PIXEL);

	for( y=startY; y<endY; y++ )
	{
		unsigned char *tSrc = src, *tDst = dst, *tMsk = msk;
		
		for( x=startX; x<endX; x++ )
		{
			if( *msk )
			{
				*(COLOR_T*)dst = *(COLOR_T*)src;
			}
			
			src += BYTES_PER_PIXEL;
			dst += BYTES_PER_PIXEL;
			msk += BYTES_PER_MASK_PIXEL;
		}
		
		src = tSrc + srcRowBytes;
		dst = tDst + dstRowBytes;
		msk = tMsk + mskRowBytes;
	}
}


void SurfaceBlitBlob( const MRect* blobRect, const MRect* destRect )
{
	SurfaceBlitMask( blobSurface, maskSurface, SDLU_GetCurrentSurface(),
	                 blobRect,    blobRect,    destRect                  );
}


void SurfaceBlitColor( SDL_Surface* mask,     SDL_Surface* dest,
                       const MRect* maskRect, const MRect* destRect, 
                       int r, int g, int b, int weight )
{
	int            startX = 0, startY = 0, endX, endY, x, y, mskRowBytes, dstRowBytes;
	unsigned char *msk, *dst;
	MRect          destBounds;
	
	endX = maskRect->right - maskRect->left;
	endY = maskRect->bottom - maskRect->top;
	
	SDLU_SDLRectToMRect( &dest->clip_rect, &destBounds );

	if( destRect->left   > destBounds.right  ||			// completely clipped?
		destRect->right  < destBounds.left   ||
		destRect->top    > destBounds.bottom ||
		destRect->bottom < destBounds.top )
	{
		return; 												// do nothing
	}
	
	msk         = (unsigned char*) mask->pixels;
	dst         = (unsigned char*) dest->pixels;
	mskRowBytes = mask->pitch;
	dstRowBytes = dest->pitch;
	
	msk += (maskRect->top * mskRowBytes) + (maskRect->left * BYTES_PER_MASK_PIXEL);
	dst += (destRect->top * dstRowBytes) + (destRect->left * BYTES_PER_PIXEL);
	
	if( destRect->left   < destBounds.left   ) startX -= destRect->left - destBounds.left;
	if( destRect->right  > destBounds.right  ) endX   -= destRect->right - destBounds.right;
	if( destRect->top    < destBounds.top    ) startY -= destRect->top - destBounds.top;
	if( destRect->bottom > destBounds.bottom ) endY   -= destRect->bottom - destBounds.bottom;
	
	msk += (mskRowBytes * startY) + (startX * BYTES_PER_MASK_PIXEL);
	dst += (dstRowBytes * startY) + (startX * BYTES_PER_PIXEL);

	r *= weight;
	g *= weight;
	b *= weight;
	weight = FULL_WEIGHT - weight;
	
	for( y=startY; y<endY; y++ )
	{
		unsigned char *tMsk = msk, *tDst = dst;
		int work, workB, workG, workR;
		
		for( x=startX; x<endX; x++ )
		{
			if( *msk )
			{
				work = *(COLOR_T*)dst;
                workB = ((((work                    ) & CHANNEL_MASK)*weight) + b) >> BITS_PER_1CHANNEL;
                workG = ((((work>>BITS_PER_1CHANNEL ) & CHANNEL_MASK)*weight) + g)                     ;
                workR = ((((work>>BITS_PER_2CHANNELS) & CHANNEL_MASK)*weight) + r) << BITS_PER_1CHANNEL;

                *(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
			}
			
			dst += BYTES_PER_PIXEL;
			msk += BYTES_PER_MASK_PIXEL;
		}
		
		msk = tMsk + mskRowBytes;
		dst = tDst + dstRowBytes;
	}
}


void SurfaceBlitAlpha( SDL_Surface* back,     SDL_Surface* source,     SDL_Surface* alpha,     SDL_Surface* dest,
                       const MRect* backRect, const MRect* sourceRect, const MRect* alphaRect, const MRect* destRect )
{
	int startX = 0, startY = 0, endX, endY, x, y, srcRowBytes, alfRowBytes, dstRowBytes, bckRowBytes;
	unsigned char *bck, *src, *alf, *dst;
	MRect destBounds;
	
	endX = sourceRect->right - sourceRect->left;
	endY = sourceRect->bottom - sourceRect->top;
	
	SDLU_SDLRectToMRect( &dest->clip_rect, &destBounds );

	if( destRect->left   > destBounds.right  ||			// completely clipped?
		destRect->right  < destBounds.left   ||
		destRect->top    > destBounds.bottom ||
		destRect->bottom < destBounds.top )
	{
		return; 												// do nothing
	}
	
	bck         = (unsigned char*) back->pixels;
	src         = (unsigned char*) source->pixels; 
	alf         = (unsigned char*) alpha->pixels;
	dst         = (unsigned char*) dest->pixels; 
	bckRowBytes = back->pitch; 
	srcRowBytes = source->pitch;
	alfRowBytes = alpha->pitch;
	dstRowBytes = dest->pitch;
	
	bck += (backRect->top   * bckRowBytes) + (backRect->left   * BYTES_PER_PIXEL);
	src += (sourceRect->top * srcRowBytes) + (sourceRect->left * BYTES_PER_PIXEL);
	alf += (alphaRect->top  * alfRowBytes) + (alphaRect->left  * BYTES_PER_PIXEL);
	dst += (destRect->top   * dstRowBytes) + (destRect->left   * BYTES_PER_PIXEL);
	
	if( destRect->left   < destBounds.left   ) startX -= destRect->left   - destBounds.left;
	if( destRect->right  > destBounds.right  ) endX   -= destRect->right  - destBounds.right;
	if( destRect->top    < destBounds.top    ) startY -= destRect->top    - destBounds.top;
	if( destRect->bottom > destBounds.bottom ) endY   -= destRect->bottom - destBounds.bottom;
	
	bck += (bckRowBytes * startY) + (startX * BYTES_PER_PIXEL);
	src += (srcRowBytes * startY) + (startX * BYTES_PER_PIXEL);
	alf += (alfRowBytes * startY) + (startX * BYTES_PER_PIXEL);
	dst += (dstRowBytes * startY) + (startX * BYTES_PER_PIXEL);

	for( y=startY; y<endY; y++ )
	{
		unsigned char *tSrc = src, *tAlf = alf, *tDst = dst, *tBck = bck;
		int pixS, pixB, weightS, weightB, workB, workG, workR;
		
		for( x=startX; x<endX; x++ )
		{
			weightB = *(COLOR_T*)alf;
			
			if( (weightB & (RED_MASK | GREEN_MASK | BLUE_MASK)) == (RED_MASK | GREEN_MASK | BLUE_MASK))
			{
				*(COLOR_T*)dst = *(COLOR_T*)bck;
			}
			else if( (weightB & (RED_MASK | GREEN_MASK | BLUE_MASK)) == 0)
			{
				*(COLOR_T*)dst = *(COLOR_T*)src;
			}
			else
			{
				weightS = ~weightB;

				pixS = *(COLOR_T*)src;
				pixB = *(COLOR_T*)bck;
								
				workB = ((((pixS                      ) & CHANNEL_MASK) * ((weightS                      ) & CHANNEL_MASK)) + (((pixB                      ) & CHANNEL_MASK) * ((weightB                      ) & CHANNEL_MASK))) >> BITS_PER_1CHANNEL;
				workG = ((((pixS >> BITS_PER_1CHANNEL ) & CHANNEL_MASK) * ((weightS >> BITS_PER_1CHANNEL ) & CHANNEL_MASK)) + (((pixB >> BITS_PER_1CHANNEL ) & CHANNEL_MASK) * ((weightB >> BITS_PER_1CHANNEL ) & CHANNEL_MASK)));
				workR = ((((pixS >> BITS_PER_2CHANNELS) & CHANNEL_MASK) * ((weightS >> BITS_PER_2CHANNELS) & CHANNEL_MASK)) + (((pixB >> BITS_PER_2CHANNELS) & CHANNEL_MASK) * ((weightB >> BITS_PER_2CHANNELS) & CHANNEL_MASK))) << BITS_PER_1CHANNEL;

				*(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
			}

			src += BYTES_PER_PIXEL;
			alf += BYTES_PER_PIXEL;
			bck += BYTES_PER_PIXEL;
            dst += BYTES_PER_PIXEL;
		}
		
		bck = tBck + bckRowBytes;
		src = tSrc + srcRowBytes;
		alf = tAlf + alfRowBytes;
		dst = tDst + dstRowBytes;
	}
}


void SurfaceBlitWeightedDualAlpha(SDL_Surface* back,     SDL_Surface* source,     SDL_Surface* mask,     SDL_Surface* alpha,     SDL_Surface* dest,
                                   const MRect* backRect, const MRect* sourceRect, const MRect* maskRect, const MRect* alphaRect, const MRect* destRect,
                                   int inWeight )
{
	int startX = 0, startY = 0, endX, endY, x, y,
	    srcRowBytes, alfRowBytes, mskRowBytes, dstRowBytes, bckRowBytes;
	unsigned char *bck, *src, *alf, *msk, *dst;
	MRect destBounds;

	endX = sourceRect->right - sourceRect->left;
	endY = sourceRect->bottom - sourceRect->top;
	
	SDLU_SDLRectToMRect( &dest->clip_rect, &destBounds );
	
	if( destRect->left   > destBounds.right  ||			// completely clipped?
		destRect->right  < destBounds.left   ||
		destRect->top    > destBounds.bottom ||
		destRect->bottom < destBounds.top )
	{
		return; 												// do nothing
	}
	
	bck = (unsigned char*) back->pixels;
	src = (unsigned char*) source->pixels;
	msk = (unsigned char*) mask->pixels;
	alf = (unsigned char*) alpha->pixels;
	dst = (unsigned char*) dest->pixels;
	
	bckRowBytes = back->pitch;
	srcRowBytes = source->pitch;
	mskRowBytes = mask->pitch;
	alfRowBytes = alpha->pitch;
	dstRowBytes = dest->pitch;
	
	bck += (backRect->top   * bckRowBytes) + (backRect->left   * BYTES_PER_PIXEL);
	src += (sourceRect->top * srcRowBytes) + (sourceRect->left * BYTES_PER_PIXEL);
	alf += (alphaRect->top  * alfRowBytes) + (alphaRect->left  * BYTES_PER_PIXEL);
	dst += (destRect->top   * dstRowBytes) + (destRect->left   * BYTES_PER_PIXEL);
	msk += (maskRect->top   * mskRowBytes) + (maskRect->left   * BYTES_PER_MASK_PIXEL);
	
	if( destRect->left   < destBounds.left   ) startX -= destRect->left - destBounds.left;
	if( destRect->right  > destBounds.right  ) endX   -= destRect->right - destBounds.right;
	if( destRect->top    < destBounds.top    ) startY -= destRect->top - destBounds.top;
	if( destRect->bottom > destBounds.bottom ) endY   -= destRect->bottom - destBounds.bottom;
	
	bck += (bckRowBytes * startY) + (startX * BYTES_PER_PIXEL);
	src += (srcRowBytes * startY) + (startX * BYTES_PER_PIXEL);
	alf += (alfRowBytes * startY) + (startX * BYTES_PER_PIXEL);
	dst += (dstRowBytes * startY) + (startX * BYTES_PER_PIXEL);
	msk += (mskRowBytes * startY) + (startX * BYTES_PER_MASK_PIXEL);
	
	for( y=startY; y<endY; y++ )
	{
		unsigned char *tSrc = src, *tAlf = alf, *tDst = dst, *tBck = bck, *tMsk = msk;
		int pixS, pixB, weightS, weightB, work, workB, workG, workR;
		
		for( x=startX; x<endX; x++ )
		{
			if( *msk )
			{
				work = *(COLOR_T*)alf;
				workB = ((((work                    ) & CHANNEL_MASK)*inWeight) ) >> BITS_PER_1CHANNEL;
				workG = ((((work>>BITS_PER_1CHANNEL ) & CHANNEL_MASK)*inWeight) );
				workR = ((((work>>BITS_PER_2CHANNELS) & CHANNEL_MASK)*inWeight) ) << BITS_PER_1CHANNEL;

				weightB = ~((workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK));
				
                if( (weightB & (RED_MASK | GREEN_MASK | BLUE_MASK)) == (RED_MASK | GREEN_MASK | BLUE_MASK))
				{
					*(COLOR_T*)dst = *(COLOR_T*)bck;
				}
                else if( (weightB & (RED_MASK | GREEN_MASK | BLUE_MASK)) == 0)
				{
					*(COLOR_T*)dst = *(COLOR_T*)src;
				}
				else
				{
					weightS = ~weightB;

					pixS = *(COLOR_T*)src;
					pixB = *(COLOR_T*)bck;
									
					workB = ((((pixS                      ) & CHANNEL_MASK) * ((weightS                      ) & CHANNEL_MASK)) + (((pixB                      ) & CHANNEL_MASK) * ((weightB                      ) & CHANNEL_MASK))) >> BITS_PER_1CHANNEL;
					workG = ((((pixS >> BITS_PER_1CHANNEL ) & CHANNEL_MASK) * ((weightS >> BITS_PER_1CHANNEL ) & CHANNEL_MASK)) + (((pixB >> BITS_PER_1CHANNEL ) & CHANNEL_MASK) * ((weightB >> BITS_PER_1CHANNEL ) & CHANNEL_MASK)));
					workR = ((((pixS >> BITS_PER_2CHANNELS) & CHANNEL_MASK) * ((weightS >> BITS_PER_2CHANNELS) & CHANNEL_MASK)) + (((pixB >> BITS_PER_2CHANNELS) & CHANNEL_MASK) * ((weightB >> BITS_PER_2CHANNELS) & CHANNEL_MASK))) << BITS_PER_1CHANNEL;

					*(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
				}
			}

			src += BYTES_PER_PIXEL;
			alf += BYTES_PER_PIXEL;
			bck += BYTES_PER_PIXEL;
			dst += BYTES_PER_PIXEL;
			msk += BYTES_PER_MASK_PIXEL;
		}
		
		bck = tBck + bckRowBytes;
		src = tSrc + srcRowBytes;
		alf = tAlf + alfRowBytes;
		dst = tDst + dstRowBytes;
		msk = tMsk + mskRowBytes;
	}
}

void SurfaceBlitWeightedCharacter( SkittlesFontPtr font, unsigned char text, MPoint *dPoint, int r, int g, int b, int alpha )
{
	if (alpha == FULL_WEIGHT)
	{
		SurfaceBlitCharacter( font, text, dPoint, r, g, b, 0 );
        return;
	}
    
	if (alpha == 0)
	{
		return;
	}

    SDL_Surface*   destSurface;
    unsigned char* src;
    unsigned char* dst;
    int            srcRowBytes;
    int            dstRowBytes;
    int            index;
    MRect          destBounds;
    
    int height = font->surface->h;
    int width  = font->width[text];
    int across = font->across[text];
    
    destSurface = SDLU_GetCurrentSurface();
    SDLU_SDLRectToMRect( &destSurface->clip_rect, &destBounds );
    
    if( (dPoint->h + width)  > destBounds.right           ||      // clipped?
        (dPoint->v + height) > destBounds.bottom          || 
         dPoint->h           < destBounds.left            ||
         dPoint->v           < destBounds.top                )
    {
        dPoint->h += width;
        return;                                               // do nothing
    }
    
    srcRowBytes = font->surface->pitch;
    dstRowBytes = destSurface->pitch;
    
    src = (unsigned char*) font->surface->pixels + across;
    dst = (unsigned char*) destSurface->pixels + (dPoint->h * BYTES_PER_PIXEL) + (dPoint->v * dstRowBytes);
    
    while( height-- )
    {
        unsigned char *tSrc = src, *tDst = dst;
        
        for( index=0; index<width; index++ )
        {
            int workR, workG, workB, work, weightS, weightD;
            weightS = *src & CHANNEL_MASK;
            
            weightS = (weightS * alpha) >> BITS_PER_1CHANNEL;
            
            if( weightS )
            {
                weightD = FULL_WEIGHT - weightS;

                work = *(COLOR_T*)dst;
                workB = ((((work                    ) & CHANNEL_MASK) * weightD) + (b * weightS)) >> BITS_PER_1CHANNEL;
                workG = ((((work>>BITS_PER_1CHANNEL ) & CHANNEL_MASK) * weightD) + (g * weightS));
                workR = ((((work>>BITS_PER_2CHANNELS) & CHANNEL_MASK) * weightD) + (r * weightS)) << BITS_PER_1CHANNEL;

                *(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
            }
            
            src++;
            dst+=BYTES_PER_PIXEL;
        }
        
        src = tSrc + srcRowBytes;
        dst = tDst + dstRowBytes;
    }
        
    dPoint->h += width;
}

void SurfaceBlitCharacter( SkittlesFontPtr font, unsigned char text, MPoint *dPoint, int r, int g, int b, int dropShadow )
{
    SDL_Surface*    destSurface;
	unsigned char*  src;
	unsigned char*  dst;
	int             srcRowBytes;
	int             dstRowBytes;
	int             index;
	int             rgbPremixed;
	MRect           destBounds;
	
	int height = font->surface->h;
	int width  = font->width[text];
	int across = font->across[text];
	
	destSurface = SDLU_GetCurrentSurface();
	SDLU_SDLRectToMRect( &destSurface->clip_rect, &destBounds );	
	
	if( (dPoint->h + width)  > destBounds.right           ||      // clipped?
	    (dPoint->v + height) > destBounds.bottom          || 
	     dPoint->h           < destBounds.left            ||
	     dPoint->v           < destBounds.top                )
	{
		dPoint->h += width;
		return;                                               // do nothing
	}
	
	srcRowBytes = font->surface->pitch;
	dstRowBytes = destSurface->pitch;
	
	src = (unsigned char*) font->surface->pixels + across;
	dst = (unsigned char*) destSurface->pixels + (dPoint->h * BYTES_PER_PIXEL) + (dPoint->v * dstRowBytes);
	rgbPremixed = (r << BITS_PER_2CHANNELS) | (g << BITS_PER_1CHANNEL) | b;
	
	switch( dropShadow )
	{
		case 0:
			while( height-- )
			{
				unsigned char *tSrc = src, *tDst = dst;
				
				for( index=0; index<width; index++ )
				{
					int workR, workG, workB, work, weightS, weightD;
					weightS = *src & CHANNEL_MASK;
					
					if( weightS == CHANNEL_MASK )
					{
						*(COLOR_T*)dst = rgbPremixed;
					}
					else if( weightS > 0 )
					{
						weightD = FULL_WEIGHT - weightS;

						work = *(COLOR_T*)dst;
						workB = ((((work                      ) & CHANNEL_MASK) * weightD) + (b * weightS)) >> BITS_PER_1CHANNEL;
						workG = ((((work >> BITS_PER_1CHANNEL ) & CHANNEL_MASK) * weightD) + (g * weightS));
						workR = ((((work >> BITS_PER_2CHANNELS) & CHANNEL_MASK) * weightD) + (r * weightS)) << BITS_PER_1CHANNEL;

						*(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
					}
					
					src++;
					dst+=BYTES_PER_PIXEL;
				}
				
				src = tSrc + srcRowBytes;
				dst = tDst + dstRowBytes;
			}
			break;
		
		default:
			{
				unsigned char *drp = dst + ((dstRowBytes + BYTES_PER_PIXEL) * dropShadow);
				
				while( height-- )
				{
					unsigned char *tSrc = src, *tDst = dst, *tDrp = drp;
					
					for( index=0; index<width; index++ )
					{
						int workR, workG, workB, work, weightS, weightD;
						weightS = *src & CHANNEL_MASK;
						
						if( weightS == CHANNEL_MASK )
						{
							*(COLOR_T*)drp = 0;
							*(COLOR_T*)dst = rgbPremixed;
						}
						else if( weightS > 0 )
						{
							weightD = FULL_WEIGHT - weightS;

							work = *(COLOR_T*)drp;
							workB = ((((work                    ) & CHANNEL_MASK) * weightD)) >> BITS_PER_1CHANNEL;
							workG = ((((work>>BITS_PER_1CHANNEL ) & CHANNEL_MASK) * weightD));
							workR = ((((work>>BITS_PER_2CHANNELS) & CHANNEL_MASK) * weightD)) << BITS_PER_1CHANNEL;
							*(COLOR_T*)drp = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);

							work = *(COLOR_T*)dst;
							workB = ((((work                    ) & CHANNEL_MASK) * weightD) + (b * weightS)) >> BITS_PER_1CHANNEL;
							workG = ((((work>>BITS_PER_1CHANNEL ) & CHANNEL_MASK) * weightD) + (g * weightS));
							workR = ((((work>>BITS_PER_2CHANNELS) & CHANNEL_MASK) * weightD) + (r * weightS)) << BITS_PER_1CHANNEL;
							*(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
						}
						
						src++;
						dst+=BYTES_PER_PIXEL;
						drp+=BYTES_PER_PIXEL;
					}
					
					src = tSrc + srcRowBytes;
					dst = tDst + dstRowBytes;
					drp = tDrp + dstRowBytes;
				}
				break;
			}
	}	
	dPoint->h += width;
}

void SurfaceBlitColorOver( SDL_Surface* source,     SDL_Surface* dest,
                           const MRect* sourceRect, const MRect* destRect,
                           int r, int g, int b, int weight )
{
    int            startX = 0, startY = 0, endX, endY, x, y, dstRowBytes, srcRowBytes;
	unsigned char* src;
	unsigned char* dst;
	MRect          destBounds;
	
	SDLU_SDLRectToMRect( &dest->clip_rect, &destBounds );
	
	endX = destRect->right - destRect->left;
	endY = destRect->bottom - destRect->top;
	
	if( destRect->left   > destBounds.right  ||			// completely clipped?
		destRect->right  < destBounds.left   ||
		destRect->top    > destBounds.bottom ||
		destRect->bottom < destBounds.top )
	{
		return; 												// do nothing
	}
	
	src         = (unsigned char*) source->pixels;
	dst         = (unsigned char*) dest->pixels;
	srcRowBytes = source->pitch;
	dstRowBytes = dest->pitch;
	
	src += (sourceRect->top * srcRowBytes) + (sourceRect->left * BYTES_PER_PIXEL);
	dst += (destRect->top * dstRowBytes) + (destRect->left * BYTES_PER_PIXEL);
	
	if( destRect->left   < destBounds.left   ) startX -= destRect->left - destBounds.left;
	if( destRect->right  > destBounds.right  ) endX   -= destRect->right - destBounds.right;
	if( destRect->top    < destBounds.top    ) startY -= destRect->top - destBounds.top;
	if( destRect->bottom > destBounds.bottom ) endY   -= destRect->bottom - destBounds.bottom;
	
	src += (srcRowBytes * startY) + (startX * BYTES_PER_PIXEL);
	dst += (dstRowBytes * startY) + (startX * BYTES_PER_PIXEL);

	r *= weight;
	g *= weight;
	b *= weight;
	weight = FULL_WEIGHT - weight;
	
	for( y=startY; y<endY; y++ )
	{
		unsigned char *tSrc = src, *tDst = dst;
		int work, workB, workG, workR;
		
		for( x=startX; x<endX; x++ )
		{
			work = *(COLOR_T*)src;
			workB = ((((work                    ) & CHANNEL_MASK)*weight) + b) >> BITS_PER_1CHANNEL;
			workG = ((((work>>BITS_PER_1CHANNEL ) & CHANNEL_MASK)*weight) + g);
			workR = ((((work>>BITS_PER_2CHANNELS) & CHANNEL_MASK)*weight) + r) << BITS_PER_1CHANNEL;

			*(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
			
			src += BYTES_PER_PIXEL;
			dst += BYTES_PER_PIXEL;
		}
		
		src = tSrc + srcRowBytes;
		dst = tDst + dstRowBytes;
	}
}

// NOTE: due to rounding error, there should never be a case of transitioning all the way from 0 to 255.
// You'll overflow and get weird glitches on the edges.

void SurfaceBlitBlendOver(SDL_Surface* source,     SDL_Surface* dest,
                           const MRect* sourceRect, const MRect* destRect, 
                           int r1, int g1, int b1, 
                           int r2, int g2, int b2, 
                           int r3, int g3, int b3, 
                           int r4, int g4, int b4, 
                           int weight )
{
	int startX = 0, startY = 0, endX, endY, x, y;
	int rA, gA, bA;
	int rB, gB, bB;
	int rI, gI, bI;
	int vrLI, vgLI, vbLI;
	int vrRI, vgRI, vbRI;
	int weight12, ditherDiff;
	int width, height, dstRowBytes, srcRowBytes;
	unsigned char *src, *dst;
	MRect destBounds;
	MBoolean oddX = false;

	SDLU_SDLRectToMRect( &dest->clip_rect, &destBounds );
	
	if( destRect->left   > destBounds.right  ||			// completely clipped?
		destRect->right  < destBounds.left   ||
		destRect->top    > destBounds.bottom ||
		destRect->bottom < destBounds.top )
	{
		return; 												// do nothing
	}

	endX = destRect->right - destRect->left;
	endY = destRect->bottom - destRect->top;
	
	src         = (unsigned char*) source->pixels; 
	dst         = (unsigned char*) dest->pixels;
	srcRowBytes = source->pitch;
	dstRowBytes = dest->pitch;
	
	src += (sourceRect->top * srcRowBytes) + (sourceRect->left * BYTES_PER_PIXEL);
	dst += (destRect->top * dstRowBytes)   + (destRect->left * BYTES_PER_PIXEL);
	
	if( destRect->left   < destBounds.left   ) startX -= destRect->left - destBounds.left;
	if( destRect->right  > destBounds.right  ) endX   -= destRect->right - destBounds.right;
	if( destRect->top    < destBounds.top    ) startY -= destRect->top - destBounds.top;
	if( destRect->bottom > destBounds.bottom ) endY   -= destRect->bottom - destBounds.bottom;
	
	src += (srcRowBytes * startY) + (startX * BYTES_PER_PIXEL);
	dst += (dstRowBytes * startY) + (startX * BYTES_PER_PIXEL);

	height = endY - startY;
	width  = endX - startX;
	
	weight12 = weight << 12;
	
	r1 *= weight12;		g1 *= weight12;		b1 *= weight12;
	r2 *= weight12;		g2 *= weight12;		b2 *= weight12;
	r3 *= weight12;		g3 *= weight12;		b3 *= weight12;
	r4 *= weight12;		g4 *= weight12;		b4 *= weight12;
	ditherDiff = weight12 >> 1;
	
	vrLI = (r3 - r1) / height;
	vgLI = (g3 - g1) / height;
	vbLI = (b3 - b1) / height;

	vrRI = (r4 - r2) / height;
	vgRI = (g4 - g2) / height;
	vbRI = (b4 - b2) / height;

	weight = FULL_WEIGHT - weight;
    weight12 = weight << 12;

    if( (endX - startX) & 1 )
	{
		endX--;
		oddX = true;
	}
	
	for( y=startY; y<endY; y++ )
	{
		unsigned char *tSrc = src, *tDst = dst;
		int work, workB, workG, workR;
		
		if( y & 1 )
		{
			rA =  r1;
			gA =  g1;
			bA =  b1;
			rB =  r1 - ditherDiff; if( rB < 0 ) rB = 0;
			gB =  g1 - ditherDiff; if( gB < 0 ) gB = 0;
			bB =  b1 - ditherDiff; if( bB < 0 ) bB = 0;
		}
		else
		{
			rA =  r1 - ditherDiff; if( rA < 0 ) rA = 0;
			gA =  g1 - ditherDiff; if( gA < 0 ) gA = 0;
			bA =  b1 - ditherDiff; if( bA < 0 ) bA = 0;
			rB =  r1;
			gB =  g1;
			bB =  b1;
		}
		
		rI = (2 * (r2 - r1)) / width;
		gI = (2 * (g2 - g1)) / width;
		bI = (2 * (b2 - b1)) / width;
					
		for( x=startX; x<endX; x+=2 )
		{
			work = *(COLOR_T*)src;

            workB = ((((work                      ) & CHANNEL_MASK) * weight12) + bA) >> (12 + BITS_PER_1CHANNEL);
            workG = ((((work >> BITS_PER_1CHANNEL ) & CHANNEL_MASK) * weight12) + gA) >> (12                    );
            workR = ((((work >> BITS_PER_2CHANNELS) & CHANNEL_MASK) * weight12) + rA) >> (12 - BITS_PER_1CHANNEL);

            *(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
			
			src+= BYTES_PER_PIXEL;
			dst+= BYTES_PER_PIXEL;
			rA += rI; 
			gA += gI;
			bA += bI;

			work = *(COLOR_T*)src;

            workB = ((((work                      ) & CHANNEL_MASK) * weight12) + bB) >> (12 + BITS_PER_1CHANNEL);
            workG = ((((work >> BITS_PER_1CHANNEL ) & CHANNEL_MASK) * weight12) + gB) >> (12                    );
            workR = ((((work >> BITS_PER_2CHANNELS) & CHANNEL_MASK) * weight12) + rB) >> (12 - BITS_PER_1CHANNEL);

            *(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
			
            src+= BYTES_PER_PIXEL;
            dst+= BYTES_PER_PIXEL;
			rB += rI;
			gB += gI;
			bB += bI;
		}
		
		if( oddX )
		{
			work = *(COLOR_T*)src;
            
            workB = ((((work                      ) & CHANNEL_MASK) * weight12) + bA) >> (12 + BITS_PER_1CHANNEL);
            workG = ((((work >> BITS_PER_1CHANNEL ) & CHANNEL_MASK) * weight12) + gA) >> (12                    );
            workR = ((((work >> BITS_PER_2CHANNELS) & CHANNEL_MASK) * weight12) + rA) >> (12 - BITS_PER_1CHANNEL);

            *(COLOR_T*)dst = (workR & RED_MASK) | (workG & GREEN_MASK) | (workB & BLUE_MASK);
		}
		
		src = tSrc + srcRowBytes;
		dst = tDst + dstRowBytes;

		r1 += vrLI; r2 += vrRI;
		g1 += vgLI; g2 += vgRI;
		b1 += vbLI; b2 += vbRI;
	}
}