/*
*	SDL Graphics Extension
*	Triangles of every sort
*
*	Started 000428
*
*	License: LGPL v2+ (see the file LICENSE)
*	(c)2000-2003 Anders Lindström & Johan E. Thelin
*/

/*********************************************************************
 *  This library is free software; you can redistribute it and/or    *
 *  modify it under the terms of the GNU Library General Public      *
 *  License as published by the Free Software Foundation; either     *
 *  version 2 of the License, or (at your option) any later version. *
 *********************************************************************/

/*
*  Written with some help from Johan E. Thelin.
*/

#include "SDL.h"
#include "sge_surface.h"
#include "sge_primitives.h"
#include "sge_blib.h"

#define SWAP(x,y,temp) temp=x;x=y;y=temp

/* Globals used for sge_Update/sge_Lock (defined in sge_surface) */
extern Uint8 _sge_update;
extern Uint8 _sge_lock;
extern Uint8 _sge_alpha_hack;

/* We need some internal functions */
extern void _Line(SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color);
extern void _LineAlpha(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 Color, Uint8 alpha);
extern void _HLine(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color);
extern void _HLineAlpha(SDL_Surface *Surface, Sint16 x1, Sint16 x2, Sint16 y, Uint32 Color, Uint8 alpha);
extern void callback_alpha_hack(SDL_Surface *surf, Sint16 x, Sint16 y, Uint32 color);
extern void _AALineAlpha(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha);
extern void _AAmcLineAlpha(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r1, Uint8 g1, Uint8 b1, Uint8 r2, Uint8 g2, Uint8 b2, Uint8 alpha);

/* Macro to inline RGB mapping */
#define MapRGB(format, r, g, b)\
	(r >> format->Rloss) << format->Rshift\
		| (g >> format->Gloss) << format->Gshift\
		| (b >> format->Bloss) << format->Bshift


//==================================================================================
// Draws a horisontal line, fading the colors
//==================================================================================
void _FadedLine(SDL_Surface *dest,Sint16 x1,Sint16 x2,Sint16 y,Uint8 r1,Uint8 g1,Uint8 b1,Uint8 r2,Uint8 g2,Uint8 b2)
{
	Sint16 x;
	Uint8 t;
	
	/* Fix coords */
	if ( x1 > x2 ) {
		SWAP(x1,x2,x);
		SWAP(r1,r2,t);
		SWAP(g1,g2,t);
		SWAP(b1,b2,t);
	}	
	
	/* We use fixedpoint math */
	Sint32 R = r1<<16;
	Sint32 G = g1<<16;
	Sint32 B = b1<<16;
	
	/* Color step value */
	Sint32 rstep = Sint32((r2-r1)<<16) / Sint32(x2-x1+1);
	Sint32 gstep = Sint32((g2-g1)<<16) / Sint32(x2-x1+1);
	Sint32 bstep = Sint32((b2-b1)<<16) / Sint32(x2-x1+1);
	
	
	/* Clipping */
	if(x2<sge_clip_xmin(dest) || x1>sge_clip_xmax(dest) || y<sge_clip_ymin(dest) || y>sge_clip_ymax(dest))
		return;
	if (x1 < sge_clip_xmin(dest)){
		/* Update start colors */
		R += (sge_clip_xmin(dest)-x1)*rstep;
		G += (sge_clip_xmin(dest)-x1)*gstep;
		B += (sge_clip_xmin(dest)-x1)*bstep;
  		x1 = sge_clip_xmin(dest);
	}
	if (x2 > sge_clip_xmax(dest))
  		x2 = sge_clip_xmax(dest);

	
	switch (dest->format->BytesPerPixel) {
		case 1: { /* Assuming 8-bpp */
			Uint8 *pixel;
			Uint8 *row = (Uint8 *)dest->pixels + y*dest->pitch;
			
			for (x = x1; x <= x2; x++){
				pixel = row + x;
				
				*pixel = SDL_MapRGB( dest->format, R>>16, G>>16, B>>16 );
		
				R += rstep;
				G += gstep;
				B += bstep;
			}
		}
		break;

		case 2: { /* Probably 15-bpp or 16-bpp */
			Uint16 *pixel;
			Uint16 *row = (Uint16 *)dest->pixels + y*dest->pitch/2;
			
			for (x = x1; x <= x2; x++){
				pixel = row + x;
				
				*pixel = MapRGB( dest->format, R>>16, G>>16, B>>16 );
		
				R += rstep;
				G += gstep;
				B += bstep;
			}
		}
		break;

		case 3: { /* Slow 24-bpp mode, usually not used */
			Uint8 *pixel;
			Uint8 *row = (Uint8 *)dest->pixels + y*dest->pitch;
			
			Uint8 rshift8=dest->format->Rshift/8;
			Uint8 gshift8=dest->format->Gshift/8;
			Uint8 bshift8=dest->format->Bshift/8;
			
			for (x = x1; x <= x2; x++){
				pixel = row + x*3;
		
				*(pixel+rshift8) = R>>16;
  				*(pixel+gshift8) = G>>16;
  				*(pixel+bshift8) = B>>16;
		
				R += rstep;
				G += gstep;
				B += bstep;
			}
		}
		break;

		case 4: { /* Probably 32-bpp */
			Uint32 *pixel;
			Uint32 *row = (Uint32 *)dest->pixels + y*dest->pitch/4;
			
			for (x = x1; x <= x2; x++){
				pixel = row + x;
				
				*pixel = MapRGB( dest->format, R>>16, G>>16, B>>16 );
		
				R += rstep;
				G += gstep;
				B += bstep;
			}
		}
		break;
	}
}

void sge_FadedLine(SDL_Surface *dest,Sint16 x1,Sint16 x2,Sint16 y,Uint8 r1,Uint8 g1,Uint8 b1,Uint8 r2,Uint8 g2,Uint8 b2)
{
	if ( SDL_MUSTLOCK(dest) && _sge_lock )
		if ( SDL_LockSurface(dest) < 0 )
			return;

	_FadedLine(dest,x1,x2,y,r1,g1,b1,r2,g2,b2);
	
	if ( SDL_MUSTLOCK(dest) && _sge_lock )
		SDL_UnlockSurface(dest);
		
	if(_sge_update!=1){return;}
	if ( x1 > x2 )
		sge_UpdateRect(dest, x1, y, x1-x2+1, 1);
	else
		sge_UpdateRect(dest, x1, y, x2-x1+1, 1);	
}


//==================================================================================
// Draws a horisontal, textured line
//==================================================================================
void _TexturedLine(SDL_Surface *dest,Sint16 x1,Sint16 x2,Sint16 y,SDL_Surface *source,Sint16 sx1,Sint16 sy1,Sint16 sx2,Sint16 sy2)
{
	Sint16 x;
	
	/* Fix coords */
	if ( x1 > x2 ) {
		SWAP(x1,x2,x);
		SWAP(sx1,sx2,x);
		SWAP(sy1,sy2,x);
	}	
	
	/* Fixed point texture starting coords */
	Sint32 srcx = sx1<<16;
	Sint32 srcy = sy1<<16;
	
	/* Texture coords stepping value */
	Sint32 xstep = Sint32((sx2-sx1)<<16) / Sint32(x2-x1+1);
	Sint32 ystep = Sint32((sy2-sy1)<<16) / Sint32(x2-x1+1);
	
	
	/* Clipping */
	if(x2<sge_clip_xmin(dest) || x1>sge_clip_xmax(dest) || y<sge_clip_ymin(dest) || y>sge_clip_ymax(dest))
		return;
	if (x1 < sge_clip_xmin(dest)){
		/* Fix texture starting coord */
		srcx += (sge_clip_xmin(dest)-x1)*xstep;
		srcy += (sge_clip_xmin(dest)-x1)*ystep;
  		x1 = sge_clip_xmin(dest);
	}
	if (x2 > sge_clip_xmax(dest))
  		x2 = sge_clip_xmax(dest);

	
	if(dest->format->BytesPerPixel == source->format->BytesPerPixel){
		/* Fast mode. Just copy the pixel */
	
		switch (dest->format->BytesPerPixel) {
			case 1: { /* Assuming 8-bpp */
				Uint8 *pixel;
				Uint8 *row = (Uint8 *)dest->pixels + y*dest->pitch;
			
				for (x = x1; x <= x2; x++){
					pixel = row + x;
				
					*pixel = *((Uint8 *)source->pixels + (srcy>>16)*source->pitch + (srcx>>16));
		
					srcx += xstep;
					srcy += ystep;
				}
			}
			break;

			case 2: { /* Probably 15-bpp or 16-bpp */
				Uint16 *pixel;
				Uint16 *row = (Uint16 *)dest->pixels + y*dest->pitch/2;
			
				Uint16 pitch = source->pitch/2;
			
				for (x = x1; x <= x2; x++){
					pixel = row + x;
				
					*pixel = *((Uint16 *)source->pixels + (srcy>>16)*pitch + (srcx>>16));
		
					srcx += xstep;
					srcy += ystep;
				}
			}
			break;

			case 3: { /* Slow 24-bpp mode, usually not used */
				Uint8 *pixel, *srcpixel;
				Uint8 *row = (Uint8 *)dest->pixels + y*dest->pitch;
			
				Uint8 rshift8=dest->format->Rshift/8;
				Uint8 gshift8=dest->format->Gshift/8;
				Uint8 bshift8=dest->format->Bshift/8;
			
				for (x = x1; x <= x2; x++){
					pixel = row + x*3;
					srcpixel = (Uint8 *)source->pixels + (srcy>>16)*source->pitch + (srcx>>16)*3;
		
					*(pixel+rshift8) = *(srcpixel+rshift8);
  					*(pixel+gshift8) = *(srcpixel+gshift8);
  					*(pixel+bshift8) = *(srcpixel+bshift8);
		
					srcx += xstep;
					srcy += ystep;
				}	
			}
			break;

			case 4: { /* Probably 32-bpp */
				Uint32 *pixel;
				Uint32 *row = (Uint32 *)dest->pixels + y*dest->pitch/4;
			
				Uint16 pitch = source->pitch/4;
			
				for (x = x1; x <= x2; x++){
					pixel = row + x;
				
					*pixel = *((Uint32 *)source->pixels + (srcy>>16)*pitch + (srcx>>16));
		
					srcx += xstep;
					srcy += ystep;
				}
			}
			break;
		}
	}else{
		/* Slow mode. We must translate every pixel color! */
	
		Uint8 r=0,g=0,b=0;
	
		switch (dest->format->BytesPerPixel) {
			case 1: { /* Assuming 8-bpp */
				Uint8 *pixel;
				Uint8 *row = (Uint8 *)dest->pixels + y*dest->pitch;
			
				for (x = x1; x <= x2; x++){
					pixel = row + x;
				
					SDL_GetRGB(sge_GetPixel(source, srcx>>16, srcy>>16), source->format, &r, &g, &b);
					*pixel = SDL_MapRGB( dest->format, r, g, b );
		
					srcx += xstep;
					srcy += ystep;
				}
			}
			break;

			case 2: { /* Probably 15-bpp or 16-bpp */
				Uint16 *pixel;
				Uint16 *row = (Uint16 *)dest->pixels + y*dest->pitch/2;
			
				for (x = x1; x <= x2; x++){
					pixel = row + x;
					
					SDL_GetRGB(sge_GetPixel(source, srcx>>16, srcy>>16), source->format, &r, &g, &b);
					*pixel = MapRGB( dest->format, r, g, b );
		
					srcx += xstep;
					srcy += ystep;
				}
			}
			break;

			case 3: { /* Slow 24-bpp mode, usually not used */
				Uint8 *pixel, *srcpixel;
				Uint8 *row = (Uint8 *)dest->pixels + y*dest->pitch;
			
				Uint8 rshift8=dest->format->Rshift/8;
				Uint8 gshift8=dest->format->Gshift/8;
				Uint8 bshift8=dest->format->Bshift/8;
			
				for (x = x1; x <= x2; x++){
					pixel = row + x*3;
					srcpixel = (Uint8 *)source->pixels + (srcy>>16)*source->pitch + (srcx>>16)*3;
		
					SDL_GetRGB(sge_GetPixel(source, srcx>>16, srcy>>16), source->format, &r, &g, &b);
					
					*(pixel+rshift8) = r;
  					*(pixel+gshift8) = g;
  					*(pixel+bshift8) = b;
		
					srcx += xstep;
					srcy += ystep;
				}	
			}
			break;

			case 4: { /* Probably 32-bpp */
				Uint32 *pixel;
				Uint32 *row = (Uint32 *)dest->pixels + y*dest->pitch/4;
			
				for (x = x1; x <= x2; x++){
					pixel = row + x;
				
					SDL_GetRGB(sge_GetPixel(source, srcx>>16, srcy>>16), source->format, &r, &g, &b);
					*pixel = MapRGB( dest->format, r, g, b );
		
					srcx += xstep;
					srcy += ystep;
				}
			}
			break;
		}
	}
}

void sge_TexturedLine(SDL_Surface *dest,Sint16 x1,Sint16 x2,Sint16 y,SDL_Surface *source,Sint16 sx1,Sint16 sy1,Sint16 sx2,Sint16 sy2)
{
	if ( SDL_MUSTLOCK(dest) && _sge_lock )
		if ( SDL_LockSurface(dest) < 0 )
			return;
	if ( SDL_MUSTLOCK(source) && _sge_lock )
		if ( SDL_LockSurface(source) < 0 )
			return;

	_TexturedLine(dest,x1,x2,y,source,sx1,sy1,sx2,sy2);
	
	if ( SDL_MUSTLOCK(dest) && _sge_lock )
		SDL_UnlockSurface(dest);
	if ( SDL_MUSTLOCK(source) && _sge_lock )
		SDL_UnlockSurface(source);
		
	if(_sge_update!=1){return;}
	if ( x1 > x2 )
		sge_UpdateRect(dest, x1, y, x1-x2+1, 1);
	else
		sge_UpdateRect(dest, x1, y, x2-x1+1, 1);	
}

//==================================================================================
// Draws a trigon
//==================================================================================
void sge_Trigon(SDL_Surface *dest,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color)
{
	if ( SDL_MUSTLOCK(dest) && _sge_lock )
		if ( SDL_LockSurface(dest) < 0 )
			return;

	_Line(dest,x1,y1,x2,y2,color);
	_Line(dest,x1,y1,x3,y3,color);
	_Line(dest,x3,y3,x2,y2,color);
	
	if ( SDL_MUSTLOCK(dest) && _sge_lock )
		SDL_UnlockSurface(dest);
		
	if(_sge_update!=1){return;}
	
	Sint16 xmax=x1, ymax=y1, xmin=x1, ymin=y1;
	xmax= (xmax>x2)? xmax : x2;  ymax= (ymax>y2)? ymax : y2;
	xmin= (xmin<x2)? xmin : x2;  ymin= (ymin<y2)? ymin : y2;
	xmax= (xmax>x3)? xmax : x3;  ymax= (ymax>y3)? ymax : y3;
	xmin= (xmin<x3)? xmin : x3;  ymin= (ymin<y3)? ymin : y3;
	
	sge_UpdateRect(dest, xmin, ymin, xmax-xmin+1, ymax-ymin+1);
}

void sge_Trigon(SDL_Surface *dest,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint8 R, Uint8 G, Uint8 B)
{
	sge_Trigon(dest,x1,y1,x2,y2,x3,y3, SDL_MapRGB(dest->format, R,G,B));
}


//==================================================================================
// Draws a trigon (alpha)
//==================================================================================
void sge_TrigonAlpha(SDL_Surface *dest,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color, Uint8 alpha)
{
	if ( SDL_MUSTLOCK(dest) && _sge_lock )
		if ( SDL_LockSurface(dest) < 0 )
			return;
	
	_LineAlpha(dest,x1,y1,x2,y2,color,alpha);
	_LineAlpha(dest,x1,y1,x3,y3,color,alpha);
	_LineAlpha(dest,x3,y3,x2,y2,color,alpha);
	
	if ( SDL_MUSTLOCK(dest) && _sge_lock )
		SDL_UnlockSurface(dest);
	
	
	if(_sge_update!=1){return;}
	
	Sint16 xmax=x1, ymax=y1, xmin=x1, ymin=y1;
	xmax= (xmax>x2)? xmax : x2;  ymax= (ymax>y2)? ymax : y2;
	xmin= (xmin<x2)? xmin : x2;  ymin= (ymin<y2)? ymin : y2;
	xmax= (xmax>x3)? xmax : x3;  ymax= (ymax>y3)? ymax : y3;
	xmin= (xmin<x3)? xmin : x3;  ymin= (ymin<y3)? ymin : y3;
	
	sge_UpdateRect(dest, xmin, ymin, xmax-xmin+1, ymax-ymin+1);
}

void sge_TrigonAlpha(SDL_Surface *dest,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint8 R, Uint8 G, Uint8 B, Uint8 alpha)
{
	sge_TrigonAlpha(dest,x1,y1,x2,y2,x3,y3, SDL_MapRGB(dest->format, R,G,B), alpha);
}


//==================================================================================
// Draws an AA trigon (alpha)
//==================================================================================
void sge_AATrigonAlpha(SDL_Surface *dest,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color, Uint8 alpha)
{
	if ( SDL_MUSTLOCK(dest) && _sge_lock )
		if ( SDL_LockSurface(dest) < 0 )
			return;
	
	_AALineAlpha(dest,x1,y1,x2,y2,color,alpha);
	_AALineAlpha(dest,x1,y1,x3,y3,color,alpha);
	_AALineAlpha(dest,x3,y3,x2,y2,color,alpha);
	
	if ( SDL_MUSTLOCK(dest) && _sge_lock )
		SDL_UnlockSurface(dest);	

	
	if(_sge_update!=1){return;}
	
	Sint16 xmax=x1, ymax=y1, xmin=x1, ymin=y1;
	xmax= (xmax>x2)? xmax : x2;  ymax= (ymax>y2)? ymax : y2;
	xmin= (xmin<x2)? xmin : x2;  ymin= (ymin<y2)? ymin : y2;
	xmax= (xmax>x3)? xmax : x3;  ymax= (ymax>y3)? ymax : y3;
	xmin= (xmin<x3)? xmin : x3;  ymin= (ymin<y3)? ymin : y3;
	
	sge_UpdateRect(dest, xmin, ymin, xmax-xmin+1, ymax-ymin+1);
}

void sge_AATrigonAlpha(SDL_Surface *dest,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint8 R, Uint8 G, Uint8 B, Uint8 alpha)
{
	sge_AATrigonAlpha(dest,x1,y1,x2,y2,x3,y3, SDL_MapRGB(dest->format, R,G,B), alpha);
}

void sge_AATrigon(SDL_Surface *dest,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color)
{
	sge_AATrigonAlpha(dest,x1,y1,x2,y2,x3,y3, color, 255);
}

void sge_AATrigon(SDL_Surface *dest,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint8 R, Uint8 G, Uint8 B)
{
	sge_AATrigonAlpha(dest,x1,y1,x2,y2,x3,y3, SDL_MapRGB(dest->format, R,G,B), 255);
}


//==================================================================================
// Draws a filled trigon
//==================================================================================
void sge_FilledTrigon(SDL_Surface *dest,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color)
{
	Sint16 y;

	if( y1==y3 )
		return;

	/* Sort coords */
	if ( y1 > y2 ) {
		SWAP(y1,y2,y);
		SWAP(x1,x2,y);
	}
	if ( y2 > y3 ) {
		SWAP(y2,y3,y);
		SWAP(x2,x3,y);
	}
	if ( y1 > y2 ) {
		SWAP(y1,y2,y);
		SWAP(x1,x2,y);
	}
	
	/*
	 * How do we calculate the starting and ending x coordinate of the horizontal line
	 * on each y coordinate?  We can do this by using a standard line algorithm but
	 * instead of plotting pixels, use the x coordinates as start and stop
	 * coordinates for the horizontal line.
	 * So we will simply trace the outlining of the triangle; this will require 3 lines.
	 * Line 1 is the line between (x1,y1) and (x2,y2)
	 * Line 2 is the line between (x1,y1) and (x3,y3)
	 * Line 3 is the line between (x2,y2) and (x3,y3)
	 *
	 * We can divide the triangle into 2 halfs. The upper half will be outlined by line
	 * 1 and 2. The lower half will be outlined by line line 2 and 3.
	*/
	
	
	/* Starting coords for the three lines */
	Sint32 xa = Sint32(x1<<16);
	Sint32 xb = xa;
	Sint32 xc = Sint32(x2<<16);

	/* Lines step values */
	Sint32 m1 = 0;
	Sint32 m2 = Sint32((x3 - x1)<<16)/Sint32(y3 - y1);
	Sint32 m3 = 0;
	
	/* Upper half of the triangle */
	if( y1==y2 )
		_HLine(dest, x1, x2, y1, color);
	else{
		m1 = Sint32((x2 - x1)<<16)/Sint32(y2 - y1);
		
		for ( y = y1; y <= y2; y++) {
			_HLine(dest, xa>>16, xb>>16, y, color);
				
			xa += m1;
			xb += m2;
		}
	}
	
	/* Lower half of the triangle */
	if( y2==y3 )
		_HLine(dest, x2, x3, y2, color);
	else{
		m3 = Sint32((x3 - x2)<<16)/Sint32(y3 - y2);
		
		for ( y = y2+1; y <= y3; y++) {
			_HLine(dest, xb>>16, xc>>16, y, color);

			xb += m2;
			xc += m3;
		}
	}
	
	
	if(_sge_update!=1){return;}
	
	Sint16 xmax=x1, xmin=x1;
	xmax= (xmax>x2)? xmax : x2;
	xmin= (xmin<x2)? xmin : x2;
	xmax= (xmax>x3)? xmax : x3;
	xmin= (xmin<x3)? xmin : x3;
	
	sge_UpdateRect(dest, xmin, y1, xmax-xmin+1, y3-y1+1);
}

void sge_FilledTrigon(SDL_Surface *dest,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint8 R, Uint8 G, Uint8 B)
{
	sge_FilledTrigon(dest,x1,y1,x2,y2,x3,y3, SDL_MapRGB(dest->format, R,G,B));
}


//==================================================================================
// Draws a filled trigon (alpha)
//==================================================================================
void sge_FilledTrigonAlpha(SDL_Surface *dest,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color, Uint8 alpha)
{
	Sint16 y;

	if( y1==y3 )
		return;

	/* Sort coords */
	if ( y1 > y2 ) {
		SWAP(y1,y2,y);
		SWAP(x1,x2,y);
	}
	if ( y2 > y3 ) {
		SWAP(y2,y3,y);
		SWAP(x2,x3,y);
	}
	if ( y1 > y2 ) {
		SWAP(y1,y2,y);
		SWAP(x1,x2,y);
	}

	Sint32 xa = Sint32(x1<<16);
	Sint32 xb = xa;
	Sint32 xc = Sint32(x2<<16);

	Sint32 m1 = 0;
	Sint32 m2 = Sint32((x3 - x1)<<16)/Sint32(y3 - y1);
	Sint32 m3 = 0;
	
	if ( SDL_MUSTLOCK(dest) && _sge_lock )
		if ( SDL_LockSurface(dest) < 0 )
			return;
	
	/* Upper half of the triangle */
	if( y1==y2 )
		_HLineAlpha(dest, x1, x2, y1, color, alpha);
	else{
		m1 = Sint32((x2 - x1)<<16)/Sint32(y2 - y1);
		
		for ( y = y1; y <= y2; y++) {
			_HLineAlpha(dest, xa>>16, xb>>16, y, color, alpha);
				
			xa += m1;
			xb += m2;
		}
	}
	
	/* Lower half of the triangle */
	if( y2==y3 )
		_HLineAlpha(dest, x2, x3, y2, color, alpha);
	else{
		m3 = Sint32((x3 - x2)<<16)/Sint32(y3 - y2);
		
		for ( y = y2+1; y <= y3; y++) {
			_HLineAlpha(dest, xb>>16, xc>>16, y, color, alpha);

			xb += m2;
			xc += m3;
		}
	}
	
	
	if ( SDL_MUSTLOCK(dest) && _sge_lock )
		SDL_UnlockSurface(dest);
	
	
	if(_sge_update!=1){return;}
	
	Sint16 xmax=x1, xmin=x1;
	xmax= (xmax>x2)? xmax : x2;
	xmin= (xmin<x2)? xmin : x2;
	xmax= (xmax>x3)? xmax : x3;
	xmin= (xmin<x3)? xmin : x3;
	
	sge_UpdateRect(dest, xmin, y1, xmax-xmin+1, y3-y1+1);
}

void sge_FilledTrigonAlpha(SDL_Surface *dest,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint8 R, Uint8 G, Uint8 B, Uint8 alpha)
{
	sge_FilledTrigonAlpha(dest,x1,y1,x2,y2,x3,y3, SDL_MapRGB(dest->format, R,G,B),alpha);
}


//==================================================================================
// Draws a gourand shaded trigon
//==================================================================================
void sge_FadedTrigon(SDL_Surface *dest,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 c1,Uint32 c2,Uint32 c3)
{
	Sint16 y;

	if( y1==y3 )
		return;
		
	Uint8 c=0;
	SDL_Color col1;
	SDL_Color col2;
	SDL_Color col3;
	
	col1 = sge_GetRGB(dest,c1);
	col2 = sge_GetRGB(dest,c2);
	col3 = sge_GetRGB(dest,c3);

	/* Sort coords */
	if ( y1 > y2 ) {
		SWAP(y1,y2,y);
		SWAP(x1,x2,y);
		SWAP(col1.r,col2.r,c);
		SWAP(col1.g,col2.g,c);
		SWAP(col1.b,col2.b,c);
	}
	if ( y2 > y3 ) {
		SWAP(y2,y3,y);
		SWAP(x2,x3,y);
		SWAP(col2.r,col3.r,c);
		SWAP(col2.g,col3.g,c);
		SWAP(col2.b,col3.b,c);
	}
	if ( y1 > y2 ) {
		SWAP(y1,y2,y);
		SWAP(x1,x2,y);
		SWAP(col1.r,col2.r,c);
		SWAP(col1.g,col2.g,c);
		SWAP(col1.b,col2.b,c);
	}

	/*
	 * We trace three lines exactly like in sge_FilledTrigon(), but here we
	 * must also keep track of the colors. We simply calculate how the color
	 * will change along the three lines.
	*/

	/* Starting coords for the three lines */
	Sint32 xa = Sint32(x1<<16);
	Sint32 xb = xa;
	Sint32 xc = Sint32(x2<<16);
	
	/* Starting colors (rgb) for the three lines */
	Sint32 r1 = Sint32(col1.r<<16);
	Sint32 r2 = r1;
	Sint32 r3 = Sint32(col2.r<<16);
	
	Sint32 g1 = Sint32(col1.g<<16);
	Sint32 g2 = g1;
	Sint32 g3 = Sint32(col2.g<<16);
	
	Sint32 b1 = Sint32(col1.b<<16);
	Sint32 b2 = b1;
	Sint32 b3 = Sint32(col2.b<<16);
	
	/* Lines step values */
	Sint32 m1 = 0;
	Sint32 m2 = Sint32((x3 - x1)<<16)/Sint32(y3 - y1);
	Sint32 m3 = 0;
	
	/* Colors step values */
	Sint32 rstep1 = 0;
	Sint32 rstep2 = Sint32((col3.r - col1.r) << 16) / Sint32(y3 - y1);
	Sint32 rstep3 = 0;
	
	Sint32 gstep1 = 0;
	Sint32 gstep2 = Sint32((col3.g - col1.g) << 16) / Sint32(y3 - y1);
	Sint32 gstep3 = 0;
	
	Sint32 bstep1 = 0;
	Sint32 bstep2 = Sint32((col3.b - col1.b) << 16) / Sint32(y3 - y1);
	Sint32 bstep3 = 0;
	
	if ( SDL_MUSTLOCK(dest) && _sge_lock )
		if ( SDL_LockSurface(dest) < 0 )
			return;
	
	/* Upper half of the triangle */
	if( y1==y2 )
		_FadedLine(dest, x1, x2, y1, col1.r, col1.g, col1.b, col2.r, col2.g, col2.b);
	else{
		m1 = Sint32((x2 - x1)<<16)/Sint32(y2 - y1);
		
		rstep1 = Sint32((col2.r - col1.r) << 16) / Sint32(y2 - y1);
		gstep1 = Sint32((col2.g - col1.g) << 16) / Sint32(y2 - y1);
		bstep1 = Sint32((col2.b - col1.b) << 16) / Sint32(y2 - y1);
		
		for ( y = y1; y <= y2; y++) {
			_FadedLine(dest, xa>>16, xb>>16, y, r1>>16, g1>>16, b1>>16, r2>>16, g2>>16, b2>>16);
				
			xa += m1;
			xb += m2;
			
			r1 += rstep1;
			g1 += gstep1;
			b1 += bstep1;
			
			r2 += rstep2;
			g2 += gstep2;
			b2 += bstep2;
		}
	}
	
	/* Lower half of the triangle */
	if( y2==y3 )
		_FadedLine(dest, x2, x3, y2, col2.r, col2.g, col2.b, col3.r, col3.g, col3.b);
	else{
		m3 = Sint32((x3 - x2)<<16)/Sint32(y3 - y2);
		
		rstep3 = Sint32((col3.r - col2.r) << 16) / Sint32(y3 - y2);
		gstep3 = Sint32((col3.g - col2.g) << 16) / Sint32(y3 - y2);
		bstep3 = Sint32((col3.b - col2.b) << 16) / Sint32(y3 - y2);
		
		for ( y = y2+1; y <= y3; y++) {
			_FadedLine(dest, xb>>16, xc>>16, y, r2>>16, g2>>16, b2>>16, r3>>16, g3>>16, b3>>16);

			xb += m2;
			xc += m3;
			
			r2 += rstep2;
			g2 += gstep2;
			b2 += bstep2;
			
			r3 += rstep3;
			g3 += gstep3;
			b3 += bstep3;
		}
	}
	
	if ( SDL_MUSTLOCK(dest) && _sge_lock )
		SDL_UnlockSurface(dest);
	
	if(_sge_update!=1){return;}
	
	Sint16 xmax=x1, xmin=x1;
	xmax= (xmax>x2)? xmax : x2;
	xmin= (xmin<x2)? xmin : x2;
	xmax= (xmax>x3)? xmax : x3;
	xmin= (xmin<x3)? xmin : x3;
	
	sge_UpdateRect(dest, xmin, y1, xmax-xmin+1, y3-y1+1);
}


//==================================================================================
// Draws a texured trigon (fast)
//==================================================================================
void sge_TexturedTrigon(SDL_Surface *dest,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,SDL_Surface *source,Sint16 sx1,Sint16 sy1,Sint16 sx2,Sint16 sy2,Sint16 sx3,Sint16 sy3)
{
	Sint16 y;

	if( y1==y3 )
		return;

	/* Sort coords */
	if ( y1 > y2 ) {
		SWAP(y1,y2,y);
		SWAP(x1,x2,y);
		SWAP(sx1,sx2,y);
		SWAP(sy1,sy2,y);
	}
	if ( y2 > y3 ) {
		SWAP(y2,y3,y);
		SWAP(x2,x3,y);
		SWAP(sx2,sx3,y);
		SWAP(sy2,sy3,y);
	}
	if ( y1 > y2 ) {
		SWAP(y1,y2,y);
		SWAP(x1,x2,y);
		SWAP(sx1,sx2,y);
		SWAP(sy1,sy2,y);
	}

	/*
	 * Again we do the same thing as in sge_FilledTrigon(). But here we must keep track of how the 
	 * texture coords change along the lines.
	*/

	/* Starting coords for the three lines */
	Sint32 xa = Sint32(x1<<16);
	Sint32 xb = xa;
	Sint32 xc = Sint32(x2<<16);

	/* Lines step values */
	Sint32 m1 = 0;
	Sint32 m2 = Sint32((x3 - x1)<<16)/Sint32(y3 - y1);
	Sint32 m3 = 0;

	/* Starting texture coords for the three lines */	
	Sint32 srcx1 = Sint32(sx1<<16);
	Sint32 srcx2 = srcx1;
	Sint32 srcx3 = Sint32(sx2<<16);
	
	Sint32 srcy1 = Sint32(sy1<<16);
	Sint32 srcy2 = srcy1;
	Sint32 srcy3 = Sint32(sy2<<16);
	
	/* Texture coords stepping value */
	Sint32 xstep1 = 0;
	Sint32 xstep2 = Sint32((sx3 - sx1) << 16) / Sint32(y3 - y1);
	Sint32 xstep3 = 0;
	
	Sint32 ystep1 = 0;
	Sint32 ystep2 = Sint32((sy3 - sy1) << 16) / Sint32(y3 - y1);
	Sint32 ystep3 = 0;
	
	if ( SDL_MUSTLOCK(dest) && _sge_lock )
		if ( SDL_LockSurface(dest) < 0 )
			return;
	if ( SDL_MUSTLOCK(source) && _sge_lock )
		if ( SDL_LockSurface(source) < 0 )
			return;
	
	/* Upper half of the triangle */
	if( y1==y2 )
		_TexturedLine(dest,x1,x2,y1,source,sx1,sy1,sx2,sy2);
	else{
		m1 = Sint32((x2 - x1)<<16)/Sint32(y2 - y1);
		
		xstep1 = Sint32((sx2 - sx1) << 16) / Sint32(y2 - y1);
		ystep1 = Sint32((sy2 - sy1) << 16) / Sint32(y2 - y1);
		
		for ( y = y1; y <= y2; y++) {
			_TexturedLine(dest, xa>>16, xb>>16, y, source, srcx1>>16, srcy1>>16, srcx2>>16, srcy2>>16);
				
			xa += m1;
			xb += m2;
			
			srcx1 += xstep1;
			srcx2 += xstep2;
			srcy1 += ystep1;
			srcy2 += ystep2;
		}
	}
	
	/* Lower half of the triangle */
	if( y2==y3 )
		_TexturedLine(dest,x2,x3,y2,source,sx2,sy2,sx3,sy3);
	else{
		m3 = Sint32((x3 - x2)<<16)/Sint32(y3 - y2);
		
		xstep3 = Sint32((sx3 - sx2) << 16) / Sint32(y3 - y2);
		ystep3 = Sint32((sy3 - sy2) << 16) / Sint32(y3 - y2);
		
		for ( y = y2+1; y <= y3; y++) {
			_TexturedLine(dest, xb>>16, xc>>16, y, source, srcx2>>16, srcy2>>16, srcx3>>16, srcy3>>16);

			xb += m2;
			xc += m3;
			
			srcx2 += xstep2;
			srcx3 += xstep3;
			srcy2 += ystep2;
			srcy3 += ystep3;
		}
	}
	
	if ( SDL_MUSTLOCK(dest) && _sge_lock )
		SDL_UnlockSurface(dest);
	if ( SDL_MUSTLOCK(source) && _sge_lock )
		SDL_UnlockSurface(source);
	
	if(_sge_update!=1){return;}
	
	Sint16 xmax=x1, xmin=x1;
	xmax= (xmax>x2)? xmax : x2;
	xmin= (xmin<x2)? xmin : x2;
	xmax= (xmax>x3)? xmax : x3;
	xmin= (xmin<x3)? xmin : x3;
	
	sge_UpdateRect(dest, xmin, y1, xmax-xmin+1, y3-y1+1);
}


//==================================================================================
// Draws a texured *RECTANGLE*
//==================================================================================
void sge_TexturedRect(SDL_Surface *dest,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Sint16 x4,Sint16 y4,SDL_Surface *source,Sint16 sx1,Sint16 sy1,Sint16 sx2,Sint16 sy2,Sint16 sx3,Sint16 sy3,Sint16 sx4,Sint16 sy4)
{
	Sint16 y;
	
	if( y1==y3 || y1 == y4 || y4 == y2 )
		return;
	
	/* Sort the coords */
	if ( y1 > y2 ) {
		SWAP(x1,x2,y);
		SWAP(y1,y2,y);
		SWAP(sx1,sx2,y);
		SWAP(sy1,sy2,y);
	}
	if ( y2 > y3 ) {
		SWAP(x3,x2,y);
		SWAP(y3,y2,y);
		SWAP(sx3,sx2,y);
		SWAP(sy3,sy2,y);
	}
	if ( y1 > y2 ) {
		SWAP(x1,x2,y);
		SWAP(y1,y2,y);
		SWAP(sx1,sx2,y);
		SWAP(sy1,sy2,y);
	}
	if ( y3 > y4 ) {
		SWAP(x3,x4,y);
		SWAP(y3,y4,y);
		SWAP(sx3,sx4,y);
		SWAP(sy3,sy4,y);
	}
	if ( y2 > y3 ) {
		SWAP(x3,x2,y);
		SWAP(y3,y2,y);
		SWAP(sx3,sx2,y);
		SWAP(sy3,sy2,y);
	}
	if ( y1 > y2 ) {
		SWAP(x1,x2,y);
		SWAP(y1,y2,y);
		SWAP(sx1,sx2,y);
		SWAP(sy1,sy2,y);
	}

	/*
	 * We do this exactly like sge_TexturedTrigon(), but here we must trace four lines.
	*/

	Sint32 xa = Sint32(x1<<16);
	Sint32 xb = xa;
	Sint32 xc = Sint32(x2<<16);
	Sint32 xd = Sint32(x3<<16);

	Sint32 m1 = 0;
	Sint32 m2 = Sint32((x3 - x1)<<16)/Sint32(y3 - y1);
	Sint32 m3 = Sint32((x4 - x2)<<16)/Sint32(y4 - y2);
	Sint32 m4 = 0;
	
	Sint32 srcx1 = Sint32(sx1<<16);
	Sint32 srcx2 = srcx1;
	Sint32 srcx3 = Sint32(sx2<<16);
	Sint32 srcx4 = Sint32(sx3<<16);
	
	Sint32 srcy1 = Sint32(sy1<<16);
	Sint32 srcy2 = srcy1;
	Sint32 srcy3 = Sint32(sy2<<16);
	Sint32 srcy4 = Sint32(sy3<<16);
	
	Sint32 xstep1 = 0;
	Sint32 xstep2 = Sint32((sx3 - sx1) << 16) / Sint32(y3 - y1);
	Sint32 xstep3 = Sint32((sx4 - sx2) << 16) / Sint32(y4 - y2);
	Sint32 xstep4 = 0;
	
	Sint32 ystep1 = 0;
	Sint32 ystep2 = Sint32((sy3 - sy1) << 16) / Sint32(y3 - y1);
	Sint32 ystep3 = Sint32((sy4 - sy2) << 16) / Sint32(y4 - y2);
	Sint32 ystep4 = 0;
	
	if ( SDL_MUSTLOCK(dest) && _sge_lock )
		if ( SDL_LockSurface(dest) < 0 )
			return;
	
	/* Upper bit of the rectangle */
	if( y1==y2 )
		_TexturedLine(dest,x1,x2,y1,source,sx1,sy1,sx2,sy2);
	else{
		m1 = Sint32((x2 - x1)<<16)/Sint32(y2 - y1);
		
		xstep1 = Sint32((sx2 - sx1) << 16) / Sint32(y2 - y1);
		ystep1 = Sint32((sy2 - sy1) << 16) / Sint32(y2 - y1);
		
		for ( y = y1; y <= y2; y++) {
			_TexturedLine(dest, xa>>16, xb>>16, y, source, srcx1>>16, srcy1>>16, srcx2>>16, srcy2>>16);
				
			xa += m1;
			xb += m2;
			
			srcx1 += xstep1;
			srcx2 += xstep2;
			srcy1 += ystep1;
			srcy2 += ystep2;
		}
	}
	
	/* Middle bit of the rectangle */	
	for ( y = y2+1; y <= y3; y++) {
		_TexturedLine(dest, xb>>16, xc>>16, y, source, srcx2>>16, srcy2>>16, srcx3>>16, srcy3>>16);

		xb += m2;
		xc += m3;
			
		srcx2 += xstep2;
		srcx3 += xstep3;
		srcy2 += ystep2;
		srcy3 += ystep3;
	}
	
	/* Lower bit of the rectangle */
	if( y3==y4 )
		_TexturedLine(dest,x3,x4,y3,source,sx3,sy3,sx4,sy4);
	else{
		m4 = Sint32((x4 - x3)<<16)/Sint32(y4 - y3);
		
		xstep4 = Sint32((sx4 - sx3) << 16) / Sint32(y4 - y3);
		ystep4 = Sint32((sy4 - sy3) << 16) / Sint32(y4 - y3);
		
		for ( y = y3+1; y <= y4; y++) {
			_TexturedLine(dest, xc>>16, xd>>16, y, source, srcx3>>16, srcy3>>16, srcx4>>16, srcy4>>16);

			xc += m3;
			xd += m4;
			
			srcx3 += xstep3;
			srcx4 += xstep4;
			srcy3 += ystep3;
			srcy4 += ystep4;
		}
			
	}
	
	
	if ( SDL_MUSTLOCK(dest) && _sge_lock )
		SDL_UnlockSurface(dest);
	
	if(_sge_update!=1){return;}
	
	Sint16 xmax=x1, xmin=x1;
	xmax= (xmax>x2)? xmax : x2;
	xmin= (xmin<x2)? xmin : x2;
	xmax= (xmax>x3)? xmax : x3;
	xmin= (xmin<x3)? xmin : x3;
	xmax= (xmax>x4)? xmax : x4;
	xmin= (xmin<x4)? xmin : x4;
	
	sge_UpdateRect(dest, xmin, y1, xmax-xmin+1, y4-y1+1);
}



//==================================================================================
// And now to something completly different: Polygons!
//==================================================================================

/* Base polygon structure */
class pline{
public:
	Sint16 x1,x2, y1,y2;
	
	Sint32 fx, fm;
	
	Sint16 x;
	
	pline *next;
	
	virtual void update(void)
	{
		x = Sint16(fx>>16);
		fx += fm;
	}
};

/* Pointer storage (to preserve polymorphism) */
struct pline_p{
	pline *p;
};

/* Radix sort */
pline* rsort(pline *inlist)
{
	if(!inlist)
		return NULL;

	// 16 radix-buckets
	pline* bucket[16] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
	pline* bi[16];     // bucket itterator (points to last element in bucket)
	
	pline *plist = inlist;
	
	int i,k;
	pline *j;
	Uint8 nr;
	
	// Radix sort in 4 steps (16-bit numbers)
	for( i = 0; i < 4; i++ ){
		for( j = plist; j; j = j->next ){
			nr = Uint8( ( j->x >> (4*i) ) & 0x000F);  // Get bucket number
			
			if( !bucket[nr] )
				bucket[nr] = j;   // First in bucket
			else
				bi[nr]->next = j; // Put last in bucket
				
			bi[nr] = j;           // Update bucket itterator
		}
		
		// Empty buckets (recombine list)
		j = NULL;
		for( k = 0; k < 16; k++ ){
			if( bucket[k] ){
				if( j )
					j->next = bucket[k]; // Connect elements in buckets
				else
					plist = bucket[k];   // First element
				
				j = bi[k];
			}
			bucket[k] = NULL;            // Empty 
		}
		j->next = NULL;                  // Terminate list
	} 
	
	return plist;
}

/* Calculate the scanline for y */
pline* get_scanline(pline_p *plist, Uint16 n, Sint32 y)
{
	pline* p = NULL;
	pline* list = NULL;
	pline* li = NULL;
		
	for( int i = 0; i < n; i++ ){
		// Is polyline on this scanline?
		p = plist[i].p;
		if( p->y1 <= y  &&  p->y2 >= y  &&  (p->y1 != p->y2) ){		
			if( list )
				li->next = p; // Add last in list
			else
				list = p;     // Add first in list	
							
			li = p;           // Update itterator
					
			// Calculate x
			p->update();
		}
	}

	if( li )
		li->next = NULL;  // terminate

	// Sort list
	return rsort(list);
}

/* Removes duplicates if needed */
inline void remove_dup(pline *li, Sint16 y)
{
	if( li->next )
		if( (y==li->y1 || y==li->y2) && (y==li->next->y1 || y==li->next->y2) )
			if( ((y == li->y1)? -1:1) != ((y == li->next->y1)? -1:1) )
				li->next = li->next->next;
}


//==================================================================================
// Draws a n-points filled polygon
//==================================================================================

int sge_FilledPolygonAlpha(SDL_Surface *dest, Uint16 n, Sint16 *x, Sint16 *y, Uint32 color, Uint8 alpha)
{
	if(n<3)
		return -1;

	if (SDL_MUSTLOCK(dest) && _sge_lock)
		if (SDL_LockSurface(dest) < 0)
			return -2;

	pline *line = new pline[n];
	pline_p *plist = new pline_p[n];
	
	Sint16 y1,y2, x1, x2, tmp, sy;
	Sint16 ymin = y[1], ymax=y[1];
	Sint16 xmin = x[1], xmax=x[1];
	Uint16 i;
	
	/* Decompose polygon into straight lines */
	for( i = 0; i < n; i++ ){
		y1 = y[i];
		x1 = x[i];
		
		if( i == n-1 ){
			// Last point == First point
			y2 = y[0];
			x2 = x[0];
		}else{
		 	y2 = y[i+1];
			x2 = x[i+1];
		}
		
		// Make sure y1 <= y2
		if( y1 > y2 ) {
			SWAP(y1,y2,tmp);
			SWAP(x1,x2,tmp);
		}
		
		// Reject polygons with negative coords
		if( y1 < 0  ||  x1 < 0  ||  x2 < 0 ){
			if (SDL_MUSTLOCK(dest) && _sge_lock)
				SDL_UnlockSurface(dest);
			
			delete[] line;
			delete[] plist;
			return -1;
		}
		
		if( y1 < ymin )
			ymin = y1;
		if( y2 > ymax )
			ymax = y2;
		if( x1 < xmin )
			xmin = x1;
		else if( x1 > xmax )
			xmax = x1;
		if( x2 < xmin )
			xmin = x2;
		else if( x2 > xmax )
			xmax = x2;
		
		//Fill structure
		line[i].y1 = y1;
		line[i].y2 = y2;
		line[i].x1 = x1;
		line[i].x2 = x2;
		
		// Start x-value (fixed point)
		line[i].fx = Sint32(x1<<16);
		
		// Lines step value (fixed point)
		if( y1 != y2)
			line[i].fm = Sint32((x2 - x1)<<16)/Sint32(y2 - y1);
		else
			line[i].fm = 0;
		
		line[i].next = NULL;
		
		// Add to list
		plist[i].p = &line[i];
		
		// Draw the polygon outline (looks nicer)
		if( alpha == SDL_ALPHA_OPAQUE )
			_Line(dest,x1,y1,x2,y2,color); // Can't do this with alpha, might overlap with the filling
	}
	
	/* Remove surface lock if _HLine() is to be used */
	if (SDL_MUSTLOCK(dest) && _sge_lock && alpha == SDL_ALPHA_OPAQUE)
		SDL_UnlockSurface(dest);
	
	pline* list = NULL;
	pline* li = NULL;   // list itterator
	
	// Scan y-lines
	for( sy = ymin; sy <= ymax; sy++){
		list = get_scanline(plist, n, sy);
		
		if( !list )
			continue;     // nothing in list... hmmmm
			
		x1 = x2 = -1;
		
		// Draw horizontal lines between pairs
		for( li = list; li; li = li->next ){
			remove_dup(li, sy);
			
			if( x1 < 0 )
				x1 = li->x+1;
			else if( x2 < 0 )
				x2 = li->x;
				
			if( x1 >= 0  &&  x2 >= 0 ){
				if( x2-x1 < 0  && alpha == SDL_ALPHA_OPAQUE ){
					// Already drawn by the outline
					x1 = x2 = -1;
					continue;
				}
			
				if( alpha == SDL_ALPHA_OPAQUE )
					_HLine(dest, x1, x2, sy, color);
				else
					_HLineAlpha(dest, x1-1, x2, sy, color, alpha);
					
				x1 = x2 = -1;
			}
		}
	}
	
	if (SDL_MUSTLOCK(dest) && _sge_lock && alpha != SDL_ALPHA_OPAQUE)
		SDL_UnlockSurface(dest);
	
	delete[] line;
	delete[] plist;
	
	if(_sge_update!=1){return 0;}
	
	sge_UpdateRect(dest, xmin, ymin, xmax-xmin+1, ymax-ymin+1);
	
	return 0;
}

int sge_FilledPolygonAlpha(SDL_Surface *dest, Uint16 n, Sint16 *x, Sint16 *y, Uint8 r, Uint8 g, Uint8 b, Uint8 alpha)
{
	return sge_FilledPolygonAlpha(dest, n, x, y, SDL_MapRGB(dest->format,r,g,b), alpha);
}

int sge_FilledPolygon(SDL_Surface *dest, Uint16 n, Sint16 *x, Sint16 *y, Uint32 color)
{
	return sge_FilledPolygonAlpha(dest, n, x, y, color, SDL_ALPHA_OPAQUE);
}

int sge_FilledPolygon(SDL_Surface *dest, Uint16 n, Sint16 *x, Sint16 *y, Uint8 r, Uint8 g, Uint8 b)
{
	return sge_FilledPolygonAlpha(dest, n, x, y, SDL_MapRGB(dest->format,r,g,b), SDL_ALPHA_OPAQUE);
}


//==================================================================================
// Draws a n-points (AA) filled polygon
//==================================================================================

int sge_AAFilledPolygon(SDL_Surface *dest, Uint16 n, Sint16 *x, Sint16 *y, Uint32 color)
{
	if(n<3)
		return -1;

	
	if (SDL_MUSTLOCK(dest) && _sge_lock)
		if (SDL_LockSurface(dest) < 0)
			return -2;

	pline *line = new pline[n];
	pline_p *plist = new pline_p[n];
	
	Sint16 y1,y2, x1, x2, tmp, sy;
	Sint16 ymin = y[1], ymax=y[1];
	Sint16 xmin = x[1], xmax=x[1];
	Uint16 i;
	
	/* Decompose polygon into straight lines */
	for( i = 0; i < n; i++ ){
		y1 = y[i];
		x1 = x[i];
		
		if( i == n-1 ){
			// Last point == First point
			y2 = y[0];
			x2 = x[0];
		}else{
		 	y2 = y[i+1];
			x2 = x[i+1];
		}
		
		// Make sure y1 <= y2
		if( y1 > y2 ) {
			SWAP(y1,y2,tmp);
			SWAP(x1,x2,tmp);
		}
		
		// Reject polygons with negative coords
		if( y1 < 0  ||  x1 < 0  ||  x2 < 0 ){
			if (SDL_MUSTLOCK(dest) && _sge_lock)
				SDL_UnlockSurface(dest);
		
			delete[] line;
			delete[] plist;
			return -1;
		}
		
		if( y1 < ymin )
			ymin = y1;
		if( y2 > ymax )
			ymax = y2;
		if( x1 < xmin )
			xmin = x1;
		else if( x1 > xmax )
			xmax = x1;
		if( x2 < xmin )
			xmin = x2;
		else if( x2 > xmax )
			xmax = x2;
		
		//Fill structure
		line[i].y1 = y1;
		line[i].y2 = y2;
		line[i].x1 = x1;
		line[i].x2 = x2;
		
		// Start x-value (fixed point)
		line[i].fx = Sint32(x1<<16);
		
		// Lines step value (fixed point)
		if( y1 != y2)
			line[i].fm = Sint32((x2 - x1)<<16)/Sint32(y2 - y1);
		else
			line[i].fm = 0;
		
		line[i].next = NULL;
		
		// Add to list
		plist[i].p = &line[i];
		
		// Draw AA Line				
		_AALineAlpha(dest,x1,y1,x2,y2,color,SDL_ALPHA_OPAQUE);
	}
	
	if (SDL_MUSTLOCK(dest) && _sge_lock)
		SDL_UnlockSurface(dest);
	

	pline* list = NULL;
	pline* li = NULL;   // list itterator
	
	// Scan y-lines
	for( sy = ymin; sy <= ymax; sy++){
		list = get_scanline(plist, n, sy);
		
		if( !list )
			continue;     // nothing in list... hmmmm
			
		x1 = x2 = -1;
		
		// Draw horizontal lines between pairs
		for( li = list; li; li = li->next ){
			remove_dup(li, sy);
			
			if( x1 < 0 )
				x1 = li->x+1;
			else if( x2 < 0 )
				x2 = li->x;
				
			if( x1 >= 0  &&  x2 >= 0 ){
				if( x2-x1 < 0 ){
					x1 = x2 = -1;
					continue;
				}
			
				_HLine(dest, x1, x2, sy, color);

				x1 = x2 = -1;
			}
		}
	}
	
	delete[] line;
	delete[] plist;
	
	if(_sge_update!=1){return 0;}
	
	sge_UpdateRect(dest, xmin, ymin, xmax-xmin+1, ymax-ymin+1);
	
	return 0;
}

int sge_AAFilledPolygon(SDL_Surface *dest, Uint16 n, Sint16 *x, Sint16 *y, Uint8 r, Uint8 g, Uint8 b)
{
	return sge_AAFilledPolygon(dest, n, x, y, SDL_MapRGB(dest->format,r,g,b));
}


//==================================================================================
// Draws a n-points gourand shaded polygon
//==================================================================================

/* faded polygon structure */
class fpline : public pline{
public:
	Uint8 r1, r2; 
	Uint8 g1, g2; 
	Uint8 b1, b2;
	
	Uint32 fr, fg, fb;
	Sint32 fmr, fmg, fmb;
	
	Uint8 r,g,b;
	
	virtual void update(void)
	{
		x = Sint16(fx>>16);
		fx += fm;
		
		r = Uint8(fr>>16);
		g = Uint8(fg>>16);
		b = Uint8(fb>>16);
		
		fr += fmr;
		fg += fmg;
		fb += fmb;
	}
};

int sge_FadedPolygonAlpha(SDL_Surface *dest, Uint16 n, Sint16 *x, Sint16 *y, Uint8 *R, Uint8 *G, Uint8 *B, Uint8 alpha)
{
	if(n<3)
		return -1;

	if (SDL_MUSTLOCK(dest) && _sge_lock)
		if (SDL_LockSurface(dest) < 0)
			return -2;

	fpline *line = new fpline[n];
	pline_p *plist = new pline_p[n];
	
	Sint16 y1,y2, x1, x2, tmp, sy;
	Sint16 ymin = y[1], ymax=y[1];
	Sint16 xmin = x[1], xmax=x[1];
	Uint16 i;
	Uint8 r1=0, g1=0, b1=0, r2=0, g2=0, b2=0, t;
	
	// Decompose polygon into straight lines
	for( i = 0; i < n; i++ ){
		y1 = y[i];
		x1 = x[i];
		r1 = R[i];
		g1 = G[i];
		b1 = B[i];
		
		if( i == n-1 ){
			// Last point == First point
			y2 = y[0];
			x2 = x[0];
			r2 = R[0];
			g2 = G[0];
			b2 = B[0];
		}else{
		 	y2 = y[i+1];
			x2 = x[i+1];
			r2 = R[i+1];
			g2 = G[i+1];
			b2 = B[i+1];
		}
		
		// Make sure y1 <= y2
		if( y1 > y2 ) {
			SWAP(y1,y2,tmp);
			SWAP(x1,x2,tmp);
			SWAP(r1,r2,t);
			SWAP(g1,g2,t);
			SWAP(b1,b2,t);
		}
		
		// Reject polygons with negative coords
		if( y1 < 0  ||  x1 < 0  ||  x2 < 0 ){
			if ( SDL_MUSTLOCK(dest) && _sge_lock )
				SDL_UnlockSurface(dest);
			
			delete[] line;
			delete[] plist;
			return -1;
		}
		
		if( y1 < ymin )
			ymin = y1;
		if( y2 > ymax )
			ymax = y2;
		if( x1 < xmin )
			xmin = x1;
		else if( x1 > xmax )
			xmax = x1;
		if( x2 < xmin )
			xmin = x2;
		else if( x2 > xmax )
			xmax = x2;
		
		//Fill structure
		line[i].y1 = y1;
		line[i].y2 = y2;
		line[i].x1 = x1;
		line[i].x2 = x2;
		line[i].r1 = r1;
		line[i].g1 = g1;
		line[i].b1 = b1;
		line[i].r2 = r2;
		line[i].g2 = g2;
		line[i].b2 = b2;
		
		// Start x-value (fixed point)
		line[i].fx = Sint32(x1<<16);

		line[i].fr = Uint32(r1<<16);
		line[i].fg = Uint32(g1<<16);
		line[i].fb = Uint32(b1<<16);
		
		// Lines step value (fixed point)
		if( y1 != y2){
			line[i].fm  = Sint32((x2 - x1)<<16)/Sint32(y2 - y1);
			
			line[i].fmr = Sint32((r2 - r1)<<16)/Sint32(y2 - y1);
			line[i].fmg = Sint32((g2 - g1)<<16)/Sint32(y2 - y1);
			line[i].fmb = Sint32((b2 - b1)<<16)/Sint32(y2 - y1);
		}else{
			line[i].fm  = 0;
			line[i].fmr = 0;
			line[i].fmg = 0;
			line[i].fmb = 0;
		}
		
		line[i].next = NULL;
		
		// Add to list
		plist[i].p = &line[i];
		
		// Draw the polygon outline (looks nicer)
		if( alpha == SDL_ALPHA_OPAQUE )
			sge_DomcLine(dest,x1,y1,x2,y2,r1,g1,b1,r2,g2,b2, _PutPixel); // Can't do this with alpha, might overlap with the filling
	}
	
	fpline* list = NULL;
	fpline* li = NULL;   // list itterator
	
	// Scan y-lines
	for( sy = ymin; sy <= ymax; sy++){
		list = (fpline *)get_scanline(plist, n, sy);
		
		if( !list )
			continue;     // nothing in list... hmmmm
			
		x1 = x2 = -1;
		
		// Draw horizontal lines between pairs
		for( li = list; li; li = (fpline *)li->next ){
			remove_dup(li, sy);
			
			if( x1 < 0 ){
				x1 = li->x+1;
				r1 = li->r;
				g1 = li->g;
				b1 = li->b;
			}else if( x2 < 0 ){
				x2 = li->x;
				r2 = li->r;
				g2 = li->g;
				b2 = li->b;
			}
				
			if( x1 >= 0  &&  x2 >= 0 ){
				if( x2-x1 < 0 && alpha == SDL_ALPHA_OPAQUE){
					x1 = x2 = -1;
					continue;
				}
			
				if( alpha == SDL_ALPHA_OPAQUE )
					_FadedLine(dest, x1, x2, sy, r1, g1, b1, r2, g2, b2);
				else{
					_sge_alpha_hack = alpha;
					sge_DomcLine(dest, x1-1, sy, x2, sy, r1, g1, b1, r2, g2, b2, callback_alpha_hack);
				}
				
				x1 = x2 = -1;
			}
		}
	}
	
	if ( SDL_MUSTLOCK(dest) && _sge_lock )
		SDL_UnlockSurface(dest);
		
	delete[] line;
	delete[] plist;
	
	if(_sge_update!=1){return 0;}
	
	sge_UpdateRect(dest, xmin, ymin, xmax-xmin+1, ymax-ymin+1);
	
	return 0;
}

int sge_FadedPolygon(SDL_Surface *dest, Uint16 n, Sint16 *x, Sint16 *y, Uint8 *R, Uint8 *G, Uint8 *B)
{
	return sge_FadedPolygonAlpha(dest, n, x, y, R, G, B, SDL_ALPHA_OPAQUE);
}


//==================================================================================
// Draws a n-points (AA) gourand shaded polygon
//==================================================================================
int sge_AAFadedPolygon(SDL_Surface *dest, Uint16 n, Sint16 *x, Sint16 *y, Uint8 *R, Uint8 *G, Uint8 *B)
{
	if(n<3)
		return -1;

	if (SDL_MUSTLOCK(dest) && _sge_lock)
		if (SDL_LockSurface(dest) < 0)
			return -2;

	fpline *line = new fpline[n];
	pline_p *plist = new pline_p[n];
	
	Sint16 y1,y2, x1, x2, tmp, sy;
	Sint16 ymin = y[1], ymax=y[1];
	Sint16 xmin = x[1], xmax=x[1];
	Uint16 i;
	Uint8 r1=0, g1=0, b1=0, r2=0, g2=0, b2=0, t;
	
	// Decompose polygon into straight lines
	for( i = 0; i < n; i++ ){
		y1 = y[i];
		x1 = x[i];
		r1 = R[i];
		g1 = G[i];
		b1 = B[i];
		
		if( i == n-1 ){
			// Last point == First point
			y2 = y[0];
			x2 = x[0];
			r2 = R[0];
			g2 = G[0];
			b2 = B[0];
		}else{
		 	y2 = y[i+1];
			x2 = x[i+1];
			r2 = R[i+1];
			g2 = G[i+1];
			b2 = B[i+1];
		}
		
		// Make sure y1 <= y2
		if( y1 > y2 ) {
			SWAP(y1,y2,tmp);
			SWAP(x1,x2,tmp);
			SWAP(r1,r2,t);
			SWAP(g1,g2,t);
			SWAP(b1,b2,t);
		}
		
		// Reject polygons with negative coords
		if( y1 < 0  ||  x1 < 0  ||  x2 < 0 ){
			if ( SDL_MUSTLOCK(dest) && _sge_lock )
				SDL_UnlockSurface(dest);
			
			delete[] line;
			delete[] plist;
			return -1;
		}
		
		if( y1 < ymin )
			ymin = y1;
		if( y2 > ymax )
			ymax = y2;
		if( x1 < xmin )
			xmin = x1;
		else if( x1 > xmax )
			xmax = x1;
		if( x2 < xmin )
			xmin = x2;
		else if( x2 > xmax )
			xmax = x2;
		
		//Fill structure
		line[i].y1 = y1;
		line[i].y2 = y2;
		line[i].x1 = x1;
		line[i].x2 = x2;
		line[i].r1 = r1;
		line[i].g1 = g1;
		line[i].b1 = b1;
		line[i].r2 = r2;
		line[i].g2 = g2;
		line[i].b2 = b2;
		
		// Start x-value (fixed point)
		line[i].fx = Sint32(x1<<16);

		line[i].fr = Uint32(r1<<16);
		line[i].fg = Uint32(g1<<16);
		line[i].fb = Uint32(b1<<16);
		
		// Lines step value (fixed point)
		if( y1 != y2){
			line[i].fm  = Sint32((x2 - x1)<<16)/Sint32(y2 - y1);
			
			line[i].fmr = Sint32((r2 - r1)<<16)/Sint32(y2 - y1);
			line[i].fmg = Sint32((g2 - g1)<<16)/Sint32(y2 - y1);
			line[i].fmb = Sint32((b2 - b1)<<16)/Sint32(y2 - y1);
		}else{
			line[i].fm  = 0;
			line[i].fmr = 0;
			line[i].fmg = 0;
			line[i].fmb = 0;
		}
		
		line[i].next = NULL;
		
		// Add to list
		plist[i].p = &line[i];
		
		// Draw the polygon outline (AA)
		_AAmcLineAlpha(dest,x1,y1,x2,y2,r1,g1,b1,r2,g2,b2,SDL_ALPHA_OPAQUE);
	}
	
	fpline* list = NULL;
	fpline* li = NULL;   // list itterator
	
	// Scan y-lines
	for( sy = ymin; sy <= ymax; sy++){
		list = (fpline *)get_scanline(plist, n, sy);
		
		if( !list )
			continue;     // nothing in list... hmmmm
			
		x1 = x2 = -1;
		
		// Draw horizontal lines between pairs
		for( li = list; li; li = (fpline *)li->next ){
			remove_dup(li, sy);
			
			if( x1 < 0 ){
				x1 = li->x+1;
				r1 = li->r;
				g1 = li->g;
				b1 = li->b;
			}else if( x2 < 0 ){
				x2 = li->x;
				r2 = li->r;
				g2 = li->g;
				b2 = li->b;
			}
				
			if( x1 >= 0  &&  x2 >= 0 ){
				if( x2-x1 < 0 ){
					x1 = x2 = -1;
					continue;
				}
			
				_FadedLine(dest, x1, x2, sy, r1, g1, b1, r2, g2, b2);

				x1 = x2 = -1;
			}
		}
	}
	
	if ( SDL_MUSTLOCK(dest) && _sge_lock )
		SDL_UnlockSurface(dest);
		
	delete[] line;
	delete[] plist;
	
	if(_sge_update!=1){return 0;}
	
	sge_UpdateRect(dest, xmin, ymin, xmax-xmin+1, ymax-ymin+1);
	
	return 0;
}
