Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
290 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 ee9e8c00..c7ddf44d 100644
--- a/util/sdl/bitmap.cpp
+++ b/util/sdl/bitmap.cpp
@@ -1,1415 +1,1426 @@
#include "../bitmap.h"
#include "../lit_bitmap.h"
#include "../trans-bitmap.h"
#include "../funcs.h"
#include "sprig/sprig.h"
#include <SDL.h>
#include "image/SDL_image.h"
#include <math.h>
#include "exceptions/exception.h"
static const int WINDOWED = 0;
static const int FULLSCREEN = 1;
/* 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 inline 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 inline unsigned int multiplyBlender(unsigned int x, unsigned int y, unsigned int n){
Uint8 redX = 0;
Uint8 greenX = 0;
Uint8 blueX = 0;
SDL_GetRGB(x, screen->format, &redX, &greenX, &blueX);
Uint8 redY = 0;
Uint8 greenY = 0;
Uint8 blueY = 0;
SDL_GetRGB(y, screen->format, &redY, &greenY, &blueY);
int r = redX * redY / 256;
int g = greenX * greenY / 256;
int b = blueX * blueY / 256;
return transBlender(Bitmap::makeColor(r, g, b), y, n);
}
static inline unsigned int addBlender(unsigned int x, unsigned int y, unsigned int n){
Uint8 redX = 0;
Uint8 greenX = 0;
Uint8 blueX = 0;
SDL_GetRGB(x, screen->format, &redX, &greenX, &blueX);
Uint8 redY = 0;
Uint8 greenY = 0;
Uint8 blueY = 0;
SDL_GetRGB(y, screen->format, &redY, &greenY, &blueY);
int r = redY + redX * n / 256;
int g = greenY + greenX * n / 256;
int b = blueY + blueX * n / 256;
r = Util::min(r, 255);
g = Util::min(g, 255);
b = Util::min(b, 255);
return Bitmap::makeColor(r, g, b);
}
static inline int iabs(int x){
return x < 0 ? -x : x;
}
static inline unsigned int differenceBlender(unsigned int x, unsigned int y, unsigned int n){
Uint8 redX = 0;
Uint8 greenX = 0;
Uint8 blueX = 0;
SDL_GetRGB(x, screen->format, &redX, &greenX, &blueX);
Uint8 redY = 0;
Uint8 greenY = 0;
Uint8 blueY = 0;
SDL_GetRGB(y, screen->format, &redY, &greenY, &blueY);
int r = iabs(redY - redX);
int g = iabs(greenY - greenX);
int b = iabs(blueY - blueX);
return transBlender(Bitmap::makeColor(r, g, b), y, n);
}
static inline 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_applyTrans16(SDL_Surface * dst, const int color);
static void paintown_draw_sprite_ex16(SDL_Surface * dst, SDL_Surface * src, int dx, int dy, int mode, int flip );
-static void paintown_light16(SDL_Surface * dst, const int x, const int y, const int width, const int height, const int start_y, const int focus_alpha, const int edge_alpha, const int focus_color, const int edge_color);
+static void paintown_light16(SDL_Surface * dst, const int x, const int y, int width, int height, const int start_y, const int focus_alpha, const int edge_alpha, const int focus_color, const int edge_color);
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;
clip_top = 0;
clip_bottom = surface->h;
}
Bitmap::Bitmap():
own(NULL),
mustResize(false){
/* TODO */
}
Bitmap::Bitmap(SDL_Surface * who, bool deep_copy):
own(NULL),
mustResize(false){
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 {
getData().setSurface(who);
}
}
Bitmap::Bitmap(int w, int h):
mustResize(false){
SDL_Surface * surface = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, SCREEN_DEPTH, 0, 0, 0, 0);
if (surface == NULL){
throw Exception::Base(__FILE__, __LINE__);
}
getData().setSurface(surface);
own = new int;
*own = 1;
}
Bitmap::Bitmap( const char * load_file ):
own(NULL),
mustResize(false){
internalLoadFile(load_file);
}
Bitmap::Bitmap( const std::string & load_file ):
own(NULL),
mustResize(false){
internalLoadFile(load_file.c_str());
}
Bitmap::Bitmap( const char * load_file, int sx, int sy ):
own(NULL),
mustResize(false){
Bitmap temp(load_file);
SDL_Surface * surface = SDL_CreateRGBSurface(SDL_SWSURFACE, sx, sy, SCREEN_DEPTH, 0, 0, 0, 0);
getData().setSurface(surface);
own = new int;
*own = 1;
temp.Stretch(*this);
}
/* unused */
Bitmap::Bitmap( const char * load_file, int sx, int sy, double accuracy ):
own(NULL),
mustResize(false){
throw Exception::Base(__FILE__, __LINE__);
}
Bitmap::Bitmap( const Bitmap & copy, bool deep_copy):
own(NULL),
mustResize(false){
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),
mustResize(false){
/* TODO */
}
Bitmap::Bitmap( const Bitmap & copy, int sx, int sy, double accuracy ):
own(NULL),
mustResize(false){
/* 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),
mustResize(false){
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 Exception::Base(__FILE__, __LINE__);
}
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){
case WINDOWED : {
// screen = SDL_SetVideoMode(width, height, SCREEN_DEPTH, SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_RESIZABLE);
screen = SDL_SetVideoMode(width, height, SCREEN_DEPTH, SDL_SWSURFACE | SDL_RESIZABLE);
SDL_ShowCursor(0);
// screen = SDL_SetVideoMode(width, height, SCREEN_DEPTH, SDL_SWSURFACE | SDL_DOUBLEBUF);
if (!screen){
return 1;
}
break;
}
case FULLSCREEN : {
screen = SDL_SetVideoMode(width, height, SCREEN_DEPTH, SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_FULLSCREEN);
SDL_ShowCursor(0);
// screen = SDL_SetVideoMode(width, height, SCREEN_DEPTH, SDL_SWSURFACE | SDL_DOUBLEBUF);
if (!screen){
return 1;
}
break;
}
}
if (SCALE_X == 0){
SCALE_X = width;
}
SCALE_X = width;
if (SCALE_Y == 0){
SCALE_Y = height;
}
SCALE_Y = height;
+ SCALE_X = 640;
+ SCALE_Y = 480;
+
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);
Scaler = new Bitmap(width, height);
/*
if ( width != 0 && height != 0 && (width != SCALE_X || height != SCALE_Y) ){
Scaler = new Bitmap(width, height);
Buffer = new Bitmap(SCALE_X, SCALE_Y);
}
*/
}
for (std::vector<Bitmap*>::iterator it = needResize.begin(); it != needResize.end(); it++){
Bitmap * who = *it;
who->resize(width, height);
}
return 0;
}
void Bitmap::shutdown(){
delete Screen;
Screen = NULL;
delete Scaler;
Scaler = NULL;
delete Buffer;
Buffer = NULL;
}
void Bitmap::addBlender( int r, int g, int b, int a ){
globalBlend.red = r;
globalBlend.green = g;
globalBlend.blue = b;
globalBlend.alpha = a;
globalBlend.currentBlender = ::addBlender;
}
void Bitmap::multiplyBlender( int r, int g, int b, int a ){
globalBlend.red = r;
globalBlend.green = g;
globalBlend.blue = b;
globalBlend.alpha = a;
globalBlend.currentBlender = ::multiplyBlender;
}
void Bitmap::differenceBlender( int r, int g, int b, int a ){
globalBlend.red = r;
globalBlend.green = g;
globalBlend.blue = b;
globalBlend.alpha = a;
globalBlend.currentBlender = ::differenceBlender;
}
Bitmap & Bitmap::operator=(const Bitmap & copy){
releaseInternalBitmap();
path = copy.getPath();
getData().setSurface(copy.getData().getSurface());
// own = false;
own = copy.own;
if (own)
*own += 1;
return *this;
}
int Bitmap::setGfxModeText(){
/* TODO */
return 0;
}
int Bitmap::setGfxModeFullscreen(int x, int y){
return setGraphicsMode(FULLSCREEN, x, y);
}
int Bitmap::setGfxModeWindowed( int x, int y ){
return setGraphicsMode(WINDOWED, 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 {
SDL_Rect area;
area.x = x1;
area.y = y1;
area.w = x2 - x1;
area.h = y2 - y1;
SDL_SetClipRect(getData().getSurface(), &area);
SDL_GetClipRect(getData().getSurface(), &area);
getData().setClip(area.x, area.y, area.x + area.w, area.y + area.h);
}
void Bitmap::getClipRect(int & x1, int & y1, int & x2, int & y2) const {
x1 = getData().clip_left;
y1 = getData().clip_top;
x2 = getData().clip_right;
y2 = getData().clip_bottom;
}
void Bitmap::destroyPrivateData(){
SDL_FreeSurface(getData().getSurface());
}
static void doPutPixel(SDL_Surface * surface, int x, int y, int pixel, bool translucent){
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:
if (translucent){
*(Uint16 *)p = globalBlend.currentBlender(pixel, *(Uint16*)p, globalBlend.alpha);
} else {
*(Uint16 *)p = pixel;
}
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::putPixel(int x, int y, int pixel) const {
/* clip it */
if (getData().isClipped(x, y)){
return;
}
SDL_Surface * surface = getData().getSurface();
doPutPixel(surface, x, y, pixel, false);
}
void Bitmap::putPixelNormal(int x, int y, int col) const {
putPixel(x, y, col);
}
void TranslucentBitmap::putPixelNormal(int x, int y, int color) const {
if (getData().isClipped(x, y)){
return;
}
SDL_Surface * surface = getData().getSurface();
doPutPixel(surface, x, y, color, true);
}
bool Bitmap::getError(){
/* TODO */
return false;
}
void Bitmap::rectangle( int x1, int y1, int x2, int y2, int color ) const {
SPG_Rect(getData().getSurface(), x1, y1, x2, y2, color);
}
void TranslucentBitmap::rectangle( int x1, int y1, int x2, int y2, int color ) const {
int alpha = globalBlend.alpha;
SPG_RectBlend(getData().getSurface(), x1, y1, x2, y2, color, alpha);
}
void Bitmap::rectangleFill( int x1, int y1, int x2, int y2, int color ) const {
SPG_RectFilled(getData().getSurface(), x1, y1, x2, y2, color);
}
void TranslucentBitmap::rectangleFill(int x1, int y1, int x2, int y2, int color) const {
int alpha = globalBlend.alpha;
SPG_RectFilledBlend(getData().getSurface(), x1, y1, x2, y2, color, alpha);
}
void Bitmap::circleFill(int x, int y, int radius, int color) const {
switch (::drawingMode){
case MODE_SOLID : {
SPG_CircleFilled(getData().getSurface(), x, y, radius, color);
break;
}
case MODE_TRANS : {
int alpha = globalBlend.alpha;
SPG_CircleFilledBlend(getData().getSurface(), x, y, radius, color, alpha);
break;
}
}
}
void Bitmap::circle(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 : {
SPG_Circle(getData().getSurface(), x, y, radius, color);
break;
}
case MODE_TRANS : {
int alpha = globalBlend.alpha;
SPG_CircleBlend(getData().getSurface(), x, y, radius, color, alpha);
break;
}
}
// circleRGBA(getData().getSurface(), x, y, radius, red, green, blue, alpha);
}
void Bitmap::line( const int x1, const int y1, const int x2, const int y2, const int color ) const {
switch (::drawingMode){
case MODE_SOLID : {
SPG_Line(getData().getSurface(), x1, y1, x2, y2, color);
break;
}
case MODE_TRANS : {
int alpha = globalBlend.alpha;
SPG_LineBlend(getData().getSurface(), x1, y1, x2, y2, color, alpha);
break;
}
}
}
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::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 {
paintown_draw_sprite_ex16(where.getData().getSurface(), getData().getSurface(), x, y, Bitmap::SPRITE_NORMAL, Bitmap::SPRITE_V_FLIP );
}
void Bitmap::drawHVFlip( 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_V_FLIP | Bitmap::SPRITE_H_FLIP);
}
void Bitmap::drawTrans( const int x, const int y, const Bitmap & where ) const {
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 {
paintown_draw_sprite_ex16(where.getData().getSurface(), getData().getSurface(), x, y, Bitmap::SPRITE_TRANS, Bitmap::SPRITE_H_FLIP);
}
void Bitmap::drawTransVFlip( const int x, const int y, const Bitmap & where ) const {
paintown_draw_sprite_ex16(where.getData().getSurface(), getData().getSurface(), x, y, Bitmap::SPRITE_TRANS, Bitmap::SPRITE_V_FLIP);
}
void Bitmap::drawTransHVFlip( const int x, const int y, const Bitmap & where ) const {
paintown_draw_sprite_ex16(where.getData().getSurface(), getData().getSurface(), x, y, Bitmap::SPRITE_TRANS, SPRITE_V_FLIP | SPRITE_H_FLIP);
}
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_Surface * src = getData().getSurface();
SDL_Surface * dst = who.getData().getSurface();
int myWidth = src->w;
int myHeight = src->h;
int hisWidth = new_width;
int hisHeight = new_height;
int useX = x;
int useY = y;
int myX = 0;
int myY = 0;
float xscale = (float) hisWidth / (float) myWidth;
float yscale = (float) hisHeight / (float) myHeight;
/* sprig wont do the clipping right, if you start drawing from a negative offset
* sprig will do nothing.
*/
if (useX < 0){
useX = 0;
myX = -x / xscale;
}
if (useY < 0){
useY = 0;
myY = -y / yscale;
}
SPG_TransformX(src, dst, 0, xscale, yscale, myX, myY, useX, useY, SPG_TCOLORKEY);
}
}
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);
}
static void doBlit(SDL_Surface * mine, const int mx, const int my, const int width, const int height, const int wx, const int wy, const Bitmap & where ){
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(mine, &source, where.getData().getSurface(), &destination);
}
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_SetColorKey(getData().getSurface(), 0, MaskColor());
doBlit(getData().getSurface(), mx, my, width, height, wx, wy, where);
/* FIXME: this is a hack, maybe put a call here for the other bitmap to update stuff
* like where->Blitted()
*/
if (&where == Screen){
SDL_Flip(Screen->getData().getSurface());
}
}
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 {
SDL_SetColorKey(getData().getSurface(), SDL_SRCCOLORKEY, MaskColor());
doBlit(getData().getSurface(),mx, my, width, height, wx, wy, where);
/* FIXME: this is a hack, maybe put a call here for the other bitmap to update stuff
* like where->Blitted()
*/
if (&where == Screen){
SDL_Flip(Screen->getData().getSurface());
}
}
void Bitmap::BlitToScreen(const int upper_left_x, const int upper_left_y) const {
if (getWidth() != Screen->getWidth() || getHeight() != Screen->getHeight()){
/*
this->Blit( upper_left_x, upper_left_y, *Buffer );
Buffer->Stretch(*Scaler);
Scaler->Blit(0, 0, 0, 0, *Screen);
*/
this->Stretch(*Scaler, 0, 0, getWidth(), getHeight(), upper_left_x, upper_left_y, Scaler->getWidth(), Scaler->getHeight());
Scaler->Blit(0, 0, 0, 0, *Screen);
} else {
this->Blit( upper_left_x, upper_left_y, *Screen );
}
/*
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 {
if ( Scaler != NULL ){
double mult_x = (double) Scaler->getWidth() / (double) SCALE_X;
double mult_y = (double) Scaler->getHeight() / (double) SCALE_Y;
int x = (int)(upper_left_x * mult_x);
int y = (int)(upper_left_y * mult_y);
int w = (int)(this->getWidth() * mult_x);
int h = (int)(this->getHeight() * mult_y);
// printf("ux %d uy %d uw %d uh %d. x %d y %d w %d h %d\n", upper_left_x, upper_left_y, getWidth(), getHeight(), x, y, w, h );
this->Stretch( *Scaler, 0, 0, this->getWidth(), this->getHeight(), x, y, w, h );
Bitmap tmp(*Scaler, x, y, w, h );
tmp.Blit( x, y, *Screen );
// Scaler->Blit( x, y, w, h, *Screen );
} else {
this->Blit( upper_left_x, upper_left_y, *Screen );
}
}
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_Surface * src = getData().getSurface();
SDL_Surface * dst = where.getData().getSurface();
float xscale = (float) destWidth / (float) sourceWidth;
float yscale = (float) destHeight / (float) sourceHeight;
SDL_SetColorKey(src, 0, MaskColor());
SPG_TransformX(src, dst, 0, xscale, yscale, sourceX, sourceY, destX, destY, SPG_NONE);
/*
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_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 {
switch (::drawingMode){
case MODE_SOLID : {
SPG_TrigonFilled(getData().getSurface(), x1, y1, x2, y2, x3, y3, color);
break;
}
case MODE_TRANS : {
int alpha = globalBlend.alpha;
SPG_TrigonFilledBlend(getData().getSurface(), x1, y1, x2, y2, x3, y3, color, alpha);
break;
}
}
}
void Bitmap::ellipse( int x, int y, int rx, int ry, int color ) const {
switch (::drawingMode){
case MODE_SOLID : {
SPG_Ellipse(getData().getSurface(), x, y, rx, ry, color);
break;
}
case MODE_TRANS : {
int alpha = globalBlend.alpha;
SPG_EllipseBlend(getData().getSurface(), x, y, rx, ry, color, alpha);
break;
}
}
}
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 {
paintown_light16(getData().getSurface(), x, y, width, height, start_y, focus_alpha, edge_alpha, focus_color, edge_color);
}
void Bitmap::applyTrans(const int color) const {
paintown_applyTrans16(getData().getSurface(), color);
}
void Bitmap::floodfill( const int x, const int y, const int color ) const {
SPG_FloodFill(getData().getSurface(), x, y, color);
}
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);
}
/*
void TranslucentBitmap::fill(int color) const {
rectangleFill(0, 0, getWidth(), getHeight(), color);
}
*/
int Bitmap::darken( int color, double factor ){
/* TODO */
return color;
}
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 ){
SDL_SetColorKey(getData().getSurface(), SDL_SRCCOLORKEY, MaskColor());
SDL_Surface * src = getData().getSurface();
SDL_Surface * dst = where.getData().getSurface();
SPG_TransformX(src, dst, angle, 1, 1, 0, 0, x, y, SPG_TCOLORKEY);
}
void Bitmap::drawPivot( const int centerX, const int centerY, const int x, const int y, const int angle, const Bitmap & where ){
SDL_SetColorKey(getData().getSurface(), SDL_SRCCOLORKEY, MaskColor());
SDL_Surface * src = getData().getSurface();
SDL_Surface * dst = where.getData().getSurface();
SPG_TransformX(src, dst, angle, 1, 1, centerX, centerY, x, y, SPG_TCOLORKEY);
}
void Bitmap::drawPivot( const int centerX, const int centerY, const int x, const int y, const int angle, const double scale, const Bitmap & where ){
SDL_SetColorKey(getData().getSurface(), SDL_SRCCOLORKEY, MaskColor());
SDL_Surface * src = getData().getSurface();
SDL_Surface * dst = where.getData().getSurface();
SPG_TransformX(src, dst, angle, scale, scale, centerX, centerY, x, y, SPG_TCOLORKEY);
}
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);
SDL_Surface * display = SDL_DisplayFormat(pcx);
Bitmap out(display, true);
if (pcx->format->BitsPerPixel == 8){
SDL_Color color = pcx->format->palette->colors[pcx->format->colorkey];
int bad = makeColor(color.r, color.g, color.b);
for (int x = 0; x < out.getWidth(); x++){
for (int y = 0; y < out.getHeight(); y++){
if (out.getPixel(x, y) == bad){
out.putPixel(x, y, MaskColor());
}
}
}
}
SDL_FreeSurface(pcx);
SDL_FreeSurface(display);
// out.floodfill(0, 0, makeColor(255, 0, 255));
return out;
}
int Bitmap::getPixel( const int x, const int y ) const {
return SPG_GetPixel(getData().getSurface(), x, y);
}
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 {
paintown_draw_sprite_ex16( where.getData().getSurface(), getData().getSurface(), x, y, Bitmap::SPRITE_LIT, Bitmap::SPRITE_NO_FLIP );
}
void LitBitmap::drawHFlip( const int x, const int y, const Bitmap & where ) const {
paintown_draw_sprite_ex16( where.getData().getSurface(), getData().getSurface(), x, y, Bitmap::SPRITE_LIT, Bitmap::SPRITE_H_FLIP );
}
void LitBitmap::drawVFlip( const int x, const int y, const Bitmap & where ) const {
paintown_draw_sprite_ex16( where.getData().getSurface(), getData().getSurface(), x, y, Bitmap::SPRITE_LIT, Bitmap::SPRITE_V_FLIP );
}
void LitBitmap::drawHVFlip( const int x, const int y, const Bitmap & where ) const {
paintown_draw_sprite_ex16( where.getData().getSurface(), getData().getSurface(), x, y, SPRITE_LIT, SPRITE_V_FLIP | SPRITE_H_FLIP);
}
/*
#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_applyTrans16(SDL_Surface * dst, const int color){
int y1 = 0;
int y2 = dst->h;
int x1 = 0;
int x2 = dst->w - 1;
y1 = dst->clip_rect.y;
y2 = dst->clip_rect.y + dst->clip_rect.h;
x1 = dst->clip_rect.x;
x2 = dst->clip_rect.x + dst->clip_rect.w;
int bpp = dst->format->BytesPerPixel;
unsigned int mask = Bitmap::makeColor(255, 0, 255);
for (int y = y1; y < y2; y++) {
Uint8 * sourceLine = computeOffset(dst, x1, y);
for (int x = x2 - 1; x >= x1; sourceLine += bpp, x--) {
unsigned long sourcePixel = *(Uint16*) sourceLine;
if (!(sourcePixel == mask)){
sourcePixel = globalBlend.currentBlender(color, sourcePixel, globalBlend.alpha);
*(Uint16 *)sourceLine = sourcePixel;
}
}
}
}
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;
}
}
}
break;
}
case Bitmap::SPRITE_LIT : {
int bpp = src->format->BytesPerPixel;
int litColor = Bitmap::makeColor(globalBlend.red, globalBlend.green, globalBlend.blue);
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(litColor, sourcePixel, globalBlend.alpha);
*(Uint16 *)destLine = sourcePixel;
}
}
}
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(sourcePixel, destPixel, 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);
}
}
/* ultra special-case for drawing a light (like from a lamp).
* center of light is x,y and shines in a perfect isosolese triangle.
*/
-static void paintown_light16(SDL_Surface * dst, const int x, const int y, const int width, const int height, const int start_y, const int focus_alpha, const int edge_alpha, const int focus_color, const int edge_color){
+static void paintown_light16(SDL_Surface * dst, const int x, const int y, int width, int height, const int start_y, const int focus_alpha, const int edge_alpha, const int focus_color, const int edge_color){
+
+ if (width > dst->w){
+ width = dst->w;
+ }
+
+ if (height > dst->h){
+ height = dst->h;
+ }
int dxbeg = x - width;
int x_dir = 1;
unsigned char * alphas = new unsigned char[width];
int * colors = new int[width];
for (int i = 0; i < width; i++){
alphas[i] = (unsigned char)((double)(edge_alpha - focus_alpha) * (double)i / (double)width + focus_alpha);
}
Util::blend_palette(colors, width, focus_color, edge_color);
if (SDL_MUSTLOCK(dst)){
SDL_LockSurface(dst);
}
int min_y, max_y, min_x, max_x;
min_y = dst->clip_rect.y;
- max_y = dst->clip_rect.y + dst->clip_rect.h;
+ max_y = dst->clip_rect.y + dst->clip_rect.h - 1;
min_x = dst->clip_rect.x;
- max_x = dst->clip_rect.x + dst->clip_rect.w;
+ max_x = dst->clip_rect.x + dst->clip_rect.w - 1;
int dybeg = y;
/* tan(theta) = y / x */
double xtan = (double) height / (double) width;
int bpp = dst->format->BytesPerPixel;
for (int sy = start_y; sy < height; sy++) {
if (dybeg + sy < min_y || dybeg + sy > max_y){
continue;
}
/* x = y / tan(theta) */
int top_width = (int)((double) sy / xtan);
if (top_width == 0){
continue;
}
dxbeg = x - top_width;
Uint8* line = computeOffset(dst, dxbeg, dybeg + y);
for (int sx = -top_width; sx <= top_width; line += x_dir * bpp, sx++) {
if (sx + x < min_x || sx + x > max_x){
continue;
}
unsigned long c = *(Uint16*) line;
/* TODO:
* converting to a double and calling fabs is overkill, just
* write an integer abs() function.
*/
int sx_abs = (int) fabs((double) sx);
int alphaUse = alphas[sx_abs];
int color = colors[sx_abs];
c = globalBlend.currentBlender(color, c, alphaUse);
*(Uint16*) line = c;
}
}
delete[] alphas;
delete[] colors;
if (SDL_MUSTLOCK(dst)){
SDL_UnlockSurface(dst);
}
}
diff --git a/util/sdl/sprig/SPG_polygon.c b/util/sdl/sprig/SPG_polygon.c
index 723e0854..f96081a7 100644
--- a/util/sdl/sprig/SPG_polygon.c
+++ b/util/sdl/sprig/SPG_polygon.c
@@ -1,2596 +1,2593 @@
/*
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;
+ 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--;
- }
+ // 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
index 45e03b45..32e424ea 100644
--- a/util/sdl/sprig/SPG_primitives.c
+++ b/util/sdl/sprig/SPG_primitives.c
@@ -1,5001 +1,5000 @@
/*
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
*/
if (y < SPG_CLIP_YMIN(Surface) ||
y > SPG_CLIP_YMAX(Surface) ||
x1 > SPG_CLIP_XMAX(Surface) ||
x2 < SPG_CLIP_XMIN(Surface)){
return;
}
if (x1 < SPG_CLIP_XMIN(Surface)){
x1 = SPG_CLIP_XMIN(Surface);
}
if (x2 > SPG_CLIP_XMAX(Surface)){
x2 = SPG_CLIP_XMAX(Surface);
}
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
*/
if (y < SPG_CLIP_YMIN(Surface) ||
y > SPG_CLIP_YMAX(Surface) ||
x1 > SPG_CLIP_XMAX(Surface) ||
x2 < SPG_CLIP_XMIN(Surface)){
return;
}
if (x1 < SPG_CLIP_XMIN(Surface)){
x1 = SPG_CLIP_XMIN(Surface);
}
if (x2 > SPG_CLIP_XMAX(Surface)){
x2 = SPG_CLIP_XMAX(Surface);
}
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
*/
if (x < SPG_CLIP_XMIN(Surface) ||
x > SPG_CLIP_XMAX(Surface) ||
y1 > SPG_CLIP_YMAX(Surface) ||
y2 < SPG_CLIP_YMIN(Surface)){
return;
}
if (y1 < SPG_CLIP_YMIN(Surface)){
y1 = SPG_CLIP_YMIN(Surface);
}
if (y2 > SPG_CLIP_YMAX(Surface)){
y2 = SPG_CLIP_YMAX(Surface);
}
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
*/
if (x < SPG_CLIP_XMIN(Surface) ||
x > SPG_CLIP_XMAX(Surface) ||
y1 > SPG_CLIP_YMAX(Surface) ||
y2 < SPG_CLIP_YMIN(Surface)){
return;
}
if (y1 < SPG_CLIP_YMIN(Surface)){
y1 = SPG_CLIP_YMIN(Surface);
}
if (y2 > SPG_CLIP_YMAX(Surface)){
y2 = SPG_CLIP_YMAX(Surface);
}
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
*/
if (x2 < SPG_CLIP_XMIN(Surface) ||
x1 > SPG_CLIP_XMAX(Surface) ||
y1 > SPG_CLIP_YMAX(Surface) ||
y2 < SPG_CLIP_YMIN(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);
}
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
*/
if (x2 < SPG_CLIP_XMIN(Surface) ||
x1 > SPG_CLIP_XMAX(Surface) ||
y1 > SPG_CLIP_YMAX(Surface) ||
y2 < SPG_CLIP_YMIN(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);
}
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
*/
if (x2 < SPG_CLIP_XMIN(Surface) ||
x1 > SPG_CLIP_XMAX(Surface) ||
y1 > SPG_CLIP_YMAX(Surface) ||
y2 < SPG_CLIP_YMIN(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);
}
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
index 3bbb2437..2214752c 100644
--- a/util/sdl/sprig/SPG_rotation.c
+++ b/util/sdl/sprig/SPG_rotation.c
@@ -1,736 +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;\
+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; \
- } \
- }
+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) && (ry>=symin) && (ry<=symax) ) /* Changed from (rx<=sxmax) to (rx<=sxmax+1) Edge fix 7-13-08*. Reverted this change on 7/3/2010 - Jon Rafkind */\
+ {\
+ 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;
}

File Metadata

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

Event Timeline