/* * 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; }