Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
382 KB
Referenced Files
None
Subscribers
None
This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/util/sdl/bitmap.cpp b/util/sdl/bitmap.cpp
index c41c6d1e..220bd504 100644
--- a/util/sdl/bitmap.cpp
+++ b/util/sdl/bitmap.cpp
@@ -1,1025 +1,1065 @@
#include "../bitmap.h"
#include "../lit_bitmap.h"
#include "stretch/SDL_stretch.h"
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_gfxPrimitives.h>
#include <exception>
static const int FULLSCREEN = 0;
/* bits per pixel */
static int SCREEN_DEPTH = 16;
static SDL_Surface * screen;
typedef unsigned int (*blender)(unsigned int color1, unsigned int color2, unsigned int alpha);
/* taken from allegro 4.2: src/colblend.c, _blender_trans16 */
static unsigned int transBlender(unsigned int x, unsigned int y, unsigned int n){
unsigned long result;
if (n)
n = (n + 1) / 8;
x = ((x & 0xFFFF) | (x << 16)) & 0x7E0F81F;
y = ((y & 0xFFFF) | (y << 16)) & 0x7E0F81F;
result = ((x - y) * n / 32 + y) & 0x7E0F81F;
return ((result & 0xFFFF) | (result >> 16));
}
static unsigned int noBlender(unsigned int a, unsigned int b, unsigned int c){
return a;
}
struct BlendingData{
BlendingData():
red(0), green(0), blue(0), alpha(0), currentBlender(noBlender){}
int red, green, blue, alpha;
blender currentBlender;
};
static BlendingData globalBlend;
static int drawingMode = Bitmap::MODE_SOLID;
static int drawingAlpha(){
switch (::drawingMode){
case Bitmap::MODE_SOLID : return 255;
case Bitmap::MODE_TRANS : return globalBlend.alpha;
default : return 255;
}
}
static void paintown_draw_sprite_ex16(SDL_Surface * dst, SDL_Surface * src, int dx, int dy, int mode, int flip );
const int Bitmap::MaskColor(){
static int mask = makeColor(255, 0, 255);
return mask;
}
Bitmap * Bitmap::Screen = NULL;
static Bitmap * Scaler = NULL;
static Bitmap * Buffer = NULL;
void BitmapData::setSurface(SDL_Surface * surface){
this->surface = surface;
clip_left = 0;
clip_right = surface->w - 1;
clip_top = 0;
clip_bottom = surface->h - 1;
}
Bitmap::Bitmap():
own(NULL){
/* TODO */
}
Bitmap::Bitmap(SDL_Surface * who, bool deep_copy):
own(NULL){
if (deep_copy){
SDL_Surface * surface = SDL_CreateRGBSurface(SDL_SWSURFACE, who->w, who->h, SCREEN_DEPTH, 0, 0, 0, 0);
SDL_Rect source;
SDL_Rect destination;
source.w = surface->w;
source.h = surface->h;
source.x = 0;
source.y = 0;
destination.w = surface->w;
destination.h = surface->h;
destination.x = 0;
destination.y = 0;
SDL_BlitSurface(who, &source, surface, &destination);
getData().setSurface(surface);
own = new int;
*own = 1;
} else {
/* FIXME: handle deep_copy */
getData().setSurface(who);
}
}
Bitmap::Bitmap(int w, int h){
SDL_Surface * surface = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, SCREEN_DEPTH, 0, 0, 0, 0);
if (surface == NULL){
/* FIXME */
throw std::exception();
}
getData().setSurface(surface);
own = new int;
*own = 1;
}
Bitmap::Bitmap( const char * load_file ):
own(NULL){
internalLoadFile(load_file);
}
Bitmap::Bitmap( const std::string & load_file ):
own(NULL){
internalLoadFile(load_file.c_str());
}
Bitmap::Bitmap( const char * load_file, int sx, int sy ):
own(NULL){
/* TODO */
}
Bitmap::Bitmap( const char * load_file, int sx, int sy, double accuracy ):
own(NULL){
/* TODO */
}
Bitmap::Bitmap( const Bitmap & copy, bool deep_copy):
own(NULL){
if (deep_copy){
SDL_Surface * who = copy.getData().getSurface();
SDL_Surface * surface = SDL_CreateRGBSurface(SDL_SWSURFACE, who->w, who->h, SCREEN_DEPTH, 0, 0, 0, 0);
SDL_Rect source;
SDL_Rect destination;
source.w = surface->w;
source.h = surface->h;
source.x = 0;
source.y = 0;
destination.w = surface->w;
destination.h = surface->h;
destination.x = 0;
destination.y = 0;
SDL_BlitSurface(who, &source, surface, &destination);
getData().setSurface(surface);
own = new int;
*own = 1;
} else {
getData().setSurface(copy.getData().getSurface());
own = copy.own;
if (own){
*own += 1;
}
}
}
Bitmap::Bitmap( const Bitmap & copy, int sx, int sy ):
own(NULL){
/* TODO */
}
Bitmap::Bitmap( const Bitmap & copy, int sx, int sy, double accuracy ):
own(NULL){
/* TODO */
}
static Uint8* computeOffset(SDL_Surface * surface, int x, int y){
int bpp = surface->format->BytesPerPixel;
return ((Uint8*)surface->pixels) + y * surface->pitch + x * bpp;
}
Bitmap::Bitmap( const Bitmap & copy, int x, int y, int width, int height ):
own(NULL){
/* TODO */
path = copy.getPath();
SDL_Surface * his = copy.getData().getSurface();
if ( x < 0 )
x = 0;
if ( y < 0 )
y = 0;
if ( width > his->w )
width = his->w;
if ( height > his->h )
height = his->h;
SDL_Surface * sub = SDL_CreateRGBSurfaceFrom(computeOffset(his, x, y), width, height, SCREEN_DEPTH, his->pitch, 0, 0, 0, 0);
getData().setSurface(sub);
own = new int;
*own = 1;
}
void Bitmap::internalLoadFile(const char * path){
this->path = path;
SDL_Surface * loaded = IMG_Load(path);
if (loaded){
getData().setSurface(SDL_DisplayFormat(loaded));
SDL_FreeSurface(loaded);
} else {
/* FIXME: throw a standard bitmap exception */
throw std::exception();
}
own = new int;
*own = 1;
}
int Bitmap::getWidth() const {
if (getData().getSurface() != NULL){
return getData().getSurface()->w;
}
return 0;
}
int Bitmap::getHeight() const {
if (getData().getSurface() != NULL){
return getData().getSurface()->h;
}
return 0;
}
int Bitmap::getRed(int c){
Uint8 red = 0;
Uint8 green = 0;
Uint8 blue = 0;
SDL_GetRGB(c, Screen->getData().getSurface()->format, &red, &green, &blue);
return red;
}
int Bitmap::getBlue(int c){
Uint8 red = 0;
Uint8 green = 0;
Uint8 blue = 0;
SDL_GetRGB(c, Screen->getData().getSurface()->format, &red, &green, &blue);
return blue;
}
int Bitmap::getGreen(int c){
Uint8 red = 0;
Uint8 green = 0;
Uint8 blue = 0;
SDL_GetRGB(c, Screen->getData().getSurface()->format, &red, &green, &blue);
return green;
}
int Bitmap::makeColor(int red, int blue, int green){
return SDL_MapRGB(Screen->getData().getSurface()->format, red, blue, green);
}
int Bitmap::setGraphicsMode(int mode, int width, int height){
switch (mode){
default: {
// case WINDOWED : {
screen = SDL_SetVideoMode(width, height, SCREEN_DEPTH, SDL_HWSURFACE | SDL_DOUBLEBUF);
// screen = SDL_SetVideoMode(width, height, SCREEN_DEPTH, SDL_SWSURFACE | SDL_DOUBLEBUF);
if (!screen){
return 1;
}
break;
}
}
if (SCALE_X == 0){
SCALE_X = width;
}
if (SCALE_Y == 0){
SCALE_Y = height;
}
if ( Screen != NULL ){
delete Screen;
Screen = NULL;
}
if ( Scaler != NULL ){
delete Scaler;
Scaler = NULL;
}
if ( Buffer != NULL ){
delete Buffer;
Buffer = NULL;
}
if (width != 0 && height != 0){
Screen = new Bitmap(screen);
if ( width != 0 && height != 0 && (width != SCALE_X || height != SCALE_Y) ){
Scaler = new Bitmap(width, height);
Buffer = new Bitmap(SCALE_X, SCALE_Y);
}
}
return 0;
}
void Bitmap::addBlender( int r, int g, int b, int a ){
/* TODO */
}
void Bitmap::multiplyBlender( int r, int g, int b, int a ){
/* TODO */
}
void Bitmap::differenceBlender( int r, int g, int b, int a ){
/* TODO */
}
Bitmap & Bitmap::operator=(const Bitmap &){
/* TODO */
return *this;
}
int Bitmap::setGfxModeText(){
/* TODO */
return 0;
}
int Bitmap::setGfxModeFullscreen(int x, int y){
return setGraphicsMode(FULLSCREEN, x, y);
}
void Bitmap::drawingMode(int type){
::drawingMode = type;
}
void Bitmap::transBlender( int r, int g, int b, int a ){
globalBlend.red = r;
globalBlend.green = g;
globalBlend.blue = b;
globalBlend.alpha = a;
globalBlend.currentBlender = ::transBlender;
}
void Bitmap::setClipRect( int x1, int y1, int x2, int y2 ) const {
getData().setClip(x1, y1, x2, y2);
SDL_Rect area;
area.x = x1;
area.y = y1;
area.w = x2 - x1;
area.h = y2 - y1;
SDL_SetClipRect(getData().getSurface(), &area);
}
void Bitmap::destroyPrivateData(){
SDL_FreeSurface(getData().getSurface());
}
void Bitmap::putPixel(int x, int y, int pixel) const {
SDL_Surface * surface = getData().getSurface();
/* clip it */
if (getData().isClipped(x, y)){
return;
}
if (SDL_MUSTLOCK(surface)){
SDL_LockSurface(surface);
}
int bpp = surface->format->BytesPerPixel;
/* Here p is the address to the pixel we want to set */
Uint8 *p = computeOffset(surface, x, y);
switch(bpp) {
case 1:
*p = pixel;
break;
case 2:
switch (::drawingMode){
case MODE_SOLID : {
*(Uint16 *)p = pixel;
break;
}
case MODE_TRANS : {
*(Uint16 *)p = globalBlend.currentBlender(pixel, *(Uint16*)p, globalBlend.alpha);
break;
}
}
break;
case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
p[0] = (pixel >> 16) & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = pixel & 0xff;
} else {
p[0] = pixel & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = (pixel >> 16) & 0xff;
}
break;
case 4:
*(Uint32 *)p = pixel;
break;
}
if (SDL_MUSTLOCK(surface)){
SDL_UnlockSurface(surface);
}
}
void Bitmap::putPixelNormal(int x, int y, int col) const {
putPixel(x, y, col);
}
bool Bitmap::getError(){
/* TODO */
return false;
}
void Bitmap::rectangle( int x1, int y1, int x2, int y2, int color ) const {
Uint8 red, green, blue;
SDL_GetRGB(color, getData().getSurface()->format, &red, &green, &blue);
rectangleRGBA(getData().getSurface(), x1, y1, x2, y2, red, green, blue, 255);
}
void Bitmap::rectangleFill( int x1, int y1, int x2, int y2, int color ) const {
Uint8 red, green, blue;
SDL_GetRGB(color, getData().getSurface()->format, &red, &green, &blue);
boxRGBA(getData().getSurface(), x1, y1, x2, y2, red, green, blue, 255);
}
void Bitmap::circleFill(int x, int y, int radius, int color) const {
Uint8 red, green, blue;
SDL_GetRGB(color, getData().getSurface()->format, &red, &green, &blue);
int alpha = 255;
switch (::drawingMode){
case MODE_SOLID : alpha = 255; break;
case MODE_TRANS : alpha = globalBlend.alpha; break;
}
filledCircleRGBA(getData().getSurface(), x, y, radius, red, green, blue, alpha);
}
void Bitmap::circle(int x, int y, int radius, int color) const {
circleColor(getData().getSurface(), x, y, radius, color);
}
void Bitmap::line( const int x1, const int y1, const int x2, const int y2, const int color ) const {
Uint8 red, green, blue;
SDL_GetRGB(color, getData().getSurface()->format, &red, &green, &blue);
lineRGBA(getData().getSurface(), x1, y1, x2, y2, red, green, blue, drawingAlpha());
}
void Bitmap::draw(const int x, const int y, const Bitmap & where) const {
if (getData().getSurface() != NULL){
paintown_draw_sprite_ex16(where.getData().getSurface(), getData().getSurface(), x, y, Bitmap::SPRITE_NORMAL, Bitmap::SPRITE_NO_FLIP);
/*
SDL_SetColorKey(getData().getSurface(), SDL_SRCCOLORKEY, makeColor(255, 0, 255));
Blit(x, y, where);
*/
}
}
void Bitmap::draw(const int x, const int y, const int startWidth, const int startHeight, const int width, const int height, const Bitmap & where) const {
/* TODO */
}
void Bitmap::drawHFlip(const int x, const int y, const Bitmap & where) const {
paintown_draw_sprite_ex16( where.getData().getSurface(), getData().getSurface(), x, y, Bitmap::SPRITE_NORMAL, Bitmap::SPRITE_H_FLIP );
}
void Bitmap::drawVFlip( const int x, const int y, const Bitmap & where ) const {
/* TODO */
}
void Bitmap::drawHVFlip( const int x, const int y, const Bitmap & where ) const {
/* TODO */
}
void Bitmap::drawTrans( const int x, const int y, const Bitmap & where ) const {
/* FIXME */
// draw(x, y, where);
paintown_draw_sprite_ex16(where.getData().getSurface(), getData().getSurface(), x, y, Bitmap::SPRITE_TRANS, Bitmap::SPRITE_NO_FLIP);
}
void Bitmap::drawTransHFlip( const int x, const int y, const Bitmap & where ) const {
/* TODO */
}
void Bitmap::drawTransVFlip( const int x, const int y, const Bitmap & where ) const {
/* TODO */
}
void Bitmap::drawTransHVFlip( const int x, const int y, const Bitmap & where ) const {
/* TODO */
}
void Bitmap::drawMask( const int x, const int y, const Bitmap & where ){
/* TODO */
}
void Bitmap::drawStretched( const int x, const int y, const int new_width, const int new_height, const Bitmap & who ){
if (getData().getSurface() != NULL){
SDL_SetColorKey(getData().getSurface(), SDL_SRCCOLORKEY, makeColor(255, 0, 255));
SDL_Rect source;
SDL_Rect destination;
source.x = 0;
source.y = 0;
source.w = getWidth();
source.h = getHeight();
destination.x = x;
destination.y = y;
destination.w = new_width;
destination.h = new_height;
/*
if (x < 0){
source.x = -x;
source.w -= -x;
destination.x += -x;
destination.w -= -x;
}
*/
/*
source.x = 0;
source.y = 0;
source.w = getWidth() / 2;
source.h = getHeight() / 2;
destination.x = 0;
destination.y = 0;
destination.w = new_width;
destination.h = new_height;
*/
- SDL_StretchSurfaceRect(getData().getSurface(), &source, who.getData().getSurface(), &destination);
+ SDL_Surface * src = getData().getSurface();
+ SDL_Surface * dst = who.getData().getSurface();
+
+ if (SDL_MUSTLOCK(src)){
+ SDL_LockSurface(src);
+ }
+
+ if (SDL_MUSTLOCK(dst)){
+ SDL_LockSurface(dst);
+ }
+
+ SDL_StretchSurfaceRect(src, &source, dst, &destination);
+
+ if (SDL_MUSTLOCK(src)){
+ SDL_UnlockSurface(src);
+ }
+
+ if (SDL_MUSTLOCK(dst)){
+ SDL_UnlockSurface(dst);
+ }
}
}
void Bitmap::Blit( const std::string & xpath ) const {
/* TODO */
}
void Bitmap::Blit( const Bitmap & where ) const {
Blit(0, 0, where);
}
void Bitmap::Blit( const int x, const int y, const Bitmap & where ) const {
Blit(0, 0, x, y, where);
}
void Bitmap::Blit( const int mx, const int my, const int wx, const int wy, const Bitmap & where ) const {
Blit(mx, my, getWidth(), getHeight(), wx, wy, where);
}
void Bitmap::Blit( const int mx, const int my, const int width, const int height, const int wx, const int wy, const Bitmap & where ) const {
SDL_Rect source;
SDL_Rect destination;
source.w = width;
source.h = height;
source.x = mx;
source.y = my;
destination.w = width;
destination.h = height;
destination.x = wx;
destination.y = wy;
SDL_BlitSurface(getData().getSurface(), &source, where.getData().getSurface(), &destination);
}
void Bitmap::BlitMasked( const int mx, const int my, const int width, const int height, const int wx, const int wy, const Bitmap & where ) const {
/* TODO */
}
void Bitmap::BlitToScreen(const int upper_left_x, const int upper_left_y) const {
if ( Scaler == NULL ){
this->Blit( upper_left_x, upper_left_y, *Screen );
} else {
this->Blit( upper_left_x, upper_left_y, *Buffer );
Buffer->Stretch(*Scaler);
Scaler->Blit(0, 0, 0, 0, *Screen);
}
SDL_Flip(Screen->getData().getSurface());
// SDL_UpdateRect(Screen->getData().getSurface(), 0, 0, Screen->getWidth(), Screen->getHeight());
}
void Bitmap::BlitAreaToScreen(const int upper_left_x, const int upper_left_y) const {
/* TODO */
}
void Bitmap::BlitFromScreen(const int x, const int y) const {
/* TODO */
}
void Bitmap::Stretch( const Bitmap & where ) const {
if (getWidth() == where.getWidth() && getHeight() == where.getHeight()){
Blit(where);
} else {
Stretch(where, 0, 0, getWidth(), getHeight(), 0, 0, where.getWidth(), where.getHeight());
}
}
void Bitmap::Stretch( const Bitmap & where, const int sourceX, const int sourceY, const int sourceWidth, const int sourceHeight, const int destX, const int destY, const int destWidth, const int destHeight ) const {
SDL_Rect source;
SDL_Rect destination;
source.x = sourceX;
source.y = sourceY;
source.w = sourceWidth;
source.h = sourceHeight;
destination.x = destX;
destination.y = destY;
destination.w = destWidth;
destination.h = destHeight;
- SDL_StretchSurfaceRect(getData().getSurface(), &source, where.getData().getSurface(), &destination);
+ // SDL_StretchSurfaceRect(getData().getSurface(), &source, where.getData().getSurface(), &destination);
+
+ SDL_Surface * src = getData().getSurface();
+ SDL_Surface * dst = where.getData().getSurface();
+
+ if (SDL_MUSTLOCK(src)){
+ SDL_LockSurface(src);
+ }
+
+ if (SDL_MUSTLOCK(dst)){
+ SDL_LockSurface(dst);
+ }
+
+ SDL_StretchSurfaceRect(src, &source, dst, &destination);
+
+ if (SDL_MUSTLOCK(src)){
+ SDL_UnlockSurface(src);
+ }
+
+ if (SDL_MUSTLOCK(dst)){
+ SDL_UnlockSurface(dst);
+ }
}
void Bitmap::save( const std::string & str ){
/* TODO */
}
void Bitmap::triangle( int x1, int y1, int x2, int y2, int x3, int y3, int color ) const {
/* TODO */
}
void Bitmap::ellipse( int x, int y, int rx, int ry, int color ) const {
/* TODO */
}
void Bitmap::ellipseFill( int x, int y, int rx, int ry, int color ) const {
/* TODO */
}
void Bitmap::light(int x, int y, int width, int height, int start_y, int focus_alpha, int edge_alpha, int focus_color, int edge_color) const {
/* TODO */
}
void Bitmap::applyTrans(const int color){
/* TODO */
}
void Bitmap::floodfill( const int x, const int y, const int color ) const {
/* TODO */
}
void Bitmap::horizontalLine( const int x1, const int y, const int x2, const int color ) const {
/* TODO */
}
void Bitmap::hLine( const int x1, const int y, const int x2, const int color ) const {
/* TODO */
}
void Bitmap::vLine( const int y1, const int x, const int y2, const int color ) const {
/* TODO */
}
void Bitmap::polygon( const int * verts, const int nverts, const int color ) const {
/* TODO */
}
void Bitmap::arc(const int x, const int y, const double ang1, const double ang2, const int radius, const int color ) const {
/* TODO */
// arcColor(getData().getSurface(), x, y,
}
void Bitmap::fill(int color) const {
SDL_Rect area;
area.x = 0;
area.y = 0;
area.w = getWidth();
area.h = getHeight();
SDL_FillRect(getData().getSurface(), &area, color);
}
int Bitmap::darken( int color, double factor ){
/* TODO */
return color;
}
Bitmap Bitmap::greyScale(){
/* TODO */
return *this;
}
void Bitmap::drawCharacter( const int x, const int y, const int color, const int background, const Bitmap & where ) const {
/* TODO */
}
void Bitmap::drawRotate( const int x, const int y, const int angle, const Bitmap & where ){
/* TODO */
}
void Bitmap::drawPivot( const int centerX, const int centerY, const int x, const int y, const int angle, const Bitmap & where ){
/* TODO */
}
void Bitmap::drawPivot( const int centerX, const int centerY, const int x, const int y, const int angle, const double scale, const Bitmap & where ){
/* TODO */
}
Bitmap Bitmap::memoryPCX(unsigned char * const data, const int length, const bool mask){
SDL_RWops * ops = SDL_RWFromConstMem(data, length);
SDL_Surface * pcx = IMG_LoadPCX_RW(ops);
SDL_FreeRW(ops);
Bitmap out(pcx, true);
SDL_FreeSurface(pcx);
return out;
}
int Bitmap::getPixel( const int x, const int y ) const {
/* TODO */
return 0;
}
void Bitmap::readLine( std::vector< int > & vec, int y ){
/* TODO */
}
void Bitmap::StretchBy2( const Bitmap & where ){
/* TODO */
}
void Bitmap::StretchBy4( const Bitmap & where ){
/* TODO */
}
void LitBitmap::draw( const int x, const int y, const Bitmap & where ) const {
/* TODO */
}
void LitBitmap::drawHFlip( const int x, const int y, const Bitmap & where ) const {
/* TODO */
}
void LitBitmap::drawVFlip( const int x, const int y, const Bitmap & where ) const {
/* TODO */
}
void LitBitmap::drawHVFlip( const int x, const int y, const Bitmap & where ) const {
/* TODO */
}
/*
#define PAINTOWN_DLS_BLENDER BLENDER_FUNC
#define PAINTOWN_DTS_BLENDER BLENDER_FUNC
#define PAINTOWN_MAKE_DLS_BLENDER(a) _blender_func16
#define PAINTOWN_MAKE_DTS_BLENDER() _blender_func16
#define PAINTOWN_PIXEL_PTR unsigned short*
#define PAINTOWN_OFFSET_PIXEL_PTR(p,x) ((PAINTOWN_PIXEL_PTR) (p) + (x))
#define PAINTOWN_INC_PIXEL_PTR(p) ((p)++)
#define PAINTOWN_INC_PIXEL_PTR_EX(p,d) ((p) += d)
#define PAINTOWN_GET_MEMORY_PIXEL(p) (*(p))
#define PAINTOWN_IS_SPRITE_MASK(b,c) ((unsigned long) (c) == (unsigned long) MASK_COLOR)
#define PAINTOWN_DLSX_BLEND(b,n) ((*(b))(_blender_col_16, (n), globalBlend.alpha))
#define PAINTOWN_GET_PIXEL(p) *((unsigned short *) (p))
#define PAINTOWN_DTS_BLEND(b,o,n) ((*(b))((n), (o), globalBlend.alpha))
#define PAINTOWN_PUT_PIXEL(p,c) (*((unsigned short *) p) = (c))
#define PAINTOWN_PUT_MEMORY_PIXEL(p,c) (*(p) = (c))
#define PAINTOWN_SET_ALPHA(a) (globalBlend.alpha = (a))
*/
static void paintown_draw_sprite_ex16(SDL_Surface * dst, SDL_Surface * src, int dx, int dy, int mode, int flip){
int x, y, w, h;
int x_dir = 1, y_dir = 1;
int dxbeg, dybeg;
int sxbeg, sybeg;
/*
PAINTOWN_DLS_BLENDER lit_blender;
PAINTOWN_DTS_BLENDER trans_blender;
*/
/*
ASSERT(dst);
ASSERT(src);
*/
if (SDL_MUSTLOCK(src)){
SDL_LockSurface(src);
}
if (SDL_MUSTLOCK(dst)){
SDL_LockSurface(dst);
}
if ( flip & Bitmap::SPRITE_V_FLIP ){
y_dir = -1;
}
if ( flip & Bitmap::SPRITE_H_FLIP ){
x_dir = -1;
}
if (true /* dst->clip*/ ) {
int tmp;
tmp = dst->clip_rect.x - dx;
sxbeg = ((tmp < 0) ? 0 : tmp);
dxbeg = sxbeg + dx;
tmp = dst->clip_rect.x + dst->clip_rect.w - dx;
w = ((tmp > src->w) ? src->w : tmp) - sxbeg;
if (w <= 0)
return;
if ( flip & Bitmap::SPRITE_H_FLIP ){
/* use backward drawing onto dst */
sxbeg = src->w - (sxbeg + w);
dxbeg += w - 1;
}
tmp = dst->clip_rect.y - dy;
sybeg = ((tmp < 0) ? 0 : tmp);
dybeg = sybeg + dy;
tmp = dst->clip_rect.y + dst->clip_rect.h - dy;
h = ((tmp > src->h) ? src->h : tmp) - sybeg;
if (h <= 0)
return;
if ( flip & Bitmap::SPRITE_V_FLIP ){
/* use backward drawing onto dst */
sybeg = src->h - (sybeg + h);
dybeg += h - 1;
}
} else {
w = src->w;
h = src->h;
sxbeg = 0;
sybeg = 0;
dxbeg = dx;
if ( flip & Bitmap::SPRITE_H_FLIP ){
dxbeg = dx + w - 1;
}
dybeg = dy;
if ( flip & Bitmap::SPRITE_V_FLIP ){
dybeg = dy + h - 1;
}
}
/*
lit_blender = PAINTOWN_MAKE_DLS_BLENDER(0);
trans_blender = PAINTOWN_MAKE_DTS_BLENDER();
*/
#if 0
if (dst->id & (BMP_ID_VIDEO | BMP_ID_SYSTEM)) {
bmp_select(dst);
switch (mode){
case Bitmap::SPRITE_NORMAL : {
for (y = 0; y < h; y++) {
PAINTOWN_PIXEL_PTR s = PAINTOWN_OFFSET_PIXEL_PTR(src->line[sybeg + y], sxbeg);
PAINTOWN_PIXEL_PTR d = PAINTOWN_OFFSET_PIXEL_PTR(bmp_write_line(dst, dybeg + y * y_dir), dxbeg);
for (x = w - 1; x >= 0; PAINTOWN_INC_PIXEL_PTR(s), PAINTOWN_INC_PIXEL_PTR_EX(d,x_dir), x--) {
unsigned long c = PAINTOWN_GET_MEMORY_PIXEL(s);
if (!PAINTOWN_IS_SPRITE_MASK(src, c)) {
PAINTOWN_PUT_PIXEL(d, c);
}
}
}
break;
}
case Bitmap::SPRITE_LIT : {
for (y = 0; y < h; y++) {
PAINTOWN_PIXEL_PTR s = PAINTOWN_OFFSET_PIXEL_PTR(src->line[sybeg + y], sxbeg);
PAINTOWN_PIXEL_PTR d = PAINTOWN_OFFSET_PIXEL_PTR(bmp_write_line(dst, dybeg + y * y_dir), dxbeg);
for (x = w - 1; x >= 0; PAINTOWN_INC_PIXEL_PTR(s), PAINTOWN_INC_PIXEL_PTR_EX(d,x_dir), x--) {
unsigned long c = PAINTOWN_GET_MEMORY_PIXEL(s);
if (!PAINTOWN_IS_SPRITE_MASK(src, c)) {
c = PAINTOWN_DLSX_BLEND(lit_blender, c);
PAINTOWN_PUT_PIXEL(d, c);
}
}
}
break;
}
case Bitmap::SPRITE_TRANS : {
for (y = 0; y < h; y++) {
PAINTOWN_PIXEL_PTR s = PAINTOWN_OFFSET_PIXEL_PTR(src->line[sybeg + y], sxbeg);
PAINTOWN_PIXEL_PTR d = PAINTOWN_OFFSET_PIXEL_PTR(bmp_write_line(dst, dybeg + y * y_dir), dxbeg);
for (x = w - 1; x >= 0; PAINTOWN_INC_PIXEL_PTR(s), PAINTOWN_INC_PIXEL_PTR_EX(d,x_dir), x--) {
unsigned long c = PAINTOWN_GET_MEMORY_PIXEL(s);
if (!PAINTOWN_IS_SPRITE_MASK(src, c)) {
c = PAINTOWN_DTS_BLEND(trans_blender, PAINTOWN_GET_PIXEL(d), c);
PAINTOWN_PUT_PIXEL(d, c);
}
}
}
break;
}
}
#xendif
for (y = 0; y < h; y++) {
PAINTOWN_PIXEL_PTR s = PAINTOWN_OFFSET_PIXEL_PTR(src->line[sybeg + y], sxbeg);
/* flipped if y_dir is -1 */
PAINTOWN_PIXEL_PTR d = PAINTOWN_OFFSET_PIXEL_PTR(bmp_write_line(dst, dybeg + y * y_dir), dxbeg);
/* d is incremented by x_dir, -1 if flipped */
for (x = w - 1; x >= 0; PAINTOWN_INC_PIXEL_PTR(s), PAINTOWN_INC_PIXEL_PTR_EX(d,x_dir), x--) {
unsigned long c = PAINTOWN_GET_MEMORY_PIXEL(s);
if (!PAINTOWN_IS_SPRITE_MASK(src, c)) {
switch( mode ){
case Bitmap::SPRITE_NORMAL : break;
case Bitmap::SPRITE_LIT : {
c = PAINTOWN_DLSX_BLEND(lit_blender, c);
break;
}
case Bitmap::SPRITE_TRANS : {
c = PAINTOWN_DTS_BLEND(trans_blender, PAINTOWN_GET_PIXEL(d), c);
break;
}
}
PAINTOWN_PUT_PIXEL(d, c);
}
}
}
bmp_unwrite_line(dst);
}
else {
#endif
{
switch (mode){
case Bitmap::SPRITE_NORMAL : {
unsigned int mask = Bitmap::makeColor(255, 0, 255);
int bpp = src->format->BytesPerPixel;
for (y = 0; y < h; y++) {
Uint8 * sourceLine = computeOffset(src, sxbeg, sybeg + y);
Uint8 * destLine = computeOffset(dst, dxbeg, dybeg + y * y_dir);
for (x = w - 1; x >= 0; sourceLine += bpp, destLine += bpp * x_dir, x--) {
unsigned long sourcePixel = *(Uint16*) sourceLine;
if (!(sourcePixel == mask)){
// unsigned int destPixel = *(Uint16*) destLine;
// sourcePixel = globalBlend.currentBlender(destPixel, sourcePixel, globalBlend.alpha);
*(Uint16 *)destLine = sourcePixel;
}
}
}
}
/*
case Bitmap::SPRITE_LIT : {
for (y = 0; y < h; y++) {
PAINTOWN_PIXEL_PTR s = PAINTOWN_OFFSET_PIXEL_PTR(src->line[sybeg + y], sxbeg);
PAINTOWN_PIXEL_PTR d = PAINTOWN_OFFSET_PIXEL_PTR(bmp_write_line(dst, dybeg + y * y_dir), dxbeg);
for (x = w - 1; x >= 0; PAINTOWN_INC_PIXEL_PTR(s), PAINTOWN_INC_PIXEL_PTR_EX(d,x_dir), x--) {
unsigned long c = PAINTOWN_GET_MEMORY_PIXEL(s);
if (!PAINTOWN_IS_SPRITE_MASK(src, c)) {
c = PAINTOWN_DLSX_BLEND(lit_blender, c);
PAINTOWN_PUT_MEMORY_PIXEL(d, c);
}
}
}
break;
}
*/
case Bitmap::SPRITE_TRANS : {
int bpp = src->format->BytesPerPixel;
unsigned int mask = Bitmap::makeColor(255, 0, 255);
for (y = 0; y < h; y++) {
Uint8 * sourceLine = computeOffset(src, sxbeg, sybeg + y);
Uint8 * destLine = computeOffset(dst, dxbeg, dybeg + y * y_dir);
for (x = w - 1; x >= 0; sourceLine += bpp, destLine += bpp * x_dir, x--) {
unsigned long sourcePixel = *(Uint16*) sourceLine;
if (!(sourcePixel == mask)){
unsigned int destPixel = *(Uint16*) destLine;
sourcePixel = globalBlend.currentBlender(destPixel, sourcePixel, globalBlend.alpha);
*(Uint16 *)destLine = sourcePixel;
}
}
}
break;
}
default : { break; }
}
#if 0
for (y = 0; y < h; y++) {
PAINTOWN_PIXEL_PTR s = PAINTOWN_OFFSET_PIXEL_PTR(src->line[sybeg + y], sxbeg);
PAINTOWN_PIXEL_PTR d = PAINTOWN_OFFSET_PIXEL_PTR(bmp_write_line(dst, dybeg + y * y_dir), dxbeg);
for (x = w - 1; x >= 0; PAINTOWN_INC_PIXEL_PTR(s), PAINTOWN_INC_PIXEL_PTR_EX(d,x_dir), x--) {
unsigned long c = PAINTOWN_GET_MEMORY_PIXEL(s);
if (!PAINTOWN_IS_SPRITE_MASK(src, c)) {
switch( mode ){
case Bitmap::SPRITE_NORMAL : break;
case Bitmap::SPRITE_LIT : {
c = PAINTOWN_DLSX_BLEND(lit_blender, c);
break;
}
case Bitmap::SPRITE_TRANS : {
c = PAINTOWN_DTS_BLEND(trans_blender, PAINTOWN_GET_PIXEL(d), c);
break;
}
}
PAINTOWN_PUT_MEMORY_PIXEL(d, c);
}
}
}
#endif
}
if (SDL_MUSTLOCK(src)){
SDL_UnlockSurface(src);
}
if (SDL_MUSTLOCK(dst)){
SDL_UnlockSurface(dst);
}
}
diff --git a/util/sdl/sprig/Change Log.txt b/util/sdl/sprig/Change Log.txt
new file mode 100644
index 00000000..20ab9ee2
--- /dev/null
+++ b/util/sdl/sprig/Change Log.txt
@@ -0,0 +1,84 @@
+11-27-09 v1.0.1
+Applied fix for SPG_PopThickness. Thanks to Laurent Desnogues!
+
+11-8-08 v1.0.0
+Changed SPG_Fader and SPG_AlphaFader to SPG_FadedPalette32 and SPG_FadedPalette32Alpha and to use Uint32 instead of RGB. Changed SPG_SetupRainbowPalette to SPG_RainbowPalette32 and SPG_SetupBWPalette to SPG_GrayPalette32. Replaced SPG_CopyPoints with SPG_BufferPoints. They duplicate functionality and I should encourage buffering rather than dynamic stuff. Added SPG_USE_FAST_MATH (used in SPG_rotation.c). Updated docs.
+
+11-6-08
+Added SPG_ColorPalette, SPG_GrayPalette, SPG_FindPaletteColor, and SPG_PalettizeSurface. Implemented SPG_CreateSurface8 and SPG_CreateSurface16. Changed surface creation function names a little. Changed 32-bit palette stuff to use SDL_PixelFormat.
+
+10-25-08
+Changed SPG_TransformSurface to SPG_TransformX. Added SPG_DirtyAddTo. Changed SPG_ConvertRGB to SPG_ConvertColor. Removed transform stack in favor of flags. Added SPG_BufferPoints. Added more PI. Added SPG_TSLOW, but it remains unimplemented. Renamed internal functions to follow a nice naming scheme. Added SPG_EnableRadians. Updated docs.
+
+9-29-08 Prerelease of v1.0.0
+Big, new release.
+
+9-27-08
+Added thick line primitives. The alpha and anti-aliased ones still need special handling. Fixed div-by-zero problems in Trigon and Quad fns.
+
+9-22-08
+Changed SPG_FadedLine to Uint32 instead of RGB... But this function is not exported. Finished implementing dirty rect API.
+
+9-21-08
+Added Dirty Rect API. There might be some tweaks to come. The primitives still need to output the dirty rects.
+
+9-17-08
+Added Get/Set color components.
+
+9-16-08
+Changed polygons to use SPG_Point and added polygon transform functions (rotate, scale, skew, translate). Added SPG_Point versions of all trigon fns and SPG_QuadTex.
+
+7-16-08
+Added SPG_REPLACE_COLORKEY blit mode and function SPG_ReplaceColorkey().
+
+7-13-08
+Put in a fix for the missing edge problem that SPG_TransformSurface has. This fix was reverted... I think accuracy is traded for speed.
+
+7-7-08 v0.941
+Fixed the pointy circle problem that affected circles and filled arcs. Defined SPG_bool as Uint8 since there's no difference in memory.
+
+7-6-08
+Combined C and C++ inlines, changed all source files to .c to reflect full compatibility. Changed some int parameters to SDL ints.
+
+7-5-08
+Fixed SPG_ArcFilledBlend and SPG_RectRoundFilledBlend. Changed variable names of SPG_Bezier to actually make sense. Changed MAX_ERRORS to SPG_MAX_ERRORS and moved to sprig.h. Changed SPG_GetLock to return an SPG_bool. Changed SPG_Error to push to the back of the stack (queue).
+
+6-18-08 v0.94
+Fixed SPG_ArcFn. Changed SPG_LineH (and _HLine) parameters from XXY to XYX. Changed headers to use lowercase file names. Added Pi variations to sprig.h. Large overhaul to build on GNU C.
+
+6-14-08
+Added SPG_extended.cpp to the project. This frees up the standard dll from having to hold less useful functions. Hacked SPG_CircleFilledBlendAA and SPG_EllipseFilledBlendAA. Added SPG_Point structure and SPG_MakePoint.
+
+5-30-08
+Added working version of SPG_FloodFill8. Hacked SPG_TrigonFilledAA and SPG_TrigonFilledBlendAA.
+
+4-25-08
+Added SPG_GetClip, SPG_RectAND, and SPG_RectOR. Fixed SPG_RestoreClip and SPG_SetClip.
+
+1-22-08
+Changed SPG_Blit to use a function pointer. Added SPG_SetBlit and SPG_GetBlit.
+
+1-21-08
+Changed blend states, AA states, surface alpha states, and errors over to very nice linked-list-based stacks. Added SPG_GetBlend, SPG_GetAA, and SPG_GetSurfaceAlpha.
+
+1-20-08
+Added SPG_Error, SPG_GetError, SPG_NumErrors, and SPG_DisplayFormat. Fixed SPG_AlphaFader. Added standard error calls, changed Polygon return values to void. Fixed triangles not drawing at certain angles.
+
+1-19-08
+Fixed SPG_TCOLORKEY stuff. Added colorkey to SPG_BlendBlit. Added SPG_ArcFn, SPG_Arc, SPG_ArcBlend, SPG_Polygon, SPG_PolygonBlend, SPG_RectRound, SPG_RectRoundBlend, SPG_RectRoundFilled, SPG_RectRoundFilledBlend (needs filled arc to work right).
+
+1-16-08 v0.93
+Fixed SPG_LineFadeFn, _AAmcLineAlpha (LineFadeAABlend), SPG_LineFadeBlend, _PolygonFadeAA, and SPG_PolygonFadeBlend.
+Added SPG_TCOLORKEY: Thanks to Dani Gonz�lez!
+
+1-14-08
+Removed SPG_LineFade (redundant) and renamed the LineMulti calls as LineFade.
+
+1-8-08 v0.92
+Added SPG_sqrt to replace slow sqrt calls. Changed all primitives over to state-based anti-aliasing.
+
+1-5-08 v0.91
+Fixed the rotate calls, but the SPG_TAA flag isn't working right.
+
+12-22-07
+Polygons can now be drawn with negative coordinates. Special thanks to Huge for this contribution!
\ No newline at end of file
diff --git a/util/sdl/sprig/Differences from SGE.txt b/util/sdl/sprig/Differences from SGE.txt
new file mode 100644
index 00000000..16f5dd04
--- /dev/null
+++ b/util/sdl/sprig/Differences from SGE.txt
@@ -0,0 +1,31 @@
+Up-to-date (i.e. fewer bugs)!
+
+Pure C: A single library for both C and C++. Extra features of C++ are used only in inlined functions. SGE doesn't compile for C without a lot of work.
+
+Implemented strangely missing features (like SPG_Polygon)
+
+Thick primitives
+
+Arc functions
+
+Polygon transforms
+
+Rounded rectangle functions
+
+Functions work with Uint32 color values. If you want a Uint8 RGB version you'll have to write it yourself; I won't force twice as many functions on everyone.
+
+Convenience functions (Like SPG_MakeRect)
+
+Other cool functions (SPG_ReplaceColorkey)
+
+Anti-aliasing moved into stack instead of so many extra functions
+
+Naming conventions - Less typing, better auto-completion compatibility
+
+Smaller dll: Uses 4/10 SGE modules
+ - no shape classes
+ - no collision detection
+ - no bitmap text
+ - no truetype text
+ - no text classes
+ - no randomizing or delay
diff --git a/util/sdl/sprig/Known Problems.txt b/util/sdl/sprig/Known Problems.txt
new file mode 100644
index 00000000..454d0248
--- /dev/null
+++ b/util/sdl/sprig/Known Problems.txt
@@ -0,0 +1,8 @@
+Gouraud shading is horizontally-biased.
+Alpha-blended beziers overdraw pixels.
+Alpha-blending and anti-aliasing need special treatment in thick primitives.
+
+Not yet implemented:
+SPG_TSLOW
+SPG_TBLEND
+SPG_TSURFACE_ALPHA
\ No newline at end of file
diff --git a/util/sdl/sprig/Makefile b/util/sdl/sprig/Makefile
new file mode 100644
index 00000000..14c6a79d
--- /dev/null
+++ b/util/sdl/sprig/Makefile
@@ -0,0 +1,55 @@
+# Makefile for the SPriG library
+
+include Makefile.conf
+
+CFLAGS += $(SPRIG_CFLAGS) -fPIC
+LIBS = $(SPRIG_LIBS)
+
+SPRIG_VER = 1
+SPRIG_VER_MINOR = 0
+SPRIG_VER_BUGFIX = 1
+
+OBJECTS=SPG_surface.o SPG_primitives.o SPG_polygon.o SPG_rotation.o SPG_misc.o
+
+all: config $(OBJECTS)
+ @ar rsc libsprig.a $(OBJECTS)
+
+$(OBJECTS): %.o:%.c #Each object depends on its .cpp and .h file
+ $(CXX) $(CFLAGS) -c $<
+
+shared: all
+ $(CXX) $(CFLAGS) -Wl,-soname,libsprig.so.$(SPRIG_VER) -fpic -fPIC -shared -o libsprig.so $(OBJECTS) $(LIBS)
+
+shared-strip: shared
+ @strip libsprig.so
+
+# Building a dll... I have no idea how to do this, but it should be something like below.
+dll: config $(OBJECTS)
+ dlltool --output-def sprig.def $(OBJECTS)
+ dllwrap --driver-name $(CXX) -o sprig.dll --def sprig.def --output-lib libsprig.a --dllname sprig.dll $(OBJECTS) $(LIBS)
+
+dll-strip: dll
+ @strip sprig.dll
+
+clean:
+ @rm -f *.o *.so *.a *.dll *.def
+
+config:
+
+ifneq ($(QUIET),y)
+ @echo "== SPriG v$(SPRIG_VER).$(SPRIG_VER_MINOR).$(SPRIG_VER_BUGFIX)"
+endif
+
+install: shared
+ @mkdir -p $(PREFIX_H)
+ install -c -m 644 sprig.h $(PREFIX_H)
+ install -c -m 644 sprig_inline.h $(PREFIX_H)
+ @mkdir -p $(PREFIX)/lib
+ install -c -m 644 libsprig.a $(PREFIX)/lib
+ install -c libsprig.so $(PREFIX)/lib/libsprig.so.$(SPRIG_VER).$(SPRIG_VER_MINOR).$(SPRIG_VER_BUGFIX)
+ @cd $(PREFIX)/lib;\
+ ln -sf libsprig.so.$(SPRIG_VER).$(SPRIG_VER_MINOR).$(SPRIG_VER_BUGFIX) libsprig.so.$(SPRIG_VER);\
+ ln -sf libsprig.so.$(SPRIG_VER) libsprig.so;
+ @echo
+ @echo "** Headerfiles installed in $(PREFIX_H)"
+ @echo "** Library files installed in $(PREFIX)/lib"
diff --git a/util/sdl/sprig/Makefile.conf b/util/sdl/sprig/Makefile.conf
new file mode 100644
index 00000000..ef006aa6
--- /dev/null
+++ b/util/sdl/sprig/Makefile.conf
@@ -0,0 +1,35 @@
+# Configure Makefile for the SPriG library
+
+# Comment/uncomment the following line to disable/enable build options
+# (See README for more info)
+C_COMP = y
+#QUIET = y
+
+
+# Compilers (C and C++)
+CC=gcc
+CXX=g++
+
+# Make sure sdl-config is available
+HAVE_SDL =$(shell if (sdl-config --version) < /dev/null > /dev/null 2>&1; then echo "y"; else echo "n"; fi;)
+ifeq ($(HAVE_SDL),n)
+ $(error ERROR: Can't find SDL! Make sure that you have SDL [ http://www.libsdl.org/ ] and its development files installed)
+endif
+
+# Where should SPriG be installed?
+PREFIX =$(shell sdl-config --prefix)
+
+# Where should the headerfiles be installed?
+PREFIX_H =$(shell sdl-config --prefix)/include/SDL
+
+# Flags passed to the compiler
+CFLAGS =-Wall -O3 -ffast-math -s
+SPRIG_CFLAGS =$(shell sdl-config --cflags)
+# Uncomment to make some more optimizations
+#CFLAGS =-Wall -O9 -ffast-math -march=i686
+
+
+# Libs config
+SPRIG_LIBS =$(shell sdl-config --libs) -lstdc++
+
+
diff --git a/util/sdl/sprig/SPG_extended.c b/util/sdl/sprig/SPG_extended.c
new file mode 100644
index 00000000..37469568
--- /dev/null
+++ b/util/sdl/sprig/SPG_extended.c
@@ -0,0 +1,120 @@
+/*
+ SPriG - SDL Primitive Generator
+ by Jonathan Dearborn
+
+ Based on SGE: SDL Graphics Extension r030809
+ by Anders Lindström
+*/
+
+
+/*********************************************************************
+ * 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. *
+ *********************************************************************/
+
+
+#include "sprig.h"
+#ifdef SPG_USE_EXTENDED
+
+
+//the stack - This is huge, but it seems that only the
+//actual used space is counted against my memory footprint.
+// Probably compiler-dependent... (shows how much I know)
+#define stackSize 16777216
+Sint16 stack8x[stackSize];
+Sint16 stack8y[stackSize];
+Sint32 stackPointer = -1;
+
+bool pop(SDL_Surface* dest, Sint16 &x, Sint16 &y)
+{
+ if(stackPointer >= 0)
+ {
+ x = stack8x[stackPointer];
+ y = stack8y[stackPointer];
+ stackPointer--;
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+bool push(SDL_Surface* dest, Sint16 x, Sint16 y)
+{
+ if(stackPointer < stackSize - 1)
+ {
+ stackPointer++;
+ stack8x[stackPointer] = x;
+ stack8y[stackPointer] = y;
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+void emptyStack(SDL_Surface* dest)
+{
+ Sint16 x, y;
+ while(pop(dest, x, y));
+}
+
+
+// From http://student.kuleuven.be/~m0216922/CG/floodfill.html
+//8-way floodfill using our own stack routines
+void SPG_FloodFill8(SDL_Surface* dest, Sint16 x, Sint16 y, Uint32 newColor)
+{
+ Uint32 oldColor = SPG_GetPixel(dest, x, y);
+ if(newColor == oldColor)
+ return; //avoid infinite loop
+
+ stackPointer = -1;
+
+ if(!push(dest, x, y))
+ return;
+
+ while(pop(dest, x, y))
+ {
+ SPG_Pixel(dest, x, y, newColor);
+
+ if(x + 1 < dest->w && SPG_GetPixel(dest, x+1, y) == oldColor)
+ {
+ if(!push(dest, x + 1, y)) return;
+ }
+ if(x - 1 >= 0 && SPG_GetPixel(dest, x-1, y) == oldColor)
+ {
+ if(!push(dest, x - 1, y)) return;
+ }
+ if(y + 1 < dest->h && SPG_GetPixel(dest, x, y+1) == oldColor)
+ {
+ if(!push(dest, x, y + 1)) return;
+ }
+ if(y - 1 >= 0 && SPG_GetPixel(dest, x, y-1) == oldColor)
+ {
+ if(!push(dest, x, y - 1)) return;
+ }
+ if(x + 1 < dest->w && y + 1 < dest->h && SPG_GetPixel(dest, x+1, y+1) == oldColor)
+ {
+ if(!push(dest, x + 1, y + 1)) return;
+ }
+ if(x + 1 < dest->w && y - 1 >= 0 && SPG_GetPixel(dest, x+1, y-1) == oldColor)
+ {
+ if(!push(dest, x + 1, y - 1)) return;
+ }
+ if(x - 1 >= 0 && y + 1 < dest->h && SPG_GetPixel(dest, x-1, y+1) == oldColor)
+ {
+ if(!push(dest, x - 1, y + 1)) return;
+ }
+ if(x - 1 >= 0 && y - 1 >= 0 && SPG_GetPixel(dest, x-1, y-1) == oldColor)
+ {
+ if(!push(dest, x - 1, y - 1)) return;
+ }
+ }
+}
+
+
+#endif
diff --git a/util/sdl/sprig/SPG_misc.c b/util/sdl/sprig/SPG_misc.c
new file mode 100644
index 00000000..8492b1c6
--- /dev/null
+++ b/util/sdl/sprig/SPG_misc.c
@@ -0,0 +1,351 @@
+/*
+ SPriG - SDL Primitive Generator
+ by Jonathan Dearborn
+
+ Based on SGE: SDL Graphics Extension r030809
+ by Anders Lindström
+*/
+
+
+/*********************************************************************
+ * 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. *
+ *********************************************************************/
+
+
+#include "sprig.h"
+
+// Degrees here for nicer-looking tests
+SPG_bool spg_usedegrees = 1;
+
+void SPG_EnableRadians(SPG_bool enable)
+{
+ spg_usedegrees = !enable;
+}
+
+SPG_bool SPG_GetRadians()
+{
+ return !spg_usedegrees;
+}
+
+
+/*
+Dirty rect handling
+Adapted from Fixed Rate Pig by David Olofson
+*/
+
+SPG_bool spg_makedirtyrects = 0;
+
+// These two variables are exposed so that changes in the implementation
+// don't officially break compatibility, but control is still there.
+
+/* Approximate worth of one dirtyrect in pixels. */
+int spg_dirty_worst_merge = 300;
+
+/*
+ * If the merged result gets at most this many percent
+ * bigger than the larger of the two input rects,
+ * accept it as Perfect.
+ */
+int spg_dirty_instant_merge = 10;
+
+SPG_DirtyTable* spg_dirtytable_front = NULL;
+SPG_DirtyTable* spg_dirtytable_back = NULL;
+
+SDL_Surface* SPG_InitSDL(Uint16 w, Uint16 h, Uint8 bitsperpixel, Uint32 systemFlags, Uint32 screenFlags)
+{
+
+ if ( SDL_Init(systemFlags) < 0 )
+ {
+ printf("Couldn't initialize SDL: %s\n", SDL_GetError());
+ return NULL;
+ }
+
+ SDL_Surface* screen = SDL_SetVideoMode(w, h, bitsperpixel, screenFlags);
+
+ if ( screen == NULL )
+ {
+ printf("Couldn't set video mode %dx%d: %s\n", w, h, SDL_GetError());
+ return NULL;
+ }
+
+ return screen;
+}
+
+// Reset the tables to the new size
+void SPG_DirtyInit(Uint16 maxsize)
+{
+ if(spg_dirtytable_front != NULL)
+ SPG_DirtyFree(spg_dirtytable_front);
+ if(spg_dirtytable_back != NULL)
+ SPG_DirtyFree(spg_dirtytable_back);
+ if(maxsize > 0)
+ {
+ // This could be protected better from out-of-memory errors.
+ spg_dirtytable_front = SPG_DirtyMake(maxsize);
+ spg_dirtytable_back = SPG_DirtyMake(maxsize);
+ }
+ else
+ {
+ spg_dirtytable_front = NULL;
+ spg_dirtytable_back = NULL;
+ }
+}
+
+void SPG_EnableDirty(SPG_bool enable)
+{
+ spg_makedirtyrects = enable;
+}
+
+SPG_bool SPG_DirtyEnabled()
+{
+ return spg_makedirtyrects;
+}
+
+void SPG_DirtyClip(SDL_Surface* screen, SDL_Rect* rect)
+{
+ if(screen == NULL || rect == NULL)
+ return;
+
+ if(rect->x < 0)
+ {
+ if(rect->w + rect->x > 0)
+ rect->w += rect->x;
+ else
+ rect->w = 0;
+ rect->x = 0;
+ }
+ if(rect->x >= screen->w)
+ {
+ rect->x = 0;
+ rect->w = 0;
+ }
+ else if(rect->x + rect->w >= screen->w)
+ rect->w = screen->w - rect->x;
+
+ if(rect->y < 0)
+ {
+ if(rect->h + rect->y > 0)
+ rect->h += rect->y;
+ else
+ rect->h = 0;
+ rect->y = 0;
+ }
+ else if(rect->y >= screen->h)
+ {
+ rect->y = 0;
+ rect->h = 0;
+ }
+ else if(rect->y + rect->h >= screen->h)
+ rect->h = screen->h - rect->y;
+}
+
+void SPG_DirtyLevel(Uint16 optimizationLevel)
+{
+ if(optimizationLevel > 0)
+ spg_dirty_worst_merge = optimizationLevel;
+}
+
+// Unsafe for general use. Use SPG_RectOR
+void SPG_RectUnion(SDL_Rect *from, SDL_Rect *to)
+{
+ int x1 = from->x;
+ int y1 = from->y;
+ int x2 = from->x + from->w;
+ int y2 = from->y + from->h;
+ if(to->x < x1)
+ x1 = to->x;
+ if(to->y < y1)
+ y1 = to->y;
+ if(to->x + to->w > x2)
+ x2 = to->x + to->w;
+ if(to->y + to->h > y2)
+ y2 = to->y + to->h;
+ to->x = x1;
+ to->y = y1;
+ to->w = x2 - x1;
+ to->h = y2 - y1;
+}
+
+// Unsafe for general use. Use SPG_RectAND
+void SPG_RectIntersect(SDL_Rect *from, SDL_Rect *to)
+{
+ int Amin, Amax, Bmin, Bmax;
+ Amin = to->x;
+ Amax = Amin + to->w;
+ Bmin = from->x;
+ Bmax = Bmin + from->w;
+ if(Bmin > Amin)
+ Amin = Bmin;
+ to->x = Amin;
+ if(Bmax < Amax)
+ Amax = Bmax;
+ to->w = Amax - Amin > 0 ? Amax - Amin : 0;
+
+ Amin = to->y;
+ Amax = Amin + to->h;
+ Bmin = from->y;
+ Bmax = Bmin + from->h;
+ if(Bmin > Amin)
+ Amin = Bmin;
+ to->y = Amin;
+ if(Bmax < Amax)
+ Amax = Bmax;
+ to->h = Amax - Amin > 0 ? Amax - Amin : 0;
+}
+
+void SPG_DirtyAdd(SDL_Rect* rect)
+{
+ SPG_DirtyAddTo(spg_dirtytable_front, rect);
+}
+
+void SPG_DirtyAddTo(SPG_DirtyTable* table, SDL_Rect* rect)
+{
+ int i, j, best_i, best_loss;
+
+ if(table == NULL)
+ return;
+ if(rect->w == 0 || rect->h == 0)
+ return;
+ /*
+ * Look for merger candidates.
+ *
+ * We start right before the best match we
+ * had the last time around. This can give
+ * us large numbers of direct or quick hits
+ * when dealing with old/new rects for moving
+ * objects and the like.
+ */
+ best_i = -1;
+ best_loss = 100000000;
+ if(table->count)
+ i = (table->best + table->count - 1) % table->count;
+ for(j = 0; j < table->count; ++j)
+ {
+ int a1, a2, am, ratio, loss;
+ SDL_Rect testr;
+
+ a1 = rect->w * rect->h;
+
+ testr = table->rects[i];
+ a2 = testr.w * testr.h;
+
+ SPG_RectUnion(rect, &testr);
+ am = testr.w * testr.h;
+
+ //printf("a1,a2,am: %d, %d, %d", a1, a2, am);
+
+ /* Perfect or Instant Pick? */
+ ratio = 100 * am / (a1 > a2 ? a1 : a2);
+ if(ratio < spg_dirty_instant_merge)
+ {
+ /* Ok, this is good enough! Stop searching. */
+ SPG_RectUnion(rect, &table->rects[i]);
+ table->best = i;
+ return;
+ }
+
+ loss = am - a1 - a2;
+ if(loss < best_loss)
+ {
+ best_i = i;
+ best_loss = loss;
+ table->best = i;
+ }
+
+ ++i;
+ i %= table->count;
+ }
+ /* ...and if the best result is good enough, merge! */
+ if((best_i >= 0) && (best_loss < spg_dirty_worst_merge))
+ {
+ SPG_RectUnion(rect, &table->rects[best_i]);
+ return;
+ }
+
+ /* Try to add to table... */
+ if(table->count < table->size)
+ {
+ table->rects[table->count++] = *rect;
+ return;
+ }
+
+ /* Emergency: Table full! Grab best candidate... */
+ SPG_RectUnion(rect, &table->rects[best_i]);
+}
+
+SPG_DirtyTable* SPG_DirtyGet()
+{
+ return spg_dirtytable_front;
+}
+
+void SPG_DirtyClear(SPG_DirtyTable* table)
+{
+ if(table == NULL)
+ return;
+ table->count = 0;
+ table->best = 0;
+}
+
+void SPG_DirtyFree(SPG_DirtyTable* table)
+{
+ if(table == NULL)
+ return;
+ free(table->rects);
+ free(table);
+}
+
+SPG_DirtyTable* SPG_DirtyMake(Uint16 maxsize)
+{
+ SPG_DirtyTable* table = (SPG_DirtyTable *)malloc(sizeof(SPG_DirtyTable));
+ if(table == NULL)
+ return NULL;
+
+ table->size = maxsize;
+ table->rects = (SDL_Rect *)calloc(maxsize, sizeof(SDL_Rect));
+ if(table->rects == NULL)
+ {
+ free(table);
+ return NULL;
+ }
+
+ table->count = 0;
+ table->best = 0;
+ return table;
+}
+
+SPG_DirtyTable* SPG_DirtyUpdate(SDL_Surface* screen)
+{
+ if(spg_dirtytable_front != NULL && spg_dirtytable_back != NULL)
+ {
+ // Add all of the front table's rects to the back table.
+ int i;
+ for(i = 0; i < spg_dirtytable_front->count; ++i)
+ SPG_DirtyAddTo(spg_dirtytable_back, spg_dirtytable_front->rects + i); // pointer arithmetic
+
+ // Use back table for updating the screen
+ SDL_UpdateRects(screen, spg_dirtytable_back->count, spg_dirtytable_back->rects);
+ // User should now use this table to replace backgrounds.
+ // For that, we'll return the back table to the user.
+ // He'd better not free this table! I'll be mad!
+ return spg_dirtytable_back;
+ }
+ return NULL; // User can test and choose to update entire screen or whatever
+}
+
+void SPG_DirtySwap()
+{
+ if(spg_dirtytable_front != NULL && spg_dirtytable_back != NULL)
+ {
+ // Clear back table
+ spg_dirtytable_back->count = 0;
+ spg_dirtytable_back->best = 0;
+ // Swap tables (clean one up front, old one in back; The old list
+ // will be merged so we can update where stuff used to be)
+ SPG_DirtyTable* temp = spg_dirtytable_front;
+ spg_dirtytable_front = spg_dirtytable_back;
+ spg_dirtytable_back = temp;
+ }
+}
diff --git a/util/sdl/sprig/SPG_polygon.c b/util/sdl/sprig/SPG_polygon.c
new file mode 100644
index 00000000..723e0854
--- /dev/null
+++ b/util/sdl/sprig/SPG_polygon.c
@@ -0,0 +1,2596 @@
+/*
+ SPriG - SDL Primitive Generator
+ by Jonathan Dearborn
+
+ Based on SGE: SDL Graphics Extension r030809
+ by Anders Lindström
+*/
+
+
+/*********************************************************************
+ * 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. *
+ *********************************************************************/
+
+
+#include "sprig.h"
+#include "sprig_common.h"
+
+#include "math.h"
+
+/* Globals */
+extern Uint8 spg_alphahack;
+extern SPG_bool spg_useerrors;
+extern SPG_bool spg_makedirtyrects;
+extern SPG_DirtyTable* spg_dirtytable_front;
+extern Uint16 spg_thickness;
+extern SPG_bool spg_usedegrees;
+
+/* We need some internal functions */
+void spg_pixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color);
+void spg_pixelcallbackalpha(SDL_Surface *surf, Sint16 x, Sint16 y, Uint32 color);
+void spg_line(SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color);
+void spg_lineblend(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 Color, Uint8 alpha);
+void spg_lineh(SDL_Surface *Surface, Sint16 x1, Sint16 y, Sint16 x2, Uint32 Color);
+void spg_linehblend(SDL_Surface *Surface, Sint16 x1, Sint16 y, Sint16 x2, Uint32 Color, Uint8 alpha);
+void spg_lineblendaa(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha);
+void spg_linefadeblendaa(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color1, Uint8 alpha1, Uint32 color2, Uint8 alpha2);
+
+void spg_thicknesscallback(SDL_Surface *Surf, Sint16 X, Sint16 Y, Uint32 Color);
+void spg_thicknesscallbackalpha(SDL_Surface *Surf, Sint16 X, Sint16 Y, Uint32 Color);
+
+
+/* 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
+
+// Arbitrary sorting start position for drawing polygons.
+// This enables negative coords for polys. Thanks, Huge!
+#define NULL_POSITION (-0x7ffe)
+
+
+//==================================================================================
+// Draws a horizontal line, fading the colors
+//==================================================================================
+void spg_linehfade(SDL_Surface *dest,Sint16 x1,Sint16 y,Sint16 x2,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<SPG_CLIP_XMIN(dest) || x1>SPG_CLIP_XMAX(dest) || y<SPG_CLIP_YMIN(dest) || y>SPG_CLIP_YMAX(dest))
+ return;
+ if (x1 < SPG_CLIP_XMIN(dest)){
+ /* Update start colors */
+ R += (SPG_CLIP_XMIN(dest)-x1)*rstep;
+ G += (SPG_CLIP_XMIN(dest)-x1)*gstep;
+ B += (SPG_CLIP_XMIN(dest)-x1)*bstep;
+ x1 = SPG_CLIP_XMIN(dest);
+ }
+ if (x2 > SPG_CLIP_XMAX(dest))
+ x2 = SPG_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 SPG_LineHFade(SDL_Surface *dest,Sint16 x1,Sint16 y,Sint16 x2,Uint32 color1, Uint32 color2)
+{
+ if ( spg_lock(dest) < 0 )
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_LineHFade could not lock surface");
+ return;
+ }
+
+ if(spg_thickness == 1)
+ {
+ Uint8 r1, g1, b1, r2, g2, b2;
+ SDL_GetRGB(color1, dest->format, &r1, &g1, &b1);
+ SDL_GetRGB(color2, dest->format, &r2, &g2, &b2);
+ spg_linehfade(dest,x1,y,x2,r1,g1,b1,r2,g2,b2);
+
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = MIN(x1, x2);
+ rect.y = y;
+ rect.w = MAX(x1, x2) - rect.x + 1;
+ rect.h = 1;
+ // Clip it to the screen
+ SPG_DirtyClip(dest, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+ else if(spg_thickness > 0)
+ SPG_LineFade(dest, x1, y, x2, y, color1, color2);
+
+ spg_unlock(dest);
+
+}
+
+
+//==================================================================================
+// Draws a horizontal, textured line
+//==================================================================================
+void spg_linehtex(SDL_Surface *dest,Sint16 x1,Sint16 y,Sint16 x2,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<SPG_CLIP_XMIN(dest) || x1>SPG_CLIP_XMAX(dest) || y<SPG_CLIP_YMIN(dest) || y>SPG_CLIP_YMAX(dest))
+ return;
+ if (x1 < SPG_CLIP_XMIN(dest)){
+ /* Fix texture starting coord */
+ srcx += (SPG_CLIP_XMIN(dest)-x1)*xstep;
+ srcy += (SPG_CLIP_XMIN(dest)-x1)*ystep;
+ x1 = SPG_CLIP_XMIN(dest);
+ }
+ if (x2 > SPG_CLIP_XMAX(dest))
+ x2 = SPG_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(SPG_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(SPG_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(SPG_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(SPG_GetPixel(source, srcx>>16, srcy>>16), source->format, &r, &g, &b);
+ *pixel = MapRGB( dest->format, r, g, b );
+
+ srcx += xstep;
+ srcy += ystep;
+ }
+ }
+ break;
+ }
+ }
+}
+
+void SPG_LineHTex(SDL_Surface *dest,Sint16 x1,Sint16 y,Sint16 x2,SDL_Surface *source,Sint16 sx1,Sint16 sy1,Sint16 sx2,Sint16 sy2)
+{
+ if ( spg_lock(dest) < 0 )
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_LineHTex could not lock dest surface");
+ return;
+ }
+ if ( spg_lock(source) < 0 )
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_LineHTex could not lock source surface");
+ return;
+ }
+
+ spg_linehtex(dest,x1,y,x2,source,sx1,sy1,sx2,sy2);
+
+ spg_unlock(dest);
+ spg_unlock(source);
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = MIN(x1, x2);
+ rect.y = y;
+ rect.w = MAX(x1, x2) - rect.x + 1;
+ rect.h = 1;
+ // Clip it to the screen
+ SPG_DirtyClip(dest, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+
+}
+
+//==================================================================================
+// Draws a trigon
+//==================================================================================
+void SPG_Trigon(SDL_Surface *dest,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color)
+{
+ if ( spg_lock(dest) < 0 )
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_Trigon could not lock surface");
+ return;
+ }
+
+ if(spg_thickness == 1)
+ {
+ if(SPG_GetAA())
+ {
+ spg_lineblendaa(dest,x1,y1,x2,y2,color, SDL_ALPHA_OPAQUE);
+ spg_lineblendaa(dest,x1,y1,x3,y3,color, SDL_ALPHA_OPAQUE);
+ spg_lineblendaa(dest,x3,y3,x2,y2,color, SDL_ALPHA_OPAQUE);
+ }
+ else
+ {
+ spg_line(dest,x1,y1,x2,y2,color);
+ spg_line(dest,x1,y1,x3,y3,color);
+ spg_line(dest,x3,y3,x2,y2,color);
+ }
+
+ if(spg_makedirtyrects)
+ {
+ 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;
+
+ SDL_Rect rect;
+ rect.x = xmin;
+ rect.y = ymin;
+ rect.w = xmax-xmin + 1;
+ rect.h = ymax-ymin + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(dest, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+ else if(spg_thickness > 0)
+ {
+ SPG_LineFn(dest,x1,y1,x2,y2,color, spg_thicknesscallback);
+ SPG_LineFn(dest,x1,y1,x3,y3,color, spg_thicknesscallback);
+ SPG_LineFn(dest,x3,y3,x2,y2,color, spg_thicknesscallback);
+
+ if(spg_makedirtyrects)
+ {
+ 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;
+
+ SDL_Rect rect;
+ rect.x = xmin - spg_thickness/2;
+ rect.y = ymin - spg_thickness/2;
+ rect.w = xmax-xmin + 1 + spg_thickness;
+ rect.h = ymax-ymin + 1 + spg_thickness;
+ // Clip it to the screen
+ SPG_DirtyClip(dest, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+
+ spg_unlock(dest);
+
+}
+
+
+
+//==================================================================================
+// Draws a trigon (alpha)
+//==================================================================================
+void SPG_TrigonBlend(SDL_Surface *dest,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color, Uint8 alpha)
+{
+ if ( spg_lock(dest) < 0 )
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_TrigonBlend could not lock surface");
+ return;
+ }
+
+ if(spg_thickness == 1)
+ {
+ if(SPG_GetAA())
+ {
+ spg_lineblendaa(dest,x1,y1,x2,y2,color, alpha);
+ spg_lineblendaa(dest,x1,y1,x3,y3,color, alpha);
+ spg_lineblendaa(dest,x3,y3,x2,y2,color, alpha);
+ }
+ else
+ {
+ spg_lineblend(dest,x1,y1,x2,y2,color, alpha);
+ spg_lineblend(dest,x1,y1,x3,y3,color, alpha);
+ spg_lineblend(dest,x3,y3,x2,y2,color, alpha);
+ }
+
+ if(spg_makedirtyrects)
+ {
+ 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;
+
+ SDL_Rect rect;
+ rect.x = xmin;
+ rect.y = ymin;
+ rect.w = xmax-xmin + 1;
+ rect.h = ymax-ymin + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(dest, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+ else if(spg_thickness > 0)
+ {
+ spg_alphahack = alpha;
+ SPG_LineFn(dest,x1,y1,x2,y2,color, spg_thicknesscallbackalpha);
+ SPG_LineFn(dest,x1,y1,x3,y3,color, spg_thicknesscallbackalpha);
+ SPG_LineFn(dest,x3,y3,x2,y2,color, spg_thicknesscallbackalpha);
+
+ if(spg_makedirtyrects)
+ {
+ 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;
+
+ SDL_Rect rect;
+ rect.x = xmin - spg_thickness/2;
+ rect.y = ymin - spg_thickness/2;
+ rect.w = xmax-xmin + 1 + spg_thickness;
+ rect.h = ymax-ymin + 1 + spg_thickness;
+ // Clip it to the screen
+ SPG_DirtyClip(dest, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+
+ spg_unlock(dest);
+
+}
+
+
+
+//==================================================================================
+// Draws a filled trigon
+//==================================================================================
+void SPG_TrigonFilled(SDL_Surface *dest,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color)
+{
+ Sint16 y;
+
+
+ // AA hack
+ if(SPG_GetAA())
+ {
+ // Rough guess at center
+ float cx = (x1 + x2 + x3)/3.0f,
+ cy = (y1 + y2 + y3)/3.0f;
+
+ // Draw AA lines
+ spg_lineblendaa(dest,x1,y1,x2,y2,color, SDL_ALPHA_OPAQUE);
+ spg_lineblendaa(dest,x2,y2,x3,y3,color, SDL_ALPHA_OPAQUE);
+ spg_lineblendaa(dest,x3,y3,x1,y1,color, SDL_ALPHA_OPAQUE);
+
+ // Push in all points by one
+ cx > x1? x1++ : x1--;
+ cx > x2? x2++ : x2--;
+ cx > x3? x3++ : x3--;
+ cy > y1? y1++ : y1--;
+ cy > y2? y2++ : y2--;
+ cy > y3? y3++ : y3--;
+ }
+
+ //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 = (y3 != y1)? (Sint32)((x3 - x1)<<16)/(Sint32)(y3 - y1) : 400000; // That oughta be enough?
+ Sint32 m3 = 0;
+
+
+ /* Upper half of the triangle */
+ if( y1==y2 )
+ spg_lineh(dest, x1, y1, x2, color);
+ else{
+ m1 = (Sint32)((x2 - x1)<<16)/(Sint32)(y2 - y1);
+
+ for ( y = y1; y <= y2; y++) {
+ spg_lineh(dest, xa>>16, y, xb>>16, color);
+
+ xa += m1;
+ xb += m2;
+ }
+ }
+
+ /* Lower half of the triangle */
+ if( y2==y3 )
+ spg_lineh(dest, x2, y2, x3, color);
+ else{
+ m3 = (Sint32)((x3 - x2)<<16)/(Sint32)(y3 - y2);
+
+ for ( y = y2+1; y <= y3; y++) {
+ spg_lineh(dest, xb>>16, y, xc>>16, color);
+
+ xb += m2;
+ xc += m3;
+ }
+ }
+ if(spg_makedirtyrects)
+ {
+ 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;
+
+ SDL_Rect rect;
+ rect.x = xmin;
+ rect.y = ymin;
+ rect.w = xmax-xmin + 1;
+ rect.h = ymax-ymin + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(dest, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+
+
+}
+
+
+
+//==================================================================================
+// Draws a filled trigon (alpha)
+//==================================================================================
+void SPG_TrigonFilledBlend(SDL_Surface *dest,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color, Uint8 alpha)
+{
+ Sint16 y;
+
+
+ // AA hack
+ if(SPG_GetAA())
+ {
+ // Rough guess at center
+ float cx = (x1 + x2 + x3)/3.0f,
+ cy = (y1 + y2 + y3)/3.0f;
+
+ // Draw AA lines
+ spg_lineblendaa(dest,x1,y1,x2,y2,color, alpha);
+ spg_lineblendaa(dest,x2,y2,x3,y3,color, alpha);
+ spg_lineblendaa(dest,x3,y3,x1,y1,color, alpha);
+
+ // Push in all points by one
+ cx > x1? x1++ : x1--;
+ cx > x2? x2++ : x2--;
+ cx > x3? x3++ : x3--;
+ cy > y1? y1++ : y1--;
+ cy > y2? y2++ : y2--;
+ cy > y3? y3++ : y3--;
+ }
+
+ //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 = (y3 != y1)? (Sint32)((x3 - x1)<<16)/(Sint32)(y3 - y1) : 400000; // That oughta be enough?
+ Sint32 m3 = 0;
+
+ if ( spg_lock(dest) < 0 )
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_TrigonFilledBlend could not lock surface");
+ return;
+ }
+
+ /* Upper half of the triangle */
+ if( y1==y2 )
+ spg_linehblend(dest, x1, y1, x2, color, alpha);
+ else{
+ m1 = (Sint32)((x2 - x1)<<16)/(Sint32)(y2 - y1);
+
+ for ( y = y1; y <= y2; y++) {
+ spg_linehblend(dest, xa>>16, y, xb>>16, color, alpha);
+
+ xa += m1;
+ xb += m2;
+ }
+ }
+
+ /* Lower half of the triangle */
+ if( y2==y3 )
+ spg_linehblend(dest, x2, y2, x3, color, alpha);
+ else{
+ m3 = (Sint32)((x3 - x2)<<16)/(Sint32)(y3 - y2);
+
+ for ( y = y2+1; y <= y3; y++) {
+ spg_linehblend(dest, xb>>16, y, xc>>16, color, alpha);
+
+ xb += m2;
+ xc += m3;
+ }
+ }
+
+ spg_unlock(dest);
+ if(spg_makedirtyrects)
+ {
+ 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;
+
+ SDL_Rect rect;
+ rect.x = xmin;
+ rect.y = ymin;
+ rect.w = xmax-xmin + 1;
+ rect.h = ymax-ymin + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(dest, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+
+
+}
+
+
+//==================================================================================
+// Draws a gourand shaded trigon
+//==================================================================================
+void SPG_TrigonFade(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 = SPG_GetColor(dest,c1);
+ col2 = SPG_GetColor(dest,c2);
+ col3 = SPG_GetColor(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 SPG_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 = (y3 != y1)? (Sint32)((x3 - x1)<<16)/(Sint32)(y3 - y1) : 400000; // That oughta be enough?
+ Sint32 m3 = 0;
+
+ /* Colors step values */
+ Sint32 rstep1 = 0;
+ Sint32 rstep2 = (y3 != y1)? (Sint32)((col3.r - col1.r) << 16) / (Sint32)(y3 - y1) : 400000;
+ Sint32 rstep3 = 0;
+
+ Sint32 gstep1 = 0;
+ Sint32 gstep2 = (y3 != y1)? (Sint32)((col3.g - col1.g) << 16) / (Sint32)(y3 - y1) : 400000;
+ Sint32 gstep3 = 0;
+
+ Sint32 bstep1 = 0;
+ Sint32 bstep2 = (y3 != y1)? (Sint32)((col3.b - col1.b) << 16) / (Sint32)(y3 - y1) : 400000;
+ Sint32 bstep3 = 0;
+
+ if ( spg_lock(dest) < 0 )
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_TrigonFade could not lock surface");
+ return;
+ }
+
+ /* Upper half of the triangle */
+ if( y1==y2 )
+ spg_linehfade(dest, x1, y1, x2, 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++) {
+ spg_linehfade(dest, xa>>16, y, xb>>16, 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 )
+ spg_linehfade(dest, x2, y2, x3, 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++) {
+ spg_linehfade(dest, xb>>16, y, xc>>16, 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;
+ }
+ }
+
+ spg_unlock(dest);
+ if(spg_makedirtyrects)
+ {
+ 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;
+
+ SDL_Rect rect;
+ rect.x = xmin;
+ rect.y = ymin;
+ rect.w = xmax-xmin + 1;
+ rect.h = ymax-ymin + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(dest, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+
+}
+
+
+//==================================================================================
+// Draws a texured trigon (fast)
+//==================================================================================
+void SPG_TrigonTex(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 SPG_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 = (y3 != y1)? (Sint32)((x3 - x1)<<16)/(Sint32)(y3 - y1) : 400000; // That oughta be enough?
+ 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 = (y3 != y1)? (Sint32)((sx3 - sx1) << 16) / (Sint32)(y3 - y1) : 400000;
+ Sint32 xstep3 = 0;
+
+ Sint32 ystep1 = 0;
+ Sint32 ystep2 = (y3 != y1)? (Sint32)((sy3 - sy1) << 16) / (Sint32)(y3 - y1) : 400000;
+ Sint32 ystep3 = 0;
+
+ if ( spg_lock(dest) < 0 )
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_TrigonTex could not lock dest surface");
+ return;
+ }
+
+ if ( spg_lock(source) < 0 )
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_TrigonTex could not lock source surface");
+ return;
+ }
+
+ /* Upper half of the triangle */
+ if( y1==y2 )
+ spg_linehtex(dest,x1,y1,x2,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++) {
+ spg_linehtex(dest, xa>>16, y, xb>>16, 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 )
+ spg_linehtex(dest,x2,y2,x3,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++) {
+ spg_linehtex(dest, xb>>16, y, xc>>16, source, srcx2>>16, srcy2>>16, srcx3>>16, srcy3>>16);
+
+ xb += m2;
+ xc += m3;
+
+ srcx2 += xstep2;
+ srcx3 += xstep3;
+ srcy2 += ystep2;
+ srcy3 += ystep3;
+ }
+ }
+
+ spg_unlock(dest);
+ spg_unlock(source);
+
+ if(spg_makedirtyrects)
+ {
+ 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;
+
+ SDL_Rect rect;
+ rect.x = xmin;
+ rect.y = ymin;
+ rect.w = xmax-xmin + 1;
+ rect.h = ymax-ymin + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(dest, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+
+}
+
+
+//==================================================================================
+// Draws a textured quadrilateral
+//==================================================================================
+void SPG_QuadTex(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 SPG_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 = (y3 != y1)? (Sint32)((x3 - x1)<<16)/(Sint32)(y3 - y1) : 400000;
+ Sint32 m3 = (y4 != y2)? (Sint32)((x4 - x2)<<16)/(Sint32)(y4 - y2) : 400000;
+ 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 = (y3 != y1)? (Sint32)((sx3 - sx1) << 16) / (Sint32)(y3 - y1) : 400000;
+ Sint32 xstep3 = (y4 != y2)? (Sint32)((sx4 - sx2) << 16) / (Sint32)(y4 - y2) : 400000;
+ Sint32 xstep4 = 0;
+
+ Sint32 ystep1 = 0;
+ Sint32 ystep2 = (y3 != y1)? (Sint32)((sy3 - sy1) << 16) / (Sint32)(y3 - y1) : 400000;
+ Sint32 ystep3 = (y4 != y2)? (Sint32)((sy4 - sy2) << 16) / (Sint32)(y4 - y2) : 400000;
+ Sint32 ystep4 = 0;
+
+ if ( spg_lock(dest) < 0 )
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_QuadTex could not lock surface");
+ return;
+ }
+
+ /* Upper bit of the rectangle */
+ if( y1==y2 )
+ spg_linehtex(dest,x1,y1,x2,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++) {
+ spg_linehtex(dest, xa>>16, y, xb>>16, 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++) {
+ spg_linehtex(dest, xb>>16, y, xc>>16, 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 )
+ spg_linehtex(dest,x3,y3,x4,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++) {
+ spg_linehtex(dest, xc>>16, y, xd>>16, source, srcx3>>16, srcy3>>16, srcx4>>16, srcy4>>16);
+
+ xc += m3;
+ xd += m4;
+
+ srcx3 += xstep3;
+ srcx4 += xstep4;
+ srcy3 += ystep3;
+ srcy4 += ystep4;
+ }
+
+ }
+
+ spg_unlock(dest);
+
+ if(spg_makedirtyrects)
+ {
+ 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;
+ xmax= (xmax>x4)? xmax : x4; ymax= (ymax>y4)? ymax : y4;
+ xmin= (xmin<x4)? xmin : x4; ymin= (ymin<y4)? ymin : y4;
+
+ SDL_Rect rect;
+ rect.x = xmin;
+ rect.y = ymin;
+ rect.w = xmax - xmin + 1;
+ rect.h = ymax - ymin + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(dest, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+
+}
+
+
+void SPG_CopyPoints(Uint16 n, SPG_Point* points, SPG_Point* buffer)
+{
+ if(points == NULL || buffer == NULL)
+ return;
+
+ int i = 0;
+ for(; i < n; ++i)
+ {
+ buffer[i].x = points[i].x;
+ buffer[i].y = points[i].y;
+ }
+}
+
+void SPG_RotatePointsXY(Uint16 n, SPG_Point* points, float cx, float cy, float angle)
+{
+ if(points == NULL)
+ return;
+ int i = 0;
+ float dx, dy;
+ if(spg_usedegrees)
+ angle = angle*RADPERDEG;
+ float ct = cos(angle), st = sin(angle);
+ for(; i < n; ++i)
+ {
+ // Get distances from center
+ dx = points[i].x - cx;
+ dy = points[i].y - cy;
+ // Simple 2d rotation
+ points[i].x = dx*ct - dy*st + cx;
+ points[i].y = dx*st + dy*ct + cy;
+ }
+
+}
+
+void SPG_ScalePointsXY(Uint16 n, SPG_Point* points, float cx, float cy, float xscale, float yscale)
+{
+ if(points == NULL)
+ return;
+ int i = 0;
+ float dx, dy;
+ for(; i < n; ++i)
+ {
+ // Get distances from center
+ dx = points[i].x - cx;
+ dy = points[i].y - cy;
+ // Simple 2d scale
+ points[i].x = cx + xscale*dx;
+ points[i].y = cy + yscale*dy;
+ }
+}
+
+void SPG_SkewPointsXY(Uint16 n, SPG_Point* points, float cx, float cy, float xskew, float yskew)
+{
+ if(points == NULL)
+ return;
+ int i = 0;
+ float dx, dy;
+ for(; i < n; ++i)
+ {
+ // Get distances from center
+ dx = points[i].x - cx;
+ dy = points[i].y - cy;
+ // Simple 2d skew
+ points[i].x += xskew*dy;
+ points[i].y += yskew*dx;
+ }
+}
+
+
+void SPG_TranslatePoints(Uint16 n, SPG_Point* points, float x1, float y1)
+{
+ if(points == NULL)
+ return;
+ int i = 0;
+ for(; i < n; ++i)
+ {
+ points[i].x += x1;
+ points[i].y += y1;
+ }
+}
+
+
+
+
+
+
+
+//==================================================================================
+// And now to something completly different: Polygons!
+//==================================================================================
+
+void SPG_Polygon(SDL_Surface *dest, Uint16 n, SPG_Point* points, Uint32 color)
+{
+ if(points == NULL)
+ return;
+ if(n < 3)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_Polygon given n < 3");
+ return;
+ }
+
+ if ( spg_lock(dest) < 0 )
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_Polygon could not lock surface");
+ return;
+ }
+
+ Sint16 ox = points[n-1].x;
+ Sint16 oy = points[n-1].y;
+ int i;
+ if(spg_thickness == 1)
+ {
+ if(SPG_GetAA())
+ {
+ for(i = 0; i < n; i++)
+ {
+ spg_lineblendaa(dest,ox,oy,points[i].x,points[i].y,color, SDL_ALPHA_OPAQUE);
+ ox = points[i].x;
+ oy = points[i].y;
+ }
+ }
+ else
+ {
+ for(i = 0; i < n; i++)
+ {
+ spg_line(dest,ox,oy,points[i].x,points[i].y,color);
+ ox = points[i].x;
+ oy = points[i].y;
+ }
+ }
+
+
+ if(spg_makedirtyrects)
+ {
+ Sint16 xmax=points[0].x, ymax=points[0].y, xmin=points[0].x, ymin=points[0].y;
+ int i = 0;
+ for(; i < n; ++i)
+ {
+ xmax= (xmax>points[i].x)? xmax : points[i].x; ymax= (ymax>points[i].y)? ymax : points[i].y;
+ xmin= (xmin<points[i].x)? xmin : points[i].x; ymin= (ymin<points[i].y)? ymin : points[i].y;
+ }
+
+ SDL_Rect rect;
+ rect.x = xmin;
+ rect.y = ymin;
+ rect.w = xmax - xmin + 1;
+ rect.h = ymax - ymin + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(dest, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+ else if(spg_thickness > 0)
+ {
+ for(i = 0; i < n; i++)
+ {
+ SPG_LineFn(dest,ox,oy,points[i].x,points[i].y,color, spg_thicknesscallback);
+ ox = points[i].x;
+ oy = points[i].y;
+ }
+
+
+ if(spg_makedirtyrects)
+ {
+ Sint16 xmax=points[0].x, ymax=points[0].y, xmin=points[0].x, ymin=points[0].y;
+ int i = 0;
+ for(; i < n; ++i)
+ {
+ xmax= (xmax>points[i].x)? xmax : points[i].x; ymax= (ymax>points[i].y)? ymax : points[i].y;
+ xmin= (xmin<points[i].x)? xmin : points[i].x; ymin= (ymin<points[i].y)? ymin : points[i].y;
+ }
+
+ SDL_Rect rect;
+ rect.x = xmin - spg_thickness/2;
+ rect.y = ymin - spg_thickness/2;
+ rect.w = xmax - xmin + 1 + spg_thickness;
+ rect.h = ymax - ymin + 1 + spg_thickness;
+ // Clip it to the screen
+ SPG_DirtyClip(dest, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+
+ spg_unlock(dest);
+
+}
+
+void SPG_PolygonBlend(SDL_Surface *dest, Uint16 n, SPG_Point* points, Uint32 color, Uint8 alpha)
+{
+ if(points == NULL)
+ return;
+ if(n < 3)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_PolygonBlend given n < 3");
+ return;
+ }
+
+ if ( spg_lock(dest) < 0 )
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_PolygonBlend could not lock surface");
+ return;
+ }
+
+ Sint16 ox = points[n-1].x;
+ Sint16 oy = points[n-1].y;
+ int i;
+ if(spg_thickness == 1)
+ {
+ if(SPG_GetAA())
+ {
+ for(i = 0; i < n; i++)
+ {
+ spg_lineblendaa(dest,ox,oy,points[i].x,points[i].y,color, alpha);
+ ox = points[i].x;
+ oy = points[i].y;
+ }
+ }
+ else
+ {
+ spg_alphahack = alpha;
+ for(i = 0; i < n; i++)
+ {
+ SPG_LineFn(dest, ox, oy, points[i].x,points[i].y,color, spg_pixelcallbackalpha);
+ ox = points[i].x;
+ oy = points[i].y;
+ }
+ }
+
+ if(spg_makedirtyrects)
+ {
+ Sint16 xmax=points[0].x, ymax=points[0].y, xmin=points[0].x, ymin=points[0].y;
+ int i = 0;
+ for(; i < n; ++i)
+ {
+ xmax= (xmax>points[i].x)? xmax : points[i].x; ymax= (ymax>points[i].y)? ymax : points[i].y;
+ xmin= (xmin<points[i].x)? xmin : points[i].x; ymin= (ymin<points[i].y)? ymin : points[i].y;
+ }
+
+ SDL_Rect rect;
+ rect.x = xmin;
+ rect.y = ymin;
+ rect.w = xmax - xmin + 1;
+ rect.h = ymax - ymin + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(dest, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+ if(spg_thickness > 0)
+ {
+
+ spg_alphahack = alpha;
+ for(i = 0; i < n; i++)
+ {
+ SPG_LineFn(dest, ox, oy, points[i].x,points[i].y,color, spg_thicknesscallbackalpha);
+ ox = points[i].x;
+ oy = points[i].y;
+ }
+
+ if(spg_makedirtyrects)
+ {
+ Sint16 xmax=points[0].x, ymax=points[0].y, xmin=points[0].x, ymin=points[0].y;
+ int i = 0;
+ for(; i < n; ++i)
+ {
+ xmax= (xmax>points[i].x)? xmax : points[i].x; ymax= (ymax>points[i].y)? ymax : points[i].y;
+ xmin= (xmin<points[i].x)? xmin : points[i].x; ymin= (ymin<points[i].y)? ymin : points[i].y;
+ }
+
+ SDL_Rect rect;
+ rect.x = xmin - spg_thickness/2;
+ rect.y = ymin - spg_thickness/2;
+ rect.w = xmax - xmin + 1 + spg_thickness;
+ rect.h = ymax - ymin + 1 + spg_thickness;
+ // Clip it to the screen
+ SPG_DirtyClip(dest, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+
+ spg_unlock(dest);
+
+}
+
+/* Base polygon structure */
+typedef struct pline{
+ Sint16 x1,x2, y1,y2;
+
+ Sint32 fx, fm;
+
+ Sint16 x;
+
+ struct pline *next;
+
+}pline;
+
+void _pline_update(struct pline* pl)
+{
+ pl->x = (Sint16)(pl->fx>>16);
+ pl->fx += pl->fm;
+}
+
+/* Pointer storage (to preserve polymorphism) */
+typedef struct pline_p{
+ 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)( ( (Uint16)(j->x+0x7fff) >> (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 */
+struct pline* get_scanline(pline_p *plist, Uint16 n, Sint32 y)
+{
+ struct pline* p = NULL;
+ struct pline* list = NULL;
+ struct pline* li = NULL;
+ int i;
+ for(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
+ _pline_update(p);
+ }
+ }
+
+ if( li )
+ li->next = NULL; // terminate
+
+ // Sort list
+ return rsort(list);
+}
+
+/* Removes duplicates if needed */
+static 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
+//==================================================================================
+
+void SPG_PolygonFilledBlend(SDL_Surface *dest, Uint16 n, SPG_Point* points, Uint32 color, Uint8 alpha)
+{
+ if(points == NULL)
+ return;
+ if(n<3)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_PolygonFilledBlend given n < 3");
+ return;
+ }
+
+ if (spg_lock(dest) < 0)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_PolygonFilledBlend could not lock surface");
+ return;
+ }
+
+ struct pline *line = (pline*)malloc(sizeof(struct pline)*n);//pline[n];
+ struct pline_p *plist = (pline_p*)malloc(sizeof(struct pline_p)*n);
+
+ Sint16 y1,y2, x1, x2, tmp, sy;
+ Sint16 ymin = points[1].y, ymax=points[1].y;
+ Sint16 xmin = points[1].x, xmax=points[1].x;
+ Uint16 i;
+
+ /* Decompose polygon into straight lines */
+ for( i = 0; i < n; i++ ){
+ x1 = points[i].x;
+ y1 = points[i].y;
+
+ if( i == n-1 ){
+ // Last point == First point
+ x2 = points[0].x;
+ y2 = points[0].y;
+ }else{
+ x2 = points[i+1].x;
+ y2 = points[i+1].y;
+ }
+
+ // Make sure y1 <= y2
+ if( y1 > y2 ) {
+ SWAP(y1,y2,tmp);
+ SWAP(x1,x2,tmp);
+ }
+
+ // No longer Reject polygons with negative coords
+ /*
+ if( y1 < 0 || x1 < 0 || x2 < 0 ){
+ spg_unlock(dest);
+
+ delete[] line;
+ delete[] plist;
+ return;
+ }
+ */
+
+ 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 )
+ spg_line(dest,x1,y1,x2,y2,color); // Can't do this with alpha, might overlap with the filling
+ }
+
+ /* Remove surface lock if spg_lineh() is to be used */
+ if (alpha == SDL_ALPHA_OPAQUE)
+ spg_unlock(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 = NULL_POSITION;
+
+ // Draw horizontal lines between pairs
+ for( li = list; li; li = li->next ){
+ remove_dup(li, sy);
+
+ if( x1 == NULL_POSITION )
+ x1 = li->x+1;
+ else if( x2 == NULL_POSITION )
+ x2 = li->x;
+
+ if( x1 != NULL_POSITION && x2 !=NULL_POSITION ){
+ if( x2-x1 < 0 && alpha == SDL_ALPHA_OPAQUE ){
+ // Already drawn by the outline
+ x1 = x2 = NULL_POSITION;
+ continue;
+ }
+
+ if( alpha == SDL_ALPHA_OPAQUE )
+ spg_lineh(dest, x1, sy, x2, color);
+ else
+ spg_linehblend(dest, x1-1, sy, x2, color, alpha);
+
+ x1 = x2 = NULL_POSITION;
+ }
+ }
+ }
+
+ if (alpha != SDL_ALPHA_OPAQUE)
+ spg_unlock(dest);
+
+ free(line);
+ free(plist);
+
+
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = xmin;
+ rect.y = ymin;
+ rect.w = xmax - xmin + 1;
+ rect.h = ymax - ymin + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(dest, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ return;
+}
+
+
+//==================================================================================
+// Draws a n-points (AA) filled polygon
+//==================================================================================
+
+void spg_polygonfilledaa(SDL_Surface *dest, Uint16 n, SPG_Point* points, Uint32 color)
+{
+ if(points == NULL)
+ return;
+ if(n<3)
+ {
+ if(spg_useerrors)
+ SPG_Error("spg_polygonfilledaa given n < 3");
+ return;
+ }
+
+
+ if (spg_lock(dest) < 0)
+ {
+ if(spg_useerrors)
+ SPG_Error("spg_polygonfilledaa could not lock surface");
+ return;
+ }
+
+ struct pline *line = (pline*)malloc(sizeof(struct pline)*n);
+ struct pline_p *plist = (pline_p*)malloc(sizeof(struct pline_p)*n);
+
+ Sint16 y1,y2, x1, x2, tmp, sy;
+ Sint16 xmin = points[1].x, xmax=points[1].x;
+ Sint16 ymin = points[1].y, ymax=points[1].y;
+ Uint16 i;
+
+ /* Decompose polygon into straight lines */
+ for( i = 0; i < n; i++ ){
+ y1 = points[i].y;
+ x1 = points[i].x;
+
+ if( i == n-1 ){
+ // Last point == First point
+ y2 = points[0].y;
+ x2 = points[0].x;
+ }else{
+ y2 = points[i+1].y;
+ x2 = points[i+1].x;
+ }
+
+ // Make sure y1 <= y2
+ if( y1 > y2 ) {
+ SWAP(y1,y2,tmp);
+ SWAP(x1,x2,tmp);
+ }
+
+ // No longer Reject polygons with negative coords
+ /*
+ if( y1 < 0 || x1 < 0 || x2 < 0 ){
+ spg_unlock(dest);
+
+ delete[] line;
+ delete[] plist;
+ return;
+ }
+ */
+
+ 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
+ spg_lineblendaa(dest,x1,y1,x2,y2,color, SDL_ALPHA_OPAQUE);
+ }
+
+ spg_unlock(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 = NULL_POSITION;
+
+ // Draw horizontal lines between pairs
+ for( li = list; li; li = li->next ){
+ remove_dup(li, sy);
+
+ if( x1 ==NULL_POSITION )
+ x1 = li->x+1;
+ else if( x2 ==NULL_POSITION )
+ x2 = li->x;
+
+ if( x1 != NULL_POSITION && x2 !=NULL_POSITION ){
+ if( x2-x1 < 0 ){
+ x1 = x2 = NULL_POSITION;
+ continue;
+ }
+
+ spg_lineh(dest, x1, sy, x2, color);
+
+ x1 = x2 = NULL_POSITION;
+ }
+ }
+ }
+
+ free(line);
+ free(plist);
+
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = xmin;
+ rect.y = ymin;
+ rect.w = xmax - xmin + 1;
+ rect.h = ymax - ymin + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(dest, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+
+ return;
+}
+
+
+void SPG_PolygonFilled(SDL_Surface *dest, Uint16 n, SPG_Point* points, Uint32 color)
+{
+ if(SPG_GetAA())
+ spg_polygonfilledaa(dest, n, points, color);
+ else
+ SPG_PolygonFilledBlend(dest, n, points, color, SDL_ALPHA_OPAQUE);
+}
+
+
+
+
+
+//==================================================================================
+// Draws a n-points Gouraud shaded polygon
+//==================================================================================
+
+/* faded polygon structure */
+typedef struct fpline{
+ Sint16 x1,x2, y1,y2;
+
+ Sint32 fx, fm;
+
+ Sint16 x;
+
+ struct fpline *next;
+
+ Uint8 r1, r2;
+ Uint8 g1, g2;
+ Uint8 b1, b2;
+
+ Uint32 fr, fg, fb;
+ Sint32 fmr, fmg, fmb;
+
+ Uint8 r,g,b;
+
+}fpline;
+
+void _fpline_update(struct fpline* fpl)
+{
+ fpl->x = (Sint16)(fpl->fx>>16);
+ fpl->fx += fpl->fm;
+
+ fpl->r = (Uint8)(fpl->fr>>16);
+ fpl->g = (Uint8)(fpl->fg>>16);
+ fpl->b = (Uint8)(fpl->fb>>16);
+
+ fpl->fr += fpl->fmr;
+ fpl->fg += fpl->fmg;
+ fpl->fb += fpl->fmb;
+}
+
+typedef struct fpline_p{
+ fpline *p;
+}fpline_p;
+static inline void remove_dupf(fpline *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;
+}/* Radix sort */
+fpline* rsortf(fpline *inlist)
+{
+ if(!inlist)
+ return NULL;
+
+ // 16 radix-buckets
+ fpline* bucket[16] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
+ fpline* bi[16]; // bucket itterator (points to last element in bucket)
+
+ fpline *plist = inlist;
+
+ int i,k;
+ fpline *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)( ( (Uint16)(j->x+0x7fff) >> (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 */
+struct fpline* get_scanlinef(fpline_p *plist, Uint16 n, Sint32 y)
+{
+ struct fpline* p = NULL;
+ struct fpline* list = NULL;
+ struct fpline* li = NULL;
+ int i;
+ for(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 iterator
+
+ // Calculate x
+ _fpline_update(p);
+ }
+ }
+
+ if( li )
+ li->next = NULL; // terminate
+
+ // Sort list
+ return rsortf(list);
+}
+
+void SPG_PolygonFadeBlend(SDL_Surface *dest, Uint16 n, SPG_Point* points, Uint32* colors, Uint8 alpha)
+{
+ if(points == NULL)
+ return;
+ if(n<3)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_PolygonFadeBlend given n < 3");
+ return;
+ }
+
+ if (spg_lock(dest) < 0)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_PolygonFadeBlend could not lock surface");
+ return;
+ }
+
+ struct fpline *line = (fpline*)malloc(sizeof(struct fpline)*n);
+ struct fpline_p *plist = (fpline_p*)malloc(sizeof(struct fpline_p)*n);
+
+ Sint16 y1,y2, x1, x2, tmp, sy;
+ Sint16 ymin = points[1].y, ymax=points[1].y;
+ Sint16 xmin = points[1].x, xmax=points[1].x;
+ 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 = points[i].y;
+ x1 = points[i].x;
+ if(dest->format->BitsPerPixel == 8)
+ {
+ SDL_GetRGB(colors[i], dest->format, &r1, &g1, &b1);
+ }
+ else
+ {
+ r1 = (colors[i] & dest->format->Rmask) >> dest->format->Rshift;
+ g1 = (colors[i] & dest->format->Gmask) >> dest->format->Gshift;
+ b1 = (colors[i] & dest->format->Bmask) >> dest->format->Bshift;
+ }
+
+ if( i == n-1 )
+ {
+ // Last point == First point
+ y2 = points[0].y;
+ x2 = points[0].x;
+ if(dest->format->BitsPerPixel == 8)
+ {
+ SDL_GetRGB(colors[0], dest->format, &r2, &g2, &b2);
+ }
+ else
+ {
+ r2 = (colors[0] & dest->format->Rmask) >> dest->format->Rshift;
+ g2 = (colors[0] & dest->format->Gmask) >> dest->format->Gshift;
+ b2 = (colors[0] & dest->format->Bmask) >> dest->format->Bshift;
+ }
+ }
+ else
+ {
+ y2 = points[i+1].y;
+ x2 = points[i+1].x;
+
+ if(dest->format->BitsPerPixel == 8)
+ {
+ SDL_GetRGB(colors[i+1], dest->format, &r2, &g2, &b2);
+ }
+ else
+ {
+ r2 = (colors[i+1] & dest->format->Rmask) >> dest->format->Rshift;
+ g2 = (colors[i+1] & dest->format->Gmask) >> dest->format->Gshift;
+ b2 = (colors[i+1] & dest->format->Bmask) >> dest->format->Bshift;
+ }
+ }
+
+ // 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);
+ }
+
+ // No longer Reject polygons with negative coords
+ /*
+ if( y1 < 0 || x1 < 0 || x2 < 0 ){
+ spg_unlock(dest);
+
+ delete[] line;
+ delete[] plist;
+ return;
+ }
+ */
+
+ 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 )
+ SPG_LineFadeFn(dest,x1,y1,x2,y2,SDL_MapRGB(dest->format, r1,g1,b1),SDL_MapRGB(dest->format, r2,g2,b2), spg_pixel); // Can't do this with alpha, might overlap with the filling
+ }
+
+ fpline* list = NULL;
+ fpline* li = NULL; // list iterator
+
+ // Scan y-lines
+ for( sy = ymin; sy <= ymax; sy++){
+ list = (fpline *)get_scanlinef(plist, n, sy);
+
+ if( !list )
+ continue; // nothing in list... hmmmm
+
+ x1 = x2 = NULL_POSITION;
+
+ // Draw horizontal lines between pairs
+ for( li = list; li; li = (fpline *)li->next ){
+ remove_dupf(li, sy);
+
+ if( x1 == NULL_POSITION ){
+ x1 = li->x+1;
+ r1 = li->r;
+ g1 = li->g;
+ b1 = li->b;
+ }else if( x2 == NULL_POSITION ){
+ x2 = li->x;
+ r2 = li->r;
+ g2 = li->g;
+ b2 = li->b;
+ }
+
+ if( x1 !=NULL_POSITION && x2 !=NULL_POSITION ){
+ if( x2-x1 < 0 && alpha == SDL_ALPHA_OPAQUE){
+ x1 = x2 = NULL_POSITION;
+ continue;
+ }
+
+ if( alpha == SDL_ALPHA_OPAQUE )
+ spg_linehfade(dest, x1, sy, x2, r1, g1, b1, r2, g2, b2);
+ else{
+ spg_alphahack = alpha;
+ SPG_LineFadeFn(dest, x1-1, sy, x2, sy, SDL_MapRGB(dest->format, r1, g1, b1), SDL_MapRGB(dest->format, r2, g2, b2), spg_pixelcallbackalpha);
+ }
+
+ x1 = x2 = NULL_POSITION;
+ }
+ }
+ }
+
+ spg_unlock(dest);
+
+ free(line);
+ free(plist);
+
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = xmin;
+ rect.y = ymin;
+ rect.w = xmax - xmin + 1;
+ rect.h = ymax - ymin + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(dest, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ return;
+}
+
+//==================================================================================
+// Draws a n-points (AA) gourand shaded polygon
+//==================================================================================
+void spg_polygonfadeaa(SDL_Surface *dest, Uint16 n, SPG_Point* points, Uint32* colors)
+{
+ if(points == NULL)
+ return;
+ if(n<3)
+ {
+ if(spg_useerrors)
+ SPG_Error("spg_polygonfadeaa given n < 3");
+ return;
+ }
+
+ if (spg_lock(dest) < 0)
+ {
+ if(spg_useerrors)
+ SPG_Error("spg_polygonfadeaa could not lock surface");
+ return;
+ }
+
+ struct fpline *line = (fpline*)malloc(sizeof(struct fpline)*n);
+ struct fpline_p *plist = (fpline_p*)malloc(sizeof(struct fpline_p)*n);
+
+ Sint16 y1,y2, x1, x2, tmp, sy;
+ Sint16 ymin = points[1].y, ymax=points[1].y;
+ Sint16 xmin = points[1].x, xmax=points[1].x;
+ 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 = points[i].y;
+ x1 = points[i].x;
+ if(dest->format->BitsPerPixel == 8)
+ {
+ SDL_GetRGB(colors[i], dest->format, &r1, &g1, &b1);
+ }
+ else
+ {
+ r1 = (colors[i] & dest->format->Rmask) >> dest->format->Rshift;
+ g1 = (colors[i] & dest->format->Gmask) >> dest->format->Gshift;
+ b1 = (colors[i] & dest->format->Bmask) >> dest->format->Bshift;
+ }
+
+ if( i == n-1 ){
+ // Last point == First point
+ y2 = points[0].y;
+ x2 = points[0].x;
+ if(dest->format->BitsPerPixel == 8)
+ {
+ SDL_GetRGB(colors[0], dest->format, &r2, &g2, &b2);
+ }
+ else
+ {
+ r2 = (colors[0] & dest->format->Rmask) >> dest->format->Rshift;
+ g2 = (colors[0] & dest->format->Gmask) >> dest->format->Gshift;
+ b2 = (colors[0] & dest->format->Bmask) >> dest->format->Bshift;
+ }
+ }else{
+ y2 = points[i+1].y;
+ x2 = points[i+1].x;
+ if(dest->format->BitsPerPixel == 8)
+ {
+ SDL_GetRGB(colors[i+1], dest->format, &r2, &g2, &b2);
+ }
+ else
+ {
+ r2 = (colors[i+1] & dest->format->Rmask) >> dest->format->Rshift;
+ g2 = (colors[i+1] & dest->format->Gmask) >> dest->format->Gshift;
+ b2 = (colors[i+1] & dest->format->Bmask) >> dest->format->Bshift;
+ }
+ }
+
+ // 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);
+ }
+
+ // No longer Reject polygons with negative coords
+ /*
+ if( y1 < 0 || x1 < 0 || x2 < 0 ){
+
+ spg_unlock(dest);
+
+ delete[] line;
+ delete[] plist;
+ return;
+ }
+ */
+
+ 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{
+ // Is this really right? I personally would set them very high...
+ 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)
+ spg_linefadeblendaa(dest,x1,y1,x2,y2,SDL_MapRGB(dest->format, r1,g1,b1), SDL_ALPHA_OPAQUE,SDL_MapRGB(dest->format, 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_scanlinef(plist, n, sy);
+
+ if( !list )
+ continue; // nothing in list... hmmmm
+
+ x1 = x2 = NULL_POSITION;
+
+ // Draw horizontal lines between pairs
+ for( li = list; li; li = (fpline *)li->next ){
+ remove_dupf(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 != NULL_POSITION && x2 !=NULL_POSITION ){
+ if( x2-x1 < 0 ){
+ x1 = x2 = NULL_POSITION;
+ continue;
+ }
+
+ spg_linehfade(dest, x1, sy, x2, r1, g1, b1, r2, g2, b2);
+
+ x1 = x2 = NULL_POSITION;
+ }
+ }
+ }
+
+ spg_unlock(dest);
+
+ free(line);
+ free(plist);
+
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = xmin;
+ rect.y = ymin;
+ rect.w = xmax - xmin + 1;
+ rect.h = ymax - ymin + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(dest, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+
+
+ return;
+}
+
+void SPG_PolygonFade(SDL_Surface *dest, Uint16 n, SPG_Point* points, Uint32* colors)
+{
+ if(SPG_GetAA())
+ spg_polygonfadeaa(dest, n, points, colors);
+ else
+ SPG_PolygonFadeBlend(dest, n, points, colors, SDL_ALPHA_OPAQUE);
+}
+
diff --git a/util/sdl/sprig/SPG_primitives.c b/util/sdl/sprig/SPG_primitives.c
new file mode 100644
index 00000000..9b8b2189
--- /dev/null
+++ b/util/sdl/sprig/SPG_primitives.c
@@ -0,0 +1,4861 @@
+/*
+ SPriG - SDL Primitive Generator
+ by Jonathan Dearborn
+
+ Based on SGE: SDL Graphics Extension r030809
+ by Anders Lindström
+*/
+
+
+/*********************************************************************
+ * 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. *
+ *********************************************************************/
+
+
+/*
+* Some of this code is taken from the "Introduction to SDL" and
+* John Garrison's PowerPak
+*/
+#include "sprig.h"
+#include "sprig_common.h"
+
+#include <math.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+
+void spg_pixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color);
+void spg_pixelblend(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color, Uint8 alpha);
+
+/* Globals */
+extern SPG_bool spg_useerrors;
+extern SPG_bool spg_usedegrees;
+extern SPG_bool spg_makedirtyrects;
+extern SPG_DirtyTable* spg_dirtytable_front;
+
+Uint16 spg_thickness = 1;
+Uint8 spg_alphahack = 0;
+
+
+
+
+
+void spg_thicknesscallback(SDL_Surface *Surf, Sint16 X, Sint16 Y, Uint32 Color)
+{
+ if(spg_thickness > 0)
+ {
+ // Disable autolock and dirty rects
+ SPG_bool lock = spg_autolock;
+ spg_autolock = 0;
+ SPG_bool dirty = spg_makedirtyrects;
+ spg_makedirtyrects = 0;
+ SPG_CircleFilled(Surf, X, Y, (spg_thickness-1)/2.0f, Color);
+ spg_autolock = lock;
+ spg_makedirtyrects = dirty;
+ }
+}
+
+void spg_thicknesscallbackalpha(SDL_Surface *Surf, Sint16 X, Sint16 Y, Uint32 Color)
+{
+ if(spg_thickness > 0)
+ {
+ // Disable autolock and dirty rects
+ SPG_bool lock = spg_autolock;
+ spg_autolock = 0;
+ SPG_bool dirty = spg_makedirtyrects;
+ spg_makedirtyrects = 0;
+ SPG_CircleFilledBlend(Surf, X, Y, (spg_thickness-1)/2.0f, Color, spg_alphahack);
+ spg_autolock = lock;
+ spg_makedirtyrects = dirty;
+ }
+}
+
+
+
+/**********************************************************************************/
+/** Pixel functions **/
+/**********************************************************************************/
+
+//==================================================================================
+// Fast set pixel
+//==================================================================================
+void spg_pixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
+{
+ if(x>=SPG_CLIP_XMIN(surface) && x<=SPG_CLIP_XMAX(surface) && y>=SPG_CLIP_YMIN(surface) && y<=SPG_CLIP_YMAX(surface)){
+ switch (surface->format->BytesPerPixel) {
+ case 1: { /* Assuming 8-bpp */
+ *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
+ }
+ break;
+
+ case 2: { /* Probably 15-bpp or 16-bpp */
+ *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
+ }
+ break;
+
+ case 3: { /* Slow 24-bpp mode, usually not used */
+ Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
+
+ /* Gack - slow, but endian correct */
+ *(pix+surface->format->Rshift/8) = color>>surface->format->Rshift;
+ *(pix+surface->format->Gshift/8) = color>>surface->format->Gshift;
+ *(pix+surface->format->Bshift/8) = color>>surface->format->Bshift;
+ *(pix+surface->format->Ashift/8) = color>>surface->format->Ashift;
+ }
+ break;
+
+ case 4: { /* Probably 32-bpp */
+ *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
+ }
+ break;
+ }
+ }
+
+}
+
+
+//==================================================================================
+// Fast set pixel (RGB)
+//==================================================================================
+void spg_pixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y, Uint8 R, Uint8 G, Uint8 B)
+{
+ spg_pixel(surface,x,y, SDL_MapRGB(surface->format, R, G, B));
+}
+
+
+//==================================================================================
+// Fastest set pixel functions (don't mess up indata, thank you)
+//==================================================================================
+void spg_pixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
+{
+ *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
+}
+void spg_pixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
+{
+ *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
+}
+void spg_pixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
+{
+ Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
+
+ /* Gack - slow, but endian correct */
+ *(pix+surface->format->Rshift/8) = color>>surface->format->Rshift;
+ *(pix+surface->format->Gshift/8) = color>>surface->format->Gshift;
+ *(pix+surface->format->Bshift/8) = color>>surface->format->Bshift;
+ *(pix+surface->format->Ashift/8) = color>>surface->format->Ashift;
+}
+void spg_pixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
+{
+ *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
+}
+void spg_pixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
+{
+ switch ( dest->format->BytesPerPixel ) {
+ case 1:
+ *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
+ break;
+ case 2:
+ *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
+ break;
+ case 3:
+ spg_pixel24(dest,x,y,color);
+ break;
+ case 4:
+ *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
+ break;
+ }
+}
+
+
+
+//==================================================================================
+// Safe set pixel
+//==================================================================================
+void SPG_Pixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
+{
+ if(spg_lock(surface) < 0)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_Pixel could not lock surface");
+ return;
+ }
+
+ if(spg_thickness == 1)
+ {
+ spg_pixel(surface, x, y, color);
+
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = x;
+ rect.y = y;
+ rect.w = 1;
+ rect.h = 1;
+ SPG_DirtyClip(surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+ else
+ {
+ if(spg_thickness == 0) return;
+ spg_thicknesscallback(surface, x, y, color);
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.w = spg_thickness;
+ rect.h = spg_thickness;
+ rect.x = x - rect.w/2;
+ rect.y = y - rect.h/2;
+ SPG_DirtyClip(surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+
+ spg_unlock(surface);
+
+}
+
+//==================================================================================
+// Put pixel with alpha blending
+//==================================================================================
+void spg_pixelblend(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color, Uint8 alpha)
+{
+ if(x>=SPG_CLIP_XMIN(surface) && x<=SPG_CLIP_XMAX(surface) && y>=SPG_CLIP_YMIN(surface) && y<=SPG_CLIP_YMAX(surface)){
+ Uint32 Rmask = surface->format->Rmask, Gmask = surface->format->Gmask, Bmask = surface->format->Bmask, Amask = surface->format->Amask;
+ Uint32 R,G,B,A=0;//SDL_ALPHA_OPAQUE;
+ Uint32* pixel;
+ switch (surface->format->BytesPerPixel) {
+ case 1: { /* Assuming 8-bpp */
+
+ Uint8 *pixel = (Uint8 *)surface->pixels + y*surface->pitch + x;
+
+ Uint8 dR = surface->format->palette->colors[*pixel].r;
+ Uint8 dG = surface->format->palette->colors[*pixel].g;
+ Uint8 dB = surface->format->palette->colors[*pixel].b;
+ Uint8 sR = surface->format->palette->colors[color].r;
+ Uint8 sG = surface->format->palette->colors[color].g;
+ Uint8 sB = surface->format->palette->colors[color].b;
+
+ dR = dR + ((sR-dR)*alpha >> 8);
+ dG = dG + ((sG-dG)*alpha >> 8);
+ dB = dB + ((sB-dB)*alpha >> 8);
+
+ *pixel = SDL_MapRGB(surface->format, dR, dG, dB);
+
+ }
+ break;
+
+ case 2: { /* Probably 15-bpp or 16-bpp */
+
+ Uint16 *pixel = (Uint16 *)surface->pixels + y*surface->pitch/2 + x;
+ Uint32 dc = *pixel;
+
+ R = ((dc & Rmask) + (( (color & Rmask) - (dc & Rmask) ) * alpha >> 8)) & Rmask;
+ G = ((dc & Gmask) + (( (color & Gmask) - (dc & Gmask) ) * alpha >> 8)) & Gmask;
+ B = ((dc & Bmask) + (( (color & Bmask) - (dc & Bmask) ) * alpha >> 8)) & Bmask;
+ if( Amask )
+ A = ((dc & Amask) + (( (color & Amask) - (dc & Amask) ) * alpha >> 8)) & Amask;
+
+ *pixel= R | G | B | A;
+
+ }
+ break;
+
+ case 3: { /* Slow 24-bpp mode, usually not used */
+ Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
+ Uint8 rshift8=surface->format->Rshift/8;
+ Uint8 gshift8=surface->format->Gshift/8;
+ Uint8 bshift8=surface->format->Bshift/8;
+ Uint8 ashift8=surface->format->Ashift/8;
+
+
+
+ Uint8 dR, dG, dB, dA=0;
+ Uint8 sR, sG, sB, sA=0;
+
+ pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
+
+ dR = *((pix)+rshift8);
+ dG = *((pix)+gshift8);
+ dB = *((pix)+bshift8);
+ dA = *((pix)+ashift8);
+
+ sR = (color>>surface->format->Rshift)&0xff;
+ sG = (color>>surface->format->Gshift)&0xff;
+ sB = (color>>surface->format->Bshift)&0xff;
+ sA = (color>>surface->format->Ashift)&0xff;
+
+ dR = dR + ((sR-dR)*alpha >> 8);
+ dG = dG + ((sG-dG)*alpha >> 8);
+ dB = dB + ((sB-dB)*alpha >> 8);
+ dA = dA + ((sA-dA)*alpha >> 8);
+
+ *((pix)+rshift8) = dR;
+ *((pix)+gshift8) = dG;
+ *((pix)+bshift8) = dB;
+ *((pix)+ashift8) = dA;
+
+ }
+ break;
+
+ case 4: /* Probably 32-bpp */
+ pixel = (Uint32*)surface->pixels + y*surface->pitch/4 + x;
+ Uint32 dc = *pixel;
+ R = color & Rmask;
+ G = color & Gmask;
+ B = color & Bmask;
+ A = 0; // keep this as 0 to avoid corruption of non-alpha surfaces
+
+
+ switch(SPG_GetBlend())
+ {
+ case SPG_COMBINE_ALPHA: // Blend and combine src and dest alpha
+ if( alpha != SDL_ALPHA_OPAQUE ){
+ R = ((dc & Rmask) + (( R - (dc & Rmask) ) * alpha >> 8)) & Rmask;
+ G = ((dc & Gmask) + (( G - (dc & Gmask) ) * alpha >> 8)) & Gmask;
+ B = ((dc & Bmask) + (( B - (dc & Bmask) ) * alpha >> 8)) & Bmask;
+ }
+ if(Amask)
+ A = ((((dc & Amask) >> surface->format->Ashift) + alpha) >> 1) << surface->format->Ashift;
+ break;
+ case SPG_DEST_ALPHA: // Blend and keep dest alpha
+ if( alpha != SDL_ALPHA_OPAQUE ){
+ R = ((dc & Rmask) + (( R - (dc & Rmask) ) * alpha >> 8)) & Rmask;
+ G = ((dc & Gmask) + (( G - (dc & Gmask) ) * alpha >> 8)) & Gmask;
+ B = ((dc & Bmask) + (( B - (dc & Bmask) ) * alpha >> 8)) & Bmask;
+ }
+ if(Amask)
+ A = (dc & Amask);
+ break;
+ case SPG_SRC_ALPHA: // Blend and keep src alpha
+ if( alpha != SDL_ALPHA_OPAQUE ){
+ R = ((dc & Rmask) + (( R - (dc & Rmask) ) * alpha >> 8)) & Rmask;
+ G = ((dc & Gmask) + (( G - (dc & Gmask) ) * alpha >> 8)) & Gmask;
+ B = ((dc & Bmask) + (( B - (dc & Bmask) ) * alpha >> 8)) & Bmask;
+ }
+ if(Amask)
+ A = (alpha << surface->format->Ashift);
+ break;
+ case SPG_COPY_SRC_ALPHA: // Direct copy with src alpha
+ if(Amask)
+ A = (alpha << surface->format->Ashift);
+ break;
+ case SPG_COPY_DEST_ALPHA: // Direct copy with dest alpha
+ if(Amask)
+ A = (dc & Amask);
+ break;
+ case SPG_COPY_COMBINE_ALPHA: // Direct copy with combined alpha
+ if(Amask)
+ A = ((((dc & Amask) >> surface->format->Ashift) + alpha) >> 1) << surface->format->Ashift;
+ break;
+ case SPG_COPY_NO_ALPHA: // Direct copy, alpha opaque
+ if(Amask)
+ A = (SDL_ALPHA_OPAQUE << surface->format->Ashift);
+ break;
+ case SPG_COPY_ALPHA_ONLY: // Direct copy of just the alpha
+ R = dc & Rmask;
+ G = dc & Gmask;
+ B = dc & Bmask;
+ if(Amask)
+ A = (alpha << surface->format->Ashift);
+ break;
+ case SPG_COMBINE_ALPHA_ONLY: // Blend of just the alpha
+ R = dc & Rmask;
+ G = dc & Gmask;
+ B = dc & Bmask;
+ if(Amask)
+ A = ((((dc & Amask) >> surface->format->Ashift) + alpha) >> 1) << surface->format->Ashift;
+ break;
+ case SPG_REPLACE_COLORKEY: // Replace the colorkeyed color
+ if(!(surface->flags & SDL_SRCCOLORKEY) || dc != surface->format->colorkey)
+ return;
+ if(Amask)
+ A = (alpha << surface->format->Ashift);
+ break;
+ }
+
+ *pixel = R | G | B | A;
+ break;
+ }
+ }
+}
+
+void SPG_PixelBlend(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color, Uint8 alpha)
+{
+ if(spg_lock(surface) < 0)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_PixelBlend could not lock surface");
+ return;
+ }
+
+ if(spg_thickness == 1)
+ {
+ spg_pixelblend(surface,x,y,color, alpha);
+ /* unlock the display */
+
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = x;
+ rect.y = y;
+ rect.w = 1;
+ rect.h = 1;
+ // Clip it to the screen
+ SPG_DirtyClip(surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+ else
+ {
+ if(spg_thickness == 0) return;
+ spg_alphahack = alpha;
+ spg_thicknesscallbackalpha(surface, x, y, color);
+
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.w = spg_thickness;
+ rect.h = spg_thickness;
+ rect.x = x - rect.w/2;
+ rect.y = y - rect.h/2;
+ SPG_DirtyClip(surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+
+ spg_unlock(surface);
+
+}
+
+void SPG_PixelPattern(SDL_Surface *surface, SDL_Rect target, SPG_bool* pattern, Uint32* colors)
+{
+ if(spg_lock(surface) < 0)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_PixelPattern could not lock surface");
+ return;
+ }
+
+ int x = target.x, y = target.y;
+ int ox = x;//, oy = y;
+ int w = target.w, h = target.h, wh = w*h;
+ int xw = x+w, yh = y+h;
+ Uint32 color;
+ int i;
+
+
+ switch (surface->format->BytesPerPixel)
+ {
+ case 1: /* Assuming 8-bpp */
+ for (i = 0; i < wh; i++)
+ {
+ color = colors[i];
+ if (pattern[i] && x>=SPG_CLIP_XMIN(surface) && x<=SPG_CLIP_XMAX(surface) && y>=SPG_CLIP_YMIN(surface) && y<=SPG_CLIP_YMAX(surface))
+ {
+ *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
+ }
+
+ x++;
+ if (x >= xw)
+ {
+ x = ox;
+ y++;
+ if (y >= yh)
+ break;
+ }
+ }
+ break;
+
+ case 2: /* Probably 15-bpp or 16-bpp */
+ for (i = 0; i < wh; i++)
+ {
+ color = colors[i];
+ if (pattern[i] && x>=SPG_CLIP_XMIN(surface) && x<=SPG_CLIP_XMAX(surface) && y>=SPG_CLIP_YMIN(surface) && y<=SPG_CLIP_YMAX(surface))
+ {
+ *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
+ }
+
+ x++;
+ if (x >= xw)
+ {
+ x = ox;
+ y++;
+ if (y >= yh)
+ break;
+ }
+ }
+ break;
+
+ case 3: /* Slow 24-bpp mode, usually not used */
+ for (i = 0; i < wh; i++)
+ {
+ color = colors[i];
+ if (pattern[i] && x>=SPG_CLIP_XMIN(surface) && x<=SPG_CLIP_XMAX(surface) && y>=SPG_CLIP_YMIN(surface) && y<=SPG_CLIP_YMAX(surface))
+ {
+ Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
+
+ /* Gack - slow, but endian correct */
+ *(pix+surface->format->Rshift/8) = color>>surface->format->Rshift;
+ *(pix+surface->format->Gshift/8) = color>>surface->format->Gshift;
+ *(pix+surface->format->Bshift/8) = color>>surface->format->Bshift;
+ *(pix+surface->format->Ashift/8) = color>>surface->format->Ashift;
+ }
+
+ x++;
+ if (x >= xw)
+ {
+ x = ox;
+ y++;
+ if (y >= yh)
+ break;
+ }
+ }
+ break;
+
+ case 4: /* Probably 32-bpp */
+ for (i = 0; i < wh; i++)
+ {
+ color = colors[i];
+ if (pattern[i] && x>=SPG_CLIP_XMIN(surface) && x<=SPG_CLIP_XMAX(surface) && y>=SPG_CLIP_YMIN(surface) && y<=SPG_CLIP_YMAX(surface))
+ {
+ *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
+ }
+
+ x++;
+ if (x >= xw)
+ {
+ x = ox;
+ y++;
+ if (y >= yh)
+ break;
+ }
+ }
+ break;
+ }
+
+
+
+
+ spg_unlock(surface);
+
+ if(spg_makedirtyrects)
+ {
+ SPG_DirtyClip(surface, &target);
+ SPG_DirtyAddTo(spg_dirtytable_front, &target);
+ }
+}
+
+
+
+void SPG_PixelPatternBlend(SDL_Surface *surface, SDL_Rect target, SPG_bool* pattern, Uint32* colors, Uint8* pixelAlpha)
+{
+ if(spg_lock(surface) < 0)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_PixelPatternBlend could not lock surface");
+ return;
+ }
+
+ int x = target.x, y = target.y;
+ int ox = x;//, oy = y;
+ int w = target.w, h = target.h, wh = w*h;
+ int xw = x+w, yh = y+h;
+ Uint32 color;
+ Uint8 alpha;
+ Uint32 Rmask = surface->format->Rmask, Gmask = surface->format->Gmask, Bmask = surface->format->Bmask, Amask = surface->format->Amask;
+ Uint32 R,G,B,A=SDL_ALPHA_OPAQUE;
+ int i;
+
+ for (i = 0; i < wh; i++)
+ {
+ if (pattern[i] && x>=SPG_CLIP_XMIN(surface) && x<=SPG_CLIP_XMAX(surface) && y>=SPG_CLIP_YMIN(surface) && y<=SPG_CLIP_YMAX(surface))
+ {
+ color = colors[i];
+ alpha = pixelAlpha[i];
+
+ switch (surface->format->BytesPerPixel)
+ {
+ case 1: /* Assuming 8-bpp */
+ {
+ if ( alpha == SDL_ALPHA_OPAQUE )
+ {
+ *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
+ }
+ else
+ {
+ Uint8 *pixel = (Uint8 *)surface->pixels + y*surface->pitch + x;
+
+ Uint8 dR = surface->format->palette->colors[*pixel].r;
+ Uint8 dG = surface->format->palette->colors[*pixel].g;
+ Uint8 dB = surface->format->palette->colors[*pixel].b;
+ Uint8 sR = surface->format->palette->colors[color].r;
+ Uint8 sG = surface->format->palette->colors[color].g;
+ Uint8 sB = surface->format->palette->colors[color].b;
+
+ dR = dR + ((sR-dR)*alpha >> 8);
+ dG = dG + ((sG-dG)*alpha >> 8);
+ dB = dB + ((sB-dB)*alpha >> 8);
+
+ *pixel = SDL_MapRGB(surface->format, dR, dG, dB);
+ }
+ }
+ break;
+
+ case 2: /* Probably 15-bpp or 16-bpp */
+ {
+ if ( alpha == SDL_ALPHA_OPAQUE )
+ {
+ *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
+ }
+ else
+ {
+ Uint16 *pixel = (Uint16 *)surface->pixels + y*surface->pitch/2 + x;
+ Uint32 dc = *pixel;
+
+ R = ((dc & Rmask) + (( (color & Rmask) - (dc & Rmask) ) * alpha >> 8)) & Rmask;
+ G = ((dc & Gmask) + (( (color & Gmask) - (dc & Gmask) ) * alpha >> 8)) & Gmask;
+ B = ((dc & Bmask) + (( (color & Bmask) - (dc & Bmask) ) * alpha >> 8)) & Bmask;
+ if ( Amask )
+ A = ((dc & Amask) + (( (color & Amask) - (dc & Amask) ) * alpha >> 8)) & Amask;
+
+ *pixel= R | G | B | A;
+ }
+ }
+ break;
+
+ case 3: /* Slow 24-bpp mode, usually not used */
+ {
+ Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
+ Uint8 rshift8=surface->format->Rshift/8;
+ Uint8 gshift8=surface->format->Gshift/8;
+ Uint8 bshift8=surface->format->Bshift/8;
+ Uint8 ashift8=surface->format->Ashift/8;
+
+
+ if ( alpha == SDL_ALPHA_OPAQUE )
+ {
+ *(pix+rshift8) = color>>surface->format->Rshift;
+ *(pix+gshift8) = color>>surface->format->Gshift;
+ *(pix+bshift8) = color>>surface->format->Bshift;
+ *(pix+ashift8) = color>>surface->format->Ashift;
+ }
+ else
+ {
+ Uint8 dR, dG, dB, dA=0;
+ Uint8 sR, sG, sB, sA=0;
+
+ pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
+
+ dR = *((pix)+rshift8);
+ dG = *((pix)+gshift8);
+ dB = *((pix)+bshift8);
+ dA = *((pix)+ashift8);
+
+ sR = (color>>surface->format->Rshift)&0xff;
+ sG = (color>>surface->format->Gshift)&0xff;
+ sB = (color>>surface->format->Bshift)&0xff;
+ sA = (color>>surface->format->Ashift)&0xff;
+
+ dR = dR + ((sR-dR)*alpha >> 8);
+ dG = dG + ((sG-dG)*alpha >> 8);
+ dB = dB + ((sB-dB)*alpha >> 8);
+ dA = dA + ((sA-dA)*alpha >> 8);
+
+ *((pix)+rshift8) = dR;
+ *((pix)+gshift8) = dG;
+ *((pix)+bshift8) = dB;
+ *((pix)+ashift8) = dA;
+ }
+ }
+ break;
+
+ case 4: /* Probably 32-bpp */
+ {
+ if ( alpha == SDL_ALPHA_OPAQUE )
+ {
+ *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
+ }
+ else
+ {
+ Uint32 *pixel = (Uint32 *)surface->pixels + y*surface->pitch/4 + x;
+ Uint32 dc = *pixel;
+ R = color & Rmask;
+ G = color & Gmask;
+ B = color & Bmask;
+ A = 0;
+
+
+ switch (SPG_GetBlend())
+ {
+ case SPG_COMBINE_ALPHA: // Blend and combine src and dest alpha, SLOW IMPLEMENTATION
+ R = ((dc & Rmask) + (( R - (dc & Rmask) ) * alpha >> 8)) & Rmask;
+ G = ((dc & Gmask) + (( G - (dc & Gmask) ) * alpha >> 8)) & Gmask;
+ B = ((dc & Bmask) + (( B - (dc & Bmask) ) * alpha >> 8)) & Bmask;
+ if (Amask)
+ A = ((((dc & Amask) >> surface->format->Ashift) + alpha) >> 1) << surface->format->Ashift;
+ break;
+ case SPG_DEST_ALPHA: // Blend and keep dest alpha
+ R = ((dc & Rmask) + (( R - (dc & Rmask) ) * alpha >> 8)) & Rmask;
+ G = ((dc & Gmask) + (( G - (dc & Gmask) ) * alpha >> 8)) & Gmask;
+ B = ((dc & Bmask) + (( B - (dc & Bmask) ) * alpha >> 8)) & Bmask;
+ if (Amask)
+ A = (dc & Amask);
+ break;
+ case SPG_SRC_ALPHA: // Blend and keep src alpha
+ R = ((dc & Rmask) + (( R - (dc & Rmask) ) * alpha >> 8)) & Rmask;
+ G = ((dc & Gmask) + (( G - (dc & Gmask) ) * alpha >> 8)) & Gmask;
+ B = ((dc & Bmask) + (( B - (dc & Bmask) ) * alpha >> 8)) & Bmask;
+ if (Amask)
+ A = (alpha << surface->format->Ashift);
+ break;
+ case SPG_COPY_SRC_ALPHA: // Direct copy with src alpha
+ if (Amask)
+ A = (alpha << surface->format->Ashift);
+ break;
+ case SPG_COPY_DEST_ALPHA: // Direct copy with dest alpha
+ if (Amask)
+ A = (dc & Amask);
+ break;
+ case SPG_COPY_COMBINE_ALPHA: // Direct copy with combined alpha, SLOW IMPLEMENTATION
+ if (Amask)
+ A = ((((dc & Amask) >> surface->format->Ashift) + alpha) >> 1) << surface->format->Ashift;
+ break;
+ case SPG_COPY_NO_ALPHA: // Direct copy, alpha opaque
+ break;
+ case SPG_COPY_ALPHA_ONLY: // Direct copy of just the alpha
+ R = dc & Rmask;
+ G = dc & Gmask;
+ B = dc & Bmask;
+ if(Amask)
+ A = (alpha << surface->format->Ashift);
+ break;
+ case SPG_COMBINE_ALPHA_ONLY: // Blend of just the alpha
+ R = dc & Rmask;
+ G = dc & Gmask;
+ B = dc & Bmask;
+ if(Amask)
+ A = ((((dc & Amask) >> surface->format->Ashift) + alpha) >> 1) << surface->format->Ashift;
+ break;
+ case SPG_REPLACE_COLORKEY: // Replace the colorkeyed color
+ if(!(surface->flags & SDL_SRCCOLORKEY) || dc != surface->format->colorkey)
+ return;
+ if(Amask)
+ A = (alpha << surface->format->Ashift);
+ break;
+ }
+
+ *pixel = R | G | B | A;
+ }
+ }
+ break;
+ }
+ }
+
+
+ x++;
+ if (x >= xw)
+ {
+ x = ox;
+ y++;
+ if (y >= yh)
+ break;
+ }
+
+ }
+
+ spg_unlock(surface);
+
+ if(spg_makedirtyrects)
+ {
+ SPG_DirtyClip(surface, &target);
+ SPG_DirtyAddTo(spg_dirtytable_front, &target);
+ }
+}
+
+
+
+
+
+
+
+/**********************************************************************************/
+/** Line functions **/
+/**********************************************************************************/
+
+//==================================================================================
+// Internal draw horizontal line
+//==================================================================================
+void spg_lineh(SDL_Surface *Surface, Sint16 x1, Sint16 y, Sint16 x2, Uint32 Color)
+{
+ if (x1>x2)
+ {
+ Sint16 tmp=x1;
+ x1=x2;
+ x2=tmp;
+ }
+
+ //Do the clipping
+#if SDL_VERSIONNUM(SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL) < \
+ SDL_VERSIONNUM(1, 1, 5)
+ if (y<Surface->clip_miny || y>Surface->clip_maxy || x1>Surface->clip_maxx || x2<Surface->clip_minx)
+ return;
+ if (x1<Surface->clip_minx)
+ x1=Surface->clip_minx;
+ if (x2>Surface->clip_maxx)
+ x2=Surface->clip_maxx;
+#endif
+
+ SDL_Rect l;
+ l.x=x1;
+ l.y=y;
+ l.w=x2-x1+1;
+ l.h=1;
+
+ SDL_FillRect(Surface, &l, Color);
+}
+
+//==================================================================================
+// Draw horizontal line
+//==================================================================================
+void SPG_LineH(SDL_Surface *Surface, Sint16 x1, Sint16 y, Sint16 x2, Uint32 Color)
+{
+ if (x1>x2)
+ {
+ Sint16 tmp=x1;
+ x1=x2;
+ x2=tmp;
+ }
+
+ //Do the clipping
+#if SDL_VERSIONNUM(SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL) < \
+ SDL_VERSIONNUM(1, 1, 5)
+ if (y<Surface->clip_miny || y>Surface->clip_maxy || x1>Surface->clip_maxx || x2<Surface->clip_minx)
+ return;
+ if (x1<Surface->clip_minx)
+ x1=Surface->clip_minx;
+ if (x2>Surface->clip_maxx)
+ x2=Surface->clip_maxx;
+#endif
+
+ SDL_Rect l;
+ l.x=x1;
+ l.y=y;
+ l.w=x2-x1+1;
+ l.h=1;
+
+ if(spg_thickness == 1)
+ SDL_FillRect(Surface, &l, Color);
+ else
+ {
+ if(spg_thickness == 0) return;
+ l.h = spg_thickness;
+ l.y -= (l.h - 1)/2;
+ SDL_FillRect(Surface, &l, Color);
+ //SPG_DirtyClip(Surface, &l);
+ }
+
+ if(spg_makedirtyrects)
+ {
+ SPG_DirtyAddTo(spg_dirtytable_front, &l);
+ }
+}
+
+
+//==================================================================================
+// Internal draw horizontal line (alpha)
+//==================================================================================
+void spg_linehblend(SDL_Surface *Surface, Sint16 x1, Sint16 y, Sint16 x2, Uint32 Color, Uint8 alpha)
+{
+ // Disable autolock so that other functions can use this one a lot.
+ Uint8 lock = spg_autolock;
+ spg_autolock = 0;
+
+ SPG_RectFilledBlend(Surface, x1,y,x2,y, Color, alpha);
+
+ spg_autolock = lock;
+}
+
+//==================================================================================
+// Draw horizontal line (alpha)
+//==================================================================================
+void SPG_LineHBlend(SDL_Surface *Surface, Sint16 x1, Sint16 y, Sint16 x2, Uint32 Color, Uint8 alpha)
+{
+ if(spg_thickness == 1)
+ SPG_RectFilledBlend(Surface, x1,y,x2,y, Color, alpha);
+ else
+ {
+ if(spg_thickness == 0) return;
+ Sint16 h = spg_thickness;
+ y -= (h - 1)/2;
+ SPG_RectFilledBlend(Surface, x1,y,x2,y+h-1, Color, alpha);
+ }
+}
+
+
+
+//==================================================================================
+// Internal draw vertical line
+//==================================================================================
+void spg_linev(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
+{
+ if (y1>y2)
+ {
+ Sint16 tmp=y1;
+ y1=y2;
+ y2=tmp;
+ }
+
+ //Do the clipping
+#if SDL_VERSIONNUM(SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL) < \
+ SDL_VERSIONNUM(1, 1, 5)
+ if (x<Surface->clip_minx || x>Surface->clip_maxx || y1>Surface->clip_maxy || y2<Surface->clip_miny)
+ return;
+ if (y1<Surface->clip_miny)
+ y1=Surface->clip_miny;
+ if (y2>Surface->clip_maxy)
+ y2=Surface->clip_maxy;
+#endif
+
+ SDL_Rect l;
+ l.x=x;
+ l.y=y1;
+ l.w=1;
+ l.h=y2-y1+1;
+
+ SDL_FillRect(Surface, &l, Color);
+}
+
+//==================================================================================
+// Draw vertical line
+//==================================================================================
+void SPG_LineV(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color)
+{
+ if (y1>y2)
+ {
+ Sint16 tmp=y1;
+ y1=y2;
+ y2=tmp;
+ }
+
+ //Do the clipping
+#if SDL_VERSIONNUM(SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL) < \
+ SDL_VERSIONNUM(1, 1, 5)
+ if (x<Surface->clip_minx || x>Surface->clip_maxx || y1>Surface->clip_maxy || y2<Surface->clip_miny)
+ return;
+ if (y1<Surface->clip_miny)
+ y1=Surface->clip_miny;
+ if (y2>Surface->clip_maxy)
+ y2=Surface->clip_maxy;
+#endif
+
+ SDL_Rect l;
+ l.x=x;
+ l.y=y1;
+ l.w=1;
+ l.h=y2-y1+1;
+
+ if(spg_thickness == 1)
+ SDL_FillRect(Surface, &l, Color);
+ else
+ {
+ if(spg_thickness == 0) return;
+ l.w = spg_thickness;
+ l.x -= (l.w - 1)/2;
+ SDL_FillRect(Surface, &l, Color);
+ //SPG_DirtyClip(Surface, &l);
+ }
+
+ if(spg_makedirtyrects)
+ {
+ SPG_DirtyAddTo(spg_dirtytable_front, &l);
+ }
+}
+
+
+
+
+//==================================================================================
+// Internal draw vertical line (alpha - no update)
+//==================================================================================
+void spg_linevblend(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color, Uint8 alpha)
+{
+ // Disable autolock so other functions can use this one a lot.
+ Uint8 lock = spg_autolock;
+ spg_autolock = 0;
+ SPG_RectFilledBlend(Surface, x,y1,x,y2, Color, alpha);
+ spg_autolock = lock;
+}
+
+//==================================================================================
+// Draw vertical line (alpha)
+//==================================================================================
+void SPG_LineVBlend(SDL_Surface *Surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color, Uint8 alpha)
+{
+ if(spg_thickness == 1)
+ SPG_RectFilledBlend(Surface, x,y1,x,y2, Color, alpha);
+ else
+ {
+ if(spg_thickness == 0) return;
+ Sint16 w = spg_thickness;
+ x -= (w - 1)/2;
+ SPG_RectFilledBlend(Surface, x,y1,x+w-1,y2, Color, alpha);
+ }
+}
+
+
+
+
+//==================================================================================
+// Performs Callback at each line point. (From PowerPak)
+//==================================================================================
+void SPG_LineFn(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 Color, void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y, Uint32 Color))
+{
+ Sint16 dx, dy, sdx, sdy, x, y, px, py;
+
+ dx = x2 - x1;
+ dy = y2 - y1;
+
+ sdx = (dx < 0) ? -1 : 1;
+ sdy = (dy < 0) ? -1 : 1;
+
+ dx = sdx * dx + 1;
+ dy = sdy * dy + 1;
+
+ x = y = 0;
+
+ px = x1;
+ py = y1;
+
+ if (dx >= dy)
+ {
+ for (x = 0; x < dx; x++)
+ {
+ Callback(Surface, px, py, Color);
+
+ y += dy;
+ if (y >= dx)
+ {
+ y -= dx;
+ py += sdy;
+ }
+ px += sdx;
+ }
+ }
+ else
+ {
+ for (y = 0; y < dy; y++)
+ {
+ Callback(Surface, px, py, Color);
+
+ x += dx;
+ if (x >= dy)
+ {
+ x -= dy;
+ px += sdx;
+ }
+ py += sdy;
+ }
+ }
+}
+
+
+
+
+//==================================================================================
+// Line clipping
+// Standard Cohen-Sutherland algorithm (from gfxPrimitives)
+//==================================================================================
+#define CLIP_LEFT_EDGE 0x1
+#define CLIP_RIGHT_EDGE 0x2
+#define CLIP_BOTTOM_EDGE 0x4
+#define CLIP_TOP_EDGE 0x8
+#define CLIP_INSIDE(a) (!a)
+#define CLIP_REJECT(a,b) (a&b)
+#define CLIP_ACCEPT(a,b) (!(a|b))
+
+int spg_clipencode(Sint16 x, Sint16 y, Sint16 left, Sint16 top, Sint16 right, Sint16 bottom)
+{
+ int code = 0;
+
+ if (x < left)
+ code |= CLIP_LEFT_EDGE;
+ else if (x > right)
+ code |= CLIP_RIGHT_EDGE;
+
+ if (y < top)
+ code |= CLIP_TOP_EDGE;
+ else if (y > bottom)
+ code |= CLIP_BOTTOM_EDGE;
+
+ return code;
+}
+
+int spg_clipline(SDL_Surface *dst, Sint16 *x1, Sint16 *y1, Sint16 *x2, Sint16 *y2)
+{
+ int code1, code2;
+ SPG_bool draw = 0;
+
+ Sint16 tmp;
+ float m;
+
+ /* Get clipping boundary */
+ Sint16 left, right, top, bottom;
+ left = SPG_CLIP_XMIN(dst);
+ right = SPG_CLIP_XMAX(dst);
+ top = SPG_CLIP_YMIN(dst);
+ bottom = SPG_CLIP_YMAX(dst);
+
+ while (1)
+ {
+ code1 = spg_clipencode(*x1, *y1, left, top, right, bottom);
+ code2 = spg_clipencode(*x2, *y2, left, top, right, bottom);
+
+ if (CLIP_ACCEPT(code1, code2))
+ {
+ draw = 1;
+ break;
+ }
+ else if (CLIP_REJECT(code1, code2))
+ break;
+ else
+ {
+ if (CLIP_INSIDE(code1))
+ {
+ tmp = *x2;
+ *x2 = *x1;
+ *x1 = tmp;
+ tmp = *y2;
+ *y2 = *y1;
+ *y1 = tmp;
+ tmp = code2;
+ code2 = code1;
+ code1 = tmp;
+ }
+ if (*x2 != *x1)
+ m = (*y2 - *y1) / (float)(*x2 - *x1);
+ else
+ m = 1.0;
+
+
+ if (code1 & CLIP_LEFT_EDGE)
+ {
+ *y1 += (Sint16)( (left - *x1) * m );
+ *x1 = left;
+ }
+ else if (code1 & CLIP_RIGHT_EDGE)
+ {
+ *y1 += (Sint16)( (right - *x1) * m );
+ *x1 = right;
+ }
+ else if (code1 & CLIP_BOTTOM_EDGE)
+ {
+ if (*x2 != *x1)
+ {
+ *x1 += (Sint16)( (bottom - *y1) / m );
+ }
+ *y1 = bottom;
+ }
+ else if (code1 & CLIP_TOP_EDGE)
+ {
+ if (*x2 != *x1)
+ {
+ *x1 += (Sint16)( (top - *y1) / m );
+ }
+ *y1 = top;
+ }
+ }
+ }
+
+ return draw;
+}
+
+
+//==================================================================================
+// Draws a line
+//==================================================================================
+void spg_line(SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
+{
+ if ( !spg_clipline(surface, &x1, &y1, &x2, &y2) )
+ return;
+
+ Sint16 dx, dy, sdx, sdy, x, y;
+
+ dx = x2 - x1;
+ dy = y2 - y1;
+
+ sdx = (dx < 0) ? -1 : 1;
+ sdy = (dy < 0) ? -1 : 1;
+
+ dx = sdx * dx + 1;
+ dy = sdy * dy + 1;
+
+ x = y = 0;
+
+ Sint16 pixx = surface->format->BytesPerPixel;
+ Sint16 pixy = surface->pitch;
+ Uint8 *pixel = (Uint8*)surface->pixels + y1*pixy + x1*pixx;
+
+ pixx *= sdx;
+ pixy *= sdy;
+
+ if (dx < dy)
+ {
+ Sint32 tmp = dx;
+ dx = dy;
+ dy = (Sint16)(tmp);
+ tmp = pixx;
+ pixx = pixy;
+ pixy = tmp;
+ }
+
+ switch (surface->format->BytesPerPixel)
+ {
+ case 1:
+ {
+ for (x=0; x < dx; x++)
+ {
+ *pixel = color;
+
+ y += dy;
+ if (y >= dx)
+ {
+ y -= dx;
+ pixel += pixy;
+ }
+ pixel += pixx;
+ }
+ }
+ break;
+
+ case 2:
+ {
+ for (x=0; x < dx; x++)
+ {
+ *(Uint16*)pixel = color;
+
+ y += dy;
+ if (y >= dx)
+ {
+ y -= dx;
+ pixel += pixy;
+ }
+ pixel += pixx;
+ }
+ }
+ break;
+
+ case 3:
+ {
+ Uint8 rshift8 = surface->format->Rshift/8;
+ Uint8 gshift8 = surface->format->Gshift/8;
+ Uint8 bshift8 = surface->format->Bshift/8;
+ Uint8 ashift8 = surface->format->Ashift/8;
+
+ Uint8 R = (color>>surface->format->Rshift)&0xff;
+ Uint8 G = (color>>surface->format->Gshift)&0xff;
+ Uint8 B = (color>>surface->format->Bshift)&0xff;
+ Uint8 A = (color>>surface->format->Ashift)&0xff;
+
+ for (x=0; x < dx; x++)
+ {
+ *(pixel+rshift8) = R;
+ *(pixel+gshift8) = G;
+ *(pixel+bshift8) = B;
+ *(pixel+ashift8) = A;
+
+ y += dy;
+ if (y >= dx)
+ {
+ y -= dx;
+ pixel += pixy;
+ }
+ pixel += pixx;
+ }
+ }
+ break;
+
+ case 4:
+ {
+ for (x=0; x < dx; x++)
+ {
+ *(Uint32*)pixel = color;
+
+ y += dy;
+ if (y >= dx)
+ {
+ y -= dx;
+ pixel += pixy;
+ }
+ pixel += pixx;
+ }
+ }
+ break;
+ }
+}
+
+void spg_lineblendaa(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha);
+
+void SPG_Line(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
+{
+ if (spg_lock(Surface) < 0)
+ return;
+
+ if(spg_thickness == 1)
+ {
+ if(SPG_GetAA())
+ spg_lineblendaa(Surface,x1,y1,x2,y2,color, SDL_ALPHA_OPAQUE);
+ else
+ spg_line(Surface, x1,y1, x2,y2, color);
+
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = MIN(x1, x2);
+ rect.y = MIN(y1, y2);
+ rect.w = MAX(x1, x2) - rect.x + 1;
+ rect.h = MAX(y1, y2) - rect.y + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+ else if(spg_thickness > 0)
+ {
+ SPG_LineFn(Surface, x1,y1, x2,y2, color, spg_thicknesscallback);
+
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = MIN(x1, x2) - spg_thickness/2;
+ rect.y = MIN(y1, y2) - spg_thickness/2;
+ rect.w = MAX(x1, x2) - rect.x + 1 + spg_thickness;
+ rect.h = MAX(y1, y2) - rect.y + 1 + spg_thickness;
+ // Clip it to the screen
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+
+ spg_unlock(Surface);
+
+}
+
+
+
+
+//==================================================================================
+// A quick hack to get alpha working with callbacks
+//==================================================================================
+
+void spg_pixelcallbackalpha(SDL_Surface *surf, Sint16 x, Sint16 y, Uint32 color)
+{
+ spg_pixelblend(surf,x,y,color,spg_alphahack);
+}
+
+
+//==================================================================================
+// Draws a line (alpha)
+//==================================================================================
+void spg_lineblend(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 Color, Uint8 alpha)
+{
+ spg_alphahack = alpha;
+
+ /* Draw the line */
+ SPG_LineFn(Surface, x1, y1, x2, y2, Color, spg_pixelcallbackalpha);
+}
+
+//==================================================================================
+// Anti-aliased line
+// From SDL_gfxPrimitives written by A. Schiffler (aschiffler@home.com)
+//==================================================================================
+#define AAbits 8
+#define AAlevels 256 /* 2^AAbits */
+void spg_lineblendaa(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha)
+{
+
+ Uint32 erracc=0, erradj;
+ Uint32 erracctmp, wgt;
+ Sint16 tmp, y0p1, x0pxdir;
+ Uint8 a;
+
+ /* Keep on working with 32bit numbers */
+ Sint32 xx0=x1;
+ Sint32 yy0=y1;
+ Sint32 xx1=x2;
+ Sint32 yy1=y2;
+
+ /* Reorder points if required */
+ if (yy0 > yy1)
+ {
+ SWAP(yy0, yy1, tmp);
+ SWAP(xx0, xx1, tmp);
+ }
+
+ /* Calculate distance */
+ Sint16 dx = xx1 - xx0;
+ Sint16 dy = yy1 - yy0;
+
+ /* Adjust for negative dx and set xdir */
+ Sint16 xdir = 1;
+ if (dx < 0)
+ {
+ xdir=-1;
+ dx=(-dx);
+ }
+
+ /* Check for special cases */
+ if (dx==0 || dy==0 || dx==dy)
+ {
+ if (alpha==SDL_ALPHA_OPAQUE)
+ spg_line(dst,x1,y1,x2,y2,color);
+ else
+ spg_lineblend(dst,x1,y1,x2,y2,color,alpha);
+ return;
+ }
+
+ float alpha_pp = (float)(alpha)/255; /* Used to calculate alpha level if alpha != 255 */
+
+ Uint32 intshift = 32 - AAbits; /* # of bits by which to shift erracc to get intensity level */
+
+ /* Draw the initial pixel in the foreground color */
+ if (alpha==SDL_ALPHA_OPAQUE)
+ spg_pixel(dst,x1,y1, color);
+ else
+ spg_pixelblend(dst,x1,y1, color, alpha);
+
+ /* x-major or y-major? */
+ if (dy > dx)
+ {
+
+ /* y-major. Calculate 16-bit fixed point fractional part of a pixel that
+ X advances every time Y advances 1 pixel, truncating the result so that
+ we won't overrun the endpoint along the X axis */
+ erradj = ((dx << 16) / dy)<<16;
+
+ /* draw all pixels other than the first and last */
+ x0pxdir=xx0+xdir;
+ while (--dy)
+ {
+ erracctmp = erracc;
+ erracc += erradj;
+ if (erracc <= erracctmp)
+ {
+ /* rollover in error accumulator, x coord advances */
+ xx0=x0pxdir;
+ x0pxdir += xdir;
+ }
+ yy0++; /* y-major so always advance Y */
+
+ /* the AAbits most significant bits of erracc give us the intensity
+ weighting for this pixel, and the complement of the weighting for
+ the paired pixel. */
+ wgt = (erracc >> intshift) & 255;
+
+ a = (Uint8)(255-wgt);
+ if (alpha != SDL_ALPHA_OPAQUE)
+ a = (Uint8)(a*alpha_pp);
+
+ spg_pixelblend(dst,xx0,yy0,color,a);
+
+ a = (Uint8)(wgt);
+ if (alpha != SDL_ALPHA_OPAQUE)
+ a = (Uint8)(a*alpha_pp);
+
+ spg_pixelblend(dst,x0pxdir,yy0,color,a);
+ }
+ }
+ else
+ {
+
+ /* x-major line. Calculate 16-bit fixed-point fractional part of a pixel
+ that Y advances each time X advances 1 pixel, truncating the result so
+ that we won't overrun the endpoint along the X axis. */
+ erradj = ((dy << 16) / dx)<<16;
+
+ /* draw all pixels other than the first and last */
+ y0p1=yy0+1;
+ while (--dx)
+ {
+
+ erracctmp = erracc;
+ erracc += erradj;
+ if (erracc <= erracctmp)
+ {
+ /* Accumulator turned over, advance y */
+ yy0=y0p1;
+ y0p1++;
+ }
+ xx0 += xdir; /* x-major so always advance X */
+
+ /* the AAbits most significant bits of erracc give us the intensity
+ weighting for this pixel, and the complement of the weighting for
+ the paired pixel. */
+ wgt = (erracc >> intshift) & 255;
+
+ a = (Uint8)(255-wgt);
+ if (alpha != SDL_ALPHA_OPAQUE)
+ a = (Uint8)(a*alpha_pp);
+
+ spg_pixelblend(dst,xx0,yy0,color,a);
+
+ a = (Uint8)(wgt);
+ if (alpha != SDL_ALPHA_OPAQUE)
+ a = (Uint8)(a*alpha_pp);
+
+ spg_pixelblend(dst,xx0,y0p1,color,a);
+ }
+ }
+
+ /* Draw final pixel, always exactly intersected by the line and doesn't
+ need to be weighted. */
+ if (alpha==SDL_ALPHA_OPAQUE)
+ spg_pixel(dst,x2,y2, color);
+ else
+ spg_pixelblend(dst,x2,y2, color, alpha);
+
+}
+
+void SPG_LineBlend(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha)
+{
+ if (spg_lock(Surface) < 0)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_LineBlend could not lock surface");
+ return;
+ }
+
+ if(spg_thickness == 1)
+ {
+ if(SPG_GetAA())
+ spg_lineblendaa(Surface,x1,y1,x2,y2,color, alpha);
+ else
+ spg_lineblend(Surface, x1, y1, x2, y2, color, alpha);
+
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = MIN(x1, x2);
+ rect.y = MIN(y1, y2);
+ rect.w = MAX(x1, x2) - rect.x + 1;
+ rect.h = MAX(y1, y2) - rect.y + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+ else if(spg_thickness > 0)
+ {
+ spg_alphahack = alpha;
+ SPG_LineFn(Surface, x1, y1, x2, y2, color, spg_thicknesscallbackalpha);
+
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = MIN(x1, x2) - spg_thickness/2;
+ rect.y = MIN(y1, y2) - spg_thickness/2;
+ rect.w = MAX(x1, x2) - rect.x + 1 + spg_thickness;
+ rect.h = MAX(y1, y2) - rect.y + 1 + spg_thickness;
+ // Clip it to the screen
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+
+ spg_unlock(Surface);
+
+}
+
+
+
+
+
+
+//==================================================================================
+// Draws a multicolored line
+//==================================================================================
+void SPG_LineFadeFn(SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color1, Uint32 color2, void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y, Uint32 Color))
+{
+ Sint16 dx, dy, sdx, sdy, x, y, px, py;
+
+ dx = x2 - x1;
+ dy = y2 - y1;
+
+ sdx = (dx < 0) ? -1 : 1;
+ sdy = (dy < 0) ? -1 : 1;
+
+ dx = sdx * dx + 1;
+ dy = sdy * dy + 1;
+
+ x = y = 0;
+
+ px = x1;
+ py = y1;
+
+ Uint8 r1, g1, b1, r2, g2, b2;
+
+ if(surface->format->BitsPerPixel == 8)
+ {
+ SDL_GetRGB(color1, surface->format, &r1, &g1, &b1);
+ SDL_GetRGB(color2, surface->format, &r2, &g2, &b2);
+ }
+ else
+ {
+ r1 = (color1 & surface->format->Rmask) >> surface->format->Rshift;
+ g1 = (color1 & surface->format->Gmask) >> surface->format->Gshift;
+ b1 = (color1 & surface->format->Bmask) >> surface->format->Bshift;
+ r2 = (color2 & surface->format->Rmask) >> surface->format->Rshift;
+ g2 = (color2 & surface->format->Gmask) >> surface->format->Gshift;
+ b2 = (color2 & surface->format->Bmask) >> surface->format->Bshift;
+ }
+
+
+ /* We use fixedpoint math for the color fading */
+ Sint32 R = r1<<16;
+ Sint32 G = g1<<16;
+ Sint32 B = b1<<16;
+ Sint32 R2 = r2<<16;
+ Sint32 G2 = g2<<16;
+ Sint32 B2 = b2<<16;
+ Sint32 rstep;
+ Sint32 gstep;
+ Sint32 bstep;
+
+ if (dx >= dy)
+ {
+ rstep = (R2-R) / (Sint32)(dx);
+ gstep = (G2-G) / (Sint32)(dx);
+ bstep = (B2-B) / (Sint32)(dx);
+
+ for (x = 0; x < dx; x++)
+ {
+ Callback(surface, px, py, SDL_MapRGB(surface->format, (Uint8)(R>>16), (Uint8)(G>>16), (Uint8)(B>>16)) );
+
+ y += dy;
+ if (y >= dx)
+ {
+ y -= dx;
+ py += sdy;
+ }
+ px += sdx;
+
+ R += rstep;
+ G += gstep;
+ B += bstep;
+ }
+ }
+ else
+ {
+ // Why is this different than above?
+ rstep = (Sint32)((r2-r1)<<16) / (Sint32)(dy);
+ gstep = (Sint32)((g2-g1)<<16) / (Sint32)(dy);
+ bstep = (Sint32)((b2-b1)<<16) / (Sint32)(dy);
+
+ for (y = 0; y < dy; y++)
+ {
+ Callback(surface, px, py, SDL_MapRGB(surface->format, (Uint8)(R>>16), (Uint8)(G>>16), (Uint8)(B>>16)) );
+
+ x += dx;
+ if (x >= dy)
+ {
+ x -= dy;
+ px += sdx;
+ }
+ py += sdy;
+
+ R += rstep;
+ G += gstep;
+ B += bstep;
+ }
+ }
+}
+void spg_linefadeblendaa(SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color1, Uint8 alpha1, Uint32 color2, Uint8 alpha2);
+
+void SPG_LineFade(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color1, Uint32 color2)
+{
+ if (spg_lock(Surface) < 0)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_LineFade could not lock surface");
+ return;
+ }
+
+ if(spg_thickness == 1)
+ {
+ if(SPG_GetAA())
+ spg_linefadeblendaa(Surface, x1, y1, x2, y2, color1, 255, color2, 255);
+ else
+ SPG_LineFadeFn(Surface, x1,y1, x2,y2, color1, color2, spg_pixel);
+
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = MIN(x1, x2);
+ rect.y = MIN(y1, y2);
+ rect.w = MAX(x1, x2) - rect.x + 1;
+ rect.h = MAX(y1, y2) - rect.y + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+ if(spg_thickness > 0)
+ {
+ SPG_LineFadeFn(Surface, x1,y1, x2,y2, color1, color2, spg_thicknesscallback);
+
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = MIN(x1, x2) - spg_thickness/2;
+ rect.y = MIN(y1, y2) - spg_thickness/2;
+ rect.w = MAX(x1, x2) - rect.x + 1 + spg_thickness;
+ rect.h = MAX(y1, y2) - rect.y + 1 + spg_thickness;
+ // Clip it to the screen
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+
+ spg_unlock(Surface);
+
+}
+
+//==================================================================================
+// Draws a anti-aliased multicolored line
+//==================================================================================
+void spg_linefadeblendaa(SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color1, Uint8 alpha1, Uint32 color2, Uint8 alpha2)
+{
+ Uint8 r1, g1, b1, r2, g2, b2;
+
+ if(surface->format->BitsPerPixel == 8)
+ {
+ SDL_GetRGB(color1, surface->format, &r1, &g1, &b1);
+ SDL_GetRGB(color2, surface->format, &r2, &g2, &b2);
+ }
+ else
+ {
+ r1 = (color1 & surface->format->Rmask) >> surface->format->Rshift;
+ g1 = (color1 & surface->format->Gmask) >> surface->format->Gshift;
+ b1 = (color1 & surface->format->Bmask) >> surface->format->Bshift;
+
+ r2 = (color2 & surface->format->Rmask) >> surface->format->Rshift;
+ g2 = (color2 & surface->format->Gmask) >> surface->format->Gshift;
+ b2 = (color2 & surface->format->Bmask) >> surface->format->Bshift;
+ }
+
+ Uint32 erracc=0, erradj;
+ Uint32 erracctmp, wgt;
+ Sint16 tmp, y0p1, x0pxdir;
+ Uint8 a;
+
+ /* Keep on working with 32bit numbers */
+ Sint32 xx0=x1;
+ Sint32 yy0=y1;
+ Sint32 xx1=x2;
+ Sint32 yy1=y2;
+
+ /* Reorder points if required */
+ if (yy0 > yy1)
+ {
+ SWAP(yy0, yy1, tmp);
+ SWAP(xx0, xx1, tmp);
+
+ SWAP(r1, r2, a);
+ SWAP(g1, g2, a);
+ SWAP(b1, b2, a);
+ }
+
+ /* Calculate distance */
+ Sint16 dx = xx1 - xx0;
+ Sint16 dy = yy1 - yy0;
+
+ /* Adjust for negative dx and set xdir */
+ Sint16 xdir=1;
+ if (dx < 0)
+ {
+ xdir=-1;
+ dx=(-dx);
+ }
+
+ /* Check for special cases */
+ if (dx==0 || dy==0 || dx==dy)
+ {
+ //SPG_LineFadeBlend(surface, x1, y1, x2, y2, color1, alpha1, color2, alpha2);
+ spg_alphahack = alpha1;
+ SPG_LineFadeFn(surface, x1,y1, x2,y2, color1, color2, spg_pixelcallbackalpha);
+ return;
+ }
+
+ /* We use fixedpoint math for the color fading */
+ Sint32 R = r1<<16;
+ Sint32 G = g1<<16;
+ Sint32 B = b1<<16;
+ Sint32 A = alpha1<<16;
+ //Sint32 R2 = r1<<16;
+ //Sint32 G2 = g1<<16;
+ //Sint32 B2 = b1<<16;
+ //Sint32 A2 = alpha2<<16;
+ Sint32 rstep;
+ Sint32 gstep;
+ Sint32 bstep;
+ Sint32 astep;
+
+
+ int alpha = alpha1;
+ //float alpha_pp = (float)(alpha)/255; /* Used to calculate alpha level if alpha != 255 */
+ Uint32 intshift = 32 - AAbits; /* # of bits by which to shift erracc to get intensity level */
+
+ if (alpha1==SDL_ALPHA_OPAQUE)
+ spg_pixel(surface,x1,y1, SDL_MapRGB(surface->format, r1, g1, b1) ); /* Draw the initial pixel in the foreground color */
+ else
+ spg_pixelblend(surface,x1,y1, SDL_MapRGB(surface->format, r1, g1, b1), alpha);
+
+ /* x-major or y-major? */
+ if (dy > dx)
+ {
+
+ /* y-major. Calculate 16-bit fixed point fractional part of a pixel that
+ X advances every time Y advances 1 pixel, truncating the result so that
+ we won't overrun the endpoint along the X axis */
+ erradj = ((dx << 16) / dy)<<16;
+
+ rstep = (Sint32)((r2-r1)<<16) / (Sint32)(dy);
+ gstep = (Sint32)((g2-g1)<<16) / (Sint32)(dy);
+ bstep = (Sint32)((b2-b1)<<16) / (Sint32)(dy);
+ astep = (Sint32)((alpha2-alpha1)<<16) / (Sint32)(dy);
+
+ /* draw all pixels other than the first and last */
+ x0pxdir=xx0+xdir;
+ while (--dy)
+ {
+ R += rstep;
+ G += gstep;
+ B += bstep;
+ A += astep;
+
+ erracctmp = erracc;
+ erracc += erradj;
+ if (erracc <= erracctmp)
+ {
+ /* rollover in error accumulator, x coord advances */
+ xx0=x0pxdir;
+ x0pxdir += xdir;
+ }
+ yy0++; /* y-major so always advance Y */
+
+ /* the AAbits most significant bits of erracc give us the intensity
+ weighting for this pixel, and the complement of the weighting for
+ the paired pixel. */
+ wgt = (erracc >> intshift) & 255;
+
+ a = (Uint8)(255-wgt);
+ if (alpha != 255)
+ a = (Uint8)(a*(float)(A>>16)/255);
+
+ spg_pixelblend(surface,xx0,yy0,SDL_MapRGB(surface->format, (Uint8)(R>>16), (Uint8)(G>>16), (Uint8)(B>>16)),a);
+
+ a = (Uint8)(wgt);
+ if (alpha != 255)
+ a = (Uint8)(a*(float)(A>>16)/255);
+
+ spg_pixelblend(surface,x0pxdir,yy0,SDL_MapRGB(surface->format, (Uint8)(R>>16), (Uint8)(G>>16), (Uint8)(B>>16)),a);
+ }
+ }
+ else
+ {
+
+ /* x-major line. Calculate 16-bit fixed-point fractional part of a pixel
+ that Y advances each time X advances 1 pixel, truncating the result so
+ that we won't overrun the endpoint along the X axis. */
+ erradj = ((dy << 16) / dx)<<16;
+
+ rstep = (Sint32)((r2-r1)<<16) / (Sint32)(dx);
+ gstep = (Sint32)((g2-g1)<<16) / (Sint32)(dx);
+ bstep = (Sint32)((b2-b1)<<16) / (Sint32)(dx);
+ astep = (Sint32)((alpha2-alpha1)<<16) / (Sint32)(dx);
+
+ /* draw all pixels other than the first and last */
+ y0p1=yy0+1;
+ while (--dx)
+ {
+ R += rstep;
+ G += gstep;
+ B += bstep;
+ A += astep;
+
+ erracctmp = erracc;
+ erracc += erradj;
+ if (erracc <= erracctmp)
+ {
+ /* Accumulator turned over, advance y */
+ yy0=y0p1;
+ y0p1++;
+ }
+ xx0 += xdir; /* x-major so always advance X */
+
+ /* the AAbits most significant bits of erracc give us the intensity
+ weighting for this pixel, and the complement of the weighting for
+ the paired pixel. */
+ wgt = (erracc >> intshift) & 255;
+
+ a = (Uint8)(255-wgt);
+ if (alpha != 255)
+ a = (Uint8)(a*(float)(A>>16)/255);
+
+ spg_pixelblend(surface,xx0,yy0,SDL_MapRGB(surface->format, (Uint8)(R>>16), (Uint8)(G>>16), (Uint8)(B>>16)),a);
+
+ a = (Uint8)(wgt);
+ if (alpha != 255)
+ a = (Uint8)(a*(float)(A>>16)/255);
+
+ spg_pixelblend(surface,xx0,y0p1,SDL_MapRGB(surface->format, (Uint8)(R>>16), (Uint8)(G>>16), (Uint8)(B>>16)),a);
+ }
+ }
+
+ /* Draw final pixel, always exactly intersected by the line and doesn't
+ need to be weighted. */
+ if (alpha2==SDL_ALPHA_OPAQUE)
+ spg_pixel(surface,x2,y2, SDL_MapRGB(surface->format,r2, g2, b2));
+ else
+ spg_pixelblend(surface,x2,y2, SDL_MapRGB(surface->format,r2, g2, b2), alpha2);
+
+}
+
+void SPG_LineFadeBlend(SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color1, Uint8 alpha1, Uint32 color2, Uint8 alpha2)
+{
+ if (spg_lock(surface) < 0)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_LineFadeBlend could not lock surface");
+ return;
+ }
+
+ if(spg_thickness == 1)
+ {
+ if(SPG_GetAA())
+ spg_linefadeblendaa(surface, x1, y1, x2, y2, color1, alpha1, color2, alpha2);
+ else
+ {
+ Sint16 dx, dy, sdx, sdy, x, y, px, py;
+
+ dx = x2 - x1;
+ dy = y2 - y1;
+
+ sdx = (dx < 0) ? -1 : 1;
+ sdy = (dy < 0) ? -1 : 1;
+
+ dx = sdx * dx + 1;
+ dy = sdy * dy + 1;
+
+ x = y = 0;
+
+ px = x1;
+ py = y1;
+
+ Uint8 r1, g1, b1, r2, g2, b2;
+
+ if(surface->format->BitsPerPixel == 8)
+ {
+ SDL_GetRGB(color1, surface->format, &r1, &g1, &b1);
+ SDL_GetRGB(color2, surface->format, &r2, &g2, &b2);
+ }
+ else
+ {
+ r1 = (color1 & surface->format->Rmask) >> surface->format->Rshift;
+ g1 = (color1 & surface->format->Gmask) >> surface->format->Gshift;
+ b1 = (color1 & surface->format->Bmask) >> surface->format->Bshift;
+ r2 = (color2 & surface->format->Rmask) >> surface->format->Rshift;
+ g2 = (color2 & surface->format->Gmask) >> surface->format->Gshift;
+ b2 = (color2 & surface->format->Bmask) >> surface->format->Bshift;
+ }
+
+ /* We use fixedpoint math for the color fading */
+ Sint32 R = r1<<16;
+ Sint32 G = g1<<16;
+ Sint32 B = b1<<16;
+ Sint32 A = alpha1<<16;
+ Sint32 R2 = r2<<16;
+ Sint32 G2 = g2<<16;
+ Sint32 B2 = b2<<16;
+ Sint32 A2 = alpha2<<16;
+ Sint32 rstep;
+ Sint32 gstep;
+ Sint32 bstep;
+ Sint32 astep;
+
+ if (dx >= dy)
+ {
+ rstep = (R2-R) / (Sint32)(dx);
+ gstep = (G2-G) / (Sint32)(dx);
+ bstep = (B2-B) / (Sint32)(dx);
+ astep = (A2-A) / (Sint32)(dx);
+
+ for (x = 0; x < dx; x++)
+ {
+ spg_pixelblend(surface, px, py, SDL_MapRGB(surface->format, (Uint8)(R>>16), (Uint8)(G>>16), (Uint8)(B>>16)), (Uint8)(A>>16));
+
+ y += dy;
+ if (y >= dx)
+ {
+ y -= dx;
+ py += sdy;
+ }
+ px += sdx;
+
+ R += rstep;
+ G += gstep;
+ B += bstep;
+ A += astep;
+ }
+ }
+ else
+ {
+ rstep = (Sint32)(R2-R) / (Sint32)(dy);
+ gstep = (Sint32)(G2-G) / (Sint32)(dy);
+ bstep = (Sint32)(B2-B) / (Sint32)(dy);
+ astep = (Sint32)(A2-A) / (Sint32)(dy);
+
+ for (y = 0; y < dy; y++)
+ {
+ spg_pixelblend(surface, px, py, SDL_MapRGB(surface->format, (Uint8)(R>>16), (Uint8)(G>>16), (Uint8)(B>>16)), (Uint8)(A>>16));
+
+ x += dx;
+ if (x >= dy)
+ {
+ x -= dy;
+ px += sdx;
+ }
+ py += sdy;
+
+ R += rstep;
+ G += gstep;
+ B += bstep;
+ A += astep;
+ }
+ }
+ }
+
+
+
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = MIN(x1, x2);
+ rect.y = MIN(y1, y2);
+ rect.w = MAX(x1, x2) - rect.x + 1;
+ rect.h = MAX(y1, y2) - rect.y + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+ else if(spg_thickness > 0)
+ {
+
+ Sint16 dx, dy, sdx, sdy, x, y, px, py;
+
+ dx = x2 - x1;
+ dy = y2 - y1;
+
+ sdx = (dx < 0) ? -1 : 1;
+ sdy = (dy < 0) ? -1 : 1;
+
+ dx = sdx * dx + 1;
+ dy = sdy * dy + 1;
+
+ x = y = 0;
+
+ px = x1;
+ py = y1;
+
+ Uint8 r1, g1, b1, r2, g2, b2;
+
+ if(surface->format->BitsPerPixel == 8)
+ {
+ SDL_GetRGB(color1, surface->format, &r1, &g1, &b1);
+ SDL_GetRGB(color2, surface->format, &r2, &g2, &b2);
+ }
+ else
+ {
+ r1 = (color1 & surface->format->Rmask) >> surface->format->Rshift;
+ g1 = (color1 & surface->format->Gmask) >> surface->format->Gshift;
+ b1 = (color1 & surface->format->Bmask) >> surface->format->Bshift;
+ r2 = (color2 & surface->format->Rmask) >> surface->format->Rshift;
+ g2 = (color2 & surface->format->Gmask) >> surface->format->Gshift;
+ b2 = (color2 & surface->format->Bmask) >> surface->format->Bshift;
+ }
+
+ /* We use fixedpoint math for the color fading */
+ Sint32 R = r1<<16;
+ Sint32 G = g1<<16;
+ Sint32 B = b1<<16;
+ Sint32 A = alpha1<<16;
+ Sint32 R2 = r2<<16;
+ Sint32 G2 = g2<<16;
+ Sint32 B2 = b2<<16;
+ Sint32 A2 = alpha2<<16;
+ Sint32 rstep;
+ Sint32 gstep;
+ Sint32 bstep;
+ Sint32 astep;
+
+ if (dx >= dy)
+ {
+ rstep = (R2-R) / (Sint32)(dx);
+ gstep = (G2-G) / (Sint32)(dx);
+ bstep = (B2-B) / (Sint32)(dx);
+ astep = (A2-A) / (Sint32)(dx);
+
+ for (x = 0; x < dx; x++)
+ {
+ spg_alphahack = (Uint8)(A>>16);
+ spg_thicknesscallbackalpha(surface, px, py, SDL_MapRGB(surface->format, (Uint8)(R>>16), (Uint8)(G>>16), (Uint8)(B>>16)));
+
+ y += dy;
+ if (y >= dx)
+ {
+ y -= dx;
+ py += sdy;
+ }
+ px += sdx;
+
+ R += rstep;
+ G += gstep;
+ B += bstep;
+ A += astep;
+ }
+ }
+ else
+ {
+ rstep = (Sint32)(R2-R) / (Sint32)(dy);
+ gstep = (Sint32)(G2-G) / (Sint32)(dy);
+ bstep = (Sint32)(B2-B) / (Sint32)(dy);
+ astep = (Sint32)(A2-A) / (Sint32)(dy);
+
+ for (y = 0; y < dy; y++)
+ {
+ spg_alphahack = (Uint8)(A>>16);
+ spg_thicknesscallbackalpha(surface, px, py, SDL_MapRGB(surface->format, (Uint8)(R>>16), (Uint8)(G>>16), (Uint8)(B>>16)));
+
+ x += dx;
+ if (x >= dy)
+ {
+ x -= dy;
+ px += sdx;
+ }
+ py += sdy;
+
+ R += rstep;
+ G += gstep;
+ B += bstep;
+ A += astep;
+ }
+ }
+
+
+
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = MIN(x1, x2) - spg_thickness/2;
+ rect.y = MIN(y1, y2) - spg_thickness/2;
+ rect.w = MAX(x1, x2) - rect.x + 1 + spg_thickness;
+ rect.h = MAX(y1, y2) - rect.y + 1 + spg_thickness;
+ // Clip it to the screen
+ SPG_DirtyClip(surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+
+ spg_unlock(surface);
+
+}
+
+
+
+
+
+
+
+/**********************************************************************************/
+/** Figure functions **/
+/**********************************************************************************/
+
+//==================================================================================
+// Draws a rectangle
+//==================================================================================
+void SPG_Rect(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
+{
+ if(spg_thickness == 1)
+ {
+ SPG_LineH(Surface,x1,y1,x2,color);
+ SPG_LineH(Surface,x1,y2,x2,color);
+ SPG_LineV(Surface,x1,y1,y2,color);
+ SPG_LineV(Surface,x2,y1,y2,color);
+ }
+ else if(spg_thickness > 0)
+ {
+ SPG_Line(Surface,x1,y1,x2,y1,color);
+ SPG_Line(Surface,x1,y2,x2,y2,color);
+ SPG_Line(Surface,x1,y1,x1,y2,color);
+ SPG_Line(Surface,x2,y1,x2,y2,color);
+ }
+ /*if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = x1;
+ rect.y = MIN(y1, y2);
+ rect.w = 1;
+ rect.h = MAX(y1, y2) - rect.y + 1;
+
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ rect.x = x2;
+ rect.y = MIN(y1, y2);
+ rect.w = 1;
+ rect.h = MAX(y1, y2) - rect.y + 1;
+
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ rect.x = MIN(x1, x2);
+ rect.y = y1;
+ rect.w = MAX(x1, x2) - rect.x + 1;
+ rect.h = 1;
+
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ rect.x = MIN(x1, x2);
+ rect.y = y2;
+ rect.w = MAX(x1, x2) - rect.x + 1;
+ rect.h = 1;
+
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }*/
+}
+
+
+
+//==================================================================================
+// Draws a rectangle (alpha)
+//==================================================================================
+void SPG_RectBlend(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha)
+{
+ /*if (spg_lock(Surface) < 0)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_RectBlend could not lock surface");
+ return;
+ }*/
+ if(spg_thickness == 1)
+ {
+ SPG_LineHBlend(Surface,x1,y1,x2,color,alpha);
+ SPG_LineHBlend(Surface,x1,y2,x2,color,alpha);
+ SPG_LineVBlend(Surface,x1,y1,y2,color,alpha);
+ SPG_LineVBlend(Surface,x2,y1,y2,color,alpha);
+ }
+ else if(spg_thickness > 0)
+ {
+ SPG_LineBlend(Surface,x1,y1,x2, y1, color,alpha);
+ SPG_LineBlend(Surface,x1,y2,x2, y2, color,alpha);
+ SPG_LineBlend(Surface,x1,y1,x1,y2,color,alpha);
+ SPG_LineBlend(Surface,x2,y1,x2,y2,color,alpha);
+ }
+ //spg_unlock(Surface);
+/*
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = x1;
+ rect.y = MIN(y1, y2);
+ rect.w = 1;
+ rect.h = MAX(y1, y2) - rect.y + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ rect.x = x2;
+ rect.y = MIN(y1, y2);
+ rect.w = 1;
+ rect.h = MAX(y1, y2) - rect.y + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ rect.x = MIN(x1, x2);
+ rect.y = y1;
+ rect.w = MAX(x1, x2) - rect.x + 1;
+ rect.h = 1;
+ // Clip it to the screen
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ rect.x = MIN(x1, x2);
+ rect.y = y2;
+ rect.w = MAX(x1, x2) - rect.x + 1;
+ rect.h = 1;
+ // Clip it to the screen
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }*/
+}
+
+
+
+//==================================================================================
+// Draws a filled rectangle
+//==================================================================================
+void SPG_RectFilled(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
+{
+ Sint16 tmp;
+ if (x1>x2)
+ {
+ tmp=x1;
+ x1=x2;
+ x2=tmp;
+ }
+ if (y1>y2)
+ {
+ tmp=y1;
+ y1=y2;
+ y2=tmp;
+ }
+
+#if SDL_VERSIONNUM(SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL) < \
+ SDL_VERSIONNUM(1, 1, 5)
+ if (x2<Surface->clip_minx || x1>Surface->clip_maxx || y2<Surface->clip_miny || y1>Surface->clip_maxy)
+ return;
+ if (x1 < Surface->clip_minx)
+ x1=Surface->clip_minx;
+ if (x2 > Surface->clip_maxx)
+ x2=Surface->clip_maxx;
+ if (y1 < Surface->clip_miny)
+ y1=Surface->clip_miny;
+ if (y2 > Surface->clip_maxy)
+ y2=Surface->clip_maxy;
+#endif
+
+ SDL_Rect area;
+ area.x=x1;
+ area.y=y1;
+ area.w=x2-x1+1;
+ area.h=y2-y1+1;
+
+ SDL_FillRect(Surface,&area,color);
+
+ if(spg_makedirtyrects)
+ {
+ //SPG_DirtyClip(Surface, &area);
+ SPG_DirtyAddTo(spg_dirtytable_front, &area);
+ }
+}
+
+
+
+//==================================================================================
+// Draws a filled rectangle (alpha)
+//==================================================================================
+void SPG_RectFilledBlend(SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha)
+{
+
+ if ( alpha == SDL_ALPHA_OPAQUE )
+ {
+ SPG_RectFilled(surface,x1,y1,x2,y2,color);
+ return;
+ }
+
+ /* Fix coords */
+ Sint16 tmp;
+ if (x1>x2)
+ {
+ tmp=x1;
+ x1=x2;
+ x2=tmp;
+ }
+ if (y1>y2)
+ {
+ tmp=y1;
+ y1=y2;
+ y2=tmp;
+ }
+
+ /* Clipping */
+ if (x2<SPG_CLIP_XMIN(surface) || x1>SPG_CLIP_XMAX(surface) || y2<SPG_CLIP_YMIN(surface) || y1>SPG_CLIP_YMAX(surface))
+ return;
+ if (x1 < SPG_CLIP_XMIN(surface))
+ x1 = SPG_CLIP_XMIN(surface);
+ if (x2 > SPG_CLIP_XMAX(surface))
+ x2 = SPG_CLIP_XMAX(surface);
+ if (y1 < SPG_CLIP_YMIN(surface))
+ y1 = SPG_CLIP_YMIN(surface);
+ if (y2 > SPG_CLIP_YMAX(surface))
+ y2 = SPG_CLIP_YMAX(surface);
+
+ Uint32 Rmask = surface->format->Rmask, Gmask = surface->format->Gmask, Bmask = surface->format->Bmask, Amask = surface->format->Amask;
+ Uint32 R,G,B,A=0;
+ Sint16 x,y;
+
+
+
+
+ if (spg_lock(surface) < 0)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_RectFilledBlend could not lock surface");
+ return;
+ }
+
+ switch (surface->format->BytesPerPixel)
+ {
+ case 1: /* Assuming 8-bpp */
+ {
+ Uint8 *row, *pixel;
+ Uint8 dR, dG, dB;
+
+ Uint8 sR = surface->format->palette->colors[color].r;
+ Uint8 sG = surface->format->palette->colors[color].g;
+ Uint8 sB = surface->format->palette->colors[color].b;
+
+ for (y = y1; y<=y2; y++)
+ {
+ row = (Uint8 *)surface->pixels + y*surface->pitch;
+ for (x = x1; x <= x2; x++)
+ {
+ pixel = row + x;
+
+ dR = surface->format->palette->colors[*pixel].r;
+ dG = surface->format->palette->colors[*pixel].g;
+ dB = surface->format->palette->colors[*pixel].b;
+
+ dR = dR + ((sR-dR)*alpha >> 8);
+ dG = dG + ((sG-dG)*alpha >> 8);
+ dB = dB + ((sB-dB)*alpha >> 8);
+
+ *pixel = SDL_MapRGB(surface->format, dR, dG, dB);
+ }
+ }
+ }
+ break;
+
+ case 2: /* Probably 15-bpp or 16-bpp */
+ {
+ Uint16 *row, *pixel;
+ Uint32 dR=(color & Rmask),dG=(color & Gmask),dB=(color & Bmask),dA=(color & Amask);
+
+ for (y = y1; y<=y2; y++)
+ {
+ row = (Uint16 *)surface->pixels + y*surface->pitch/2;
+ for (x = x1; x <= x2; x++)
+ {
+ pixel = row + x;
+
+ R = ((*pixel & Rmask) + (( dR - (*pixel & Rmask) ) * alpha >> 8)) & Rmask;
+ G = ((*pixel & Gmask) + (( dG - (*pixel & Gmask) ) * alpha >> 8)) & Gmask;
+ B = ((*pixel & Bmask) + (( dB - (*pixel & Bmask) ) * alpha >> 8)) & Bmask;
+ if ( Amask )
+ A = ((*pixel & Amask) + (( dA - (*pixel & Amask) ) * alpha >> 8)) & Amask;
+
+ *pixel = R | G | B | A;
+ }
+ }
+ }
+ break;
+
+ case 3: /* Slow 24-bpp mode, usually not used */
+ {
+ Uint8 *row,*pix;
+ Uint8 dR, dG, dB, dA;
+ Uint8 rshift8=surface->format->Rshift/8;
+ Uint8 gshift8=surface->format->Gshift/8;
+ Uint8 bshift8=surface->format->Bshift/8;
+ Uint8 ashift8=surface->format->Ashift/8;
+
+ Uint8 sR = (color>>surface->format->Rshift)&0xff;
+ Uint8 sG = (color>>surface->format->Gshift)&0xff;
+ Uint8 sB = (color>>surface->format->Bshift)&0xff;
+ Uint8 sA = (color>>surface->format->Ashift)&0xff;
+
+ for (y = y1; y<=y2; y++)
+ {
+ row = (Uint8 *)surface->pixels + y * surface->pitch;
+ for (x = x1; x <= x2; x++)
+ {
+ pix = row + x*3;
+
+ dR = *((pix)+rshift8);
+ dG = *((pix)+gshift8);
+ dB = *((pix)+bshift8);
+ dA = *((pix)+ashift8);
+
+ dR = dR + ((sR-dR)*alpha >> 8);
+ dG = dG + ((sG-dG)*alpha >> 8);
+ dB = dB + ((sB-dB)*alpha >> 8);
+ dA = dA + ((sA-dA)*alpha >> 8);
+
+ *((pix)+rshift8) = dR;
+ *((pix)+gshift8) = dG;
+ *((pix)+bshift8) = dB;
+ *((pix)+ashift8) = dA;
+ }
+ }
+ }
+ break;
+
+ case 4: /* Probably 32-bpp */
+ {
+ Uint32 *row, *pixel;
+ Uint32 dR=(color & Rmask),dG=(color & Gmask),dB=(color & Bmask),dA=(color & Amask);
+
+ switch (SPG_GetBlend())
+ {
+ case SPG_COMBINE_ALPHA: // Blend and combine src and dest alpha
+ dA=((alpha << surface->format->Ashift) & Amask); // correct
+ for (y = y1; y<=y2; y++)
+ {
+ row = (Uint32 *)surface->pixels + y*surface->pitch/4;
+ for (x = x1; x <= x2; x++)
+ {
+ pixel = row + x;
+
+ R = ((*pixel & Rmask) + (( dR - (*pixel & Rmask) ) * alpha >> 8)) & Rmask;
+ G = ((*pixel & Gmask) + (( dG - (*pixel & Gmask) ) * alpha >> 8)) & Gmask;
+ B = ((*pixel & Bmask) + (( dB - (*pixel & Bmask) ) * alpha >> 8)) & Bmask;
+ if ( Amask )
+ A = ((((*pixel & Amask) >> surface->format->Ashift) + alpha) >> 1) << surface->format->Ashift;
+
+ *pixel= R | G | B | A;
+ }
+ }
+ break;
+ case SPG_DEST_ALPHA: // Blend and keep dest alpha
+ for (y = y1; y<=y2; y++)
+ {
+ row = (Uint32 *)surface->pixels + y*surface->pitch/4;
+ for (x = x1; x <= x2; x++)
+ {
+ pixel = row + x;
+
+ R = ((*pixel & Rmask) + (( dR - (*pixel & Rmask) ) * alpha >> 8)) & Rmask;
+ G = ((*pixel & Gmask) + (( dG - (*pixel & Gmask) ) * alpha >> 8)) & Gmask;
+ B = ((*pixel & Bmask) + (( dB - (*pixel & Bmask) ) * alpha >> 8)) & Bmask;
+ if ( Amask )
+ A = (*pixel & Amask);
+
+
+ *pixel= R | G | B | A;
+ }
+ }
+
+ break;
+ case SPG_SRC_ALPHA: // Blend and keep src alpha
+ if (Amask)
+ A = (alpha << surface->format->Ashift);
+ else
+ A = SDL_ALPHA_OPAQUE;
+ for (y = y1; y<=y2; y++)
+ {
+ row = (Uint32 *)surface->pixels + y*surface->pitch/4;
+ for (x = x1; x <= x2; x++)
+ {
+ pixel = row + x;
+
+ R = ((*pixel & Rmask) + (( dR - (*pixel & Rmask) ) * alpha >> 8)) & Rmask;
+ G = ((*pixel & Gmask) + (( dG - (*pixel & Gmask) ) * alpha >> 8)) & Gmask;
+ B = ((*pixel & Bmask) + (( dB - (*pixel & Bmask) ) * alpha >> 8)) & Bmask;
+
+ *pixel= R | G | B | A; // A is src alpha here
+ }
+ }
+
+ break;
+ case SPG_COPY_SRC_ALPHA: // Direct copy with src alpha
+ if (Amask)
+ A = (alpha << surface->format->Ashift);
+ else
+ A = SDL_ALPHA_OPAQUE;
+ for (y = y1; y<=y2; y++)
+ {
+ row = (Uint32 *)surface->pixels + y*surface->pitch/4;
+ for (x = x1; x <= x2; x++)
+ {
+ pixel = row + x;
+
+ *pixel= dR | dG | dB | A; // A is src alpha here
+ }
+ }
+ break;
+ case SPG_COPY_DEST_ALPHA: // Direct copy with dest alpha
+ for (y = y1; y<=y2; y++)
+ {
+ row = (Uint32 *)surface->pixels + y*surface->pitch/4;
+ for (x = x1; x <= x2; x++)
+ {
+ pixel = row + x;
+
+ *pixel= dR | dG | dB | (*pixel & Amask);
+ }
+ }
+ break;
+ case SPG_COPY_COMBINE_ALPHA: // Direct copy with combined alpha
+ for (y = y1; y<=y2; y++)
+ {
+ row = (Uint32 *)surface->pixels + y*surface->pitch/4;
+ for (x = x1; x <= x2; x++)
+ {
+ pixel = row + x;
+ if (Amask)
+ A = ((((*pixel & Amask) >> surface->format->Ashift) + alpha) >> 1) << surface->format->Ashift;
+
+ *pixel= dR | dG | dB | A;
+ }
+ }
+ break;
+ case SPG_COPY_NO_ALPHA: // Direct copy, alpha opaque
+ SPG_RectFilled(surface,x1,y1,x2,y2,color);
+ break;
+ case SPG_COPY_ALPHA_ONLY: // Direct copy of just the alpha
+ for (y = y1; y<=y2; y++)
+ {
+ row = (Uint32 *)surface->pixels + y*surface->pitch/4;
+ for (x = x1; x <= x2; x++)
+ {
+ pixel = row + x;
+ if(Amask)
+ A = (alpha << surface->format->Ashift);
+
+ *pixel= dR | dG | dB | A;
+ }
+ }
+ break;
+ case SPG_COMBINE_ALPHA_ONLY: // Blend of just the alpha
+ for (y = y1; y<=y2; y++)
+ {
+ row = (Uint32 *)surface->pixels + y*surface->pitch/4;
+ for (x = x1; x <= x2; x++)
+ {
+ pixel = row + x;
+ if(Amask)
+ A = ((((*pixel & Amask) >> surface->format->Ashift) + alpha) >> 1) << surface->format->Ashift;
+
+ *pixel= dR | dG | dB | A;
+ }
+ }
+ break;
+ case SPG_REPLACE_COLORKEY: // Replace the colorkeyed color
+ for (y = y1; y<=y2; y++)
+ {
+ row = (Uint32 *)surface->pixels + y*surface->pitch/4;
+ for (x = x1; x <= x2; x++)
+ {
+ pixel = row + x;
+ if(!(surface->flags & SDL_SRCCOLORKEY) || *pixel != surface->format->colorkey)
+ return;
+ if(Amask)
+ A = (alpha << surface->format->Ashift);
+ *pixel= dR | dG | dB | A;
+ }
+ }
+ break;
+ }
+
+
+ }
+ break;
+ }
+
+
+ spg_unlock(surface);
+
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = MIN(x1, x2);
+ rect.y = MIN(y1, y2);
+ rect.w = MAX(x1, x2) - rect.x + 1;
+ rect.h = MAX(y1, y2) - rect.y + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+
+}
+
+
+
+//==================================================================================
+// Draws a rounded rectangle
+//==================================================================================
+void SPG_RectRound(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, float r, Uint32 color)
+{
+ Sint16 minX = (x1 < x2? x1 : x2) + (Sint16)(r);
+ Sint16 maxX = (x1 > x2? x1 : x2) - (Sint16)(r);
+ Sint16 minY = (y1 < y2? y1 : y2) + (Sint16)(r);
+ Sint16 maxY = (y1 > y2? y1 : y2) - (Sint16)(r);
+ SPG_LineH(Surface,minX,y1,maxX,color);
+ SPG_LineH(Surface,minX,y2,maxX,color);
+ SPG_LineV(Surface,x1,minY,maxY,color);
+ SPG_LineV(Surface,x2,minY,maxY,color);
+
+ SPG_Arc(Surface, minX, minY, r, 180, 270, color);
+ SPG_Arc(Surface, maxX, minY, r, 270, 360, color);
+ SPG_Arc(Surface, maxX, maxY, r, 0, 90, color);
+ SPG_Arc(Surface, minX, maxY, r, 90, 180, color);
+ /*if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = MIN(x1, x2);
+ rect.y = MIN(y1, y2);
+ rect.w = MAX(x1, x2) - rect.x + 1;
+ rect.h = MAX(y1, y2) - rect.y + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }*/
+}
+
+
+
+//==================================================================================
+// Draws a rounded rectangle (alpha)
+//==================================================================================
+void SPG_RectRoundBlend(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, float r, Uint32 color, Uint8 alpha)
+{
+ if (spg_lock(Surface) < 0)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_RectRoundBlend could not lock surface");
+ return;
+ }
+
+ Sint16 minX = (x1 < x2? x1 : x2) + (Sint16)(r) + 1;
+ Sint16 maxX = (x1 > x2? x1 : x2) - (Sint16)(r) - 1;
+ Sint16 minY = (y1 < y2? y1 : y2) + (Sint16)(r) + 1;
+ Sint16 maxY = (y1 > y2? y1 : y2) - (Sint16)(r) - 1;
+ SPG_LineHBlend(Surface,minX,y1,maxX,color,alpha);
+ SPG_LineHBlend(Surface,minX,y2,maxX,color,alpha);
+ SPG_LineVBlend(Surface,x1,minY,maxY,color,alpha);
+ SPG_LineVBlend(Surface,x2,minY,maxY,color,alpha);
+ SPG_ArcBlend(Surface, minX, minY, r, 180, 270, color, alpha);
+ SPG_ArcBlend(Surface, maxX, minY, r, 270, 360, color, alpha);
+ SPG_ArcBlend(Surface, maxX, maxY, r, 0, 90, color, alpha);
+ SPG_ArcBlend(Surface, minX, maxY, r, 90, 180, color, alpha);
+
+
+ spg_unlock(Surface);
+ /*
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = MIN(x1, x2);
+ rect.y = MIN(y1, y2);
+ rect.w = MAX(x1, x2) - rect.x + 1;
+ rect.h = MAX(y1, y2) - rect.y + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }*/
+}
+
+
+
+//==================================================================================
+// Draws a filled rounded rectangle
+//==================================================================================
+void SPG_RectRoundFilled(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, float r, Uint32 color)
+{
+ Sint16 tmp;
+ if (x1>x2)
+ {
+ tmp=x1;
+ x1=x2;
+ x2=tmp;
+ }
+ if (y1>y2)
+ {
+ tmp=y1;
+ y1=y2;
+ y2=tmp;
+ }
+
+#if SDL_VERSIONNUM(SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL) < \
+ SDL_VERSIONNUM(1, 1, 5)
+ if (x2<Surface->clip_minx || x1>Surface->clip_maxx || y2<Surface->clip_miny || y1>Surface->clip_maxy)
+ return;
+ if (x1 < Surface->clip_minx)
+ x1=Surface->clip_minx;
+ if (x2 > Surface->clip_maxx)
+ x2=Surface->clip_maxx;
+ if (y1 < Surface->clip_miny)
+ y1=Surface->clip_miny;
+ if (y2 > Surface->clip_maxy)
+ y2=Surface->clip_maxy;
+#endif
+
+ Sint16 minX = x1 + (Sint16)(r) + 1;
+ Sint16 maxX = x2 - (Sint16)(r);
+ Sint16 minY = y1 + (Sint16)(r);
+ Sint16 maxY = y2 - (Sint16)(r) - 1;
+
+ SDL_Rect area;
+ area.x=minX;
+ area.y=minY;
+ area.w=maxX-minX+1;
+ area.h=maxY-minY+1;
+ SDL_FillRect(Surface,&area,color);
+
+ area.x= minX;
+ area.y= y1;
+ area.w= maxX-minX+1;
+ area.h= (Sint16)(r)+1;
+ SDL_FillRect(Surface,&area,color);
+
+ area.y= y2-(Sint16)(r);
+ SDL_FillRect(Surface,&area,color);
+
+ area.x= x1;
+ area.y= minY;
+ area.w= (Sint16)(r)+1;
+ area.h= maxY-minY;
+ SDL_FillRect(Surface,&area,color);
+
+ area.x= x2-(Sint16)(r);
+ SDL_FillRect(Surface,&area,color);
+
+ SPG_CircleFilled(Surface, minX, minY+1, r+1, color);
+ SPG_CircleFilled(Surface, maxX-1, minY+1, r+1, color);
+ SPG_CircleFilled(Surface, maxX-1, maxY, r+1, color);
+ SPG_CircleFilled(Surface, minX, maxY, r+1, color);
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = MIN(x1, x2);
+ rect.y = MIN(y1, y2);
+ rect.w = MAX(x1, x2) - rect.x + 1;
+ rect.h = MAX(y1, y2) - rect.y + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+}
+
+void SPG_RectRoundFilledBlend(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, float r, Uint32 color, Uint8 alpha)
+{
+ Sint16 tmp;
+ if (x1>x2)
+ {
+ tmp=x1;
+ x1=x2;
+ x2=tmp;
+ }
+ if (y1>y2)
+ {
+ tmp=y1;
+ y1=y2;
+ y2=tmp;
+ }
+
+#if SDL_VERSIONNUM(SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL) < \
+ SDL_VERSIONNUM(1, 1, 5)
+ if (x2<Surface->clip_minx || x1>Surface->clip_maxx || y2<Surface->clip_miny || y1>Surface->clip_maxy)
+ return;
+ if (x1 < Surface->clip_minx)
+ x1=Surface->clip_minx;
+ if (x2 > Surface->clip_maxx)
+ x2=Surface->clip_maxx;
+ if (y1 < Surface->clip_miny)
+ y1=Surface->clip_miny;
+ if (y2 > Surface->clip_maxy)
+ y2=Surface->clip_maxy;
+#endif
+
+ Sint16 minX = x1 + (Sint16)(r) + 1;
+ Sint16 maxX = x2 - (Sint16)(r) - 1;
+ Sint16 minY = y1 + (Sint16)(r) + 1;
+ Sint16 maxY = y2 - (Sint16)(r) - 1;
+ // Center
+ SDL_Rect area;
+ area.x=minX;
+ area.y=minY;
+ area.w=maxX-minX;
+ area.h=maxY-minY;
+ SPG_RectFilledBlend(Surface,area.x, area.y, area.x+area.w, area.y+area.h, color,alpha);
+ // Top
+ area.x= minX;
+ area.y= y1;
+ area.w= maxX-minX;
+ area.h= (Sint16)(r);
+ SPG_RectFilledBlend(Surface,area.x, area.y, area.x+area.w, area.y+area.h, color,alpha);
+ // Bottom
+ area.y= y2-(Sint16)(r);
+ SPG_RectFilledBlend(Surface,area.x, area.y, area.x+area.w, area.y+area.h, color,alpha);
+ // Left
+ area.x= x1;
+ area.y= minY-1;
+ area.w= (Sint16)(r);
+ area.h= maxY-minY+1;
+ SPG_RectFilledBlend(Surface,area.x, area.y, area.x+area.w, area.y+area.h, color,alpha);
+ // Right
+ area.x= x2-(Sint16)(r);
+ SPG_RectFilledBlend(Surface,area.x, area.y, area.x+area.w, area.y+area.h, color,alpha);
+
+
+ // UL
+ SPG_ArcFilledBlend(Surface, minX-1, minY-1, r, 180, 270, color, alpha);
+ // UR
+ SPG_ArcFilledBlend(Surface, maxX+1, minY-1, r, 270, 360, color, alpha);
+ // DR
+ SPG_ArcFilledBlend(Surface, maxX+1, maxY+1, r, 0, 90, color, alpha);
+ // DL
+ SPG_ArcFilledBlend(Surface, minX-1, maxY+1, r, 90, 180, color, alpha);
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = MIN(x1, x2);
+ rect.y = MIN(y1, y2);
+ rect.w = MAX(x1, x2) - rect.x + 1;
+ rect.h = MAX(y1, y2) - rect.y + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+
+}
+
+
+
+
+
+
+//==================================================================================
+// Performs Callback at each ellipse point.
+// (from Allegro)
+//==================================================================================
+void SPG_EllipseFn(SDL_Surface *Surface, Sint16 x, Sint16 y, float rx, float ry, Uint32 color, void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y, Uint32 Color) )
+{
+ int ix, iy;
+ int h, i, j, k;
+ int oh, oi, oj, ok;
+
+ if (rx < 1)
+ rx = 1;
+
+ if (ry < 1)
+ ry = 1;
+
+ h = i = j = k = 0xFFFF;
+
+ if (rx > ry)
+ {
+ ix = 0;
+ iy = (Sint16)(rx) * 64;
+
+ do
+ {
+ oh = h;
+ oi = i;
+ oj = j;
+ ok = k;
+
+ h = (ix + 32) >> 6;
+ i = (iy + 32) >> 6;
+ j = (h * (Sint16)(ry)) / (Sint16)(rx);
+ k = (i * (Sint16)(ry)) / (Sint16)(rx);
+
+ if (((h != oh) || (k != ok)) && (h < oi))
+ {
+ Callback(Surface, x+h, y+k, color);
+ if (h)
+ Callback(Surface, x-h, y+k, color);
+ if (k)
+ {
+ Callback(Surface, x+h, y-k, color);
+ if (h)
+ Callback(Surface, x-h, y-k, color);
+ }
+ }
+
+ if (((i != oi) || (j != oj)) && (h < i))
+ {
+ Callback(Surface, x+i, y+j, color);
+ if (i)
+ Callback(Surface, x-i, y+j, color);
+ if (j)
+ {
+ Callback(Surface, x+i, y-j, color);
+ if (i)
+ Callback(Surface, x-i, y-j, color);
+ }
+ }
+
+ ix = ix + iy / (Sint16)(rx);
+ iy = iy - ix / (Sint16)(rx);
+
+ }
+ while (i > h);
+ }
+ else
+ {
+ ix = 0;
+ iy = (Sint16)(ry) * 64;
+
+ do
+ {
+ oh = h;
+ oi = i;
+ oj = j;
+ ok = k;
+
+ h = (ix + 32) >> 6;
+ i = (iy + 32) >> 6;
+ j = (h * (Sint16)(rx)) / (Sint16)(ry);
+ k = (i * (Sint16)(rx)) / (Sint16)(ry);
+
+ if (((j != oj) || (i != oi)) && (h < i))
+ {
+ Callback(Surface, x+j, y+i, color);
+ if (j)
+ Callback(Surface, x-j, y+i, color);
+ if (i)
+ {
+ Callback(Surface, x+j, y-i, color);
+ if (j)
+ Callback(Surface, x-j, y-i, color);
+ }
+ }
+
+ if (((k != ok) || (h != oh)) && (h < oi))
+ {
+ Callback(Surface, x+k, y+h, color);
+ if (k)
+ Callback(Surface, x-k, y+h, color);
+ if (h)
+ {
+ Callback(Surface, x+k, y-h, color);
+ if (k)
+ Callback(Surface, x-k, y-h, color);
+ }
+ }
+
+ ix = ix + iy / (Sint16)(ry);
+ iy = iy - ix / (Sint16)(ry);
+
+ }
+ while (i > h);
+ }
+}
+
+
+
+//==================================================================================
+// Draws an anti-aliased ellipse (alpha)
+// Some of this code is taken from "TwinLib" (http://www.twinlib.org) written by
+// Nicolas Roard (nicolas@roard.com)
+//==================================================================================
+void spg_ellipseblendaa(SDL_Surface *surface, Sint16 xc, Sint16 yc, float rx, float ry, Uint32 color, Uint8 alpha)
+{
+ /* Sanity check */
+ if (rx < 1)
+ rx = 1;
+ if (ry < 1)
+ ry = 1;
+
+ int a2 = (Sint16)(rx) * (Sint16)(rx);
+ int b2 = (Sint16)(ry) * (Sint16)(ry);
+
+ int ds = 2 * a2;
+ int dt = 2 * b2;
+
+ int dxt = (int)(a2 / sqrt(a2 + b2));
+
+ int t = 0;
+ int s = -2 * a2 * (Sint16)(ry);
+ int d = 0;
+
+ Sint16 x = xc;
+ Sint16 y = yc - (Sint16)(ry);
+
+ Sint16 xs, ys, dyt;
+ float cp, is, ip, imax = 1.0;
+
+ Uint8 s_alpha, p_alpha;
+ float alpha_pp = (float)(alpha)/255;
+
+
+ if ( spg_lock(surface) < 0 )
+ {
+ if(spg_useerrors)
+ SPG_Error("spg_ellipseblendaa could not lock surface");
+ return;
+ }
+
+ /* "End points" */
+ spg_pixelblend(surface, x, y, color, alpha);
+ spg_pixelblend(surface, 2*xc-x, y, color, alpha);
+
+ spg_pixelblend(surface, x, 2*yc-y, color, alpha);
+ spg_pixelblend(surface, 2*xc-x, 2*yc-y, color, alpha);
+
+ int i;
+
+ for (i = 1; i <= dxt; i++)
+ {
+ x--;
+ d += t - b2;
+
+ if (d >= 0)
+ ys = y - 1;
+ else if ((d - s - a2) > 0)
+ {
+ if ((2 * d - s - a2) >= 0)
+ ys = y + 1;
+ else
+ {
+ ys = y;
+ y++;
+ d -= s + a2;
+ s += ds;
+ }
+ }
+ else
+ {
+ y++;
+ ys = y + 1;
+ d -= s + a2;
+ s += ds;
+ }
+
+ t -= dt;
+
+ /* Calculate alpha */
+ cp = (float)(abs(d)) / abs(s);
+ is = (float)( cp * imax + 0.1 );
+ ip = (float)( imax - is + 0.2 );
+
+ /* Overflow check */
+ if ( is > 1.0 )
+ is = 1.0;
+ if ( ip > 1.0 )
+ ip = 1.0;
+
+ /* Calculate alpha level */
+ s_alpha = (Uint8)(is*255);
+ p_alpha = (Uint8)(ip*255);
+ if ( alpha != 255 )
+ {
+ s_alpha = (Uint8)(s_alpha*alpha_pp);
+ p_alpha = (Uint8)(p_alpha*alpha_pp);
+ }
+
+
+ /* Upper half */
+ spg_pixelblend(surface, x, y, color, p_alpha);
+ spg_pixelblend(surface, 2*xc-x, y, color, p_alpha);
+
+ spg_pixelblend(surface, x, ys, color, s_alpha);
+ spg_pixelblend(surface, 2*xc-x, ys, color, s_alpha);
+
+
+ /* Lower half */
+ spg_pixelblend(surface, x, 2*yc-y, color, p_alpha);
+ spg_pixelblend(surface, 2*xc-x, 2*yc-y, color, p_alpha);
+
+ spg_pixelblend(surface, x, 2*yc-ys, color, s_alpha);
+ spg_pixelblend(surface, 2*xc-x, 2*yc-ys, color, s_alpha);
+ }
+
+ dyt = abs(y - yc);
+
+ for (i = 1; i <= dyt; i++)
+ {
+ y++;
+ d -= s + a2;
+
+ if (d <= 0)
+ xs = x + 1;
+ else if ((d + t - b2) < 0)
+ {
+ if ((2 * d + t - b2) <= 0)
+ xs = x - 1;
+ else
+ {
+ xs = x;
+ x--;
+ d += t - b2;
+ t -= dt;
+ }
+ }
+ else
+ {
+ x--;
+ xs = x - 1;
+ d += t - b2;
+ t -= dt;
+ }
+
+ s += ds;
+
+ /* Calculate alpha */
+ cp = (float)(abs(d)) / abs(t);
+ is = (float)( cp * imax + 0.1 );
+ ip = (float)( imax - is + 0.2 );
+
+ /* Overflow check */
+ if ( is > 1.0 )
+ is = 1.0;
+ if ( ip > 1.0 )
+ ip = 1.0;
+
+ /* Calculate alpha level */
+ s_alpha = (Uint8)(is*255);
+ p_alpha = (Uint8)(ip*255);
+ if ( alpha != 255 )
+ {
+ s_alpha = (Uint8)(s_alpha*alpha_pp);
+ p_alpha = (Uint8)(p_alpha*alpha_pp);
+ }
+
+
+ /* Upper half */
+ spg_pixelblend(surface, x, y, color, p_alpha);
+ spg_pixelblend(surface, 2*xc-x, y, color, p_alpha);
+
+ spg_pixelblend(surface, xs, y, color, s_alpha);
+ spg_pixelblend(surface, 2*xc-xs, y, color, s_alpha);
+
+
+ /* Lower half*/
+ spg_pixelblend(surface, x, 2*yc-y, color, p_alpha);
+ spg_pixelblend(surface, 2*xc-x, 2*yc-y, color, p_alpha);
+
+ spg_pixelblend(surface, xs, 2*yc-y, color, s_alpha);
+ spg_pixelblend(surface, 2*xc-xs, 2*yc-y, color, s_alpha);
+ }
+
+
+ spg_unlock(surface);
+
+}
+
+
+//==================================================================================
+// Draws an ellipse
+//==================================================================================
+void SPG_Ellipse(SDL_Surface *Surface, Sint16 x, Sint16 y, float rx, float ry, Uint32 color)
+{
+ if (spg_lock(Surface) < 0)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_Ellipse could not lock surface");
+ return;
+ }
+
+ if(spg_thickness == 1)
+ {
+ if(SPG_GetAA())
+ spg_ellipseblendaa(Surface, x, y, rx, ry, color, SDL_ALPHA_OPAQUE);
+ else
+ SPG_EllipseFn(Surface, x, y, rx, ry, color, spg_pixel);
+
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = x-rx;
+ rect.y = y-ry;
+ rect.w = 2*(Sint16)(rx) + 1; // +1 for even diameter?
+ rect.h = 2*(Sint16)(ry) + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+ else if(spg_thickness > 0)
+ {
+ SPG_EllipseFn(Surface, x, y, rx, ry, color, spg_thicknesscallback);
+
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = x-rx-spg_thickness/2;
+ rect.y = y-ry-spg_thickness/2;
+ rect.w = 2*(Sint16)(rx) + 1 + spg_thickness; // +1 for even diameter?
+ rect.h = 2*(Sint16)(ry) + 1 + spg_thickness;
+ // Clip it to the screen
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+
+ spg_unlock(Surface);
+}
+
+
+
+
+//==================================================================================
+// Draws an ellipse (alpha)
+//==================================================================================
+void SPG_EllipseBlend(SDL_Surface *Surface, Sint16 x, Sint16 y, float rx, float ry, Uint32 color, Uint8 alpha)
+{
+ if (spg_lock(Surface) < 0)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_EllipseBlend could not lock surface");
+ return;
+ }
+
+ if(spg_thickness == 1)
+ {
+ if(SPG_GetAA())
+ spg_ellipseblendaa(Surface, x, y, rx, ry, color, alpha);
+ else
+ {
+ spg_alphahack = alpha;
+ SPG_EllipseFn(Surface, x, y, rx, ry, color, spg_pixelcallbackalpha);
+
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = x-rx;
+ rect.y = y-ry;
+ rect.w = 2*(Sint16)(rx) + 1; // +1 for even diameter?
+ rect.h = 2*(Sint16)(ry) + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+ }
+ else if(spg_thickness > 0)
+ {
+ SPG_EllipseFn(Surface, x, y, rx, ry, color, spg_thicknesscallbackalpha);
+
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = x-rx-spg_thickness/2;
+ rect.y = y-ry-spg_thickness/2;
+ rect.w = 2*(Sint16)(rx) + 1 + spg_thickness; // +1 for even diameter?
+ rect.h = 2*(Sint16)(ry) + 1 + spg_thickness;
+ // Clip it to the screen
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+
+ spg_unlock(Surface);
+}
+
+
+
+
+//==================================================================================
+// Draws a filled anti-aliased ellipse
+// This is just a quick hack...
+//==================================================================================
+void spg_ellipsefilledaa(SDL_Surface *surface, Sint16 xc, Sint16 yc, float rx, float ry, Uint32 color)
+{
+ /* Sanity check */
+ if (rx < 1)
+ rx = 1;
+ if (ry < 1)
+ ry = 1;
+
+ int a2 = (Sint16)(rx) * (Sint16)(rx);
+ int b2 = (Sint16)(ry) * (Sint16)(ry);
+
+ int ds = 2 * a2;
+ int dt = 2 * b2;
+
+ int dxt = (int)(a2 / sqrt(a2 + b2));
+
+ int t = 0;
+ int s = -2 * a2 * (Sint16)(ry);
+ int d = 0;
+
+ Sint16 x = xc;
+ Sint16 y = yc - (Sint16)(ry);
+
+ Sint16 xs, ys, dyt;
+ float cp, is, ip, imax = 1.0;
+
+ if ( spg_lock(surface) < 0 )
+ {
+ if(spg_useerrors)
+ SPG_Error("spg_ellipsefilledaa could not lock surface");
+ return;
+ }
+
+ /* "End points" */
+ spg_pixel(surface, x, y, color);
+ spg_pixel(surface, 2*xc-x, y, color);
+
+ spg_pixel(surface, x, 2*yc-y, color);
+ spg_pixel(surface, 2*xc-x, 2*yc-y, color);
+
+ spg_unlock(surface);
+
+ spg_linev(surface, x, y+1, 2*yc-y-1, color);
+
+ int i;
+
+ for (i = 1; i <= dxt; i++)
+ {
+ x--;
+ d += t - b2;
+
+ if (d >= 0)
+ ys = y - 1;
+ else if ((d - s - a2) > 0)
+ {
+ if ((2 * d - s - a2) >= 0)
+ ys = y + 1;
+ else
+ {
+ ys = y;
+ y++;
+ d -= s + a2;
+ s += ds;
+ }
+ }
+ else
+ {
+ y++;
+ ys = y + 1;
+ d -= s + a2;
+ s += ds;
+ }
+
+ t -= dt;
+
+ /* Calculate alpha */
+ cp = (float) abs(d) / abs(s);
+ is = cp * imax;
+ ip = imax - is;
+
+ if ( spg_lock(surface) < 0 )
+ return;
+
+ /* Upper half */
+ spg_pixelblend(surface, x, y, color, (Uint8)(ip*255));
+ spg_pixelblend(surface, 2*xc-x, y, color, (Uint8)(ip*255));
+
+ spg_pixelblend(surface, x, ys, color, (Uint8)(is*255));
+ spg_pixelblend(surface, 2*xc-x, ys, color, (Uint8)(is*255));
+
+
+ /* Lower half */
+ spg_pixelblend(surface, x, 2*yc-y, color, (Uint8)(ip*255));
+ spg_pixelblend(surface, 2*xc-x, 2*yc-y, color, (Uint8)(ip*255));
+
+ spg_pixelblend(surface, x, 2*yc-ys, color, (Uint8)(is*255));
+ spg_pixelblend(surface, 2*xc-x, 2*yc-ys, color, (Uint8)(is*255));
+
+ spg_unlock(surface);
+
+
+ /* Fill */
+ spg_linev(surface, x, y+1, 2*yc-y-1, color);
+ spg_linev(surface, 2*xc-x, y+1, 2*yc-y-1, color);
+ spg_linev(surface, x, ys+1, 2*yc-ys-1, color);
+ spg_linev(surface, 2*xc-x, ys+1, 2*yc-ys-1, color);
+ }
+
+ dyt = abs(y - yc);
+
+ for (i = 1; i <= dyt; i++)
+ {
+ y++;
+ d -= s + a2;
+
+ if (d <= 0)
+ xs = x + 1;
+ else if ((d + t - b2) < 0)
+ {
+ if ((2 * d + t - b2) <= 0)
+ xs = x - 1;
+ else
+ {
+ xs = x;
+ x--;
+ d += t - b2;
+ t -= dt;
+ }
+ }
+ else
+ {
+ x--;
+ xs = x - 1;
+ d += t - b2;
+ t -= dt;
+ }
+
+ s += ds;
+
+ /* Calculate alpha */
+ cp = (float) abs(d) / abs(t);
+ is = cp * imax;
+ ip = imax - is;
+
+
+ if ( spg_lock(surface) < 0 )
+ {
+ if(spg_useerrors)
+ SPG_Error("spg_ellipsefilledaa could not lock surface");
+ return;
+ }
+
+ /* Upper half */
+ spg_pixelblend(surface, x, y, color, (Uint8)(ip*255));
+ spg_pixelblend(surface, 2*xc-x, y, color, (Uint8)(ip*255));
+
+ spg_pixelblend(surface, xs, y, color, (Uint8)(is*255));
+ spg_pixelblend(surface, 2*xc-xs, y, color, (Uint8)(is*255));
+
+
+ /* Lower half*/
+ spg_pixelblend(surface, x, 2*yc-y, color, (Uint8)(ip*255));
+ spg_pixelblend(surface, 2*xc-x, 2*yc-y, color, (Uint8)(ip*255));
+
+ spg_pixelblend(surface, xs, 2*yc-y, color, (Uint8)(is*255));
+ spg_pixelblend(surface, 2*xc-xs, 2*yc-y, color, (Uint8)(is*255));
+
+ spg_unlock(surface);
+
+ /* Fill */
+ spg_lineh(surface, x+1, y, 2*xc-x-1, color);
+ spg_lineh(surface, xs+1, y, 2*xc-xs-1, color);
+ spg_lineh(surface, x+1, 2*yc-y, 2*xc-x-1, color);
+ spg_lineh(surface, xs+1, 2*yc-y, 2*xc-xs-1, color);
+ }
+
+}
+
+
+//==================================================================================
+// Draws a filled ellipse
+//==================================================================================
+void SPG_EllipseFilled(SDL_Surface *Surface, Sint16 x, Sint16 y, float rx, float ry, Uint32 color)
+{
+
+ if(SPG_GetAA())
+ spg_ellipsefilledaa(Surface, x, y, rx, ry, color);
+ else
+ {
+ int ix, iy;
+ int h, i, j, k;
+ int oh, oi, oj, ok;
+
+ if (rx < 1)
+ rx = 1;
+
+ if (ry < 1)
+ ry = 1;
+
+ oh = oi = oj = ok = 0xFFFF;
+
+ if (rx > ry)
+ {
+ ix = 0;
+ iy = (Sint16)(rx) * 64;
+
+ do
+ {
+ h = (ix + 32) >> 6;
+ i = (iy + 32) >> 6;
+ j = (h * (Sint16)(ry)) / (Sint16)(rx);
+ k = (i * (Sint16)(ry)) / (Sint16)(rx);
+
+ if ((k!=ok) && (k!=oj))
+ {
+ if (k)
+ {
+ spg_lineh(Surface,x-h,y-k,x+h,color);
+ spg_lineh(Surface,x-h,y+k,x+h,color);
+ }
+ else
+ spg_lineh(Surface,x-h,y,x+h,color);
+ ok=k;
+ }
+
+ if ((j!=oj) && (j!=ok) && (k!=j))
+ {
+ if (j)
+ {
+ spg_lineh(Surface,x-i,y-j,x+i,color);
+ spg_lineh(Surface,x-i,y+j,x+i,color);
+ }
+ else
+ spg_lineh(Surface,x-i,y,x+i,color);
+ oj=j;
+ }
+
+ ix = ix + iy / (Sint16)(rx);
+ iy = iy - ix / (Sint16)(rx);
+
+ }
+ while (i > h);
+ }
+ else
+ {
+ ix = 0;
+ iy = (Sint16)(ry) * 64;
+
+ do
+ {
+ h = (ix + 32) >> 6;
+ i = (iy + 32) >> 6;
+ j = (h * (Sint16)(rx)) / (Sint16)(ry);
+ k = (i * (Sint16)(rx)) / (Sint16)(ry);
+
+ if ((i!=oi) && (i!=oh))
+ {
+ if (i)
+ {
+ spg_lineh(Surface,x-j,y-i,x+j,color);
+ spg_lineh(Surface,x-j,y+i,x+j,color);
+ }
+ else
+ spg_lineh(Surface,x-j,y,x+j,color);
+ oi=i;
+ }
+
+ if ((h!=oh) && (h!=oi) && (i!=h))
+ {
+ if (h)
+ {
+ spg_lineh(Surface,x-k,y-h,x+k,color);
+ spg_lineh(Surface,x-k,y+h,x+k,color);
+ }
+ else
+ spg_lineh(Surface,x-k,y,x+k,color);
+ oh=h;
+ }
+
+ ix = ix + iy / (Sint16)(ry);
+ iy = iy - ix / (Sint16)(ry);
+
+ }
+ while (i > h);
+ }
+ }
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = x-rx;
+ rect.y = y-ry;
+ rect.w = 2*(Sint16)(rx) + 1; // +1 for even diameter?
+ rect.h = 2*(Sint16)(ry) + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+
+
+}
+
+
+
+void spg_ellipsefilledblendaa(SDL_Surface *Surface, Sint16 x, Sint16 y, float rx, float ry, Uint32 color, Uint8 alpha)
+{
+ int ix, iy;
+ int h, i, j, k;
+ int oh, oi, oj, ok;
+
+ if (spg_lock(Surface) < 0)
+ {
+ if(spg_useerrors)
+ SPG_Error("spg_ellipsefilledblendaa could not lock surface");
+ return;
+ }
+
+
+ if (rx < 1)
+ rx = 1;
+
+ if (ry < 1)
+ ry = 1;
+
+ oh = oi = oj = ok = 0xFFFF;
+
+ if (rx > ry)
+ {
+ ix = 0;
+ iy = (Sint16)(rx) * 64;
+
+ do
+ {
+ h = (ix + 32) >> 6;
+ i = (iy + 32) >> 6;
+ j = (h * (Sint16)(ry)) / (Sint16)(rx);
+ k = (i * (Sint16)(ry)) / (Sint16)(rx);
+
+ if ((k!=ok) && (k!=oj))
+ {
+ if (k)
+ {
+ spg_linehblend(Surface,x-h,y-k,x+h,color, alpha);
+ spg_linehblend(Surface,x-h,y+k,x+h,color, alpha);
+ }
+ else
+ spg_linehblend(Surface,x-h,y,x+h,color, alpha);
+ ok=k;
+ }
+
+ if ((j!=oj) && (j!=ok) && (k!=j))
+ {
+ if (j)
+ {
+ spg_linehblend(Surface,x-i,y-j,x+i,color, alpha);
+ spg_linehblend(Surface,x-i,y+j,x+i,color, alpha);
+ }
+ else
+ spg_linehblend(Surface,x-i,y,x+i,color, alpha);
+ oj=j;
+ }
+
+ ix = ix + iy / (Sint16)(rx);
+ iy = iy - ix / (Sint16)(rx);
+
+ }
+ while (i > h);
+ }
+ else
+ {
+ ix = 0;
+ iy = (Sint16)(ry) * 64;
+
+ do
+ {
+ h = (ix + 32) >> 6;
+ i = (iy + 32) >> 6;
+ j = (h * (Sint16)(rx)) / (Sint16)(ry);
+ k = (i * (Sint16)(rx)) / (Sint16)(ry);
+
+ if ((i!=oi) && (i!=oh))
+ {
+ if (i)
+ {
+ spg_linehblend(Surface,x-j,y-i,x+j,color, alpha);
+ spg_linehblend(Surface,x-j,y+i,x+j,color, alpha);
+ }
+ else
+ spg_linehblend(Surface,x-j,y,x+j,color, alpha);
+ oi=i;
+ }
+
+ if ((h!=oh) && (h!=oi) && (i!=h))
+ {
+ if (h)
+ {
+ spg_linehblend(Surface,x-k,y-h,x+k,color, alpha);
+ spg_linehblend(Surface,x-k,y+h,x+k,color, alpha);
+ }
+ else
+ spg_linehblend(Surface,x-k,y,x+k,color, alpha);
+ oh=h;
+ }
+
+ ix = ix + iy / (Sint16)(ry);
+ iy = iy - ix / (Sint16)(ry);
+
+ }
+ while (i > h);
+ }
+
+ spg_ellipseblendaa(Surface, x, y, rx, ry, color, (Uint8)(alpha/1.5));
+
+ spg_unlock(Surface);
+
+}
+
+
+//==================================================================================
+// Draws a filled ellipse (alpha)
+//==================================================================================
+void SPG_EllipseFilledBlend(SDL_Surface *Surface, Sint16 x, Sint16 y, float rx, float ry, Uint32 color, Uint8 alpha)
+{
+
+ if(SPG_GetAA())
+ spg_ellipsefilledblendaa(Surface, x, y, rx, ry, color, alpha);
+ else
+ {
+ int ix, iy;
+ int h, i, j, k;
+ int oh, oi, oj, ok;
+
+ if (spg_lock(Surface) < 0)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_EllipseFilledBlend could not lock surface");
+ return;
+ }
+
+ if (rx < 1)
+ rx = 1;
+
+ if (ry < 1)
+ ry = 1;
+
+ oh = oi = oj = ok = 0xFFFF;
+
+ if (rx > ry)
+ {
+ ix = 0;
+ iy = (Sint16)(rx) * 64;
+
+ do
+ {
+ h = (ix + 32) >> 6;
+ i = (iy + 32) >> 6;
+ j = (h * (Sint16)(ry)) / (Sint16)(rx);
+ k = (i * (Sint16)(ry)) / (Sint16)(rx);
+
+ if ((k!=ok) && (k!=oj))
+ {
+ if (k)
+ {
+ spg_linehblend(Surface,x-h,y-k,x+h,color, alpha);
+ spg_linehblend(Surface,x-h,y+k,x+h,color, alpha);
+ }
+ else
+ spg_linehblend(Surface,x-h,y,x+h,color, alpha);
+ ok=k;
+ }
+
+ if ((j!=oj) && (j!=ok) && (k!=j))
+ {
+ if (j)
+ {
+ spg_linehblend(Surface,x-i,y-j,x+i,color, alpha);
+ spg_linehblend(Surface,x-i,y+j,x+i,color, alpha);
+ }
+ else
+ spg_linehblend(Surface,x-i,y,x+i,color, alpha);
+ oj=j;
+ }
+
+ ix = ix + iy / (Sint16)(rx);
+ iy = iy - ix / (Sint16)(rx);
+
+ }
+ while (i > h);
+ }
+ else
+ {
+ ix = 0;
+ iy = (Sint16)(ry) * 64;
+
+ do
+ {
+ h = (ix + 32) >> 6;
+ i = (iy + 32) >> 6;
+ j = (h * (Sint16)(rx)) / (Sint16)(ry);
+ k = (i * (Sint16)(rx)) / (Sint16)(ry);
+
+ if ((i!=oi) && (i!=oh))
+ {
+ if (i)
+ {
+ spg_linehblend(Surface,x-j,y-i,x+j,color, alpha);
+ spg_linehblend(Surface,x-j,y+i,x+j,color, alpha);
+ }
+ else
+ spg_linehblend(Surface,x-j,y,x+j,color, alpha);
+ oi=i;
+ }
+
+ if ((h!=oh) && (h!=oi) && (i!=h))
+ {
+ if (h)
+ {
+ spg_linehblend(Surface,x-k,y-h,x+k,color, alpha);
+ spg_linehblend(Surface,x-k,y+h,x+k,color, alpha);
+ }
+ else
+ spg_linehblend(Surface,x-k,y,x+k,color, alpha);
+ oh=h;
+ }
+
+ ix = ix + iy / (Sint16)(ry);
+ iy = iy - ix / (Sint16)(ry);
+
+ }
+ while (i > h);
+ }
+
+ spg_unlock(Surface);
+ }
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = x-rx;
+ rect.y = y-ry;
+ rect.w = 2*(Sint16)(rx) + 1; // +1 for even diameter?
+ rect.h = 2*(Sint16)(ry) + 1;
+ // Clip it to the screen
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+
+
+}
+
+
+
+void SPG_EllipseBlendArb(SDL_Surface *Surface, Sint16 x, Sint16 y, float rx, float ry, float angle, Uint32 color, Uint8 alpha)
+{
+
+}
+
+void SPG_EllipseArb(SDL_Surface *Surface, Sint16 x, Sint16 y, float rx, float ry, float angle, Uint32 color)
+{
+ SPG_EllipseBlendArb(Surface, x, y, rx, ry, angle, color, SDL_ALPHA_OPAQUE);
+}
+
+void SPG_EllipseFilledBlendArb(SDL_Surface *Surface, Sint16 x, Sint16 y, float rx, float ry, float angle, Uint32 color, Uint8 alpha)
+{
+
+}
+
+void SPG_EllipseFilledArb(SDL_Surface *Surface, Sint16 x, Sint16 y, float rx, float ry, float angle, Uint32 color)
+{
+ SPG_EllipseFilledBlendArb(Surface, x, y, rx, ry, angle, color, SDL_ALPHA_OPAQUE);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+//==================================================================================
+// Performs Callback at each circle point.
+//==================================================================================
+void SPG_CircleFn(SDL_Surface *Surface, Sint16 x, Sint16 y, float r, Uint32 color, void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y, Uint32 Color))
+{
+ if(r < 0)
+ return;
+ SPG_bool offset = 0; // even diameter fix
+ Sint16 effr = (Sint16)(r);
+ if(r == 0)
+ {
+ //Callback(Surface, x, y, color);
+ return;
+ }
+ else if(r - effr > 0.33333f && r - effr < 0.66667f)
+ offset = 1;
+ else if(r - effr >= 0.66667f)
+ effr++;
+
+ Sint16 cx = 0;
+ Sint16 cy = effr;
+ Sint16 df = 1 - effr;
+ Sint16 d_e = 3;
+ Sint16 d_se = -2 * effr + 5;
+
+
+ do
+ {
+ if(cx || offset)
+ {
+ Callback(Surface, x+cx+offset, y+cy+offset, color);
+ Callback(Surface, x+cy+offset, y-cx, color);
+ Callback(Surface, x-cx, y-cy, color);
+ Callback(Surface, x-cy, y-cx, color);
+ }
+
+ Callback(Surface, x+cx+offset, y-cy, color);
+ Callback(Surface, x-cx, y+cy+offset, color);
+ Callback(Surface, x+cy+offset, y+cx+offset, color);
+ Callback(Surface, x-cy, y+cx+offset, color);
+
+ if (df < 0)
+ {
+ df += d_e;
+ d_e += 2;
+ d_se += 2;
+ }
+ else
+ {
+ df += d_se;
+ d_e += 2;
+ d_se += 4;
+ cy--;
+ }
+
+ cx++;
+
+ }
+ while (cx <= cy);
+
+}
+
+
+
+
+//==================================================================================
+// Draws a circle
+//==================================================================================
+void SPG_Circle(SDL_Surface *Surface, Sint16 x, Sint16 y, float r, Uint32 color)
+{
+ if(r < 0)
+ return;
+
+ if (spg_lock(Surface) < 0)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_Circle could not lock surface");
+ return;
+ }
+
+ if(spg_thickness == 1)
+ {
+ if(SPG_GetAA())
+ spg_ellipseblendaa(Surface, x, y, r, r, color, SDL_ALPHA_OPAQUE);
+ else
+ SPG_CircleFn(Surface, x, y, r, color, spg_pixel);
+
+ if(spg_makedirtyrects)
+ {
+ Sint16 rr = (Sint16)(r);
+ SDL_Rect rect = {x - rr, y - rr, 2*rr + 2, 2*rr + 2}; // +1 to get to the edge, +1 more for even-diameter
+ // Clip it to the screen
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+
+ }
+ else if(spg_thickness != 0)
+ {
+ SPG_CircleFn(Surface, x, y, r, color, spg_thicknesscallback);
+ if(spg_makedirtyrects)
+ {
+ Sint16 rr = (Sint16)(r);
+ SDL_Rect rect = {x - rr - spg_thickness/2, y - rr - spg_thickness/2, 2*rr + 2 + spg_thickness, 2*rr + 2 + spg_thickness}; // +1 to get to the edge, +1 more for even-diameter
+ // Clip it to the screen
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+
+ spg_unlock(Surface);
+
+}
+
+
+
+//==================================================================================
+// Draws a circle (alpha)
+//==================================================================================
+void SPG_CircleBlend(SDL_Surface *Surface, Sint16 x, Sint16 y, float r, Uint32 color, Uint8 alpha)
+{
+ if(r < 0)
+ return;
+
+ if (spg_lock(Surface) < 0)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_CircleBlend could not lock surface");
+ return;
+ }
+
+ if(spg_thickness == 1)
+ {
+ spg_alphahack = alpha;
+ if(SPG_GetAA())
+ spg_ellipseblendaa(Surface, x, y, r, r, color, alpha);
+ else
+ SPG_CircleFn(Surface, x, y, r, color, spg_pixelcallbackalpha);
+
+ if(spg_makedirtyrects)
+ {
+ Sint16 rr = (Sint16)(r);
+ SDL_Rect rect = {x - rr, y - rr, 2*rr + 2, 2*rr + 2}; // +1 to get to the edge, +1 more for even-diameter
+ // Clip it to the screen
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+ else if(spg_thickness != 0)
+ {
+ SPG_CircleFn(Surface, x, y, r, color, spg_thicknesscallbackalpha);
+ if(spg_makedirtyrects)
+ {
+ Sint16 rr = (Sint16)(r);
+ SDL_Rect rect = {x - rr - spg_thickness/2, y - rr - spg_thickness/2, 2*rr + 2 + spg_thickness, 2*rr + 2 + spg_thickness}; // +1 to get to the edge, +1 more for even-diameter
+ // Clip it to the screen
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+
+ spg_unlock(Surface);
+
+}
+
+
+
+
+//==================================================================================
+// Draws a filled circle
+//==================================================================================
+void SPG_CircleFilled(SDL_Surface *Surface, Sint16 x, Sint16 y, float r, Uint32 color)
+{
+ if(r < 0)
+ return;
+ SPG_bool offset = 0; // even diameter fix
+ Sint16 effr = (Sint16)(r);
+ if(r == 0)
+ {
+ SPG_Pixel(Surface, x, y, color); // this is necessary for thickness stuff
+ return;
+ }
+ else if(r - effr > 0.33333f && r - effr < 0.66667f)
+ offset = 1;
+ else if(r - effr >= 0.66667f)
+ effr++;
+
+
+ if(SPG_GetAA())
+ spg_ellipsefilledaa(Surface, x, y, r, r, color);
+ else
+ {
+ Sint16 cx = 0;
+ Sint16 cy = effr;
+ Sint16 df = 1 - effr;
+ Sint16 d_e = 3;
+ Sint16 d_se = -2 * effr + 5;
+
+ do
+ {
+ if(df >= 0)
+ {
+ spg_lineh(Surface,x-cx,y+cy+offset,x+cx+offset,color);
+ spg_lineh(Surface,x-cx,y-cy,x+cx+offset,color);
+ }
+
+ if(cx != cy)
+ {
+ spg_lineh(Surface,x-cy,y+cx+offset,x+cy+offset,color);
+ if(cx || offset)
+ {
+ spg_lineh(Surface,x-cy,y-cx,x+cy+offset,color);
+ }
+ }
+
+ if (df < 0)
+ {
+ df += d_e;
+ d_e += 2;
+ d_se += 2;
+ }
+ else
+ {
+ df += d_se;
+ d_e += 2;
+ d_se += 4;
+ cy--;
+ }
+ cx++;
+ }
+ while (cx <= cy);
+ }
+ if(spg_makedirtyrects)
+ {
+ Sint16 rr = (Sint16)(r);
+ SDL_Rect rect = {x - rr, y - rr, 2*rr + 2, 2*rr + 2}; // +1 to get to the edge, +1 more for even-diameter
+ // Clip it to the screen
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+
+}
+
+
+
+//==================================================================================
+// Draws a filled circle (alpha)
+//==================================================================================
+void SPG_CircleFilledBlend(SDL_Surface *Surface, Sint16 x, Sint16 y, float r, Uint32 color, Uint8 alpha)
+{
+ if(r < 0)
+ return;
+ if(SPG_GetAA())
+ spg_ellipsefilledblendaa(Surface, x, y, r, r, color, alpha);
+ else
+ {
+ SPG_bool offset = 0; // even diameter fix
+ Sint16 effr = (Sint16)(r);
+ if(r == 0)
+ {
+ SPG_PixelBlend(Surface, x, y, color, alpha);
+ return;
+ }
+ else if(r - effr > 0.33333f && r - effr < 0.66667f)
+ offset = 1;
+ else if(r - effr >= 0.66667f)
+ effr++;
+
+ Sint16 cx = 0;
+ Sint16 cy = effr;
+ Sint16 df = 1 - effr;
+ Sint16 d_e = 3;
+ Sint16 d_se = -2 * effr + 5;
+
+ if (spg_lock(Surface) < 0)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_CircleFilledBlend could not lock surface");
+ return;
+ }
+
+ do
+ {
+ if(df >= 0)
+ {
+ spg_linehblend(Surface,x-cx,y+cy+offset,x+cx+offset,color, alpha);
+ spg_linehblend(Surface,x-cx,y-cy,x+cx+offset,color, alpha);
+ }
+
+ if(cx != cy)
+ {
+ spg_linehblend(Surface,x-cy,y+cx+offset,x+cy+offset,color, alpha);
+ if(cx || offset)
+ {
+ spg_linehblend(Surface,x-cy,y-cx,x+cy+offset,color, alpha);
+ }
+ }
+
+ if (df < 0)
+ {
+ df += d_e;
+ d_e += 2;
+ d_se += 2;
+ }
+ else
+ {
+ df += d_se;
+ d_e += 2;
+ d_se += 4;
+ cy--;
+ }
+ cx++;
+ }
+ while (cx <= cy);
+
+ spg_unlock(Surface);
+ }
+ if(spg_makedirtyrects)
+ {
+ Sint16 rr = (Sint16)(r);
+ SDL_Rect rect = {x - rr, y - rr, 2*rr + 2, 2*rr + 2}; // +1 to get to the edge, +1 more for even-diameter
+ // Clip it to the screen
+ SPG_DirtyClip(Surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+
+}
+
+
+
+
+// based on Google answer by theta-ga
+void SPG_ArcFn(SDL_Surface* surface, Sint16 cx, Sint16 cy, float radius, float startAngle, float endAngle, Uint32 color, void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y, Uint32 Color))
+{
+ float angle; // use as swap then use later
+ float originalSA = startAngle;
+
+ if(startAngle > endAngle)
+ {
+ float swapa = endAngle;
+ endAngle = startAngle;
+ startAngle = swapa;
+ }
+ if(startAngle == endAngle)
+ return;
+
+ if(!spg_usedegrees)
+ {
+ startAngle *= DEGPERRAD;
+ endAngle *= DEGPERRAD;
+ }
+
+ // Big angle
+ if(endAngle - startAngle >= 360)
+ {
+ SPG_CircleFn(surface, cx, cy, radius, color, Callback);
+ return;
+ }
+
+ // Shift together
+ while(startAngle < 0 && endAngle < 0)
+ {
+ startAngle += 360;
+ endAngle += 360;
+ }
+ while(startAngle > 360 && endAngle > 360)
+ {
+ startAngle -= 360;
+ endAngle -= 360;
+ }
+
+ // Check if the angle to be drawn crosses 0
+ SPG_bool crossesZero = (startAngle < 0 && endAngle > 0) || (startAngle < 360 && endAngle > 360);
+
+ // Push all values to 0 <= angle < 360
+ while(startAngle >= 360)
+ startAngle -= 360;
+ while(endAngle >= 360)
+ endAngle -= 360;
+ while(startAngle < 0)
+ startAngle += 360;
+ while(endAngle < 0)
+ endAngle += 360;
+
+ if(endAngle == 0)
+ endAngle = 360;
+ else if(crossesZero)
+ {
+ SPG_ArcFn(surface, cx, cy, radius, originalSA, (spg_usedegrees? 359 : PI2 - 0.02f) , color, Callback);
+ startAngle = 0;
+ }
+
+ Sint16 x = 0;
+ Sint16 y = (Sint16)(radius);
+ Sint16 p = 1 - (Sint16)(radius);
+ Sint16 d_e = 3;
+ Sint16 d_se = -2 * (Sint16)(radius) + 5;
+
+ do
+ {
+ // Calculate the angle the current point makes with the circle center
+ angle = atan2((float)y, (float)x)*DEGPERRAD;
+
+ // draw the circle points as long as they lie in the range specified
+
+ if(x)
+ {
+ // draw point in range 45 to 90 degrees
+ if (angle >= startAngle && angle <= endAngle) {
+ Callback(surface, cx + x, cy + y, color);
+ }
+ // draw point in range 180 to 225 degrees
+ if (270 - angle >= startAngle && 270 - angle <= endAngle) {
+ Callback(surface, cx - y, cy - x, color);
+ }
+ // draw point in range 225 to 270 degrees
+ if (angle + 180 >= startAngle && angle + 180 <= endAngle) {
+ Callback(surface, cx - x, cy - y, color);
+ }
+ // draw point in range 315 to 360 degrees
+ if (angle + 270 >= startAngle && angle + 270 <= endAngle) {
+ Callback(surface, cx + y, cy - x, color);
+ }
+ }
+
+ // draw point in range 0 to 45 degrees
+ if (90 - angle >= startAngle && 90 - angle <= endAngle) {
+ Callback(surface, cx + y, cy + x, color);
+ }
+
+ // draw point in range 90 to 135 degrees
+ if (180 - angle >= startAngle && 180 - angle <= endAngle) {
+ Callback(surface, cx - x, cy + y, color);
+ }
+
+ // draw point in range 135 to 180 degrees
+ if (angle + 90 >= startAngle && angle + 90 <= endAngle) {
+ Callback(surface, cx - y, cy + x, color);
+ }
+
+ // draw point in range 270 to 315 degrees
+ if (360 - angle >= startAngle && 360 - angle <= endAngle) {
+ Callback(surface, cx + x, cy - y, color);
+ }
+
+
+ x++;
+
+ if (p < 0)
+ {
+ p += d_e;
+ d_e += 2;
+ d_se += 2;
+ }
+ else
+ {
+ p += d_se;
+ d_e += 2;
+ d_se += 4;
+ y--;
+ }
+ }
+ while (x <= y);
+}
+
+void SPG_Arc(SDL_Surface* surface, Sint16 x, Sint16 y, float radius, float angle1, float angle2, Uint32 color)
+{
+ if (spg_lock(surface) < 0)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_Arc could not lock surface");
+ return;
+ }
+
+ if(spg_thickness == 1)
+ {
+ SPG_ArcFn(surface, x, y, radius, angle1, angle2, color, spg_pixel);
+ if(spg_makedirtyrects)
+ {
+ Sint16 rr = (Sint16)(radius);
+ SDL_Rect rect = {x - rr, y - rr, 2*rr + 2, 2*rr + 2}; // +1 to get to the edge, +1 more for even-diameter
+ // Clip it to the screen
+ SPG_DirtyClip(surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+ else if(spg_thickness > 0)
+ {
+ SPG_ArcFn(surface, x, y, radius, angle1, angle2, color, spg_thicknesscallback);
+ if(spg_makedirtyrects)
+ {
+ Sint16 rr = (Sint16)(radius);
+ SDL_Rect rect = {x - rr - spg_thickness/2, y - rr - spg_thickness/2, 2*rr + 2 + spg_thickness, 2*rr + 2 + spg_thickness}; // +1 to get to the edge, +1 more for even-diameter
+ // Clip it to the screen
+ SPG_DirtyClip(surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+ spg_unlock(surface);
+
+
+}
+
+void SPG_ArcBlend(SDL_Surface* surface, Sint16 x, Sint16 y, float radius, float angle1, float angle2, Uint32 color, Uint8 alpha)
+{
+ if (spg_lock(surface) < 0)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_ArcBlend could not lock surface");
+ return;
+ }
+
+ spg_alphahack = alpha;
+
+ if(spg_thickness == 1)
+ {
+ SPG_ArcFn(surface, x, y, radius, angle1, angle2, color, spg_pixelcallbackalpha);
+
+ if(spg_makedirtyrects)
+ {
+ Sint16 rr = (Sint16)(radius);
+ SDL_Rect rect = {x - rr, y - rr, 2*rr + 2, 2*rr + 2}; // +1 to get to the edge, +1 more for even-diameter
+ // Clip it to the screen
+ SPG_DirtyClip(surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+ else if(spg_thickness > 0)
+ {
+ SPG_ArcFn(surface, x, y, radius, angle1, angle2, color, spg_thicknesscallbackalpha);
+
+ if(spg_makedirtyrects)
+ {
+ Sint16 rr = (Sint16)(radius);
+ SDL_Rect rect = {x - rr - spg_thickness/2, y - rr - spg_thickness/2, 2*rr + 2 + spg_thickness, 2*rr + 2 + spg_thickness}; // +1 to get to the edge, +1 more for even-diameter
+ // Clip it to the screen
+ SPG_DirtyClip(surface, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ }
+
+ spg_unlock(surface);
+
+}
+
+static inline float min(float a, float b)
+{
+ return a < b? a : b;
+}
+
+static inline float max(float a, float b)
+{
+ return a > b? a : b;
+}
+
+
+// Draws a pie shape from startAngle to endAngle going the quickest way, numerically
+// e.g. 20 -> 210 goes positively, 180 -> 30 goes negatively, 30 -> 400 makes a full circle
+void SPG_ArcFilledBlend(SDL_Surface* surf, Sint16 x, Sint16 y, float r, float startAngle, float endAngle, Uint32 color, Uint8 alpha)
+{
+ Sint16 cx = 0;
+ Sint16 cy = (Sint16)r;
+ Sint16 df = 1 - cy;
+ Sint16 d_e = 3;
+ Sint16 d_se = -2*cy + 5;
+ Sint16 xl, xr;
+
+ if(startAngle > endAngle)
+ {
+ float swapa = endAngle;
+ endAngle = startAngle;
+ startAngle = swapa;
+ }
+ if(startAngle == endAngle)
+ return;
+
+ if(!spg_usedegrees)
+ {
+ startAngle *= DEGPERRAD;
+ endAngle *= DEGPERRAD;
+ }
+
+ SPG_bool reflex = endAngle - startAngle > 180;
+
+ Sint16 sx = (Sint16)(r*cos(startAngle*RADPERDEG));
+ Sint16 sy = (Sint16)(r*sin(startAngle*RADPERDEG));
+ Sint16 ex = (Sint16)(r*cos(endAngle*RADPERDEG));
+ Sint16 ey = (Sint16)(r*sin(endAngle*RADPERDEG));
+
+ float sm = sy/(float)(sx);
+ float em = ey/(float)(ex);
+
+ // Big angle
+ if(endAngle - startAngle >= 360)
+ {
+ SPG_CircleFilledBlend(surf, x, y, r, color, alpha);
+ return;
+ }
+ // coordinates overlap
+ if(sy == ey && sx >= ex - 1 && ex + 1 <= sx && endAngle - startAngle > 350)
+ {
+ SPG_CircleFilledBlend(surf, x, y, r, color, alpha);
+ return;
+ }
+ if(sy == ey && sx == ex && endAngle - startAngle < 10)
+ return;
+
+
+ // Push all values to 0 <= angle < 360
+ while(startAngle >= 360)
+ startAngle -= 360;
+ while(endAngle >= 360)
+ endAngle -= 360;
+ while(startAngle < 0)
+ startAngle += 360;
+ while(endAngle < 0)
+ endAngle += 360;
+
+ // I should change these to sy and ey in case the angle rounds to 180
+ SPG_bool bothTop = (startAngle > 180 && endAngle > 180);
+ SPG_bool bothBot = (startAngle < 180 && endAngle < 180);
+ //bool bothTop = sy < 0 && ey < 0;
+ //bool bothBot = sy >= 0 && ey >= 0;
+
+ // Use thse to fix special cases
+ SPG_bool s180 = sy == 0 && sx < 0;
+ SPG_bool s0 = sy == 0 && sx >= 0;
+ SPG_bool e180 = ey == 0 && ex < 0;
+ SPG_bool e0 = ey == 0 && ex >= 0;
+
+
+ do
+ {
+ if(df >= 0)
+ {
+ if(!bothTop)
+ {
+ // Draw bottom between lines
+ // Intercept of lines vs edge of circle
+ xl = ey > 0? (Sint16)max(cy/em + x, x - cx) : (Sint16)x - cx;
+ xr = sy > 0? (Sint16)min(cy/sm + x, x + cx) : (Sint16)x + cx;
+ if(xl <= xr && !(s180 && ey <= 0) && !(sy <= 0 && e0))
+ spg_linehblend(surf, xl, y + cy, xr, color, alpha);
+ }
+ else if(reflex)
+ {
+ // Draw entire bottom
+ spg_linehblend(surf, x - cx, y + cy, x + cx, color, alpha);
+
+ // Draw separated top
+ // sy <= 0, ey < 0, ex < sx
+ xl = x - cx; // Intercept of lines vs edge of circle
+ xr = ey < 0? (Sint16)min(-cy/em + x, x + cx) : x + cx;
+ if(xl <= xr)
+ spg_linehblend(surf, xl, y - cy, xr, color, alpha);
+
+ xl = sy < 0? (Sint16)max(-cy/sm + x, x - cx) : x - cx;
+ xr = x + cx;
+ if(xl <= xr)
+ spg_linehblend(surf, xl, y - cy, xr, color, alpha);
+
+ }
+ if(!bothBot)
+ {
+ // Draw top between lines
+ xl = sy < 0? (Sint16)max(-cy/sm + x, x - cx) : (Sint16)x - cx;
+ xr = ey < 0? (Sint16)min(-cy/em + x, x + cx) : (Sint16)x + cx;
+ if(xl <= xr && !(e180 && sy >= 0))
+ spg_linehblend(surf, xl, y - cy, xr, color, alpha);
+ }
+ else if(reflex)
+ {
+ // Draw entire top
+ spg_linehblend(surf, x - cx, y - cy, x + cx, color, alpha);
+
+ // Draw separated bottom
+ // sy >= 0, ey > 0, sx < ex
+ xl = x - cx; // Intercept of lines vs edge of circle
+ xr = sy > 0? (Sint16)min(cy/sm + x, x + cx) : x + cx;
+ if(xl <= xr && !s0 && !(sy > 0 && e0))
+ spg_linehblend(surf, xl, y + cy, xr, color, alpha);
+
+ xl = ey > 0? (Sint16)max(cy/em + x, x - cx) : x - cx;
+ xr = x + cx;
+ if(xl <= xr && !(sy > 0 && e0))
+ spg_linehblend(surf, xl, y + cy, xr, color, alpha);
+ }
+ }
+ if(cx != cy)
+ {
+ if(!bothTop)
+ {
+ // Draw bottom between lines
+ xl = ey > 0? (Sint16)max(cx/em + x, x - cy) : (Sint16)x - cy;
+ xr = sy > 0? (Sint16)min(cx/sm + x, x + cy) : (Sint16)x + cy;
+ if(xl <= xr && !(s180 && ey <= 0) && !(sy <= 0 && e0))
+ spg_linehblend(surf, xl, y + cx, xr, color, alpha);
+ }
+ else if(reflex)
+ {
+ if(cx != 0)
+ {
+ // Draw entire bottom
+ spg_linehblend(surf, x - cy, y + cx, x + cy, color, alpha);
+ }
+
+ // Draw separated top
+ // sy <= 0, ey < 0, ex < sx
+ xl = x - cy; // Intercept of lines vs edge of circle
+ xr = ey < 0? (Sint16)min(-cx/em + x, x + cy) : x + cy;
+ if(xl <= xr)
+ spg_linehblend(surf, xl, y - cx, xr, color, alpha);
+
+ xl = sy < 0? (Sint16)max(-cx/sm + x, x - cy) : x - cy;
+ xr = x + cy;
+ if(xl <= xr)
+ spg_linehblend(surf, xl, y - cx, xr, color, alpha);
+
+ }
+ if(cx && (!bothBot)) // Don't draw the center line twice
+ {
+ // Draw top between lines
+ xl = sy < 0? (Sint16)max(-cx/sm + x, x - cy) : (Sint16)x - cy;
+ xr = ey < 0? (Sint16)min(-cx/em + x, x + cy) : (Sint16)x + cy;
+ if(xl <= xr && !(e180 && sy >= 0))
+ spg_linehblend(surf, xl, y - cx, xr, color, alpha);
+ }
+ else if(bothBot && reflex)
+ {
+ if(cx != 0)
+ {
+ // Draw entire top
+ spg_linehblend(surf, x - cy, y - cx, x + cy, color, alpha);
+ }
+
+ // Draw separated bottom
+ // sy >= 0, ey > 0, sx < ex
+ xl = x - cy; // Intercept of lines vs edge of circle
+ xr = sy > 0? (Sint16)min(cx/sm + x, x + cy) : x + cy;
+ if(xl <= xr && !s0 && !(sy > 0 && e0))
+ spg_linehblend(surf, xl, y + cx, xr, color, alpha);
+
+ xl = ey > 0? (Sint16)max(cx/em + x, x - cy) : x - cy;
+ xr = x + cy;
+ if(xl <= xr && !(sy > 0 && e0))
+ spg_linehblend(surf, xl, y + cx, xr, color, alpha);
+
+ }
+
+ }
+ if(df < 0)
+ {
+ df += d_e;
+ d_e += 2;
+ d_se += 2;
+ }
+ else
+ {
+ df += d_se;
+ d_e += 2;
+ d_se += 4;
+ cy--;
+ }
+ cx++;
+ }while(cx <= cy);
+ if(spg_makedirtyrects)
+ {
+ Sint16 rr = (Sint16)(r);
+ SDL_Rect rect = {x - rr, y - rr, 2*rr + 2, 2*rr + 2}; // +1 to get to the edge, +1 more for even-diameter
+ // Clip it to the screen
+ SPG_DirtyClip(surf, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+
+}
+
+void SPG_ArcFilled(SDL_Surface* surface, Sint16 cx, Sint16 cy, float radius, float startAngle, float endAngle, Uint32 color)
+{
+ SPG_ArcFilledBlend(surface, cx, cy, radius, startAngle, endAngle, color, SDL_ALPHA_OPAQUE);
+}
+
+
+
+
+
+//==================================================================================
+// Draws a bezier line
+//==================================================================================
+/* Macro to do the line... 'function' is the line drawing routine */
+#define DO_BEZIER(function)\
+ /*
+* Note:
+I don't think there is any great performance win in translating this to fixed-point integer math,
+* most of the time is spent in the line drawing routine.
+*/\
+float x = (float)(startX), y = (float)(startY);\
+float xp = x, yp = y;\
+float delta;\
+float dx, d2x, d3x;\
+float dy, d2y, d3y;\
+float a, b, c;\
+int i;\
+int n = 1;\
+Sint16 xmax=startX, ymax=startY, xmin=startX, ymin=startY;\
+\
+/* compute number of iterations */\
+if(quality < 1)\
+quality=1;\
+if(quality >= 15)\
+quality=15; \
+while (quality-- > 0)\
+n*= 2;\
+delta = 1.0f / n;\
+\
+/* compute finite differences */\
+/* a, b, c are the coefficient of the polynom in t defining the parametric curve */\
+/* The computation is done independently for x and y */\
+a = (float)(-startX + 3*cx1 - 3*cx2 + endX);\
+b = (float)(3*startX - 6*cx1 + 3*cx2);\
+c = (float)(-3*startX + 3*cx1);\
+\
+d3x = 6 * a * delta*delta*delta;\
+d2x = d3x + 2 * b * delta*delta;\
+dx = a * delta*delta*delta + b * delta*delta + c * delta;\
+\
+a = (float)(-startY + 3*cy1 - 3*cy2 + endY);\
+b = (float)(3*startY - 6*cy1 + 3*cy2);\
+c = (float)(-3*startY + 3*cy1);\
+\
+d3y = 6 * a * delta*delta*delta;\
+d2y = d3y + 2 * b * delta*delta;\
+dy = a * delta*delta*delta + b * delta*delta + c * delta;\
+\
+if (spg_lock(surface) < 0) {\
+if(spg_useerrors)\
+SPG_Error("SPG_Bezier could not lock surface");\
+return; }\
+\
+/* iterate */\
+for (i = 0; i < n; i++) {\
+x += dx; dx += d2x; d2x += d3x;\
+y += dy; dy += d2y; d2y += d3y;\
+if((Sint16)(xp) != (Sint16)(x) || (Sint16)(yp) != (Sint16)(y)){\
+function;\
+if(dirty){\
+xmax= (xmax>(Sint16)(xp))? xmax : (Sint16)(xp); ymax= (ymax>(Sint16)(yp))? ymax : (Sint16)(yp);\
+xmin= (xmin<(Sint16)(xp))? xmin : (Sint16)(xp); ymin= (ymin<(Sint16)(yp))? ymin : (Sint16)(yp);\
+xmax= (xmax>(Sint16)(x))? xmax : (Sint16)(x); ymax= (ymax>(Sint16)(y))? ymax : (Sint16)(y);\
+xmin= (xmin<(Sint16)(x))? xmin : (Sint16)(x); ymin= (ymin<(Sint16)(y))? ymin : (Sint16)(y);\
+}\
+}\
+xp = x; yp = y;\
+}\
+\
+spg_unlock(surface);\
+if(dirty)\
+{\
+SDL_Rect rect = {xmin - spg_thickness/2, ymin - spg_thickness/2, xmax-xmin+1 + spg_thickness, ymax-ymin+1 + spg_thickness};\
+/* Clip it to the screen */\
+SPG_DirtyClip(surface, &rect);\
+SPG_DirtyAddTo(spg_dirtytable_front, &rect);\
+}
+
+
+//==================================================================================
+// Draws a bezier line
+//==================================================================================
+void SPG_Bezier(SDL_Surface *surface, Sint16 startX, Sint16 startY, Sint16 cx1, Sint16 cy1, Sint16 cx2, Sint16 cy2, Sint16 endX, Sint16 endY, Uint8 quality, Uint32 color)
+{
+ if (spg_lock(surface) < 0)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_Bezier could not lock surface");
+ return;
+ }
+
+ // Disable autolock so we can continually use SPG_Line's AA
+ Uint8 lock = spg_autolock;
+ SPG_bool dirty = spg_makedirtyrects;
+ spg_autolock = 0;
+ spg_makedirtyrects = 0;
+
+
+ DO_BEZIER(SPG_Line(surface, (Sint16)(xp),(Sint16)(yp), (Sint16)(x),(Sint16)(y), color));
+
+ spg_unlock(surface);
+
+ spg_autolock = lock;
+ spg_makedirtyrects = dirty;
+}
+
+
+
+//==================================================================================
+// Draws a bezier line (alpha)
+//==================================================================================
+void SPG_BezierBlend(SDL_Surface *surface, Sint16 startX, Sint16 startY, Sint16 cx1, Sint16 cy1, Sint16 cx2, Sint16 cy2, Sint16 endX, Sint16 endY, Uint8 quality, Uint32 color, Uint8 alpha)
+{
+ if (spg_lock(surface) < 0)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_BezierBlend could not lock surface");
+ return;
+ }
+
+ // Disable autolock so we can continually use SPG_LineBlend's AA
+ Uint8 lock = spg_autolock;
+ SPG_bool dirty = spg_makedirtyrects;
+ spg_autolock = 0;
+ spg_makedirtyrects = 0;
+
+
+ DO_BEZIER(SPG_LineBlend(surface, (Sint16)(xp),(Sint16)(yp), (Sint16)(x),(Sint16)(y), color, alpha));
+
+ spg_unlock(surface);
+
+ spg_autolock = lock;
+ spg_makedirtyrects = dirty;
+}
+
+
+
+
+
+
diff --git a/util/sdl/sprig/SPG_rotation.c b/util/sdl/sprig/SPG_rotation.c
new file mode 100644
index 00000000..3bbb2437
--- /dev/null
+++ b/util/sdl/sprig/SPG_rotation.c
@@ -0,0 +1,736 @@
+/*
+ SPriG - SDL Primitive Generator
+ by Jonathan Dearborn
+
+ Based on SGE: SDL Graphics Extension r030809
+ by Anders Lindström
+*/
+
+
+/*********************************************************************
+ * 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. *
+ *********************************************************************/
+
+
+#include "sprig.h"
+#include "sprig_common.h"
+
+#include <math.h>
+
+#ifdef SPG_USE_FAST_MATH
+#define sqrt fastsqrt
+// Fast sqrt for IEEE floating point. From Wikipedia.
+float fastsqrt(float value)
+{
+ union
+ {
+ int tmp;
+ float val;
+ } u;
+ u.val = value;
+ u.tmp -= 1<<23; /* Remove last bit so 1.0 gives 1.0 */
+ /* tmp is now an approximation to logbase2(val) */
+ u.tmp >>= 1; /* divide by 2 */
+ u.tmp += 1<<29; /* add 64 to exponent: (e+127)/2 =(e/2)+63, */
+ /* that represents (e/2)-64 but we want e/2 */
+ return u.val;
+}
+#endif
+
+
+
+extern SPG_bool spg_useerrors;
+extern SPG_bool spg_usedegrees;
+extern SPG_bool spg_makedirtyrects;
+extern SPG_DirtyTable* spg_dirtytable_front;
+
+void spg_pixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color);
+SDL_Rect spg_transform_tmap(SDL_Surface *src, SDL_Surface *dst, float angle, float xscale, float yscale, Uint16 qx, Uint16 qy);
+
+
+
+
+
+//==================================================================================
+// Helper function to SPG_TransformX()
+// Returns the bounding box
+//==================================================================================
+void spg_calcrect(SDL_Surface *src, SDL_Surface *dst, float theta, float xscale, float yscale, Uint16 px, Uint16 py, Uint16 qx, Uint16 qy, Sint16 *xmin, Sint16 *ymin, Sint16 *xmax, Sint16 *ymax)
+{
+ Sint16 x, y, rx, ry;
+
+ // Clip to src surface
+ Sint16 sxmin = SPG_CLIP_XMIN(src);
+ Sint16 sxmax = SPG_CLIP_XMAX(src);
+ Sint16 symin = SPG_CLIP_YMIN(src);
+ Sint16 symax = SPG_CLIP_YMAX(src);
+ Sint16 sx[]={sxmin, sxmax, sxmin, sxmax};
+ Sint16 sy[]={symin, symax, symax, symin};
+
+ // We don't really need fixed-point here
+ // but why not?
+ Sint32 const istx = (Sint32)((sin(theta)*xscale) * 8192.0); /* Inverse transform */
+ Sint32 const ictx = (Sint32)((cos(theta)*xscale) * 8192.2);
+ Sint32 const isty = (Sint32)((sin(theta)*yscale) * 8192.0);
+ Sint32 const icty = (Sint32)((cos(theta)*yscale) * 8192.2);
+ int i;
+ //Calculate the four corner points
+ for(i=0; i<4; i++){
+ rx = sx[i] - px;
+ ry = sy[i] - py;
+
+ x = (Sint16)(((ictx*rx - isty*ry) >> 13) + qx);
+ y = (Sint16)(((icty*ry + istx*rx) >> 13) + qy);
+
+
+ if(i==0){
+ *xmax = *xmin = x;
+ *ymax = *ymin = y;
+ }else{
+ if(x>*xmax)
+ *xmax=x;
+ else if(x<*xmin)
+ *xmin=x;
+
+ if(y>*ymax)
+ *ymax=y;
+ else if(y<*ymin)
+ *ymin=y;
+ }
+ }
+
+ //Better safe than sorry...
+ *xmin -= 1;
+ *ymin -= 1;
+ *xmax += 1;
+ *ymax += 1;
+
+ //Clip to dst surface
+ if( !dst )
+ return;
+ if( *xmin < SPG_CLIP_XMIN(dst) )
+ *xmin = SPG_CLIP_XMIN(dst);
+ if( *xmax > SPG_CLIP_XMAX(dst) )
+ *xmax = SPG_CLIP_XMAX(dst);
+ if( *ymin < SPG_CLIP_YMIN(dst) )
+ *ymin = SPG_CLIP_YMIN(dst);
+ if( *ymax > SPG_CLIP_YMAX(dst) )
+ *ymax = SPG_CLIP_YMAX(dst);
+}
+
+
+/*==================================================================================
+** Rotate by angle about pivot (px,py) scale by scale and place at
+** position (qx,qy).
+**
+** Transformation matrix application (rotated coords "R"):
+**
+** / rx \ / cos(theta) sin(theta) \ / dx \
+** | | = | | | |
+** \ ry / \ -sin(theta) cos(theta) / \ dy /
+**
+** => rx = cos(theta) dx + sin(theta) dy
+** ry = cos(theta) dy - sin(theta) dx
+** but represented as a fixed-point float using integer math
+**
+** Developed with the help from Terry Hancock (hancock@earthlink.net)
+**
+**==================================================================================*/
+// First we need some macros to handle different bpp
+// I'm sorry about this...
+#define TRANSFORM(UintXX, DIV) \
+ Sint32 const src_pitch=src->pitch/DIV; \
+ Sint32 const dst_pitch=dst->pitch/DIV; \
+ UintXX const *src_row = (UintXX *)src->pixels; \
+ UintXX *dst_row; \
+ Uint32 col;\
+\
+ for (y=ymin; y<=ymax; y++){ /* Changed from y<ymax to y<=ymax Edge fix 7-13-08*/\
+ dy = y - qy; \
+\
+ sx = (Sint32)(ctdx + stx*dy + mx); /* Compute source anchor points */ \
+ sy = (Sint32)(cty*dy - stdx + my); \
+\
+ /* Calculate pointer to dst surface */ \
+ dst_row = (UintXX *)dst->pixels + y*dst_pitch; \
+\
+ for (x=xmin; x<=xmax; x++){ /* Changed from x<xmax to x<=xmax Edge fix 7-13-08*/\
+ rx=(Sint16)(sx >> 13); /* Convert from fixed-point */ \
+ ry=(Sint16)(sy >> 13)+1; /* Added +1 Edge fix 7-13-08*/\
+ /* Make sure the source pixel is actually in the source image. */ \
+ if( (rx>=sxmin) && (rx<=sxmax+1) && (ry>=symin) && (ry<=symax) ) /* Changed from (rx<=sxmax) to (rx<=sxmax+1) Edge fix 7-13-08*/\
+ {\
+ col = *(src_row+ry*src_pitch+rx);\
+ if(!(flags & SPG_TCOLORKEY && src->flags & SDL_SRCCOLORKEY && col == src->format->colorkey))\
+ *(dst_row + x) = (UintXX)(col);\
+ }\
+ sx += ctx; /* Incremental transformations */ \
+ sy -= sty; \
+ } \
+ }
+
+
+#define TRANSFORM_GENERIC \
+ Uint8 R, G, B, A; \
+\
+ for (y=ymin; y<=ymax; y++){ /* Changed from y<ymax to y<=ymax Edge fix 7-13-08*/\
+ dy = y - qy; \
+\
+ sx = (Sint32)(ctdx + stx*dy + mx); /* Compute source anchor points */ \
+ sy = (Sint32)(cty*dy - stdx + my); \
+\
+ for (x=xmin; x<=xmax; x++){ /* Changed from x<xmax to x<=xmax Edge fix 7-13-08*/\
+ rx=(Sint16)(sx >> 13); /* Convert from fixed-point */ \
+ ry=(Sint16)(sy >> 13)+1; /* Added +1 Edge fix 7-13-08*/\
+\
+ /* Make sure the source pixel is actually in the source image. */ \
+ if( (rx>=sxmin) && (rx<=sxmax+1) && (ry>=symin) && (ry<=symax) ){ /* Changed from (rx<=sxmax) to (rx<=sxmax+1) Edge fix 7-13-08*/\
+ SPG_GetRGBA(SPG_GetPixel(src,rx,ry), src->format, &R, &G, &B, &A);\
+ if(!(flags & SPG_TCOLORKEY && src->flags & SDL_SRCCOLORKEY && SDL_MapRGB(src->format, R, G, B) == src->format->colorkey))\
+ spg_pixelX(dst,x,y,SPG_MapRGBA(dst->format, R, G, B, A)); \
+ \
+ } \
+ sx += ctx; /* Incremental transformations */ \
+ sy -= sty; \
+ } \
+ }
+
+
+// Interpolated transform
+#define TRANSFORM_AA(UintXX, DIV) \
+ Sint32 const src_pitch=src->pitch/DIV; \
+ Sint32 const dst_pitch=dst->pitch/DIV; \
+ UintXX const *src_row = (UintXX *)src->pixels; \
+ UintXX *dst_row; \
+ UintXX c1, c2, c3, c4;\
+ Uint32 R, G, B, A=0; \
+ UintXX Rmask = src->format->Rmask, Gmask = src->format->Gmask, Bmask = src->format->Bmask, Amask = src->format->Amask;\
+ Uint32 wx, wy;\
+ Uint32 p1, p2, p3, p4;\
+\
+ /*
+ * Interpolation:
+ * We calculate the distances from our point to the four nearest pixels, d1..d4.
+ * d(a,b) = sqrt(a�+b�) ~= 0.707(a+b) (Pythagoras (Taylor) expanded around (0.5;0.5))
+ *
+ * 1 wx 2
+ * *-|-* (+ = our point at (x,y))
+ * | | | (* = the four nearest pixels)
+ * wy --+ | wx = float(x) - int(x)
+ * | | wy = float(y) - int(y)
+ * *---*
+ * 3 4
+ * d1 = d(wx,wy) d2 = d(1-wx,wy) d3 = d(wx,1-wy) d4 = d(1-wx,1-wy)
+ * We now want to weight each pixels importance - it's vicinity to our point:
+ * w1=d4 w2=d3 w3=d2 w4=d1 (Yes it works... just think a bit about it)
+ *
+ * If the pixels have the colors c1..c4 then our point should have the color
+ * c = (w1*c1 + w2*c2 + w3*c3 + w4*c4)/(w1+w2+w3+w4) (the weighted average)
+ * but w1+w2+w3+w4 = 4*0.707 so we might as well write it as
+ * c = p1*c1 + p2*c2 + p3*c3 + p4*c4 where p1..p4 = (w1..w4)/(4*0.707)
+ *
+ * But p1..p4 are fixed point so we can just divide the fixed point constant!
+ * 8192/(4*0.71) = 2897 and we can skip 0.71 too (the division will cancel it everywhere)
+ * 8192/4 = 2048
+ *
+ * 020102: I changed the fixed-point representation for the variables in the weighted average
+ * to 24.7 to avoid problems with 32bit colors. Everything else is still 18.13. This
+ * does however not solve the problem with 32bit RGBA colors...
+ */\
+\
+ Sint32 const one = 2048>>6; /* 1 in Fixed-point */ \
+ Sint32 const two = 2*2048>>6; /* 2 in Fixed-point */ \
+\
+ for (y=ymin; y<ymax; y++){ \
+ dy = y - qy; \
+\
+ sx = (Sint32)(ctdx + stx*dy + mx); /* Compute source anchor points */ \
+ sy = (Sint32)(cty*dy - stdx + my); \
+\
+ /* Calculate pointer to dst surface */ \
+ dst_row = (UintXX *)dst->pixels + y*dst_pitch; \
+\
+ for (x=xmin; x<xmax; x++){ \
+ rx=(Sint16)(sx >> 13); /* Convert from fixed-point */ \
+ ry=(Sint16)(sy >> 13); \
+\
+ /* Make sure the source pixel is actually in the source image. */ \
+ if((rx>=sxmin) && (rx+1<=sxmax) && (ry>=symin) && (ry+1<=symax) && !((flags & SPG_TCOLORKEY) && (src->flags & SDL_SRCCOLORKEY) && *(src_row+ry*src_pitch+rx) == src->format->colorkey) ){ \
+ wx = (sx & 0x00001FFF) >>8; /* (float(x) - int(x)) / 4 */ \
+ wy = (sy & 0x00001FFF) >>8;\
+\
+ p4 = wx+wy;\
+ p3 = one-wx+wy;\
+ p2 = wx+one-wy;\
+ p1 = two-wx-wy;\
+\
+ c1 = *(src_row + ry*src_pitch + rx);\
+ c2 = *(src_row + ry*src_pitch + rx+1);\
+ c3 = *(src_row + (ry+1)*src_pitch + rx);\
+ c4 = *(src_row + (ry+1)*src_pitch + rx+1);\
+\
+ /* Calculate the average */\
+ R = ((p1*(c1 & Rmask) + p2*(c2 & Rmask) + p3*(c3 & Rmask) + p4*(c4 & Rmask))>>7) & Rmask;\
+ G = ((p1*(c1 & Gmask) + p2*(c2 & Gmask) + p3*(c3 & Gmask) + p4*(c4 & Gmask))>>7) & Gmask;\
+ B = ((p1*(c1 & Bmask) + p2*(c2 & Bmask) + p3*(c3 & Bmask) + p4*(c4 & Bmask))>>7) & Bmask;\
+ if(Amask)\
+ A = (SDL_ALPHA_OPAQUE - ((p1*(c1 & Amask) + p2*(c2 & Amask) + p3*(c3 & Amask) + p4*(c4 & Amask))>>7)) & Amask;\
+ \
+ *(dst_row + x) = R | G | B | A;\
+ } \
+ sx += ctx; /* Incremental transformations */ \
+ sy -= sty; \
+ } \
+ }
+
+#define TRANSFORM_GENERIC_AA \
+ Uint8 R, G, B, A, R1, G1, B1, A1=0, R2, G2, B2, A2=0, R3, G3, B3, A3=0, R4, G4, B4, A4=0; \
+ Sint32 wx, wy, p1, p2, p3, p4;\
+\
+ Sint32 const one = 2048; /* 1 in Fixed-point */ \
+ Sint32 const two = 2*2048; /* 2 in Fixed-point */ \
+\
+ for (y=ymin; y<ymax; y++){ \
+ dy = y - qy; \
+\
+ sx = (Sint32)(ctdx + stx*dy + mx); /* Compute source anchor points */ \
+ sy = (Sint32)(cty*dy - stdx + my); \
+\
+ for (x=xmin; x<xmax; x++){ \
+ rx=(Sint16)(sx >> 13); /* Convert from fixed-point */ \
+ ry=(Sint16)(sy >> 13); \
+\
+ /* Make sure the source pixel is actually in the source image. */ \
+ if( (rx>=sxmin) && (rx+1<=sxmax) && (ry>=symin) && (ry+1<=symax)){ \
+ wx = (sx & 0x00001FFF) >> 2; /* (float(x) - int(x)) / 4 */ \
+ wy = (sy & 0x00001FFF) >> 2;\
+\
+ p4 = wx+wy;\
+ p3 = one-wx+wy;\
+ p2 = wx+one-wy;\
+ p1 = two-wx-wy;\
+\
+ SPG_GetRGBA(SPG_GetPixel(src,rx, ry), src->format, &R1, &G1, &B1, &A1);\
+ SPG_GetRGBA(SPG_GetPixel(src,rx+1,ry), src->format, &R2, &G2, &B2, &A2);\
+ SPG_GetRGBA(SPG_GetPixel(src,rx, ry+1), src->format, &R3, &G3, &B3, &A3);\
+ SPG_GetRGBA(SPG_GetPixel(src,rx+1,ry+1), src->format, &R4, &G4, &B4, &A4);\
+\
+ /* Calculate the average */\
+ R = (p1*R1 + p2*R2 + p3*R3 + p4*R4)>>13;\
+ G = (p1*G1 + p2*G2 + p3*G3 + p4*G4)>>13;\
+ B = (p1*B1 + p2*B2 + p3*B3 + p4*B4)>>13;\
+ A = (p1*A1 + p2*A2 + p3*A3 + p4*A4)>>13;\
+ if(!(flags & SPG_TCOLORKEY && src->flags & SDL_SRCCOLORKEY && SDL_MapRGB(src->format, R, G, B) == src->format->colorkey))\
+ spg_pixelX(dst,x,y,SPG_MapRGBA(dst->format, R, G, B, A)); \
+ \
+ } \
+ sx += ctx; /* Incremental transformations */ \
+ sy -= sty; \
+ } \
+ }
+
+// We get better performance if AA and normal rendering is separated into two functions (better optimization).
+// SPG_TransformX() is used as a wrapper.
+
+SDL_Rect SPG_transformNorm(SDL_Surface *src, SDL_Surface *dst, float angle, float xscale, float yscale ,Uint16 px, Uint16 py, Uint16 qx, Uint16 qy, Uint8 flags)
+{
+ Sint32 dy, sx, sy;
+ Sint16 x, y, rx, ry;
+ SDL_Rect r;
+ r.x = r.y = r.w = r.h = 0;
+
+ if(spg_usedegrees)
+ angle *= RADPERDEG; /* Convert to radians. */
+
+
+ // Here we use 18.13 fixed point integer math
+ // Sint32 should have 31 usable bits and one for sign
+ // 2^13 = 8192
+
+ // Check scales
+ //Sint32 maxint = (Sint32)(pow(2, sizeof(Sint32)*8 - 1 - 13)); // 2^(31-13)
+ Sint32 maxint = 262144; // 2^(31-13)
+
+ if( xscale == 0 || yscale == 0)
+ {
+ return r;
+ }
+
+ if( 8192.0f/xscale > maxint )
+ xscale = 8192.0f/maxint;
+ else if( 8192.0f/xscale < -maxint )
+ xscale = -8192.0f/maxint;
+
+ if( 8192.0f/yscale > maxint )
+ yscale = 8192.0f/maxint;
+ else if( 8192.0f/yscale < -maxint )
+ yscale = -8192.0f/maxint;
+
+
+ // Fixed-point equivalents
+ Sint32 const stx = (Sint32)((sin(angle)/xscale) * 8192.0);
+ Sint32 const ctx = (Sint32)((cos(angle)/xscale) * 8192.0);
+ Sint32 const sty = (Sint32)((sin(angle)/yscale) * 8192.0);
+ Sint32 const cty = (Sint32)((cos(angle)/yscale) * 8192.0);
+ Sint32 const mx = (Sint32)(px*8192.0);
+ Sint32 const my = (Sint32)(py*8192.0);
+
+ // Compute a bounding rectangle
+ Sint16 xmin=0, xmax=dst->w, ymin=0, ymax=dst->h;
+ spg_calcrect(src, dst, angle, xscale, yscale, px, py, qx, qy, &xmin,&ymin, &xmax,&ymax);
+
+ // Clip to src surface
+ Sint16 sxmin = SPG_CLIP_XMIN(src);
+ Sint16 sxmax = SPG_CLIP_XMAX(src);
+ Sint16 symin = SPG_CLIP_YMIN(src);
+ Sint16 symax = SPG_CLIP_YMAX(src);
+
+ // Some terms in the transform are constant
+ Sint32 const dx = xmin - qx;
+ Sint32 const ctdx = ctx*dx;
+ Sint32 const stdx = sty*dx;
+
+ // Lock surfaces... hopfully less than two needs locking!
+
+ if ( spg_lock(src) < 0 )
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_Transform could not lock surface");
+ return r;
+ }
+ if ( spg_lock(dst) < 0 )
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_Transform could not lock surface");
+
+ spg_unlock(src);
+ return r;
+ }
+
+
+ // Use the correct bpp
+ if( src->format->BytesPerPixel == dst->format->BytesPerPixel && src->format->BytesPerPixel != 3 && !(flags & SPG_TSAFE)){
+ switch( src->format->BytesPerPixel ){
+ case 1: { /* Assuming 8-bpp */
+ TRANSFORM(Uint8, 1)
+ }
+ break;
+ case 2: { /* Probably 15-bpp or 16-bpp */
+ TRANSFORM(Uint16, 2)
+ }
+ break;
+ case 4: { /* Probably 32-bpp */
+ TRANSFORM(Uint32, 4)
+ }
+ break;
+ }
+ }else{
+ TRANSFORM_GENERIC
+ }
+
+
+
+ spg_unlock(src);
+ spg_unlock(dst);
+
+
+ //Return the bounding rectangle
+ r.x=xmin; r.y=ymin; r.w=xmax-xmin+1; r.h=ymax-ymin+1;
+ return r;
+}
+
+
+SDL_Rect SPG_transformAA(SDL_Surface *src, SDL_Surface *dst, float angle, float xscale, float yscale ,Uint16 px, Uint16 py, Uint16 qx, Uint16 qy, Uint8 flags)
+{
+ Sint32 dy, sx, sy;
+ Sint16 x, y, rx, ry;
+ SDL_Rect r;
+ r.x = r.y = r.w = r.h = 0;
+
+ if(spg_usedegrees)
+ angle *= RADPERDEG; /* Convert to radians. */
+
+
+ // Here we use 18.13 fixed point integer math
+ // Sint32 should have 31 usable bits and one for sign
+ // 2^13 = 8192
+
+ // Check scales
+ //Sint32 maxint = (Sint32)(pow(2, sizeof(Sint32)*8 - 1 - 13)); // 2^(31-13)
+ Sint32 maxint = 262144; // 2^(31-13)
+
+ if( xscale == 0 || yscale == 0)
+ {
+ return r;
+ }
+
+ if( 8192.0/xscale > maxint )
+ xscale = (float)(8192.0/maxint);
+ else if( 8192.0/xscale < -maxint )
+ xscale = (float)(-8192.0/maxint);
+
+ if( 8192.0/yscale > maxint )
+ yscale = (float)(8192.0/maxint);
+ else if( 8192.0/yscale < -maxint )
+ yscale = (float)(-8192.0/maxint);
+
+
+ // Fixed-point equivalents
+ Sint32 const stx = (Sint32)((sin(angle)/xscale) * 8192.0);
+ Sint32 const ctx = (Sint32)((cos(angle)/xscale) * 8192.0);
+ Sint32 const sty = (Sint32)((sin(angle)/yscale) * 8192.0);
+ Sint32 const cty = (Sint32)((cos(angle)/yscale) * 8192.0);
+ Sint32 const mx = (Sint32)(px*8192.0);
+ Sint32 const my = (Sint32)(py*8192.0);
+
+ // Compute a bounding rectangle
+ Sint16 xmin=0, xmax=dst->w, ymin=0, ymax=dst->h;
+ spg_calcrect(src, dst, angle, xscale, yscale, px, py, qx, qy, &xmin,&ymin, &xmax,&ymax);
+
+ // Clip to src surface
+ Sint16 sxmin = SPG_CLIP_XMIN(src);
+ Sint16 sxmax = SPG_CLIP_XMAX(src);
+ Sint16 symin = SPG_CLIP_YMIN(src);
+ Sint16 symax = SPG_CLIP_YMAX(src);
+
+ // Some terms in the transform are constant
+ Sint32 const dx = xmin - qx;
+ Sint32 const ctdx = ctx*dx;
+ Sint32 const stdx = sty*dx;
+
+ // Lock surfaces... hopfully less than two needs locking!
+
+ if ( spg_lock(src) < 0 )
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_Transform could not lock surface");
+ return r;
+ }
+ if ( spg_lock(dst) < 0 )
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_Transform could not lock surface");
+
+ spg_unlock(src);
+ return r;
+ }
+
+
+ // Use the correct bpp
+ if( src->format->BytesPerPixel == dst->format->BytesPerPixel && src->format->BytesPerPixel != 3 && !(flags & SPG_TSAFE) ){
+ switch( src->format->BytesPerPixel ){
+ case 1: { /* Assuming 8-bpp */
+ TRANSFORM_AA(Uint8, 1)
+ //TRANSFORM_GENERIC_AA
+ }
+ break;
+ case 2: { /* Probably 15-bpp or 16-bpp */
+ TRANSFORM_AA(Uint16, 2)
+ }
+ break;
+ case 4: { /* Probably 32-bpp */
+ TRANSFORM_AA(Uint32, 4)
+ }
+ break;
+ }
+ }else{
+ TRANSFORM_GENERIC_AA
+ }
+
+
+ // Unlock surfaces
+
+ spg_unlock(src);
+ spg_unlock(dst);
+
+ //Return the bounding rectangle
+ r.x=xmin; r.y=ymin; r.w=xmax-xmin+1; r.h=ymax-ymin+1;
+ return r;
+}
+
+SDL_Rect SPG_TransformX(SDL_Surface *src, SDL_Surface *dst, float angle, float xscale, float yscale, Uint16 pivotX, Uint16 pivotY, Uint16 destX, Uint16 destY, Uint8 flags)
+{
+ destY++; // Hacky fix for missing edges 7/13/08
+ SDL_Rect rect;
+
+ if(flags & SPG_TTMAP)
+ rect = spg_transform_tmap(src, dst, angle, xscale, yscale, destX, destY);
+ else{
+ if(flags & SPG_TAA)
+ rect = SPG_transformAA(src, dst, angle, xscale, yscale, pivotX, pivotY, destX, destY, flags);
+ else
+ rect = SPG_transformNorm(src, dst, angle, xscale, yscale, pivotX, pivotY, destX, destY, flags);
+ }
+ if(spg_makedirtyrects)
+ {
+ // Clip it to the screen
+ SPG_DirtyClip(dst, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+ return rect;
+}
+
+
+//==================================================================================
+// Same as SPG_TransformX() but returns a surface with the result
+//==================================================================================
+SDL_Surface* SPG_Transform(SDL_Surface *src, Uint32 bgColor, float angle, float xscale, float yscale, Uint8 flags)
+{
+ float theta = angle;
+
+ if(spg_usedegrees)
+ theta *= RADPERDEG; /* Convert to radians. */
+
+ // Compute a bounding rectangle
+ Sint16 xmin=0, xmax=0, ymin=0, ymax=0;
+ spg_calcrect(src, NULL, theta, xscale, yscale, 0, 0, 0, 0, &xmin,&ymin, &xmax,&ymax);
+
+ Sint16 w = xmax-xmin+1;
+ Sint16 h = ymax-ymin+1;
+
+ Sint16 qx = -xmin;
+ Sint16 qy = -ymin;
+
+ SDL_Surface *dest;
+ dest = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, src->format->BitsPerPixel, src->format->Rmask, src->format->Gmask, src->format->Bmask, src->format->Amask);
+ if(dest == NULL)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_Transform could not allocate enough memory");
+ return NULL;
+ }
+
+ // Copy flag settings (passes on colorkey and alpha blending)
+ dest->flags = src->flags;
+ dest->format->alpha = src->format->alpha;
+ dest->format->colorkey = src->format->colorkey;
+
+ SPG_Fill(dest,bgColor); //Set background color
+
+ SPG_TransformX(src, dest, angle, xscale, yscale, 0, 0, qx, qy, flags);
+
+ return dest;
+}
+
+
+//==================================================================================
+// Rotate using texture mapping
+//==================================================================================
+SDL_Rect spg_transform_tmap(SDL_Surface *src, SDL_Surface *dst, float angle, float xscale, float yscale, Uint16 qx, Uint16 qy)
+{
+ float a=(SPG_CLIP_XMAX(src) - SPG_CLIP_XMIN(src))/2.0f;
+ float b=(SPG_CLIP_YMAX(src) - SPG_CLIP_YMIN(src))/2.0f;
+
+ float cosv, sinv;
+
+ //Get an exact value if possible
+ if(angle == 0.0f || angle == 360.0f){
+ cosv=1; sinv=0;
+ }
+ else if(angle == 90.0f){
+ cosv=0; sinv=1;
+ }
+ else if(angle == 180.0f){
+ cosv=-1; sinv=0;
+ }
+ else if(angle == 270.0f){
+ cosv=0; sinv=-1;
+ }
+ else{ //Oh well
+ if(spg_usedegrees)
+ angle *= RADPERDEG; /* Convert to radians. */
+ cosv=cos(angle); sinv=sin(angle);
+ }
+
+ //Precalculate as much as possible
+ float acosv=a*cosv*xscale, bcosv=b*cosv*yscale;
+ float asinv=a*sinv*xscale, bsinv=b*sinv*yscale;
+
+
+ /* Do the math */
+ Sint16 xt[4],yt[4];
+
+ xt[0] = (Sint16)((-acosv+bsinv)+qx);
+ yt[0] = (Sint16)((-asinv-bcosv)+qy);
+
+ xt[1] = (Sint16)((acosv+bsinv)+qx);
+ yt[1] = (Sint16)((asinv-bcosv)+qy);
+
+ xt[2] = (Sint16)((-acosv-bsinv)+qx);
+ yt[2] = (Sint16)((-asinv+bcosv)+qy);
+
+ xt[3] = (Sint16)((acosv-bsinv)+qx);
+ yt[3] = (Sint16)((asinv+bcosv)+qy);
+
+
+ //Use a texture mapped rectangle
+ SPG_QuadTex(dst,xt[0],yt[0],xt[1],yt[1],xt[2],yt[2],xt[3],yt[3],src, SPG_CLIP_XMIN(src),SPG_CLIP_YMIN(src), SPG_CLIP_XMAX(src),SPG_CLIP_YMIN(src), SPG_CLIP_XMIN(src),SPG_CLIP_YMAX(src), SPG_CLIP_XMAX(src),SPG_CLIP_YMAX(src));
+
+ //Or maybe two trigons...
+ //SPG_TexturedTrigon(dest,xt[0],yt[0],xt[1],yt[1],xt[2],yt[2],src, SPG_CLIP_XMIN(src),SPG_CLIP_YMIN(src), SPG_CLIP_XMAX(src),SPG_CLIP_YMIN(src), SPG_CLIP_XMIN(src),SPG_CLIP_YMAX(src));
+ //SPG_TexturedTrigon(dest,xt[3],yt[3],xt[1],yt[1],xt[2],yt[2],src, SPG_CLIP_XMAX(src),SPG_CLIP_YMAX(src), SPG_CLIP_XMAX(src),SPG_CLIP_YMIN(src), SPG_CLIP_XMIN(src),SPG_CLIP_YMAX(src));
+
+ //For debug
+ //SPG_Trigon(dest,xt[0],yt[0],xt[1],yt[1],xt[2],yt[2],SDL_MapRGB(dest->format,255,0,0));
+ //SPG_Trigon(dest,xt[3],yt[3],xt[1],yt[1],xt[2],yt[2],SDL_MapRGB(dest->format,0,255,0));
+
+ Sint16 xmax=xt[0], xmin=xt[0];
+ xmax= (xmax>xt[1])? xmax : xt[1];
+ xmin= (xmin<xt[1])? xmin : xt[1];
+ xmax= (xmax>xt[2])? xmax : xt[2];
+ xmin= (xmin<xt[2])? xmin : xt[2];
+ xmax= (xmax>xt[3])? xmax : xt[3];
+ xmin= (xmin<xt[3])? xmin : xt[3];
+
+ Sint16 ymax=yt[0], ymin=yt[0];
+ ymax= (ymax>yt[1])? ymax : yt[1];
+ ymin= (ymin<yt[1])? ymin : yt[1];
+ ymax= (ymax>yt[2])? ymax : yt[2];
+ ymin= (ymin<yt[2])? ymin : yt[2];
+ ymax= (ymax>yt[3])? ymax : yt[3];
+ ymin= (ymin<yt[3])? ymin : yt[3];
+
+ SDL_Rect r;
+ r.x=xmin; r.y=ymin; r.w=xmax-xmin+1; r.h=ymax-ymin+1;
+ return r;
+}
+
+
+
+SDL_Surface* SPG_Rotate(SDL_Surface *src, float angle, Uint32 bgColor)
+{
+ SDL_Surface *dest;
+
+ /* Create the destination surface*/
+ int max = (int)( sqrt( (src->h*src->h/2 + src->w*src->w/2) + 1 ) );
+ dest=SDL_AllocSurface(SDL_SWSURFACE, max, max, src->format->BitsPerPixel, src->format->Rmask, src->format->Gmask, src->format->Bmask, src->format->Amask );
+ if(!dest)
+ {SPG_Error("SPG_Rotate could not allocate enough memory");return NULL;}
+
+ SDL_FillRect(dest, NULL, bgColor);
+ SPG_TransformX(src, dest, angle, 1.0f, 1.0f, src->w/2, src->h/2, dest->w/2, dest->h/2, 0);
+
+ return dest;
+}
+
+SDL_Surface* SPG_RotateAA(SDL_Surface *src, float angle, Uint32 bgColor)
+{
+ SDL_Surface *dest;
+
+ /* Create the destination surface*/
+ int max = (int)( sqrt( (src->h*src->h/2 + src->w*src->w/2) + 1 ) );
+ dest=SDL_AllocSurface(SDL_SWSURFACE, max, max, src->format->BitsPerPixel, src->format->Rmask, src->format->Gmask, src->format->Bmask, src->format->Amask );
+ if(!dest)
+ {SPG_Error("SPG_RotateAA could not allocate enough memory"); return NULL;}
+
+ SDL_FillRect(dest, NULL, bgColor);
+ SPG_TransformX(src, dest, angle, 1.0f, 1.0f, src->w/2, src->h/2, dest->w/2, dest->h/2, SPG_TAA);
+
+ return dest;
+}
+
+
+
diff --git a/util/sdl/sprig/SPG_surface.c b/util/sdl/sprig/SPG_surface.c
new file mode 100644
index 00000000..3acd0c00
--- /dev/null
+++ b/util/sdl/sprig/SPG_surface.c
@@ -0,0 +1,1220 @@
+/*
+ SPriG - SDL Primitive Generator
+ by Jonathan Dearborn
+
+ Based on SGE: SDL Graphics Extension r030809
+ by Anders Lindström
+*/
+
+
+/*********************************************************************
+ * 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. *
+ *********************************************************************/
+
+
+/*
+* Some of this code is taken from the "Introduction to SDL" and
+* John Garrison's PowerPak
+*/
+
+#include "sprig.h"
+#include "sprig_common.h"
+
+#include <math.h>
+#include <string.h>
+#include <stdarg.h>
+
+
+/* Global used for SPG_EnableAutolock */
+SPG_bool spg_autolock = 1;
+void (*spg_blitfunc)(SDL_Surface*, SDL_Rect*, SDL_Surface*, SDL_Rect*) = NULL;
+
+
+struct spg_uint8_node
+{
+ Uint8 datum;
+ struct spg_uint8_node* next;
+};
+
+struct spg_uint16_node
+{
+ Uint16 datum;
+ struct spg_uint16_node* next;
+};
+
+struct spg_bool_node
+{
+ SPG_bool datum;
+ struct spg_bool_node* next;
+};
+
+struct spg_string_node
+{
+ char* datum;
+ struct spg_string_node* next;
+};
+
+
+struct spg_uint16_node* spg_thickness_state = NULL;
+extern Uint16 spg_thickness;
+struct spg_uint8_node* spg_blend_state = NULL;
+struct spg_bool_node* spg_aa_state = NULL;
+struct spg_bool_node* spg_blit_surface_alpha_state = NULL;
+
+struct spg_string_node* _spg_errors = NULL;
+struct spg_string_node* _spg_errors_tail = NULL;
+Uint16 _spg_numerrors = 0;
+SPG_bool spg_useerrors = 0;
+extern SPG_bool spg_makedirtyrects;
+extern SPG_DirtyTable* spg_dirtytable_front;
+
+
+void spg_pixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color);
+void spg_pixelblend(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color, Uint8 alpha);
+
+void spg_pixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color);
+void spg_pixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color);
+void spg_pixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color);
+void spg_pixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color);
+void spg_pixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color);
+
+
+/**********************************************************************************/
+/** Misc. functions **/
+/**********************************************************************************/
+
+
+
+void SPG_EnableAutolock(SPG_bool enable)
+{ spg_autolock = enable;}
+
+SPG_bool SPG_GetAutolock()
+{ return spg_autolock;}
+
+
+void SPG_PushThickness(Uint16 state)
+{
+ struct spg_uint16_node* node = (struct spg_uint16_node*)malloc(sizeof(struct spg_uint16_node));
+ node->datum = state;
+ node->next = spg_thickness_state;
+ spg_thickness_state = node;
+ spg_thickness = state;
+}
+Uint16 SPG_PopThickness()
+{
+ if(spg_thickness_state == NULL)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_PopThickness popped an empty stack!");
+ spg_thickness = 1;
+ return 1;
+ }
+ struct spg_uint16_node* temp = spg_thickness_state;
+ spg_thickness = spg_thickness_state->datum;
+ spg_thickness_state = spg_thickness_state->next;
+ free(temp);
+ return spg_thickness;
+}
+Uint16 SPG_GetThickness()
+{
+ return spg_thickness;
+}
+
+void SPG_PushBlend(Uint8 state)
+{
+ struct spg_uint8_node* node = (struct spg_uint8_node*)malloc(sizeof(struct spg_uint8_node));
+ node->datum = state;
+ node->next = spg_blend_state;
+ spg_blend_state = node;
+}
+Uint8 SPG_PopBlend()
+{
+ if(spg_blend_state == NULL)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_PopBlend popped an empty stack!");
+ return 0;
+ }
+ struct spg_uint8_node* temp = spg_blend_state;
+ Uint8 result = spg_blend_state->datum;
+ spg_blend_state = spg_blend_state->next;
+ free(temp);
+ return result;
+}
+Uint8 SPG_GetBlend()
+{
+ if(spg_blend_state == NULL)
+ {
+ // Without initialization, this overfills the stack.
+ //if(spg_useerrors)
+ //SPG_Error("SPG_GetBlend checked an empty stack!");
+ return 0;
+ }
+ return spg_blend_state->datum;
+}
+
+void SPG_PushAA(SPG_bool state)
+{
+ struct spg_bool_node* node = (struct spg_bool_node*)malloc(sizeof(struct spg_bool_node));
+ node->datum = state;
+ node->next = spg_aa_state;
+ spg_aa_state = node;
+}
+SPG_bool SPG_PopAA()
+{
+ if(spg_aa_state == NULL)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_PopAA popped an empty stack!");
+ return 0;
+ }
+ struct spg_bool_node* temp = spg_aa_state;
+ SPG_bool result = spg_aa_state->datum;
+ spg_aa_state = spg_aa_state->next;
+ free(temp);
+ return result;
+}
+SPG_bool SPG_GetAA()
+{
+ if(spg_aa_state == NULL)
+ {
+ // Without initialization, this overfills the stack.
+ //if(spg_useerrors)
+ //SPG_Error("SPG_GetAA checked an empty stack!");
+ return 0;
+ }
+ return spg_aa_state->datum;
+}
+
+void SPG_PushSurfaceAlpha(SPG_bool state)
+{
+ struct spg_bool_node* node = (struct spg_bool_node*)malloc(sizeof(struct spg_bool_node));
+ node->datum = state;
+ node->next = spg_blit_surface_alpha_state;
+ spg_blit_surface_alpha_state = node;
+}
+SPG_bool SPG_PopSurfaceAlpha()
+{
+ if(spg_blit_surface_alpha_state == NULL)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_PopSurfaceAlpha popped an empty stack!");
+ return 0;
+ }
+ struct spg_bool_node* temp = spg_blit_surface_alpha_state;
+ SPG_bool result = spg_blit_surface_alpha_state->datum;
+ spg_blit_surface_alpha_state = spg_blit_surface_alpha_state->next;
+ free(temp);
+ return result;
+}
+SPG_bool SPG_GetSurfaceAlpha()
+{
+ if(spg_blit_surface_alpha_state == NULL)
+ {
+ // Without initialization, this overfills the stack.
+ //if(spg_useerrors)
+ //SPG_Error("SPG_GetSurfaceAlpha checked an empty stack!");
+ return 0;
+ }
+ return spg_blit_surface_alpha_state->datum;
+}
+
+
+void SPG_Error(const char* err)
+{
+ if(err == NULL || _spg_numerrors >= SPG_MAX_ERRORS)
+ return;
+ struct spg_string_node* node = (struct spg_string_node*)malloc(sizeof(struct spg_string_node));
+ node->datum = (char*)malloc(strlen(err)+20);
+ sprintf(node->datum, "%s at time %ums", err, SDL_GetTicks());
+ // push to front
+ //node->next = _spg_errors;
+ //_spg_errors = node;
+
+ // push to back
+ node->next = NULL;
+ if(_spg_errors == NULL || _spg_errors_tail == NULL)
+ _spg_errors = node;
+ else
+ _spg_errors_tail->next = node;
+ _spg_errors_tail = node;
+
+ _spg_numerrors++;
+}
+
+char* SPG_GetError()
+{
+ if(_spg_numerrors == 0 || _spg_errors == NULL)
+ return NULL;
+
+ struct spg_string_node* temp = _spg_errors;
+ char* result = _spg_errors->datum;
+ _spg_errors = _spg_errors->next;
+ _spg_numerrors--;
+ free(temp);
+ return result;
+}
+
+Uint16 SPG_NumErrors()
+{
+ return _spg_numerrors;
+}
+
+void SPG_EnableErrors(SPG_bool enable)
+{
+ spg_useerrors = enable;
+}
+
+
+
+/*
+* Get the smallest bounding box from two (SDL_Rect) rectangles
+*/
+void SPG_RectOR(const SDL_Rect rect1, const SDL_Rect rect2, SDL_Rect* dst_rect)
+{
+ if(dst_rect == NULL)
+ return;
+
+ dst_rect->x = (rect1.x < rect2.x)? rect1.x : rect2.x;
+ dst_rect->y = (rect1.y < rect2.y)? rect1.y : rect2.y;
+ dst_rect->w = (rect1.x + rect1.w > rect2.x + rect2.w)? rect1.x + rect1.w - dst_rect->x : rect2.x + rect2.w - dst_rect->x;
+ dst_rect->h = (rect1.y + rect1.h > rect2.y + rect2.h)? rect1.y + rect1.h - dst_rect->y : rect2.y + rect2.h - dst_rect->y;
+}
+
+// Adapted from SDL_IntersectRect
+SPG_bool SPG_RectAND(const SDL_Rect A, const SDL_Rect B, SDL_Rect* intersection)
+{
+ int resX, resY, resW, resH;
+ int Amin, Amax, Bmin, Bmax;
+
+ // Horizontal intersection
+ Amin = A.x;
+ Amax = Amin + A.w;
+ Bmin = B.x;
+ Bmax = Bmin + B.w;
+ if(Bmin > Amin)
+ Amin = Bmin;
+ resX = Amin;
+ if(Bmax < Amax)
+ Amax = Bmax;
+ resW = Amax - Amin > 0 ? Amax - Amin : 0;
+
+ // Vertical intersection
+ Amin = A.y;
+ Amax = Amin + A.h;
+ Bmin = B.y;
+ Bmax = Bmin + B.h;
+ if(Bmin > Amin)
+ Amin = Bmin;
+ resY = Amin;
+ if(Bmax < Amax)
+ Amax = Bmax;
+ resH = Amax - Amin > 0 ? Amax - Amin : 0;
+
+ if(intersection != NULL)
+ {
+ intersection->x = resX;
+ intersection->y = resY;
+ intersection->w = resW;
+ intersection->h = resH;
+ }
+
+ return (resW && resH);
+}
+
+
+// Adapted from SDL_SetClipRect
+void SPG_SetClip(SDL_Surface *surface, const SDL_Rect rect)
+{
+ //SDL_Rect full_rect;
+ int Amin, Amax, Bmax;
+
+ if (!surface)
+ return;
+
+ // Set the clipping rectangle with the intersection of
+ // the given rect with the full surface.
+ // Horizontal intersection
+ Amin = rect.x;
+ Amax = Amin + rect.w;
+ Bmax = surface->w;
+ if(Amin < 0)
+ Amin = 0;
+ surface->clip_rect.x = Amin;
+ if(Bmax < Amax)
+ Amax = Bmax;
+ surface->clip_rect.w = Amax - Amin > 0 ? Amax - Amin : 0;
+
+ // Vertical intersection
+ Amin = rect.y;
+ Amax = Amin + rect.h;
+ Bmax = surface->h;
+ if(Amin < 0)
+ Amin = 0;
+ surface->clip_rect.y = Amin;
+ if(Bmax < Amax)
+ Amax = Bmax;
+ surface->clip_rect.h = Amax - Amin > 0 ? Amax - Amin : 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+//==================================================================================
+// Calculate y pitch offset
+// (the y pitch offset is constant for the same y coord and surface)
+//==================================================================================
+Sint32 SPG_CalcYPitch(SDL_Surface *dest,Sint16 y)
+{
+ if(y>=SPG_CLIP_YMIN(dest) && y<=SPG_CLIP_YMAX(dest)){
+ switch ( dest->format->BytesPerPixel ) {
+ case 1:
+ return y*dest->pitch;
+ break;
+ case 2:
+ return y*dest->pitch/2;
+ break;
+ case 3:
+ return y*dest->pitch;
+ break;
+ case 4:
+ return y*dest->pitch/4;
+ break;
+ }
+ }
+
+ return -1;
+}
+
+
+//==================================================================================
+// Set pixel with precalculated y pitch offset
+//==================================================================================
+void SPG_pSetPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
+{
+ if(x>=SPG_CLIP_XMIN(surface) && x<=SPG_CLIP_XMAX(surface) && ypitch>=0){
+ switch (surface->format->BytesPerPixel) {
+ case 1: { /* Assuming 8-bpp */
+ *((Uint8 *)surface->pixels + ypitch + x) = color;
+ }
+ break;
+
+ case 2: { /* Probably 15-bpp or 16-bpp */
+ *((Uint16 *)surface->pixels + ypitch + x) = color;
+ }
+ break;
+
+ case 3: { /* Slow 24-bpp mode, usually not used */
+ /* Gack - slow, but endian correct */
+ Uint8 *pix = (Uint8 *)surface->pixels + ypitch + x*3;
+
+ *(pix+surface->format->Rshift/8) = color>>surface->format->Rshift;
+ *(pix+surface->format->Gshift/8) = color>>surface->format->Gshift;
+ *(pix+surface->format->Bshift/8) = color>>surface->format->Bshift;
+ *(pix+surface->format->Ashift/8) = color>>surface->format->Ashift;
+ }
+ break;
+
+ case 4: { /* Probably 32-bpp */
+ *((Uint32 *)surface->pixels + ypitch + x) = color;
+ }
+ break;
+ }
+ }
+}
+
+
+//==================================================================================
+// Get pixel
+//==================================================================================
+Uint32 SPG_GetPixel(SDL_Surface *surface, Sint16 x, Sint16 y)
+{
+ if(x<0 || x>=surface->w || y<0 || y>=surface->h)
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_GetPixel was used out of the surface bounds");
+ return 0;
+ }
+
+ switch (surface->format->BytesPerPixel) {
+ case 1: { /* Assuming 8-bpp */
+ return *((Uint8 *)surface->pixels + y*surface->pitch + x);
+ }
+ break;
+
+ case 2: { /* Probably 15-bpp or 16-bpp */
+ return *((Uint16 *)surface->pixels + y*surface->pitch/2 + x);
+ }
+ break;
+
+ case 3: { /* Slow 24-bpp mode, usually not used */
+ Uint8 *pix;
+ int shift;
+ Uint32 color=0;
+
+ pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
+ shift = surface->format->Rshift;
+ color = *(pix+shift/8)<<shift;
+ shift = surface->format->Gshift;
+ color|= *(pix+shift/8)<<shift;
+ shift = surface->format->Bshift;
+ color|= *(pix+shift/8)<<shift;
+ shift = surface->format->Ashift;
+ color|= *(pix+shift/8)<<shift;
+ return color;
+ }
+ break;
+
+ case 4: { /* Probably 32-bpp */
+ return *((Uint32 *)surface->pixels + y*surface->pitch/4 + x);
+ }
+ break;
+ }
+ return 0;
+}
+
+
+
+
+
+
+
+
+/**********************************************************************************/
+/** Block functions **/
+/**********************************************************************************/
+
+//==================================================================================
+// The SPG_write_block* functions copies the given block (a surface line) directly
+// to the surface. This is *much* faster then using the put pixel functions to
+// update a line. The block consist of Surface->w (the width of the surface) numbers
+// of color values. Note the difference in byte size for the block elements for
+// different color depths. 24 bpp is slow and not included!
+//==================================================================================
+// See sprig_inline.h
+
+
+
+
+
+
+// SDL's clipping
+SDL_Rect* SPG_BlitClip(SDL_Surface* source, SDL_Rect* srect, SDL_Surface* dest, SDL_Rect* drect)
+{
+ // Clip rects
+ SDL_Rect fulldst;
+ int srcx, srcy, w, h;
+
+
+ /* If the destination rectangle is NULL, use the entire dest surface */
+ if ( drect == NULL ) {
+ fulldst.x = fulldst.y = 0;
+ fulldst.w = dest->w;
+ fulldst.h = dest->h;
+ drect = &fulldst;
+ }
+
+ /* clip the source rectangle to the source surface */
+ if(srect) {
+ int maxw, maxh;
+
+ srcx = srect->x;
+ w = srect->w;
+ if(srcx < 0) {
+ w += srcx;
+ drect->x -= srcx;
+ srcx = 0;
+ }
+ maxw = source->w - srcx;
+ if(maxw < w)
+ w = maxw;
+
+ srcy = srect->y;
+ h = srect->h;
+ if(srcy < 0) {
+ h += srcy;
+ drect->y -= srcy;
+ srcy = 0;
+ }
+ maxh = source->h - srcy;
+ if(maxh < h)
+ h = maxh;
+
+ } else {
+ srcx = srcy = 0;
+ w = source->w;
+ h = source->h;
+ }
+
+ /* clip the destination rectangle against the clip rectangle */
+ {
+ SDL_Rect *clip = &dest->clip_rect;
+ int dx, dy;
+
+ dx = clip->x - drect->x;
+ if(dx > 0) {
+ w -= dx;
+ drect->x += dx;
+ srcx += dx;
+ }
+ dx = drect->x + w - clip->x - clip->w;
+ if(dx > 0)
+ w -= dx;
+
+ dy = clip->y - drect->y;
+ if(dy > 0) {
+ h -= dy;
+ drect->y += dy;
+ srcy += dy;
+ }
+ dy = drect->y + h - clip->y - clip->h;
+ if(dy > 0)
+ h -= dy;
+ }
+
+ if(w <= 0 || h <= 0)
+ return NULL;
+
+
+ SDL_Rect* result = (SDL_Rect*)malloc(sizeof(SDL_Rect));
+
+
+ result->x = srcx;
+ result->y = srcy;
+ result->w = drect->w = w;
+ result->h = drect->h = h;
+
+ return result;
+}
+
+void SPG_BlendBlit(SDL_Surface* source, SDL_Rect* srect, SDL_Surface* dest, SDL_Rect* drect)
+{
+ int lowSX, highSX, lowSY, highSY;
+
+ if(srect)
+ {
+ lowSX = srect->x;
+ highSX = srect->x + srect->w;
+ lowSY = srect->y;
+ highSY = srect->y + srect->h;
+ }
+ else
+ {
+ lowSX = 0;
+ highSX = dest->w;
+ lowSY = 0;
+ highSY = dest->h;
+ }
+
+ int lowDX, highDX, lowDY, highDY;
+
+ if(drect)
+ {
+ lowDX = drect->x;
+ highDX = drect->x + drect->w;
+ lowDY = drect->y;
+ highDY = drect->y + drect->h;
+ }
+ else
+ {
+ lowDX = 0;
+ highDX = dest->w;
+ lowDY = 0;
+ highDY = dest->h;
+ }
+
+
+
+ // Get the per-surface alpha
+ Uint8 perSAlpha = source->format->alpha;
+
+ // Ready the recycling loop variables
+ int sx = 0, sy = 0, dx = 0, dy = 0;
+ Uint32 color;
+ Uint8 r;
+ Uint8 g;
+ Uint8 b;
+ Uint8 a;
+
+
+ /*if ( spg_lock(surface) < 0 )
+ return;
+ if ( spg_lock(dest) < 0 )
+ return;*/
+
+ SPG_bool ncolorkeyed = !(source->flags & SDL_SRCCOLORKEY);
+ Uint32 colorkey = source->format->colorkey;
+
+ // Go through the rect we made
+ for (sx = lowSX, sy = lowSY, dx = lowDX, dy = lowDY; sy < highSY;)
+ {
+ // Get the source color
+ color = SPG_GetPixel(source, sx, sy);
+ SDL_GetRGBA(color, source->format, &r, &g, &b, &a);
+
+ // Combine per-surface and per-pixel alpha
+ if(SPG_GetSurfaceAlpha())
+ a = (Uint8)(a*(perSAlpha)/255.0);
+
+ // Convert color to dest color
+ color = SDL_MapRGB(dest->format, r, g, b);
+ // If not a colorkeyed color, then draw the pixel (blending done in put pixel function)
+ if(ncolorkeyed || color != colorkey)
+ spg_pixelblend(dest, dx, dy, color, a);
+
+ // Increment here so we can use the auto test on dy
+ sx++;
+ dx++;
+
+ // Check sx bound to move on to the next horizontal line
+ if (sx >= highSX)
+ {
+ sx = lowSX;
+ sy++;
+ dx = lowDX;
+ dy++;
+ }
+ }
+
+ /*spg_unlock(surface);
+ spg_unlock(dest);*/
+ if(spg_makedirtyrects)
+ {
+ SDL_Rect rect;
+ rect.x = lowDX;
+ rect.y = lowDY;
+ rect.w = highDX - lowDX;
+ rect.h = highDY - lowDY;
+ // Clip it to the screen
+ SPG_DirtyClip(dest, &rect);
+ SPG_DirtyAddTo(spg_dirtytable_front, &rect);
+ }
+}
+
+// SDL's clipping
+int SPG_Blit(SDL_Surface* source, SDL_Rect* srect, SDL_Surface* dest, SDL_Rect* drect)
+{
+ /* Make sure the surfaces aren't locked */
+ if ( ! source || ! dest ) {
+ SDL_SetError("SPG_Blit was passed a NULL surface");
+ return -1;
+ }
+ if ( source->locked || dest->locked ) {
+ SDL_SetError("SPG_Blit was passed a locked surface");
+ return -1;
+ }
+
+
+ srect = SPG_BlitClip(source, srect, dest, drect);
+ if(spg_blitfunc == NULL)
+ spg_blitfunc = SPG_BlendBlit;
+ spg_blitfunc(source, srect, dest, drect);
+
+
+ free(srect);
+
+ return 0;
+}
+
+void SPG_SetBlit(void (*blitfn)(SDL_Surface*, SDL_Rect*, SDL_Surface*, SDL_Rect*))
+{
+ spg_blitfunc = blitfn;
+}
+
+void (*SPG_GetBlit())(SDL_Surface*, SDL_Rect*, SDL_Surface*, SDL_Rect*)
+{
+ return spg_blitfunc;
+}
+
+
+// Returns a new surface that is a copy of the dest surface but with
+// the color value replaced by the values on the src surface.
+SDL_Surface* SPG_ReplaceColor(SDL_Surface* src, SDL_Rect* srcrect, SDL_Surface* dest, SDL_Rect* destrect, Uint32 color)
+{
+ if(src == NULL || dest == NULL)
+ return NULL;
+
+ // Save per-surface alpha
+ Uint32 srcAlpha = src->flags & SDL_SRCALPHA;
+ Uint32 destAlpha = dest->flags & SDL_SRCALPHA;
+ // ... and disable blending.
+ SDL_SetAlpha(src, 0, src->format->alpha);
+ SDL_SetAlpha(dest, 0, dest->format->alpha);
+
+ // Save colorkey info
+ Uint32 destCK = dest->format->colorkey;
+ Uint32 destCKflag = dest->flags & SDL_SRCCOLORKEY;
+ // ... and set the key to the desired color.
+ SPG_SetColorkey(dest, color);
+
+ // srcrect != NULL: Take piece of src and use it (looks like placing piece on top of dest)
+ // destrect != NULL: Move src somewhere before blitting
+ SDL_Surface* temp = SDL_CreateRGBSurface(SDL_SWSURFACE, dest->w, dest->h, dest->format->BitsPerPixel,
+ dest->format->Rmask, dest->format->Gmask, dest->format->Bmask, dest->format->Amask);
+
+ SDL_BlitSurface(src, srcrect, temp, destrect); // BG color is always BLACK and TRANSPARENT...
+ SDL_BlitSurface(dest, NULL, temp, NULL);
+
+ // Restore stuff
+ SDL_SetColorKey(dest, destCKflag, destCK);
+ SDL_SetAlpha(src, srcAlpha, src->format->alpha);
+ SDL_SetAlpha(dest, destAlpha, dest->format->alpha);
+ return temp;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+/**********************************************************************************/
+/** Palette functions **/
+/**********************************************************************************/
+
+// 8-bit palettes
+
+// Returns an 8-bit rainbow palette with 256 colors.
+// Code adapted from SDL_DitherColors in SDL_pixels.c
+SDL_Color* SPG_ColorPalette()
+{
+ SDL_Color* colors = (SDL_Color*)malloc(sizeof(SDL_Color)*256);
+ int i;
+
+ for(i = 0; i < 256; i++) {
+ int r, g, b;
+ // map each bit field to the full [0, 255] interval,
+ //so 0 is mapped to (0, 0, 0) and 255 to (255, 255, 255)
+ r = i & 0xe0;
+ r |= r >> 3 | r >> 6;
+ colors[i].r = r;
+ g = (i << 3) & 0xe0;
+ g |= g >> 3 | g >> 6;
+ colors[i].g = g;
+ b = i & 0x3;
+ b |= b << 2;
+ b |= b << 4;
+ colors[i].b = b;
+ }
+ return colors;
+}
+
+// Returns an 8-bit black and white (grayscale) palette with 256 colors.
+SDL_Color* SPG_GrayPalette()
+{
+ SDL_Color* colors = (SDL_Color*)malloc(sizeof(SDL_Color)*256);
+ int i;
+
+ for(i = 0; i < 256; i++) {
+ colors[i].r = i;
+ colors[i].g = i;
+ colors[i].b = i;
+ }
+ return colors;
+}
+
+SDL_Surface* SPG_CreateSurface8(Uint32 flags, Uint16 width, Uint16 height)
+{
+ SDL_Surface* result = SDL_CreateRGBSurface(flags, width, height, 8, 0, 0, 0, 0);
+
+ // Try to use existing palette...
+ SDL_Surface* videoSurf = SDL_GetVideoSurface();
+ if(videoSurf != NULL && videoSurf->format->BitsPerPixel == 8)
+ {
+ SDL_SetColors(result, videoSurf->format->palette->colors, 0, videoSurf->format->palette->ncolors);
+ }
+ else // else create one
+ {
+ SDL_Color* p = SPG_ColorPalette();
+ SDL_SetColors(result, p, 0, 256);
+ free(p);
+ }
+ return result;
+}
+
+//returns the closest index into the palette for a given r,g,b color
+// Adapted from Meetul Kinarivala, SDL mailing list, 2001
+Uint32 SPG_FindPaletteColor(SDL_Palette* palette, Uint8 r, Uint8 g, Uint8 b)
+{
+ SDL_Color* colors = palette->colors;
+ int Distance, MinDistance = 0xFFFFFF; //init to large value
+ Uint32 index = 0;
+ int i;
+
+ //find index with minimum spatial distance to given r,g,b
+ for (i = 0; i < palette->ncolors; ++i)
+ {
+ // d = r^2 + g^2 + b^2
+ Distance = ((int)(colors[i].r)-(int)(r))*((int)(colors[i].r)-(int)(r))
+ +((int)(colors[i].g)-(int)(g))*((int)(colors[i].g)-(int)(g))
+ +((int)(colors[i].b)-(int)(b))*((int)(colors[i].b)-(int)(b));
+
+ if (MinDistance > Distance)
+ {
+ MinDistance = Distance;
+ index = i;
+ if(MinDistance == 0)
+ break; //color match !!
+ }
+ }
+
+ return index;
+}
+
+//converts any surface -> 8 bit indexed, using shared palette
+//quality optimized but slow
+//returns NULL on error
+// Adapted from Meetul Kinarivala, SDL mailing list, 2001
+SDL_Surface* SPG_PalettizeSurface(SDL_Surface* surface, SDL_Palette* palette)
+{
+ if(surface == NULL || palette == NULL)
+ return NULL;
+
+ SDL_Surface* result = SDL_CreateRGBSurface(surface->flags, surface->w, surface->h, 8, 0, 0, 0, 0);
+
+ if(result == NULL)
+ return NULL;
+
+ int x, y;
+ Uint8 r, g, b;
+
+ for (y=0; y < surface->h; ++y)
+ {
+ for (x=0; x < surface->w; ++x)
+ {
+ SDL_GetRGB(SPG_GetPixel(surface, x, y), surface->format, &r, &g, &b);
+ SPG_Pixel(result, x, y, SPG_FindPaletteColor(palette, r, g, b));
+ }
+ }
+
+ return result;
+}
+
+
+// 32-bit palettes
+
+//==================================================================================
+// Fades from (sR,sG,sB) to (dR,dG,dB), puts result in ctab[start] to ctab[stop]
+//==================================================================================
+void SPG_FadedPalette32(SDL_PixelFormat* format, Uint32 color1, Uint32 color2, Uint32* colorArray, Uint16 startIndex, Uint16 stopIndex)
+{
+ Uint8 sR, sG, sB, dR, dG, dB;
+ SDL_GetRGB(color1, format, &sR, &sG, &sB);
+ SDL_GetRGB(color2, format, &dR, &dG, &dB);
+ // (sR,sG,sB) and (dR,dG,dB) are two points in space (the RGB cube).
+
+ /* The vector for the straight line */
+ int v[3];
+ v[0]=(int)dR-(int)sR; v[1]=(int)dG-(int)sG; v[2]=(int)dB-(int)sB;
+
+ /* Ref. point */
+ int x0=sR, y0=sG, z0=sB;
+
+ // The line's equation is:
+ // x= x0 + v[0] * t
+ // y= y0 + v[1] * t
+ // z= z0 + v[2] * t
+ //
+ // (x,y,z) will travel between the two points when t goes from 0 to 1.
+
+ int i = startIndex;
+ float step = 1.0f/((stopIndex+1)-startIndex);
+ float t;
+ for(t=0.0f; t<=1.0f && i<=stopIndex ; t+=step){
+ colorArray[i++]=SDL_MapRGB(format, (Uint8)(x0+v[0]*t), (Uint8)(y0+v[1]*t), (Uint8)(z0+v[2]*t) );
+ }
+}
+
+
+//==================================================================================
+// Fades from (sR,sG,sB,sA) to (dR,dG,dB,dA), puts result in ctab[start] to ctab[stop]
+//==================================================================================
+void SPG_FadedPalette32Alpha(SDL_PixelFormat* format, Uint32 color1, Uint8 alpha1, Uint32 color2, Uint8 alpha2, Uint32* colorArray, Uint16 startIndex, Uint16 stopIndex)
+{
+ Uint8 sR, sG, sB, dR, dG, dB;
+ SDL_GetRGB(color1, format, &sR, &sG, &sB);
+ SDL_GetRGB(color2, format, &dR, &dG, &dB);
+ // (sR,sG,sB,sA) and (dR,dG,dB,dA) are two points in hyperspace (the RGBA hypercube).
+
+ /* The vector for the straight line */
+ int v[4];
+ v[0]=(int)dR-(int)sR; v[1]=(int)dG-(int)sG; v[2]=(int)dB-(int)sB; v[3]=(int)alpha2-(int)alpha1;
+
+ /* Ref. point */
+ int x0=sR, y0=sG, z0=sB, w0=alpha1;
+
+ // The line's equation is:
+ // x= x0 + v[0] * t
+ // y= y0 + v[1] * t
+ // z= z0 + v[2] * t
+ // w= w0 + v[3] * t
+ //
+ // (x,y,z,w) will travel between the two points when t goes from 0 to 1.
+
+ int i = startIndex;
+ float step = 1.0f/((stopIndex+1)-startIndex);
+ float t;
+ for(t=0.0f; t<=1.0f && i<=stopIndex ; t+=step)
+ colorArray[i++]=SDL_MapRGBA(format, (Uint8)(x0+v[0]*t), (Uint8)(y0+v[1]*t), (Uint8)(z0+v[2]*t), (Uint8)(w0+v[3]*t));
+
+}
+
+
+//==================================================================================
+// Copies a nice rainbow palette to the color table (ctab[start] to ctab[stop]).
+// You must also set the intensity of the palette (0-dark 255-bright)
+//==================================================================================
+void SPG_RainbowPalette32(SDL_PixelFormat* format, Uint32* colorArray, Uint8 intensity, Uint16 startIndex, Uint16 stopIndex)
+{
+ intensity = 255 - intensity;
+ int slice=(int)((stopIndex-startIndex)/6.0f);
+ Uint32 red = SDL_MapRGB(format, 255, intensity, intensity),
+ yellow = SDL_MapRGB(format, 255, 255, intensity),
+ green = SDL_MapRGB(format, intensity, 255, intensity),
+ teal = SDL_MapRGB(format, intensity, 255, 255),
+ blue = SDL_MapRGB(format, intensity, intensity, 255),
+ purple = SDL_MapRGB(format, 255, intensity, 255);
+
+ /* R-Y */
+ SPG_FadedPalette32(format, red, yellow, colorArray, startIndex, startIndex+slice);
+ /* Y-G */
+ SPG_FadedPalette32(format, yellow, green, colorArray, startIndex+slice+1, startIndex+2*slice);
+ /* G-T */
+ SPG_FadedPalette32(format, green, teal, colorArray, startIndex+2*slice+1, startIndex+3*slice);
+ /* T-B */
+ SPG_FadedPalette32(format, teal, blue, colorArray, startIndex+3*slice+1, startIndex+4*slice);
+ /* B-P */
+ SPG_FadedPalette32(format, blue, purple, colorArray, startIndex+4*slice+1, startIndex+5*slice);
+ /* P-R */
+ SPG_FadedPalette32(format, purple, red, colorArray, startIndex+5*slice+1, stopIndex);
+}
+
+
+//==================================================================================
+// Copies a B&W palette to the color table (ctab[start] to ctab[stop]).
+//==================================================================================
+void SPG_GrayPalette32(SDL_PixelFormat* format, Uint32* colorArray, Uint16 startIndex, Uint16 stopIndex)
+{
+ SPG_FadedPalette32(format, SDL_MapRGB(format, 0,0,0), SDL_MapRGB(format, 255,255,255), colorArray, startIndex, stopIndex);
+}
+
+
+
+/**********************************************************************************/
+/** Color filling functions **/
+/**********************************************************************************/
+
+//==================================================================================
+// SPG_FloodFill: Fast non-recursive flood fill
+//
+// Algorithm originally written by
+// Paul Heckbert, 13 Sept 1982, 28 Jan 1987
+//==================================================================================
+/* horizontal segment of scan line y */
+typedef struct seg{
+ Sint16 y, xl, xr, dy;
+}seg;
+
+#define MAXSTACK 1000 /* max depth of stack */
+
+#define PUSH(Y, XL, XR, DY){\
+ if (sp<stack+MAXSTACK && Y+(DY)>=SPG_CLIP_YMIN(dst) && Y+(DY)<=SPG_CLIP_YMAX(dst)){\
+ sp->y = Y;\
+ sp->xl = XL;\
+ sp->xr = XR;\
+ sp->dy = DY;\
+ sp++;\
+ }\
+}
+
+#define POP(Y, XL, XR, DY){\
+ sp--;\
+ DY = sp->dy;\
+ Y = sp->y + sp->dy;\
+ XL = sp->xl;\
+ XR = sp->xr;\
+}
+
+
+/*
+ * set the pixel at (x,y) and all of its 4-connected neighbors
+ * with the same pixel value to the new pixel color.
+ * A 4-connected neighbor is a pixel above, below, left, or right of a pixel.
+ */
+// First a generic (slow) version and then 8/16/32 bpp versions
+void _FloodFillX(SDL_Surface *dst, Sint16 x, Sint16 y, Uint32 color)
+{
+ Sint16 l, x1, x2, dy;
+ Uint32 oc; /* old pixel color */
+ seg stack[MAXSTACK], *sp = stack; /* stack of filled segments */
+
+ if (x<SPG_CLIP_XMIN(dst) || x>SPG_CLIP_XMAX(dst) || y<SPG_CLIP_YMIN(dst) || y>SPG_CLIP_YMAX(dst))
+ return;
+
+ oc = SPG_GetPixel(dst, x,y); /* read color at seed point */
+
+ if (oc == color)
+ return;
+
+ PUSH(y, x, x, 1); /* needed in some cases */
+ PUSH(y+1, x, x, -1); /* seed segment (popped 1st) */
+
+ while (sp>stack) {
+ /* pop segment off stack and fill a neighboring scan line */
+ POP(y, x1, x2, dy);
+
+ /*
+ * segment of scan line y-dy for x1<=x<=x2 was previously filled,
+ * now explore adjacent pixels in scan line y
+ */
+ for (x=x1; x>=SPG_CLIP_XMIN(dst); x--){
+ if( SPG_GetPixel(dst, x,y) != oc )
+ break;
+
+ spg_pixel(dst, x, y, color);
+ }
+
+ if (x>=x1)
+ goto skip;
+
+ l = x+1;
+ if (l<x1)
+ PUSH(y, l, x1-1, -dy); /* leak on left? */
+
+ x = x1+1;
+
+ do {
+ for (; x<=SPG_CLIP_XMAX(dst); x++){
+ if( SPG_GetPixel(dst, x,y) != oc )
+ break;
+
+ spg_pixel(dst, x, y, color);
+ }
+
+ PUSH(y, l, x-1, dy);
+
+ if (x>x2+1)
+ PUSH(y, x2+1, x-1, -dy); /* leak on right? */
+skip:
+ for (x++; x<=x2; x++)
+ if( SPG_GetPixel(dst, x,y) == oc )
+ break;
+
+ l = x;
+ } while (x<=x2);
+ }
+}
+
+/* Macro for 8/16/32 bpp */
+#define DO_FILL(UintXX, label)\
+{\
+ Sint16 l, x1, x2, dy;\
+ Uint32 oc; /* old pixel color */\
+ seg stack[MAXSTACK], *sp = stack; /* stack of filled segments */\
+ Uint16 pitch = dst->pitch/dst->format->BytesPerPixel;\
+ UintXX *row = (UintXX*)dst->pixels + y*pitch;\
+ UintXX *pixel = row + x;\
+\
+ if (x<SPG_CLIP_XMIN(dst) || x>SPG_CLIP_XMAX(dst) || y<SPG_CLIP_YMIN(dst) || y>SPG_CLIP_YMAX(dst))\
+ return;\
+\
+ oc = *pixel; /* read color at seed point */\
+\
+ if (oc == color)\
+ return;\
+\
+ PUSH(y, x, x, 1); /* needed in some cases */\
+ PUSH(y+1, x, x, -1); /* seed segment (popped 1st) */\
+\
+ while (sp>stack) {\
+ /* pop segment off stack and fill a neighboring scan line */\
+ POP(y, x1, x2, dy);\
+ row = (UintXX*)dst->pixels + y*pitch;\
+ pixel = row + x1;\
+\
+ /*\
+ * segment of scan line y-dy for x1<=x<=x2 was previously filled,
+ * now explore adjacent pixels in scan line y
+ */\
+ for (x=x1; x>=SPG_CLIP_XMIN(dst) && *pixel == oc; x--, pixel--)\
+ *pixel = color;\
+\
+ if (x>=x1)\
+ goto label;\
+\
+ l = x+1;\
+ if (l<x1)\
+ PUSH(y, l, x1-1, -dy); /* leak on left? */\
+\
+ x = x1+1;\
+ pixel = row + x;\
+\
+ do {\
+ for (; x<=SPG_CLIP_XMAX(dst) && *pixel == oc; x++, pixel++)\
+ *pixel = color;\
+\
+ PUSH(y, l, x-1, dy);\
+\
+ if (x>x2+1)\
+ PUSH(y, x2+1, x-1, -dy); /* leak on right? */\
+label:\
+ pixel++;\
+\
+ for (x++; x<=x2 && *pixel != oc; x++, pixel++);\
+\
+ l = x;\
+ } while (x<=x2);\
+ }\
+}
+
+// Wrapper function
+void SPG_FloodFill(SDL_Surface *dst, Sint16 x, Sint16 y, Uint32 color)
+{
+ if ( spg_lock(dst) < 0 )
+ {
+ if(spg_useerrors)
+ SPG_Error("SPG_FloodFill could not lock surface");
+ return;
+ }
+
+ switch (dst->format->BytesPerPixel) {
+ case 1: /* Assuming 8-bpp */
+ DO_FILL(Uint8, skip8)
+ break;
+
+ case 2: /* Probably 15-bpp or 16-bpp */
+ DO_FILL(Uint16, skip16)
+ break;
+
+ case 3: /* Slow 24-bpp mode, usually not used */
+ _FloodFillX(dst, x,y, color);
+ break;
+
+ case 4: /* Probably 32-bpp */
+ DO_FILL(Uint32, skip32)
+ break;
+ }
+
+ spg_unlock(dst);
+
+}
+
+
+
diff --git a/util/sdl/sprig/Version.txt b/util/sdl/sprig/Version.txt
new file mode 100644
index 00000000..de299a82
--- /dev/null
+++ b/util/sdl/sprig/Version.txt
@@ -0,0 +1,4 @@
+SPriG - SDL Primitive Generator
+by Jonathan Dearborn
+version 1.0.1
+11-27-09
\ No newline at end of file
diff --git a/util/sdl/sprig/license b/util/sdl/sprig/license
new file mode 100644
index 00000000..b1e3f5a2
--- /dev/null
+++ b/util/sdl/sprig/license
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/util/sdl/sprig/sprig.h b/util/sdl/sprig/sprig.h
new file mode 100644
index 00000000..f979021d
--- /dev/null
+++ b/util/sdl/sprig/sprig.h
@@ -0,0 +1,453 @@
+/*
+ SPriG - SDL Primitive Generator
+ by Jonathan Dearborn
+
+ Based on SGE: SDL Graphics Extension r030809
+ by Anders Lindström
+*/
+
+
+/*********************************************************************
+ * 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. *
+ *********************************************************************/
+
+
+#ifndef _SPRIG_H__
+#define _SPRIG_H__
+
+
+#include "SDL.h"
+
+#define SPG_VER 1 // Check this for MISSING functionality
+#define SPG_VER_MINOR 0 // Check this for ADDED functionality
+#define SPG_VER_BUGFIX 1
+
+#define SPG_C_AND_CPP // undef this if you want to force C under a C++ compiler
+//#define SPG_USE_EXTENDED // Build Sprig with this to add some extra functions
+#define SPG_DEFINE_PI // Allow defines of pi variations
+#define SPG_MAX_ERRORS 40 // Max size of error message stack
+#define SPG_USE_FAST_MATH // undef this to use math.h's sqrt()
+
+
+
+
+/*
+* C compatibility
+* Thanks to Ohbayashi Ippei (ohai@kmc.gr.jp) for this clever hack!
+*/
+#ifdef SPG_C_AND_CPP
+ #ifdef __cplusplus
+ #define SPG_CPP /* use extern "C" on base functions */
+ #else
+ #define SPG_C_ONLY /* remove overloaded functions */
+ #endif
+#else
+ #define SPG_C_ONLY
+#endif
+
+//PI_8, PI_4, PI_2, PI3_4, PI, PI5_4, PI3_2, PI7_4, PI2
+#ifdef SPG_DEFINE_PI
+ #ifndef PI_8
+ #define PI_8 0.392699082f
+ #endif
+ #ifndef PI_4
+ #define PI_4 0.785398163f
+ #endif
+ #ifndef PI_2
+ #define PI_2 1.57079633f
+ #endif
+ #ifndef PI3_4
+ #define PI3_4 2.35619449f
+ #endif
+ #ifndef PI
+ #define PI 3.14159265f
+ #endif
+ #ifndef PI5_4
+ #define PI5_4 3.92699082f
+ #endif
+ #ifndef PI3_2
+ #define PI3_2 4.71238898f
+ #endif
+ #ifndef PI7_4
+ #define PI7_4 5.49778714f
+ #endif
+ #ifndef PI2
+ #define PI2 6.28318531f
+ #endif
+
+ #ifndef DEGPERRAD
+ #define DEGPERRAD 57.2957795f
+ #endif
+ #ifndef RADPERDEG
+ #define RADPERDEG 0.0174532925f
+ #endif
+#endif
+
+
+/*
+* Bit flags
+*/
+#define SPG_FLAG0 0
+#define SPG_FLAG1 0x01
+#define SPG_FLAG2 0x02
+#define SPG_FLAG3 0x04
+#define SPG_FLAG4 0x08
+#define SPG_FLAG5 0x10
+#define SPG_FLAG6 0x20
+#define SPG_FLAG7 0x40
+#define SPG_FLAG8 0x80
+
+
+/*
+* Define the right alpha values
+* (they were flipped in SDL 1.1.5+)
+* That means alpha is now a measure of opacity
+*/
+#ifndef SDL_ALPHA_OPAQUE
+ #define SDL_ALPHA_OPAQUE 255
+#endif
+#ifndef SDL_ALPHA_TRANSPARENT
+ #define SDL_ALPHA_TRANSPARENT 0
+#endif
+
+
+/*
+* Older versions of SDL don't have SDL_VERSIONNUM
+*/
+#ifndef SDL_VERSIONNUM
+ #define SDL_VERSIONNUM(X, Y, Z) ((X)*1000 + (Y)*100 + (Z))
+#endif
+
+
+/*
+* Older versions of SDL don't have SDL_CreateRGBSurface
+*/
+#ifndef SDL_AllocSurface
+ #define SDL_CreateRGBSurface SDL_AllocSurface
+#endif
+
+
+/*
+* Macro to get clipping
+*/
+#if SDL_VERSIONNUM(SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL) >= \
+ SDL_VERSIONNUM(1, 1, 5)
+ #define SPG_CLIP_XMIN(pnt) pnt->clip_rect.x
+ #define SPG_CLIP_XMAX(pnt) pnt->clip_rect.x + pnt->clip_rect.w-1
+ #define SPG_CLIP_YMIN(pnt) pnt->clip_rect.y
+ #define SPG_CLIP_YMAX(pnt) pnt->clip_rect.y + pnt->clip_rect.h-1
+#else
+ #define SPG_CLIP_XMIN(pnt) pnt->clip_minx
+ #define SPG_CLIP_XMAX(pnt) pnt->clip_maxx
+ #define SPG_CLIP_YMIN(pnt) pnt->clip_miny
+ #define SPG_CLIP_YMAX(pnt) pnt->clip_maxy
+#endif
+
+
+/*
+* We need to use alpha sometimes but older versions of SDL don't have
+* alpha support.
+*/
+#if SDL_VERSIONNUM(SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL) >= \
+ SDL_VERSIONNUM(1, 1, 5)
+ #define SPG_MapRGBA SDL_MapRGBA
+ #define SPG_GetRGBA SDL_GetRGBA
+#else
+ #define SPG_MapRGBA(fmt, r, g, b, a) SDL_MapRGB(fmt, r, g, b)
+ #define SPG_GetRGBA(pixel, fmt, r, g, b, a) SDL_GetRGB(pixel, fmt, r, g, b)
+#endif
+
+
+/*
+* Some compilers use a special export keyword
+* Thanks to Seung Chan Lim (limsc@maya.com or slim@djslim.com) to pointing this out
+* (From SDL)
+*/
+#ifndef DECLSPEC
+ #ifdef __BEOS__
+ #if defined(__GNUC__)
+ #define DECLSPEC __declspec(dllexport)
+ #else
+ #define DECLSPEC __declspec(export)
+ #endif
+ #else
+ #ifdef WIN32
+ #define DECLSPEC __declspec(dllexport)
+ #else
+ #define DECLSPEC
+ #endif
+ #endif
+#endif
+
+typedef struct SPG_Point
+{
+ float x;
+ float y;
+}SPG_Point;
+
+/* A table of dirtyrects for one display page */
+typedef struct SPG_DirtyTable
+{
+ Uint16 size; /* Table size */
+ SDL_Rect *rects; /* Table of rects */
+ Uint16 count; /* # of rects currently used */
+ Uint16 best; /* Merge testing starts here! */
+} SPG_DirtyTable;
+
+
+#define SPG_bool Uint8
+
+// default = 0
+#define SPG_DEST_ALPHA 0
+#define SPG_SRC_ALPHA 1
+#define SPG_COMBINE_ALPHA 2
+#define SPG_COPY_NO_ALPHA 3
+#define SPG_COPY_SRC_ALPHA 4
+#define SPG_COPY_DEST_ALPHA 5
+#define SPG_COPY_COMBINE_ALPHA 6
+#define SPG_COPY_ALPHA_ONLY 7
+#define SPG_COMBINE_ALPHA_ONLY 8
+#define SPG_REPLACE_COLORKEY 9
+
+// Alternate names:
+#define SPG_SRC_MASK 4
+#define SPG_DEST_MASK 5
+
+
+/* Transformation flags */
+#define SPG_NONE SPG_FLAG0
+#define SPG_TAA SPG_FLAG1
+#define SPG_TSAFE SPG_FLAG2
+#define SPG_TTMAP SPG_FLAG3
+#define SPG_TSLOW SPG_FLAG4
+#define SPG_TCOLORKEY SPG_FLAG5
+#define SPG_TBLEND SPG_FLAG6
+#define SPG_TSURFACE_ALPHA SPG_FLAG7
+
+#ifdef SPG_CPP // BOTH C and C++
+extern "C" {
+#endif
+
+
+// MISC
+DECLSPEC SDL_Surface* SPG_InitSDL(Uint16 w, Uint16 h, Uint8 bitsperpixel, Uint32 systemFlags, Uint32 screenFlags);
+
+DECLSPEC void SPG_EnableAutolock(SPG_bool enable);
+DECLSPEC SPG_bool SPG_GetAutolock();
+
+DECLSPEC void SPG_EnableRadians(SPG_bool enable);
+DECLSPEC SPG_bool SPG_GetRadians();
+
+DECLSPEC void SPG_Error(const char* err);
+DECLSPEC void SPG_EnableErrors(SPG_bool enable);
+DECLSPEC char* SPG_GetError();
+DECLSPEC Uint16 SPG_NumErrors();
+
+DECLSPEC void SPG_PushThickness(Uint16 state);
+DECLSPEC Uint16 SPG_PopThickness();
+DECLSPEC Uint16 SPG_GetThickness();
+DECLSPEC void SPG_PushBlend(Uint8 state);
+DECLSPEC Uint8 SPG_PopBlend();
+DECLSPEC Uint8 SPG_GetBlend();
+DECLSPEC void SPG_PushAA(SPG_bool state);
+DECLSPEC SPG_bool SPG_PopAA();
+DECLSPEC SPG_bool SPG_GetAA();
+DECLSPEC void SPG_PushSurfaceAlpha(SPG_bool state);
+DECLSPEC SPG_bool SPG_PopSurfaceAlpha();
+DECLSPEC SPG_bool SPG_GetSurfaceAlpha();
+
+DECLSPEC void SPG_RectOR(const SDL_Rect rect1, const SDL_Rect rect2, SDL_Rect* dst_rect);
+DECLSPEC SPG_bool SPG_RectAND(const SDL_Rect A, const SDL_Rect B, SDL_Rect* intersection);
+
+// DIRTY RECT
+// Important stuff
+DECLSPEC void SPG_EnableDirty(SPG_bool enable);
+DECLSPEC void SPG_DirtyInit(Uint16 maxsize);
+DECLSPEC void SPG_DirtyAdd(SDL_Rect* rect);
+DECLSPEC SPG_DirtyTable* SPG_DirtyUpdate(SDL_Surface* screen);
+DECLSPEC void SPG_DirtySwap();
+// Other stuff
+DECLSPEC SPG_bool SPG_DirtyEnabled();
+DECLSPEC SPG_DirtyTable* SPG_DirtyMake(Uint16 maxsize);
+DECLSPEC void SPG_DirtyAddTo(SPG_DirtyTable* table, SDL_Rect* rect);
+DECLSPEC void SPG_DirtyFree(SPG_DirtyTable* table);
+DECLSPEC SPG_DirtyTable* SPG_DirtyGet();
+DECLSPEC void SPG_DirtyClear(SPG_DirtyTable* table);
+DECLSPEC void SPG_DirtyLevel(Uint16 optimizationLevel);
+DECLSPEC void SPG_DirtyClip(SDL_Surface* screen, SDL_Rect* rect);
+
+// PALETTE
+DECLSPEC SDL_Color* SPG_ColorPalette();
+DECLSPEC SDL_Color* SPG_GrayPalette();
+DECLSPEC Uint32 SPG_FindPaletteColor(SDL_Palette* palette, Uint8 r, Uint8 g, Uint8 b);
+DECLSPEC SDL_Surface* SPG_PalettizeSurface(SDL_Surface* surface, SDL_Palette* palette);
+
+DECLSPEC void SPG_FadedPalette32(SDL_PixelFormat* format, Uint32 color1, Uint32 color2, Uint32* colorArray, Uint16 startIndex, Uint16 stopIndex);
+DECLSPEC void SPG_FadedPalette32Alpha(SDL_PixelFormat* format, Uint32 color1, Uint8 alpha1, Uint32 color2, Uint8 alpha2, Uint32* colorArray, Uint16 start, Uint16 stop);
+DECLSPEC void SPG_RainbowPalette32(SDL_PixelFormat* format, Uint32 *colorArray, Uint8 intensity, Uint16 startIndex, Uint16 stopIndex);
+DECLSPEC void SPG_GrayPalette32(SDL_PixelFormat* format, Uint32 *colorArray, Uint16 startIndex, Uint16 stopIndex);
+
+// SURFACE
+
+DECLSPEC SDL_Surface* SPG_CreateSurface8(Uint32 flags, Uint16 width, Uint16 height);
+DECLSPEC Uint32 SPG_GetPixel(SDL_Surface *surface, Sint16 x, Sint16 y);
+DECLSPEC void SPG_SetClip(SDL_Surface *surface, const SDL_Rect rect);
+
+DECLSPEC SDL_Rect SPG_TransformX(SDL_Surface *src, SDL_Surface *dst, float angle, float xscale, float yscale, Uint16 pivotX, Uint16 pivotY, Uint16 destX, Uint16 destY, Uint8 flags);
+DECLSPEC SDL_Surface* SPG_Transform(SDL_Surface *src, Uint32 bgColor, float angle, float xscale, float yscale, Uint8 flags);
+DECLSPEC SDL_Surface* SPG_Rotate(SDL_Surface *src, float angle, Uint32 bgColor);
+DECLSPEC SDL_Surface* SPG_RotateAA(SDL_Surface *src, float angle, Uint32 bgColor);
+
+DECLSPEC SDL_Surface* SPG_ReplaceColor(SDL_Surface* src, SDL_Rect* srcrect, SDL_Surface* dest, SDL_Rect* destrect, Uint32 color);
+
+
+// DRAWING
+
+DECLSPEC int SPG_Blit(SDL_Surface *Src, SDL_Rect* srcRect, SDL_Surface *Dest, SDL_Rect* destRect);
+DECLSPEC void SPG_SetBlit(void (*blitfn)(SDL_Surface*, SDL_Rect*, SDL_Surface*, SDL_Rect*));
+DECLSPEC void (*SPG_GetBlit())(SDL_Surface*, SDL_Rect*, SDL_Surface*, SDL_Rect*);
+
+DECLSPEC void SPG_FloodFill(SDL_Surface *dst, Sint16 x, Sint16 y, Uint32 color);
+
+
+// PRIMITIVES
+
+DECLSPEC void SPG_Pixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color);
+DECLSPEC void SPG_PixelBlend(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color, Uint8 alpha);
+DECLSPEC void SPG_PixelPattern(SDL_Surface *surface, SDL_Rect target, SPG_bool* pattern, Uint32* colors);
+DECLSPEC void SPG_PixelPatternBlend(SDL_Surface *surface, SDL_Rect target, SPG_bool* pattern, Uint32* colors, Uint8* pixelAlpha);
+
+DECLSPEC void SPG_LineH(SDL_Surface *surface, Sint16 x1, Sint16 y, Sint16 x2, Uint32 Color);
+DECLSPEC void SPG_LineHBlend(SDL_Surface *surface, Sint16 x1, Sint16 y, Sint16 x2, Uint32 color, Uint8 alpha);
+
+DECLSPEC void SPG_LineHFade(SDL_Surface *dest,Sint16 x1,Sint16 y,Sint16 x2,Uint32 color1, Uint32 color2);
+DECLSPEC void SPG_LineHTex(SDL_Surface *dest,Sint16 x1,Sint16 y,Sint16 x2,SDL_Surface *source,Sint16 sx1,Sint16 sy1,Sint16 sx2,Sint16 sy2);
+
+DECLSPEC void SPG_LineV(SDL_Surface *surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 Color);
+DECLSPEC void SPG_LineVBlend(SDL_Surface *surface, Sint16 x, Sint16 y1, Sint16 y2, Uint32 color, Uint8 alpha);
+
+DECLSPEC void SPG_LineFn(SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 Color, void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y, Uint32 Color));
+DECLSPEC void SPG_Line(SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 Color);
+DECLSPEC void SPG_LineBlend(SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha);
+
+DECLSPEC void SPG_LineFadeFn(SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color1, Uint32 color2, void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y, Uint32 Color));
+DECLSPEC void SPG_LineFade(SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color1, Uint32 color2);
+DECLSPEC void SPG_LineFadeBlend(SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color1, Uint8 alpha1, Uint32 color2, Uint8 alpha2);
+
+
+DECLSPEC void SPG_Rect(SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color);
+DECLSPEC void SPG_RectBlend(SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha);
+
+DECLSPEC void SPG_RectFilled(SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color);
+DECLSPEC void SPG_RectFilledBlend(SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha);
+
+
+DECLSPEC void SPG_RectRound(SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, float r, Uint32 color);
+DECLSPEC void SPG_RectRoundBlend(SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, float r, Uint32 color, Uint8 alpha);
+
+DECLSPEC void SPG_RectRoundFilled(SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, float r, Uint32 color);
+DECLSPEC void SPG_RectRoundFilledBlend(SDL_Surface *surface, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, float r, Uint32 color, Uint8 alpha);
+
+
+DECLSPEC void SPG_EllipseFn(SDL_Surface *surface, Sint16 x, Sint16 y, float rx, float ry, Uint32 color, void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y, Uint32 Color));
+DECLSPEC void SPG_Ellipse(SDL_Surface *surface, Sint16 x, Sint16 y, float rx, float ry, Uint32 color);
+DECLSPEC void SPG_EllipseBlend(SDL_Surface *surface, Sint16 x, Sint16 y, float rx, float ry, Uint32 color, Uint8 alpha);
+
+DECLSPEC void SPG_EllipseFilled(SDL_Surface *surface, Sint16 x, Sint16 y, float rx, float ry, Uint32 color);
+DECLSPEC void SPG_EllipseFilledBlend(SDL_Surface *surface, Sint16 x, Sint16 y, float rx, float ry, Uint32 color, Uint8 alpha);
+
+
+DECLSPEC void SPG_EllipseArb(SDL_Surface *Surface, Sint16 x, Sint16 y, float rx, float ry, float angle, Uint32 color);
+DECLSPEC void SPG_EllipseBlendArb(SDL_Surface *Surface, Sint16 x, Sint16 y, float rx, float ry, float angle, Uint32 color, Uint8 alpha);
+
+DECLSPEC void SPG_EllipseFilledArb(SDL_Surface *Surface, Sint16 x, Sint16 y, float rx, float ry, float angle, Uint32 color);
+DECLSPEC void SPG_EllipseFilledBlendArb(SDL_Surface *Surface, Sint16 x, Sint16 y, float rx, float ry, float angle, Uint32 color, Uint8 alpha);
+
+
+DECLSPEC void SPG_CircleFn(SDL_Surface *surface, Sint16 x, Sint16 y, float r, Uint32 color, void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y, Uint32 Color));
+DECLSPEC void SPG_Circle(SDL_Surface *surface, Sint16 x, Sint16 y, float r, Uint32 color);
+DECLSPEC void SPG_CircleBlend(SDL_Surface *surface, Sint16 x, Sint16 y, float r, Uint32 color, Uint8 alpha);
+
+DECLSPEC void SPG_CircleFilled(SDL_Surface *surface, Sint16 x, Sint16 y, float r, Uint32 color);
+DECLSPEC void SPG_CircleFilledBlend(SDL_Surface *surface, Sint16 x, Sint16 y, float r, Uint32 color, Uint8 alpha);
+
+
+DECLSPEC void SPG_ArcFn(SDL_Surface* surface, Sint16 cx, Sint16 cy, float radius, float startAngle, float endAngle, Uint32 color, void Callback(SDL_Surface *Surf, Sint16 X, Sint16 Y, Uint32 Color));
+DECLSPEC void SPG_Arc(SDL_Surface* surface, Sint16 x, Sint16 y, float radius, float startAngle, float endAngle, Uint32 color);
+DECLSPEC void SPG_ArcBlend(SDL_Surface* surface, Sint16 x, Sint16 y, float radius, float startAngle, float endAngle, Uint32 color, Uint8 alpha);
+
+DECLSPEC void SPG_ArcFilled(SDL_Surface* surface, Sint16 cx, Sint16 cy, float radius, float startAngle, float endAngle, Uint32 color);
+DECLSPEC void SPG_ArcFilledBlend(SDL_Surface* surface, Sint16 cx, Sint16 cy, float radius, float startAngle, float endAngle, Uint32 color, Uint8 alpha);
+
+
+DECLSPEC void SPG_Bezier(SDL_Surface *surface, Sint16 startX, Sint16 startY, Sint16 cx1, Sint16 cy1, Sint16 cx2, Sint16 cy2, Sint16 endX, Sint16 endY, Uint8 quality, Uint32 color);
+DECLSPEC void SPG_BezierBlend(SDL_Surface *surface, Sint16 startX, Sint16 startY, Sint16 cx1, Sint16 cy1, Sint16 cx2, Sint16 cy2, Sint16 endX, Sint16 endY, Uint8 quality, Uint32 color, Uint8 alpha);
+
+
+// POLYGONS
+
+DECLSPEC void SPG_Trigon(SDL_Surface *surface,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color);
+DECLSPEC void SPG_TrigonBlend(SDL_Surface *surface,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color, Uint8 alpha);
+
+DECLSPEC void SPG_TrigonFilled(SDL_Surface *surface,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color);
+DECLSPEC void SPG_TrigonFilledBlend(SDL_Surface *surface,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color, Uint8 alpha);
+
+DECLSPEC void SPG_TrigonFade(SDL_Surface *surface,Sint16 x1,Sint16 y1,Sint16 x2,Sint16 y2,Sint16 x3,Sint16 y3,Uint32 color1,Uint32 color2,Uint32 color3);
+DECLSPEC void SPG_TrigonTex(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);
+
+
+DECLSPEC void SPG_QuadTex(SDL_Surface* dest, Sint16 destULx, Sint16 destULy, Sint16 destDLx, Sint16 destDLy, Sint16 destDRx, Sint16 destDRy, Sint16 destURx, Sint16 destURy, SDL_Surface* source, Sint16 srcULx, Sint16 srcULy, Sint16 srcDLx, Sint16 srcDLy, Sint16 srcDRx, Sint16 srcDRy, Sint16 srcURx, Sint16 srcURy);
+
+DECLSPEC void SPG_Polygon(SDL_Surface *dest, Uint16 n, SPG_Point* points, Uint32 color);
+DECLSPEC void SPG_PolygonBlend(SDL_Surface *dest, Uint16 n, SPG_Point* points, Uint32 color, Uint8 alpha);
+
+DECLSPEC void SPG_PolygonFilled(SDL_Surface *surface, Uint16 n, SPG_Point* points, Uint32 color);
+DECLSPEC void SPG_PolygonFilledBlend(SDL_Surface *surface, Uint16 n, SPG_Point* points, Uint32 color, Uint8 alpha);
+
+DECLSPEC void SPG_PolygonFade(SDL_Surface *surface, Uint16 n, SPG_Point* points, Uint32* colors);
+DECLSPEC void SPG_PolygonFadeBlend(SDL_Surface *surface, Uint16 n, SPG_Point* points, Uint32* colors, Uint8 alpha);
+
+DECLSPEC void SPG_CopyPoints(Uint16 n, SPG_Point* points, SPG_Point* buffer);
+DECLSPEC void SPG_RotatePointsXY(Uint16 n, SPG_Point* points, float cx, float cy, float angle);
+DECLSPEC void SPG_ScalePointsXY(Uint16 n, SPG_Point* points, float cx, float cy, float xscale, float yscale);
+DECLSPEC void SPG_SkewPointsXY(Uint16 n, SPG_Point* points, float cx, float cy, float xskew, float yskew);
+DECLSPEC void SPG_TranslatePoints(Uint16 n, SPG_Point* points, float x, float y);
+
+
+#ifdef SPG_CPP
+} // extern "C"
+#endif
+
+
+
+
+// Include all convenience calls
+#include "sprig_inline.h"
+
+// Include extended calls
+#ifdef SPG_USE_EXTENDED
+
+
+ #ifdef SPG_CPP // BOTH C and C++
+ extern "C" {
+ #endif
+
+
+ DECLSPEC void SPG_FloodFill8(SDL_Surface* dest, Sint16 x, Sint16 y, Uint32 newColor);
+
+
+ #ifdef SPG_CPP // BOTH C and C++
+ } // extern "C"
+ #endif
+
+
+#endif
+
+
+
+
+#endif /* _SPRIG_H__ */
+
diff --git a/util/sdl/sprig/sprig_common.h b/util/sdl/sprig/sprig_common.h
new file mode 100644
index 00000000..95841fe4
--- /dev/null
+++ b/util/sdl/sprig/sprig_common.h
@@ -0,0 +1,33 @@
+/*
+This header file is used internally by Sprig when it is compiled. You do not
+need to copy this to your compiler's 'include' folder.
+*/
+
+
+#ifndef _SPRIG_INTERNAL_H__
+#define _SPRIG_INTERNAL_H__
+
+extern SPG_bool spg_autolock;
+
+
+#define SWAP(x,y,temp) temp=x;x=y;y=temp
+#define MIN(x,y) (x < y? x : y)
+#define MAX(x,y) (x > y? x : y)
+
+/* Lock the surface, returning negative on error */
+static inline int spg_lock(SDL_Surface* surface)
+{
+ if(spg_autolock && SDL_MUSTLOCK(surface) && SDL_LockSurface(surface) < 0)
+ return -1;
+ return 0;
+}
+
+/* Unlock the surface */
+static inline void spg_unlock(SDL_Surface* surface)
+{
+ if(spg_autolock && SDL_MUSTLOCK(surface))
+ SDL_UnlockSurface(surface);
+}
+
+
+#endif
diff --git a/util/sdl/sprig/sprig_inline.h b/util/sdl/sprig/sprig_inline.h
new file mode 100644
index 00000000..eede980a
--- /dev/null
+++ b/util/sdl/sprig/sprig_inline.h
@@ -0,0 +1,355 @@
+#ifndef _SPG_INLINE_H__
+#define _SPG_INLINE_H__
+
+
+/* Colors */
+
+static inline Uint8 SPG_GetRed(SDL_PixelFormat* format, Uint32 color)
+{
+ return (color & format->Rmask) >> format->Rshift;
+}
+static inline Uint8 SPG_GetGreen(SDL_PixelFormat* format, Uint32 color)
+{
+ return (color & format->Gmask) >> format->Gshift;
+}
+static inline Uint8 SPG_GetBlue(SDL_PixelFormat* format, Uint32 color)
+{
+ return (color & format->Bmask) >> format->Bshift;
+}
+static inline Uint8 SPG_GetAlpha(SDL_PixelFormat* format, Uint32 color)
+{
+ return (color & format->Amask) >> format->Ashift;
+}
+
+
+static inline Uint32 SPG_MixRed(SDL_PixelFormat* format, Uint32 color, Uint8 red)
+{
+ return (color & (~(format->Rmask))) | (red << format->Rshift);
+}
+static inline Uint32 SPG_MixGreen(SDL_PixelFormat* format, Uint32 color, Uint8 green)
+{
+ return (color & (~(format->Gmask))) | (green << format->Gshift);
+}
+static inline Uint32 SPG_MixBlue(SDL_PixelFormat* format, Uint32 color, Uint8 blue)
+{
+ return (color & (~(format->Bmask))) | (blue << format->Bshift);
+}
+static inline Uint32 SPG_MixAlpha(SDL_PixelFormat* format, Uint32 color, Uint8 alpha)
+{
+ return (color & (~(format->Amask))) | (alpha << format->Ashift);
+}
+
+static inline Uint32 SPG_ConvertColor(SDL_PixelFormat* srcfmt, Uint32 srccolor, SDL_PixelFormat* destfmt)
+{
+ if(srcfmt == NULL || destfmt == NULL)
+ return 0;
+ Uint8 r, g, b;
+ SDL_GetRGB(srccolor, srcfmt, &r, &g, &b);
+ return SDL_MapRGB(destfmt, r, g, b);
+}
+
+static inline SDL_Color SPG_GetColor(SDL_Surface* Surface, Uint32 Color)
+{
+ SDL_Color rgb;
+ SDL_GetRGB(Color, Surface->format, &(rgb.r), &(rgb.g), &(rgb.b));
+ rgb.unused = 0;
+ return rgb;
+}
+
+static inline SDL_Color SPG_MakeColor(Uint8 R, Uint8 G, Uint8 B)
+{
+ SDL_Color color = {R, G, B, 0};
+ return color;
+}
+
+static inline SDL_Color SPG_MakeColorAlpha(Uint8 R, Uint8 G, Uint8 B, Uint8 A)
+{
+ SDL_Color color = {R, G, B, A};
+ return color;
+}
+
+
+/* Points */
+
+static inline SPG_Point SPG_MakePoint(Sint16 x, Sint16 y)
+{
+ SPG_Point p = {x, y};
+ return p;
+}
+
+static inline void SPG_RotatePoints(Uint16 n, SPG_Point* points, float angle)
+{
+ SPG_RotatePointsXY(n, points, 0, 0, angle);
+}
+
+static inline void SPG_ScalePoints(Uint16 n, SPG_Point* points, float xscale, float yscale)
+{
+ SPG_ScalePointsXY(n, points, 0, 0, xscale, yscale);
+}
+
+static inline void SPG_SkewPoints(Uint16 n, SPG_Point* points, float xskew, float yskew)
+{
+ SPG_SkewPointsXY(n, points, 0, 0, xskew, yskew);
+}
+
+static inline void SPG_TrigonTexPoints(SDL_Surface* dest, SPG_Point* dest_points, SDL_Surface* source, SPG_Point* source_points)
+{
+ SPG_TrigonTex(dest, (Sint16)(dest_points[0].x + 0.5f), (Sint16)(dest_points[0].y + 0.5f), (Sint16)(dest_points[1].x + 0.5f), (Sint16)(dest_points[1].y + 0.5f), (Sint16)(dest_points[2].x + 0.5f), (Sint16)(dest_points[2].y + 0.5f),
+ source, (Sint16)(source_points[0].x + 0.5f), (Sint16)(source_points[0].y + 0.5f), (Sint16)(source_points[1].x + 0.5f), (Sint16)(source_points[1].y + 0.5f), (Sint16)(source_points[2].x + 0.5f), (Sint16)(source_points[2].y + 0.5f));
+}
+
+static inline void SPG_QuadTexPoints(SDL_Surface* dest, SPG_Point* dest_points, SDL_Surface *source, SPG_Point* source_points)
+{
+ SPG_QuadTex(dest, (Sint16)(dest_points[0].x + 0.5f), (Sint16)(dest_points[0].y + 0.5f), (Sint16)(dest_points[1].x + 0.5f), (Sint16)(dest_points[1].y + 0.5f), (Sint16)(dest_points[2].x + 0.5f), (Sint16)(dest_points[2].y + 0.5f),(Sint16)(dest_points[3].x + 0.5f),(Sint16)(dest_points[3].y + 0.5f),
+ source, (Sint16)(source_points[0].x + 0.5f), (Sint16)(source_points[0].y + 0.5f), (Sint16)(source_points[1].x + 0.5f), (Sint16)(source_points[1].y + 0.5f), (Sint16)(source_points[2].x + 0.5f), (Sint16)(source_points[2].y + 0.5f), (Sint16)(source_points[3].x + 0.5f),(Sint16)(source_points[3].y + 0.5f));
+}
+
+
+/* Scale */
+
+static inline SDL_Surface* SPG_Scale(SDL_Surface *src, float xscale, float yscale)
+{
+ return SPG_Transform(src, 0x000000, 0, xscale, yscale, 0);
+}
+
+static inline SDL_Surface* SPG_ScaleAA(SDL_Surface *src, float xscale, float yscale)
+{
+ return SPG_Transform(src, 0x000000, 0, xscale, yscale, SPG_TAA);
+}
+
+
+/* C++ Rotate without bgColor */
+
+#ifndef SPG_C_ONLY
+
+static inline SDL_Surface* SPG_Rotate(SDL_Surface *src, float angle)
+{
+ return SPG_Rotate(src, angle, 0);
+}
+
+static inline SDL_Surface* SPG_RotateAA(SDL_Surface *src, float angle)
+{
+ return SPG_RotateAA(src, angle, 0);
+}
+#endif
+
+
+/* Surface */
+
+static inline void SPG_Free(SDL_Surface* surface)
+{
+ SDL_FreeSurface(surface);
+}
+
+static inline void SPG_SetColorkey(SDL_Surface* surface, Uint32 color)
+{
+ SDL_SetColorKey(surface, SDL_SRCCOLORKEY, color);
+}
+
+static inline SDL_Surface* SPG_DisplayFormat(SDL_Surface* surf)
+{
+ SDL_Surface* temp = SDL_DisplayFormat(surf);
+ SDL_FreeSurface(surf);
+ return temp;
+}
+
+static inline SDL_Surface* SPG_DisplayFormatAlpha(SDL_Surface* surf)
+{
+ SDL_Surface* temp = SDL_DisplayFormatAlpha(surf);
+ SDL_FreeSurface(surf);
+ return temp;
+}
+
+static inline SDL_Rect SPG_GetClip(SDL_Surface* surface)
+{
+ if (surface)
+ return surface->clip_rect;
+ else
+ {
+ SDL_Rect r;
+ r.x = 0;
+ r.y = 0;
+ r.w = 0;
+ r.h = 0;
+ return r;
+ }
+}
+
+static inline void SPG_RestoreClip(SDL_Surface* surface)
+{
+ if(surface)
+ {
+ surface->clip_rect.x = 0;
+ surface->clip_rect.y = 0;
+ surface->clip_rect.w = surface->w;
+ surface->clip_rect.h = surface->h;
+ }
+}
+
+// 5-5-5
+static inline SDL_Surface* SPG_CreateSurface16(Uint32 flags, Uint16 width, Uint16 height)
+{
+ SDL_Surface* result = SDL_CreateRGBSurface(flags, width, height, 16, 31 << 10, 31 << 5, 31, 0);
+
+ return result;
+}
+
+// 4-4-4-4
+static inline SDL_Surface* SPG_CreateSurface16Alpha(Uint32 flags, Uint16 width, Uint16 height)
+{
+ #if SDL_BYTEORDER == SDL_BIG_ENDIAN
+ SDL_Surface* result = SDL_CreateRGBSurface(flags, width, height, 16, 0xf000, 0x0f00, 0x00f0, 0x000f);
+ #else
+ SDL_Surface* result = SDL_CreateRGBSurface(flags, width, height, 16, 0x00f0, 0x000f, 0xf000, 0x0f00);
+ #endif
+
+ return result;
+}
+
+static inline SDL_Surface* SPG_CreateSurface24(Uint32 flags, Uint16 width, Uint16 height)
+{
+ #if SDL_BYTEORDER == SDL_BIG_ENDIAN
+ SDL_Surface* result = SDL_CreateRGBSurface(flags,width,height,24, 0xFF0000, 0x00FF00, 0x0000FF, 0);
+ #else
+ SDL_Surface* result = SDL_CreateRGBSurface(flags,width,height,24, 0x0000FF, 0x00FF00, 0xFF0000, 0);
+ #endif
+ SDL_SetAlpha(result, 0, SDL_ALPHA_OPAQUE);
+ return result;
+}
+
+static inline SDL_Surface* SPG_CreateSurface32(Uint32 flags, Uint16 width, Uint16 height)
+{
+ #if SDL_BYTEORDER == SDL_BIG_ENDIAN
+ SDL_Surface* result = SDL_CreateRGBSurface(flags,width,height,32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
+ #else
+ SDL_Surface* result = SDL_CreateRGBSurface(flags,width,height,32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
+ #endif
+ SDL_SetAlpha(result, SDL_SRCALPHA, SDL_ALPHA_OPAQUE);
+ return result;
+}
+
+#define SPG_CreateSurface SPG_CreateSurface32
+
+
+static inline SDL_Surface* SPG_CreateSurfaceFrom(void* linearArray, Uint16 width, Uint16 height, SDL_PixelFormat* format)
+{
+ if(linearArray == NULL || format == NULL)
+ return NULL;
+ SDL_Surface* result = SDL_CreateRGBSurfaceFrom(linearArray, width, height, format->BitsPerPixel, width*format->BytesPerPixel, format->Rmask, format->Gmask, format->Bmask, format->Amask);
+ if(format->Amask)
+ SDL_SetAlpha(result, SDL_SRCALPHA, SDL_ALPHA_OPAQUE);
+ return result;
+}
+
+static inline SDL_Surface* SPG_CopySurface(SDL_Surface* src)
+{
+ return SDL_ConvertSurface(src, src->format, SDL_SWSURFACE);
+}
+
+static inline void SPG_SetSurfaceAlpha(SDL_Surface* surface, Uint8 alpha)
+{
+ SDL_SetAlpha(surface, surface->flags & SDL_SRCALPHA, alpha);
+}
+
+
+/* Misc */
+
+static inline int SPG_Clamp(int value, int min, int max)
+{
+ return ((value < min)? min : (value > max)? max : value);
+}
+
+static inline SDL_Rect SPG_MakeRect(Sint16 x, Sint16 y, Uint16 w, Uint16 h)
+{
+ SDL_Rect r;
+ r.x = x;
+ r.y = y;
+ r.w = w;
+ r.h = h;
+ return r;
+}
+
+static inline SDL_Rect SPG_MakeRectRelative(Sint16 x, Sint16 y, Sint16 x2, Sint16 y2)
+{
+ SDL_Rect r;
+ r.x = x;
+ r.y = y;
+ r.w = x2 - x;
+ r.h = y2 - y;
+ return r;
+}
+
+
+/* Drawing */
+
+static inline void SPG_Fill(SDL_Surface* surface, Uint32 color)
+{
+ SDL_FillRect(surface, NULL, color);
+}
+
+static inline void SPG_FillAlpha(SDL_Surface* surface, Uint32 color, Uint8 alpha)
+{
+ SDL_FillRect(surface, NULL, SPG_MixAlpha(surface->format, color, alpha));
+}
+
+
+static inline void SPG_BlockWrite8(SDL_Surface* Surface, Uint8* block, Sint16 y)
+{
+ memcpy( (Uint8 *)Surface->pixels + y*Surface->pitch, block, sizeof(Uint8)*Surface->w );
+}
+static inline void SPG_BlockWrite16(SDL_Surface* Surface, Uint16* block, Sint16 y)
+{
+ memcpy( (Uint16 *)Surface->pixels + y*Surface->pitch/2, block, sizeof(Uint16)*Surface->w );
+}
+static inline void SPG_BlockWrite32(SDL_Surface* Surface, Uint32* block, Sint16 y)
+{
+ memcpy( (Uint32 *)Surface->pixels + y*Surface->pitch/4, block, sizeof(Uint32)*Surface->w );
+}
+
+static inline void SPG_BlockRead8(SDL_Surface* Surface, Uint8* block, Sint16 y)
+{
+ memcpy( block,(Uint8 *)Surface->pixels + y*Surface->pitch, sizeof(Uint8)*Surface->w );
+}
+static inline void SPG_BlockRead16(SDL_Surface* Surface, Uint16* block, Sint16 y)
+{
+ memcpy( block,(Uint16 *)Surface->pixels + y*Surface->pitch/2, sizeof(Uint16)*Surface->w );
+}
+static inline void SPG_BlockRead32(SDL_Surface* Surface, Uint32* block, Sint16 y)
+{
+ memcpy( block,(Uint32 *)Surface->pixels + y*Surface->pitch/4, sizeof(Uint32)*Surface->w );
+}
+
+
+
+
+static inline void SPG_Draw(SDL_Surface* source, SDL_Surface* dest, Sint16 x, Sint16 y)
+{
+ SDL_Rect rect;
+ rect.x = x;
+ rect.y = y;
+ SDL_BlitSurface(source, NULL, dest, &rect);
+}
+
+static inline void SPG_DrawCenter(SDL_Surface* source, SDL_Surface* dest, Sint16 x, Sint16 y)
+{
+ SDL_Rect rect;
+ rect.x = x - source->w/2;
+ rect.y = y - source->h/2;
+ SDL_BlitSurface(source, NULL, dest, &rect);
+}
+
+static inline void SPG_DrawBlit(SDL_Surface* source, SDL_Surface* dest, Sint16 x, Sint16 y)
+{
+ SDL_Rect rect;
+ rect.x = x;
+ rect.y = y;
+ SPG_Blit(source, NULL, dest, &rect);
+}
+
+
+
+
+
+
+
+#endif

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jun 11, 1:01 PM (3 w, 4 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
69149
Default Alt Text
(382 KB)

Event Timeline