Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
299 KB
Referenced Files
None
Subscribers
None
This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/util/input/sdl/keyboard.cpp b/util/input/sdl/keyboard.cpp
index 7ce4b7f0..445cb7b3 100644
--- a/util/input/sdl/keyboard.cpp
+++ b/util/input/sdl/keyboard.cpp
@@ -1,214 +1,214 @@
#include <SDL.h>
#include "../keyboard.h"
#include "../input-manager.h"
#include "util/funcs.h"
-#ifdef PS3
+#if SDL_VERSION_ATLEAST(1, 3, 0)
Uint8 * getKeyState(int * keys){
return SDL_GetKeyboardState(keys);
}
#else
Uint8 * getKeyState(int * keys){
return SDL_GetKeyState(keys);
}
#endif
Keyboard::Keyboard():
enableBuffer(false){
}
void Keyboard::poll(){
buffer.clear();
SDL_PumpEvents();
}
void Keyboard::wait(){
while (keypressed()){
Util::rest(1);
poll();
}
}
bool Keyboard::keypressed(){
int keys = 0;
Uint8 * state = getKeyState(&keys);
for (int i = 0; i < keys; i++){
if (i != SDLK_NUMLOCK && state[i] == 1){
return true;
}
}
return false;
}
void Keyboard::disableKeyRepeat(){
SDL_EnableKeyRepeat(0, 0);
}
void Keyboard::enableKeyRepeat(){
SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
}
#if 0
void Keyboard::readKeys( std::vector<int> & all_keys ){
int keys = 0;
Uint8 * state = getKeyState(&keys);
/* FIXME: the mapping between SDLK_* and our keyboard values are not 1-1 so
* use a function here that returns the right mapping.
*/
for (int i = 0; i < keys; i++){
if (i != SDLK_NUMLOCK && state[i] == 1){
all_keys.push_back(i);
}
}
}
#endif
void Keyboard::readKeys(std::vector<int> & all_keys){
for (std::map<KeyType, KeyData>::iterator it = keyState.begin(); it != keyState.end(); it++){
KeyType key = it->first;
const KeyData & data = it->second;
if (data.enabled){
all_keys.push_back(key);
}
}
}
/*
int Keyboard::readKey(){
std::vector<int> keys;
do{
readKeys(keys);
Util::rest(1);
InputManager::poll();
poll();
} while (keys.size() == 0);
return keys.front();
}
*/
void Keyboard::clear(){
buffer.clear();
keyState.clear();
}
Keyboard::KeyType Keyboard::Key_A = SDLK_a;
Keyboard::KeyType Keyboard::Key_B = SDLK_b;
Keyboard::KeyType Keyboard::Key_C = SDLK_c;
Keyboard::KeyType Keyboard::Key_D = SDLK_d;
Keyboard::KeyType Keyboard::Key_E = SDLK_e;
Keyboard::KeyType Keyboard::Key_F = SDLK_f;
Keyboard::KeyType Keyboard::Key_G = SDLK_g;
Keyboard::KeyType Keyboard::Key_H = SDLK_h;
Keyboard::KeyType Keyboard::Key_I = SDLK_i;
Keyboard::KeyType Keyboard::Key_J = SDLK_j;
Keyboard::KeyType Keyboard::Key_K = SDLK_k;
Keyboard::KeyType Keyboard::Key_L = SDLK_l;
Keyboard::KeyType Keyboard::Key_M = SDLK_m;
Keyboard::KeyType Keyboard::Key_N = SDLK_n;
Keyboard::KeyType Keyboard::Key_O = SDLK_o;
Keyboard::KeyType Keyboard::Key_P = SDLK_p;
Keyboard::KeyType Keyboard::Key_Q = SDLK_q;
Keyboard::KeyType Keyboard::Key_R = SDLK_r;
Keyboard::KeyType Keyboard::Key_S = SDLK_s;
Keyboard::KeyType Keyboard::Key_T = SDLK_t;
Keyboard::KeyType Keyboard::Key_U = SDLK_u;
Keyboard::KeyType Keyboard::Key_V = SDLK_v;
Keyboard::KeyType Keyboard::Key_W = SDLK_w;
Keyboard::KeyType Keyboard::Key_X = SDLK_x;
Keyboard::KeyType Keyboard::Key_Y = SDLK_y;
Keyboard::KeyType Keyboard::Key_Z = SDLK_z;
Keyboard::KeyType Keyboard::Key_0 = SDLK_0;
Keyboard::KeyType Keyboard::Key_1 = SDLK_1;
Keyboard::KeyType Keyboard::Key_2 = SDLK_2;
Keyboard::KeyType Keyboard::Key_3 = SDLK_3;
Keyboard::KeyType Keyboard::Key_4 = SDLK_4;
Keyboard::KeyType Keyboard::Key_5 = SDLK_5;
Keyboard::KeyType Keyboard::Key_6 = SDLK_6;
Keyboard::KeyType Keyboard::Key_7 = SDLK_7;
Keyboard::KeyType Keyboard::Key_8 = SDLK_8;
Keyboard::KeyType Keyboard::Key_9 = SDLK_9;
Keyboard::KeyType Keyboard::Key_0_PAD = SDLK_KP0;
Keyboard::KeyType Keyboard::Key_1_PAD = SDLK_KP1;
Keyboard::KeyType Keyboard::Key_2_PAD = SDLK_KP2;
Keyboard::KeyType Keyboard::Key_3_PAD = SDLK_KP3;
Keyboard::KeyType Keyboard::Key_4_PAD = SDLK_KP4;
Keyboard::KeyType Keyboard::Key_5_PAD = SDLK_KP5;
Keyboard::KeyType Keyboard::Key_6_PAD = SDLK_KP6;
Keyboard::KeyType Keyboard::Key_7_PAD = SDLK_KP7;
Keyboard::KeyType Keyboard::Key_8_PAD = SDLK_KP8;
Keyboard::KeyType Keyboard::Key_9_PAD = SDLK_KP9;
Keyboard::KeyType Keyboard::Key_F1 = SDLK_F1;
Keyboard::KeyType Keyboard::Key_F2 = SDLK_F2;
Keyboard::KeyType Keyboard::Key_F3 = SDLK_F3;
Keyboard::KeyType Keyboard::Key_F4 = SDLK_F4;
Keyboard::KeyType Keyboard::Key_F5 = SDLK_F5;
Keyboard::KeyType Keyboard::Key_F6 = SDLK_F6;
Keyboard::KeyType Keyboard::Key_F7 = SDLK_F7;
Keyboard::KeyType Keyboard::Key_F8 = SDLK_F8;
Keyboard::KeyType Keyboard::Key_F9 = SDLK_F9;
Keyboard::KeyType Keyboard::Key_F10 = SDLK_F10;
Keyboard::KeyType Keyboard::Key_F11 = SDLK_F11;
Keyboard::KeyType Keyboard::Key_F12 = SDLK_F12;
Keyboard::KeyType Keyboard::Key_ESC = SDLK_ESCAPE;
Keyboard::KeyType Keyboard::Key_TILDE = SDLK_BACKQUOTE;
Keyboard::KeyType Keyboard::Key_MINUS = SDLK_MINUS;
Keyboard::KeyType Keyboard::Key_EQUALS = SDLK_EQUALS;
Keyboard::KeyType Keyboard::Key_BACKSPACE = SDLK_BACKSPACE;
Keyboard::KeyType Keyboard::Key_TAB = SDLK_TAB;
Keyboard::KeyType Keyboard::Key_OPENBRACE = SDLK_LEFTBRACKET;
Keyboard::KeyType Keyboard::Key_CLOSEBRACE = SDLK_RIGHTBRACKET;
Keyboard::KeyType Keyboard::Key_ENTER = SDLK_RETURN;
Keyboard::KeyType Keyboard::Key_COLON = SDLK_COLON;
Keyboard::KeyType Keyboard::Key_QUOTE = SDLK_QUOTEDBL;
Keyboard::KeyType Keyboard::Key_BACKSLASH = SDLK_BACKSLASH;
Keyboard::KeyType Keyboard::Key_BACKSLASH2 = 999; /* FIXME */
Keyboard::KeyType Keyboard::Key_COMMA = SDLK_COMMA;
Keyboard::KeyType Keyboard::Key_STOP = SDLK_PERIOD;
Keyboard::KeyType Keyboard::Key_SLASH = SDLK_SLASH;
Keyboard::KeyType Keyboard::Key_SPACE = SDLK_SPACE;
Keyboard::KeyType Keyboard::Key_INSERT = SDLK_INSERT;
Keyboard::KeyType Keyboard::Key_DEL = SDLK_DELETE;
Keyboard::KeyType Keyboard::Key_HOME = SDLK_HOME;
Keyboard::KeyType Keyboard::Key_END = SDLK_END;
Keyboard::KeyType Keyboard::Key_PGUP = SDLK_PAGEUP;
Keyboard::KeyType Keyboard::Key_PGDN = SDLK_PAGEDOWN;
Keyboard::KeyType Keyboard::Key_LEFT = SDLK_LEFT;
Keyboard::KeyType Keyboard::Key_RIGHT = SDLK_RIGHT;
Keyboard::KeyType Keyboard::Key_UP = SDLK_UP;
Keyboard::KeyType Keyboard::Key_DOWN = SDLK_DOWN;
Keyboard::KeyType Keyboard::Key_SLASH_PAD = SDLK_KP_DIVIDE;
Keyboard::KeyType Keyboard::Key_ASTERISK = SDLK_ASTERISK;
Keyboard::KeyType Keyboard::Key_MINUS_PAD = SDLK_KP_MINUS;
Keyboard::KeyType Keyboard::Key_PLUS_PAD = SDLK_KP_PLUS;
Keyboard::KeyType Keyboard::Key_DEL_PAD = 1000; /* FIXME */
Keyboard::KeyType Keyboard::Key_ENTER_PAD = SDLK_KP_ENTER;
Keyboard::KeyType Keyboard::Key_PRTSCR = SDLK_PRINT;
Keyboard::KeyType Keyboard::Key_PAUSE = SDLK_PAUSE;
Keyboard::KeyType Keyboard::Key_ABNT_C1 = 1001; /* FIXME */
Keyboard::KeyType Keyboard::Key_YEN = 1002;
Keyboard::KeyType Keyboard::Key_KANA = 1003;
Keyboard::KeyType Keyboard::Key_CONVERT = 1004;
Keyboard::KeyType Keyboard::Key_NOCONVERT = 1005;
Keyboard::KeyType Keyboard::Key_AT = SDLK_AT;
Keyboard::KeyType Keyboard::Key_CIRCUMFLEX = SDLK_CARET;
Keyboard::KeyType Keyboard::Key_COLON2 = 1006;
Keyboard::KeyType Keyboard::Key_KANJI = 1007;
Keyboard::KeyType Keyboard::Key_EQUALS_PAD = SDLK_KP_EQUALS;
Keyboard::KeyType Keyboard::Key_BACKQUOTE = 1008;
Keyboard::KeyType Keyboard::Key_SEMICOLON = SDLK_SEMICOLON;
Keyboard::KeyType Keyboard::Key_COMMAND = 1009;
Keyboard::KeyType Keyboard::Key_MODIFIERS = 1010;
Keyboard::KeyType Keyboard::Key_LSHIFT = SDLK_LSHIFT;
Keyboard::KeyType Keyboard::Key_RSHIFT = SDLK_RSHIFT;
Keyboard::KeyType Keyboard::Key_LCONTROL = SDLK_LCTRL;
Keyboard::KeyType Keyboard::Key_RCONTROL = SDLK_RCTRL;
Keyboard::KeyType Keyboard::Key_ALT = SDLK_LALT;
Keyboard::KeyType Keyboard::Key_ALTGR = SDLK_RALT;
Keyboard::KeyType Keyboard::Key_LWIN = SDLK_LMETA;
Keyboard::KeyType Keyboard::Key_RWIN = SDLK_RMETA;
Keyboard::KeyType Keyboard::Key_MENU = SDLK_HELP;
Keyboard::KeyType Keyboard::Key_SCRLOCK = SDLK_SCROLLOCK;
Keyboard::KeyType Keyboard::Key_NUMLOCK = SDLK_NUMLOCK;
Keyboard::KeyType Keyboard::Key_CAPSLOCK = SDLK_CAPSLOCK;
diff --git a/util/sdl/bitmap.cpp b/util/sdl/bitmap.cpp
index fa359db7..19034b82 100644
--- a/util/sdl/bitmap.cpp
+++ b/util/sdl/bitmap.cpp
@@ -1,1926 +1,1920 @@
#include "../bitmap.h"
#include "../lit_bitmap.h"
#include "../trans-bitmap.h"
#include "../funcs.h"
#include "../../util/debug.h"
#include "../system.h"
#include "../init.h"
#include "sprig/sprig.h"
#include "stretch/SDL_stretch.h"
#include <SDL.h>
#include "image/SDL_image.h"
#include <math.h>
#include "exceptions/exception.h"
#include <string>
#include <sstream>
namespace Graphics{
static const int WINDOWED = 0;
static const int FULLSCREEN = 1;
/* bits per pixel */
static int SCREEN_DEPTH = 16;
static SDL_Surface * screen;
static SDL_PixelFormat format565;
typedef unsigned int (*blender)(unsigned int color1, unsigned int color2, unsigned int alpha);
/* taken from allegro 4.2: src/colblend.c, _blender_trans16 */
/* this function performs a psuedo-SIMD operation on the pixel
* components in RGB 5-6-5 format. To get this to work for some
* other format probably all that needs to happen is to change
* the 0x7E0F81F constant to something else. 5-5-5:
* binary: 0011 1110 000 0111 1100 0001 1111
* hex: 0x174076037
*/
static inline unsigned int transBlender(unsigned int x, unsigned int y, unsigned int n){
unsigned long result;
if (n)
n = (n + 1) / 8;
/* hex: 0x7E0F81F
* binary: 0111 1110 0000 1111 1000 0001 1111
*/
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, &format565, &redX, &greenX, &blueX);
Uint8 redY = 0;
Uint8 greenY = 0;
Uint8 blueY = 0;
SDL_GetRGB(y, &format565, &redY, &greenY, &blueY);
int r = redX * redY / 256;
int g = greenX * greenY / 256;
int b = blueX * blueY / 256;
return transBlender(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, &format565, &redX, &greenX, &blueX);
Uint8 redY = 0;
Uint8 greenY = 0;
Uint8 blueY = 0;
SDL_GetRGB(y, &format565, &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 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, &format565, &redX, &greenX, &blueX);
Uint8 redY = 0;
Uint8 greenY = 0;
Uint8 blueY = 0;
SDL_GetRGB(y, &format565, &redY, &greenY, &blueY);
// int r = iabs(redY - redX);
// int g = iabs(greenY - greenX);
// int b = iabs(blueY - blueX);
int r = redY - redX;
int g = greenY - greenX;
int b = blueY - blueX;
if (r < 0){
r = 0;
}
if (g < 0){
g = 0;
}
if (b < 0){
b = 0;
}
return transBlender(makeColor(r, g, b), y, n);
}
static inline unsigned int burnBlender(unsigned int x, unsigned int y, unsigned int n){
Uint8 redX = 0;
Uint8 greenX = 0;
Uint8 blueX = 0;
SDL_GetRGB(x, &format565, &redX, &greenX, &blueX);
Uint8 redY = 0;
Uint8 greenY = 0;
Uint8 blueY = 0;
SDL_GetRGB(y, &format565, &redY, &greenY, &blueY);
int r = redX - redY;
int g = greenX - greenY;
int b = blueX - blueY;
if (r < 0){
r = 0;
}
if (g < 0){
g = 0;
}
if (b < 0){
g = 0;
}
return transBlender(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;
};
BitmapData::~BitmapData(){
if (surface != NULL && destroy){
SDL_FreeSurface(surface);
}
}
static BlendingData globalBlend;
static int drawingMode = Bitmap::MODE_SOLID;
static int drawingAlpha(){
if (drawingMode == Bitmap::MODE_SOLID){
return 255;
}
if (drawingMode == Bitmap::MODE_TRANS){
return globalBlend.alpha;
}
return 255;
}
static void paintown_applyTrans16(SDL_Surface * dst, const int color);
static void paintown_replace16(SDL_Surface * dst, const int original, const int replace);
static void paintown_draw_sprite_ex16(SDL_Surface * dst, SDL_Surface * src, int dx, int dy, int mode, int flip, Bitmap::Filter * filter);
static void paintown_draw_sprite_filter_ex16(SDL_Surface * dst, SDL_Surface * src, int x, int y, Bitmap::Filter * filter);
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 MaskColor(){
static int mask = makeColor(255, 0, 255);
return mask;
}
static SDL_Surface * optimizedSurface(SDL_Surface * in){
/* SDL_DisplayFormat will return 0 if a graphics context is not set,
* like if a test is running instead of the real game.
*/
// SDL_Surface * out = SDL_DisplayFormat(in);
SDL_Surface * out = SDL_ConvertSurface(in, &format565, SDL_SWSURFACE);
if (out == NULL){
// out = SDL_CreateRGBSurface(SDL_SWSURFACE, in->w, in->h, in->format->BitsPerPixel, 0, 0, 0, 0);
out = SDL_CreateRGBSurface(SDL_SWSURFACE, in->w, in->h, SCREEN_DEPTH, format565.Rmask, format565.Gmask, format565.Bmask, format565.Amask);
if (out == NULL){
std::ostringstream out;
out << "Could not create RGB surface of size " << in->w << ", " << in->h << ". Memory usage: " << System::memoryUsage();
throw BitmapException(__FILE__, __LINE__, out.str());
}
SDL_Rect source;
SDL_Rect destination;
source.w = in->w;
source.h = in->h;
source.x = 0;
source.y = 0;
destination.w = in->w;
destination.h = in->h;
destination.x = 0;
destination.y = 0;
SDL_BlitSurface(in, &source, out, &destination);
}
return out;
}
static Bitmap * Scaler = NULL;
static Bitmap * Buffer = NULL;
BitmapData::BitmapData(SDL_Surface * surface):
surface(surface),
destroy(true){
setSurface(surface);
}
void BitmapData::setSurface(SDL_Surface * surface){
this->surface = surface;
clip_left = 0;
clip_top = 0;
if (surface){
clip_right = surface->w;
clip_bottom = surface->h;
} else {
clip_right = 0;
clip_bottom = 0;
}
}
Bitmap::Bitmap():
mustResize(false),
bit8MaskColor(0){
/* TODO */
}
Bitmap::Bitmap(const char * data, int length):
mustResize(false),
bit8MaskColor(0){
SDL_RWops * ops = SDL_RWFromConstMem(data, length);
SDL_Surface * loaded = IMG_Load_RW(ops, 1);
if (loaded){
setData(new BitmapData(optimizedSurface(loaded)));
SDL_FreeSurface(loaded);
} else {
std::ostringstream out;
out << "Could not load surface from memory " << (void*) data << " length " << length;
throw BitmapException(__FILE__, __LINE__, out.str());
}
}
Bitmap::Bitmap(SDL_Surface * who, bool deep_copy):
mustResize(false),
bit8MaskColor(0){
if (deep_copy){
SDL_Surface * surface = SDL_CreateRGBSurface(SDL_SWSURFACE, who->w, who->h, SCREEN_DEPTH, format565.Rmask, format565.Gmask, format565.Bmask, format565.Amask);
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);
setData(new BitmapData(surface));
} else {
setData(new BitmapData(who));
}
}
Bitmap::Bitmap(int w, int h):
mustResize(false),
bit8MaskColor(0){
if (w < 1){
w = 1;
}
if (h < 1){
h = 1;
}
SDL_Surface * surface = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, SCREEN_DEPTH, format565.Rmask, format565.Gmask, format565.Bmask, format565.Amask);
if (surface == NULL){
std::ostringstream out;
out << "Could not create surface with dimensions " << w << ", " << h;
throw BitmapException(__FILE__, __LINE__, out.str());
}
setData(new BitmapData(surface));
}
Bitmap::Bitmap( const char * load_file ):
mustResize(false),
bit8MaskColor(0){
internalLoadFile(load_file);
}
Bitmap::Bitmap( const std::string & load_file ):
mustResize(false){
internalLoadFile(load_file.c_str());
}
Bitmap::Bitmap( const char * load_file, int sx, int sy ):
mustResize(false),
bit8MaskColor(0){
Bitmap temp(load_file);
SDL_Surface * surface = SDL_CreateRGBSurface(SDL_SWSURFACE, sx, sy, SCREEN_DEPTH, format565.Rmask, format565.Gmask, format565.Bmask, format565.Amask);
setData(new BitmapData(surface));
temp.Stretch(*this);
}
/* unused */
Bitmap::Bitmap( const char * load_file, int sx, int sy, double accuracy ):
mustResize(false),
bit8MaskColor(0){
throw BitmapException(__FILE__, __LINE__, "Unimplemented constructor");
}
Bitmap::Bitmap( const Bitmap & copy, bool deep_copy):
mustResize(false),
bit8MaskColor(copy.bit8MaskColor){
if (deep_copy){
SDL_Surface * who = copy.getData()->getSurface();
SDL_Surface * surface = SDL_CreateRGBSurface(SDL_SWSURFACE, who->w, who->h, SCREEN_DEPTH, format565.Rmask, format565.Gmask, format565.Bmask, format565.Amask);
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);
setData(new BitmapData(surface));
} else {
setData(copy.getData());
}
}
Bitmap::Bitmap( const Bitmap & copy, int sx, int sy ):
mustResize(false),
bit8MaskColor(copy.bit8MaskColor){
/* TODO */
}
Bitmap::Bitmap( const Bitmap & copy, int sx, int sy, double accuracy ):
mustResize(false),
bit8MaskColor(copy.bit8MaskColor){
/* TODO */
}
static inline 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 ):
mustResize(false),
bit8MaskColor(copy.bit8MaskColor){
path = copy.getPath();
SDL_Surface * his = copy.getData()->getSurface();
if (x < 0)
x = 0;
if (y < 0)
y = 0;
if (width + x > his->w )
width = his->w - x;
if (height + y > his->h)
height = his->h - y;
SDL_Surface * sub = SDL_CreateRGBSurfaceFrom(computeOffset(his, x, y), width, height, SCREEN_DEPTH, his->pitch, format565.Rmask, format565.Gmask, format565.Bmask, format565.Amask);
setData(new BitmapData(sub));
}
void Bitmap::internalLoadFile(const char * path){
this->path = path;
SDL_Surface * loaded = IMG_Load(path);
if (loaded){
setData(new BitmapData(optimizedSurface(loaded)));
SDL_FreeSurface(loaded);
} else {
std::ostringstream out;
out << "Could not load file '" << path << "'";
throw BitmapException(__FILE__, __LINE__, out.str());
}
}
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 getRed(int c){
Uint8 red = 0;
Uint8 green = 0;
Uint8 blue = 0;
SDL_GetRGB(c, &format565, &red, &green, &blue);
return red;
}
int getBlue(int c){
Uint8 red = 0;
Uint8 green = 0;
Uint8 blue = 0;
SDL_GetRGB(c, &format565, &red, &green, &blue);
return blue;
}
int getGreen(int c){
Uint8 red = 0;
Uint8 green = 0;
Uint8 blue = 0;
SDL_GetRGB(c, &format565, &red, &green, &blue);
return green;
}
int makeColor(int red, int blue, int green){
return SDL_MapRGB(&format565, red, blue, green);
}
void initializeExtraStuff(){
/* this is as good a place as any to initialize our format */
format565.palette = 0;
format565.BitsPerPixel = 16;
format565.BytesPerPixel = 2;
format565.Rloss = 3;
format565.Gloss = 2;
format565.Bloss = 3;
format565.Aloss = 0;
format565.Rshift = 11;
format565.Gshift = 5;
format565.Bshift = 0;
format565.Ashift = 0;
format565.Rmask = 63488;
format565.Gmask = 2016;
format565.Bmask = 31;
format565.Amask = 0;
-#ifndef PS3
+#if !SDL_VERSION_ATLEAST(1, 3, 0)
format565.colorkey = 0;
format565.alpha = 255;
#endif
}
+/* This code isn't used but leave it here for reference */
#ifdef PS3
#include <rsx/rsx.h>
#include <sysutil/video.h>
void getNativePs3Resolution(int * width, int * height){
videoState state;
videoGetState(0,0,&state);
videoResolution resolution;
videoGetResolution(state.displayMode.resolution, &resolution);
*height = resolution.height;
/* preserve 640x480 aspect ratio */
*width = (int)((*height) * 1.33333);
}
#endif
int setGraphicsMode(int mode, int width, int height){
initializeExtraStuff();
- /* HACK! On the ps3 we query what the native resolution is and
- * set the width/height based on it.
- */
-#ifdef PS3
- // getNativePs3Resolution(&width, &height);
-#endif
-
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;
}
}
Global::debug(1) << "SDL Screen format palette: " << screen->format->palette <<
" bits per pixel: " << (int) screen->format->BitsPerPixel <<
" bytes per pixel: " << (int) screen->format->BytesPerPixel <<
" rloss: " << (int) screen->format->Rloss <<
" gloss: " << (int) screen->format->Gloss <<
" bloss: " << (int) screen->format->Bloss <<
" aloss: " << (int) screen->format->Aloss <<
" rshift: " << (int) screen->format->Rshift <<
" gshift: " << (int) screen->format->Gshift <<
" bshift: " << (int) screen->format->Bshift <<
" ashift: " << (int) screen->format->Ashift <<
" rmask: " << (int) screen->format->Rmask <<
" gmask: " << (int) screen->format->Gmask <<
" bmask: " << (int) screen->format->Bmask <<
" amask: " << (int) screen->format->Amask <<
-#ifndef PS3
+#if !SDL_VERSION_ATLEAST(1, 3, 0)
" colorkey: " << (int) screen->format->colorkey <<
" alpha: " << (int) screen->format->alpha << std::endl;
#else
std::endl;
#endif
if (SCALE_X == 0){
SCALE_X = width;
}
SCALE_X = width;
if (SCALE_Y == 0){
SCALE_Y = height;
}
SCALE_Y = height;
/* does this need to be here? I think configuration will set SCALE_ */
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);
/* don't destroy the screen */
Screen->getData()->destroy = false;
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 = Graphics::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 = Graphics::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 = Graphics::differenceBlender;
}
void Bitmap::burnBlender(int r, int g, int b, int a){
globalBlend.red = r;
globalBlend.green = g;
globalBlend.blue = b;
globalBlend.alpha = a;
globalBlend.currentBlender = Graphics::burnBlender;
}
int setGfxModeText(){
/* TODO */
return 0;
}
int setGfxModeFullscreen(int x, int y){
return setGraphicsMode(FULLSCREEN, x, y);
}
int setGfxModeWindowed( int x, int y ){
return setGraphicsMode(WINDOWED, x, y);
}
void Bitmap::drawingMode(int type){
Graphics::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 = Graphics::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;
}
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 {
SPG_CircleFilled(getData()->getSurface(), x, y, radius, color);
/*
if (Graphics::drawingMode == MODE_SOLID){
SPG_CircleFilled(getData().getSurface(), x, y, radius, color);
} else if (Graphics::drawingMode == MODE_TRANS){
int alpha = globalBlend.alpha;
SPG_CircleFilledBlend(getData().getSurface(), x, y, radius, color, alpha);
}
*/
}
void TranslucentBitmap::circleFill(int x, int y, int radius, int color) const {
int alpha = globalBlend.alpha;
SPG_CircleFilledBlend(getData()->getSurface(), x, y, radius, color, alpha);
}
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;
if (Graphics::drawingMode == MODE_SOLID){
SPG_Circle(getData()->getSurface(), x, y, radius, color);
} else if (Graphics::drawingMode == MODE_TRANS){
int alpha = globalBlend.alpha;
SPG_CircleBlend(getData()->getSurface(), x, y, radius, color, alpha);
}
// 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 {
SPG_Line(getData()->getSurface(), x1, y1, x2, y2, color);
/*
if (Graphics::drawingMode == MODE_SOLID){
SPG_Line(getData().getSurface(), x1, y1, x2, y2, color);
} else if (Graphics::drawingMode == MODE_TRANS){
int alpha = globalBlend.alpha;
SPG_LineBlend(getData().getSurface(), x1, y1, x2, y2, color, alpha);
}
*/
}
void TranslucentBitmap::line(const int x1, const int y1, const int x2, const int y2, const int color ) const {
int alpha = globalBlend.alpha;
SPG_LineBlend(getData()->getSurface(), x1, y1, x2, y2, color, alpha);
}
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, SPRITE_NORMAL, SPRITE_NO_FLIP, NULL);
/*
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, SPRITE_NORMAL, SPRITE_H_FLIP, NULL);
}
void Bitmap::drawHFlip(const int x, const int y, Filter * filter, const Bitmap & where) const {
paintown_draw_sprite_ex16( where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_NORMAL, SPRITE_H_FLIP, filter);
}
void Bitmap::drawVFlip( const int x, const int y, const Bitmap & where ) const {
paintown_draw_sprite_ex16(where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_NORMAL, SPRITE_V_FLIP, NULL);
}
void Bitmap::drawVFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const {
paintown_draw_sprite_ex16(where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_NORMAL, SPRITE_V_FLIP, filter);
}
void Bitmap::drawHVFlip( const int x, const int y, const Bitmap & where ) const {
paintown_draw_sprite_ex16(where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_NORMAL, SPRITE_V_FLIP | SPRITE_H_FLIP, NULL);
}
void Bitmap::drawHVFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const {
paintown_draw_sprite_ex16(where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_NORMAL, SPRITE_V_FLIP | SPRITE_H_FLIP, filter);
}
void TranslucentBitmap::draw(const int x, const int y, const Bitmap & where) const {
paintown_draw_sprite_ex16(where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_TRANS, SPRITE_NO_FLIP, NULL);
}
void TranslucentBitmap::draw( const int x, const int y, Filter * filter, const Bitmap & where ) const {
paintown_draw_sprite_ex16(where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_TRANS, SPRITE_NO_FLIP, filter);
}
void TranslucentBitmap::drawHFlip( const int x, const int y, const Bitmap & where ) const {
paintown_draw_sprite_ex16(where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_TRANS, SPRITE_H_FLIP, NULL);
}
void TranslucentBitmap::drawHFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const {
paintown_draw_sprite_ex16(where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_TRANS, SPRITE_H_FLIP, filter);
}
void TranslucentBitmap::drawVFlip( const int x, const int y, const Bitmap & where ) const {
paintown_draw_sprite_ex16(where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_TRANS, SPRITE_V_FLIP, NULL);
}
void TranslucentBitmap::drawVFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const {
paintown_draw_sprite_ex16(where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_TRANS, SPRITE_V_FLIP, filter);
}
void TranslucentBitmap::drawHVFlip( const int x, const int y, const Bitmap & where ) const {
paintown_draw_sprite_ex16(where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_TRANS, SPRITE_V_FLIP | SPRITE_H_FLIP, NULL);
}
void TranslucentBitmap::drawHVFlip( const int x, const int y, Filter * filter,const Bitmap & where ) const {
paintown_draw_sprite_ex16(where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_TRANS, SPRITE_V_FLIP | SPRITE_H_FLIP, filter);
}
void Bitmap::drawStretched( const int x, const int y, const int new_width, const int new_height, const Bitmap & who ) const {
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);
}
}
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 {
if (destWidth <= 0 || destHeight <= 0 ||
sourceWidth <= 0 || sourceHeight <= 0){
return;
}
Bitmap subSource(*this, sourceX, sourceY, sourceWidth, sourceHeight);
Bitmap subDestination(where, destX, destY, destWidth, destHeight);
SDL_Surface * src = subSource.getData()->getSurface();
SDL_Surface * dst = subDestination.getData()->getSurface();
if (SDL_MUSTLOCK(src)){
SDL_LockSurface(src);
}
if (SDL_MUSTLOCK(dst)){
SDL_LockSurface(dst);
}
SDL_StretchSurfaceRect(src, NULL, dst, NULL);
if (SDL_MUSTLOCK(src)){
SDL_UnlockSurface(src);
}
if (SDL_MUSTLOCK(dst)){
SDL_UnlockSurface(dst);
}
/*
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 ) const {
/* TODO */
}
void Bitmap::triangle( int x1, int y1, int x2, int y2, int x3, int y3, int color ) const {
if (Graphics::drawingMode == MODE_SOLID){
SPG_TrigonFilled(getData()->getSurface(), x1, y1, x2, y2, x3, y3, color);
} else if (Graphics::drawingMode == MODE_TRANS){
int alpha = globalBlend.alpha;
SPG_TrigonFilledBlend(getData()->getSurface(), x1, y1, x2, y2, x3, y3, color, alpha);
}
}
void Bitmap::ellipse( int x, int y, int rx, int ry, int color ) const {
if (Graphics::drawingMode == MODE_SOLID){
SPG_Ellipse(getData()->getSurface(), x, y, rx, ry, color);
} else if (Graphics::drawingMode == MODE_TRANS){
int alpha = globalBlend.alpha;
SPG_EllipseBlend(getData()->getSurface(), x, y, rx, ry, color, alpha);
}
}
void TranslucentBitmap::ellipse( int x, int y, int rx, int ry, int color ) const {
int alpha = globalBlend.alpha;
SPG_EllipseBlend(getData()->getSurface(), x, y, rx, ry, color, alpha);
}
void Bitmap::ellipseFill( int x, int y, int rx, int ry, int color ) const {
SPG_EllipseFilled(getData()->getSurface(), x, y, rx, ry, color);
}
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 {
SPG_LineH(getData().getSurface(), x1, y, x2, color);
}
*/
void Bitmap::hLine( const int x1, const int y, const int x2, const int color ) const {
SPG_LineH(getData()->getSurface(), x1, y, x2, color);
}
void TranslucentBitmap::hLine( const int x1, const int y, const int x2, const int color ) const {
int alpha = globalBlend.alpha;
SPG_LineHBlend(getData()->getSurface(), x1, y, x2, color, alpha);
}
void Bitmap::vLine( const int y1, const int x, const int y2, const int color ) const {
SPG_LineV(getData()->getSurface(), x, y1, y2, color);
}
void Bitmap::polygon( const int * verts, const int nverts, const int color ) const {
SPG_Point * points = new SPG_Point[nverts];
for (int i = 0; i < nverts; i++){
points[i].x = verts[i*2];
points[i].y = verts[i*2+1];
}
SPG_PolygonFilled(getData()->getSurface(), nverts, points, color);
delete[] points;
}
static const double RAD_TO_DEG = 180.0/Util::pi;
static const double DEG_TO_RAD = Util::pi/180.0;
static double toDegrees(double radians){
return RAD_TO_DEG * radians;
}
static const double arcPhase = -Util::pi / 2;
/* 0 = right. pi/2 = up. pi = left. 3pi/2 = down */
void Bitmap::arc(const int x, const int y, const double ang1, const double ang2, const int radius, const int color ) const {
SPG_Arc(getData()->getSurface(), x, y, radius, toDegrees(ang1 + arcPhase), toDegrees(ang2 + arcPhase), color);
}
void Bitmap::arcFilled(const int x, const int y, const double ang1, const double ang2, const int radius, const int color ) const {
SPG_ArcFilled(getData()->getSurface(), x, y, radius, toDegrees(ang1 + arcPhase), toDegrees(ang2 + arcPhase), color);
}
void TranslucentBitmap::arc(const int x, const int y, const double ang1, const double ang2, const int radius, const int color ) const {
int alpha = globalBlend.alpha;
SPG_ArcBlend(getData()->getSurface(), x, y, radius, toDegrees(ang1 + arcPhase), toDegrees(ang2 + arcPhase), color, alpha);
}
void TranslucentBitmap::arcFilled(const int x, const int y, const double ang1, const double ang2, const int radius, const int color ) const {
int alpha = globalBlend.alpha;
SPG_ArcFilledBlend(getData()->getSurface(), x, y, radius, toDegrees(ang1 + arcPhase), toDegrees(ang2 + arcPhase), color, alpha);
}
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);
}
*/
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);
}
void Bitmap::replaceColor(const Color & original, const Color & replaced){
paintown_replace16(getData()->getSurface(), original, replaced);
}
static SDL_Color pcxMaskColor(unsigned char * data, const int length){
if (length >= 769){
if (data[length - 768 - 1] == 12){
unsigned char * palette = &data[length - 768];
unsigned char red = palette[0];
unsigned char green = palette[1];
unsigned char blue = palette[2];
SDL_Color color;
color.r = red;
color.g = green;
color.b = blue;
return color;
}
}
SDL_Color color;
color.r = 255;
color.g = 255;
color.b = 255;
return color;
}
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);
if (!pcx){
std::ostringstream out;
out << "Could not load PCX file at " << (void*) data << " length " << length;
throw BitmapException(__FILE__, __LINE__, out.str());
}
SDL_Surface * display = optimizedSurface(pcx);
Bitmap out(display, true);
if (pcx->format->BitsPerPixel == 8){
-#ifdef PS3
+#if SDL_VERSION_ATLEAST(1, 3, 0)
SDL_Color color = pcxMaskColor(data, length);
#else
SDL_Color color = pcx->format->palette->colors[pcx->format->colorkey];
#endif
int bad = makeColor(color.r, color.g, color.b);
out.set8BitMaskColor(bad);
// int mask = MaskColor();
// out.replaceColor(bad, mask);
}
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 > & line, int y ){
for (int x = 0; x < getWidth(); x++){
line.push_back(getPixel(x, y));
}
}
void Bitmap::StretchBy2( const Bitmap & where ){
/* TODO */
}
void Bitmap::StretchBy4( const Bitmap & where ){
/* TODO */
}
void Bitmap::draw(const int x, const int y, Filter * filter, const Bitmap & where) const {
// paintown_draw_sprite_filter_ex16(where.getData().getSurface(), getData().getSurface(), x, y, filter);
paintown_draw_sprite_ex16(where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_NORMAL, SPRITE_NO_FLIP, filter);
}
void LitBitmap::draw( const int x, const int y, const Bitmap & where ) const {
paintown_draw_sprite_ex16( where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_LIT, SPRITE_NO_FLIP, NULL);
}
void LitBitmap::draw( const int x, const int y, Filter * filter, const Bitmap & where ) const {
paintown_draw_sprite_ex16( where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_LIT, SPRITE_NO_FLIP, filter);
}
void LitBitmap::drawHFlip( const int x, const int y, const Bitmap & where ) const {
paintown_draw_sprite_ex16( where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_LIT, SPRITE_H_FLIP, NULL);
}
void LitBitmap::drawHFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const {
paintown_draw_sprite_ex16( where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_LIT, SPRITE_H_FLIP, filter);
}
void LitBitmap::drawVFlip( 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, NULL);
}
void LitBitmap::drawVFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const {
paintown_draw_sprite_ex16( where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_LIT, SPRITE_V_FLIP, filter);
}
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, NULL);
}
void LitBitmap::drawHVFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const {
paintown_draw_sprite_ex16( where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_LIT, SPRITE_V_FLIP | SPRITE_H_FLIP, filter);
}
/*
#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 = 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_replace16(SDL_Surface * dst, const int original, const int replace){
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;
/* Attempted manual unrolling. Gcc can optimize the naive loop below better
* than this unrolling attempt.
*/
/*
for (int y = y1; y < y2; y += 4){
switch (y2 - y1){
case 1 : {
Uint8 * source1 = computeOffset(dst, x1, y);
for (int x = x2 - 1; x >= x1; source1 += bpp, x--) {
unsigned long sourcePixel = *(Uint16*) source1;
if ((int) sourcePixel == original){
*(Uint16 *)source1 = replace;
}
}
break;
}
case 2 : {
Uint8 * source1 = computeOffset(dst, x1, y);
Uint8 * source2 = computeOffset(dst, x1, y + 1);
for (int x = x2 - 1; x >= x1; source1 += bpp, source2 += bpp, x--) {
unsigned long sourcePixel = *(Uint16*) source1;
unsigned long sourcePixel2 = *(Uint16*) source2;
if ((int) sourcePixel == original){
*(Uint16 *)source1 = replace;
}
if ((int) sourcePixel2 == original){
*(Uint16 *)source2 = replace;
}
}
break;
}
case 3 : {
Uint8 * source1 = computeOffset(dst, x1, y);
Uint8 * source2 = computeOffset(dst, x1, y + 1);
Uint8 * source3 = computeOffset(dst, x1, y + 2);
for (int x = x2 - 1; x >= x1; source1 += bpp, source2 += bpp, source3 += bpp, x--) {
unsigned long sourcePixel = *(Uint16*) source1;
unsigned long sourcePixel2 = *(Uint16*) source2;
unsigned long sourcePixel3 = *(Uint16*) source3;
if ((int) sourcePixel == original){
*(Uint16 *)source1 = replace;
}
if ((int) sourcePixel2 == original){
*(Uint16 *)source2 = replace;
}
if ((int) sourcePixel3 == original){
*(Uint16 *)source3 = replace;
}
}
break;
}
default:
case 4 : {
Uint8 * source1 = computeOffset(dst, x1, y);
Uint8 * source2 = computeOffset(dst, x1, y + 1);
Uint8 * source3 = computeOffset(dst, x1, y + 2);
Uint8 * source4 = computeOffset(dst, x1, y + 3);
for (int x = x2 - 1; x >= x1; source1 += bpp, source2 += bpp, source3 += bpp, source4 += bpp, x--) {
unsigned long sourcePixel = *(Uint16*) source1;
unsigned long sourcePixel2 = *(Uint16*) source2;
unsigned long sourcePixel3 = *(Uint16*) source3;
unsigned long sourcePixel4 = *(Uint16*) source4;
if ((int) sourcePixel == original){
*(Uint16 *)source1 = replace;
}
if ((int) sourcePixel2 == original){
*(Uint16 *)source2 = replace;
}
if ((int) sourcePixel3 == original){
*(Uint16 *)source3 = replace;
}
if ((int) sourcePixel4 == original){
*(Uint16 *)source4 = replace;
}
}
break;
}
}
}
*/
if (SDL_MUSTLOCK(dst)){
SDL_LockSurface(dst);
}
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 ((int) sourcePixel == original){
*(Uint16 *)sourceLine = replace;
}
}
}
if (SDL_MUSTLOCK(dst)){
SDL_UnlockSurface(dst);
}
}
static void paintown_draw_sprite_filter_ex16(SDL_Surface * dst, SDL_Surface * src, int dx, int dy, Bitmap::Filter * filter){
int x, y, w, h;
int x_dir = 1, y_dir = 1;
int dxbeg, dybeg;
int sxbeg, sybeg;
if (SDL_MUSTLOCK(dst)){
SDL_LockSurface(dst);
}
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;
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;
}
unsigned int mask = 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)){
*(Uint16 *)destLine = filter->filter(sourcePixel);
} else {
*(Uint16 *)destLine = mask;
}
}
}
if (SDL_MUSTLOCK(dst)){
SDL_UnlockSurface(dst);
}
}
static void paintown_draw_sprite_ex16(SDL_Surface * dst, SDL_Surface * src, int dx, int dy, int mode, int flip, Bitmap::Filter * filter){
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 & SPRITE_V_FLIP ){
y_dir = -1;
}
if ( flip & 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 & 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 & 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 & SPRITE_H_FLIP ){
dxbeg = dx + w - 1;
}
dybeg = dy;
if ( flip & 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 SPRITE_NORMAL : {
unsigned int mask = 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);
if (filter != NULL){
*(Uint16 *)destLine = filter->filter(sourcePixel);
} else {
*(Uint16 *)destLine = sourcePixel;
}
}
}
}
break;
}
case SPRITE_LIT : {
int bpp = src->format->BytesPerPixel;
int litColor = makeColor(globalBlend.red, globalBlend.green, globalBlend.blue);
unsigned int mask = 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;
if (filter != NULL){
sourcePixel = globalBlend.currentBlender(litColor, filter->filter(sourcePixel), globalBlend.alpha);
*(Uint16 *)destLine = sourcePixel;
} else {
sourcePixel = globalBlend.currentBlender(litColor, sourcePixel, globalBlend.alpha);
*(Uint16 *)destLine = sourcePixel;
}
}
}
}
break;
}
case SPRITE_TRANS : {
int bpp = src->format->BytesPerPixel;
unsigned int mask = 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;
if (filter != NULL){
sourcePixel = globalBlend.currentBlender(filter->filter(sourcePixel), destPixel, globalBlend.alpha);
*(Uint16 *)destLine = sourcePixel;
} else {
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, 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);
}
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 - 1;
min_x = dst->clip_rect.x;
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);
}
}
}
#include "../software-renderer/bitmap.cpp"
diff --git a/util/sdl/sprig/SPG_primitives.c b/util/sdl/sprig/SPG_primitives.c
index 6a4a4430..3f7b3071 100644
--- a/util/sdl/sprig/SPG_primitives.c
+++ b/util/sdl/sprig/SPG_primitives.c
@@ -1,5006 +1,5006 @@
/*
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;
-#ifndef PS3
+#if !SDL_VERSION_ATLEAST(1, 3, 0)
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;
#endif
}
*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;
-#ifndef PS3
+#if !SDL_VERSION_ATLEAST(1, 3, 0)
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;
#endif
}
*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;
-#ifndef PS3
+#if !SDL_VERSION_ATLEAST(1, 3, 0)
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;
#endif
}
}
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 00b1ae87..e8ef22db 100644
--- a/util/sdl/sprig/SPG_rotation.c
+++ b/util/sdl/sprig/SPG_rotation.c
@@ -1,751 +1,751 @@
/*
SPriG - SDL Primitive Generator
by Jonathan Dearborn
Based on SGE: SDL Graphics Extension r030809
by Anders Lindström
*/
/*********************************************************************
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
*********************************************************************/
#include "sprig.h"
#include "sprig_common.h"
#include <math.h>
#ifdef SPG_USE_FAST_MATH
#define sqrt fastsqrt
// Fast sqrt for IEEE floating point. From Wikipedia.
float fastsqrt(float value)
{
union
{
int tmp;
float val;
} u;
u.val = value;
u.tmp -= 1<<23; /* Remove last bit so 1.0 gives 1.0 */
/* tmp is now an approximation to logbase2(val) */
u.tmp >>= 1; /* divide by 2 */
u.tmp += 1<<29; /* add 64 to exponent: (e+127)/2 =(e/2)+63, */
/* that represents (e/2)-64 but we want e/2 */
return u.val;
}
#endif
extern SPG_bool spg_useerrors;
extern SPG_bool spg_usedegrees;
extern SPG_bool spg_makedirtyrects;
extern SPG_DirtyTable* spg_dirtytable_front;
void spg_pixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color);
SDL_Rect spg_transform_tmap(SDL_Surface *src, SDL_Surface *dst, float angle, float xscale, float yscale, Uint16 qx, Uint16 qy);
//==================================================================================
// Helper function to SPG_TransformX()
// Returns the bounding box
//==================================================================================
void spg_calcrect(SDL_Surface *src, SDL_Surface *dst, float theta, float xscale, float yscale, Uint16 px, Uint16 py, Uint16 qx, Uint16 qy, Sint16 *xmin, Sint16 *ymin, Sint16 *xmax, Sint16 *ymax)
{
Sint16 x, y, rx, ry;
// Clip to src surface
Sint16 sxmin = SPG_CLIP_XMIN(src);
Sint16 sxmax = SPG_CLIP_XMAX(src);
Sint16 symin = SPG_CLIP_YMIN(src);
Sint16 symax = SPG_CLIP_YMAX(src);
Sint16 sx[]={sxmin, sxmax, sxmin, sxmax};
Sint16 sy[]={symin, symax, symax, symin};
// We don't really need fixed-point here
// but why not?
Sint32 const istx = (Sint32)((sin(theta)*xscale) * 8192.0); /* Inverse transform */
Sint32 const ictx = (Sint32)((cos(theta)*xscale) * 8192.2);
Sint32 const isty = (Sint32)((sin(theta)*yscale) * 8192.0);
Sint32 const icty = (Sint32)((cos(theta)*yscale) * 8192.2);
int i;
//Calculate the four corner points
for(i=0; i<4; i++){
rx = sx[i] - px;
ry = sy[i] - py;
x = (Sint16)(((ictx*rx - isty*ry) >> 13) + qx);
y = (Sint16)(((icty*ry + istx*rx) >> 13) + qy);
if(i==0){
*xmax = *xmin = x;
*ymax = *ymin = y;
}else{
if(x>*xmax)
*xmax=x;
else if(x<*xmin)
*xmin=x;
if(y>*ymax)
*ymax=y;
else if(y<*ymin)
*ymin=y;
}
}
//Better safe than sorry...
*xmin -= 1;
*ymin -= 1;
*xmax += 1;
*ymax += 1;
//Clip to dst surface
if( !dst )
return;
if( *xmin < SPG_CLIP_XMIN(dst) )
*xmin = SPG_CLIP_XMIN(dst);
if( *xmax > SPG_CLIP_XMAX(dst) )
*xmax = SPG_CLIP_XMAX(dst);
if( *ymin < SPG_CLIP_YMIN(dst) )
*ymin = SPG_CLIP_YMIN(dst);
if( *ymax > SPG_CLIP_YMAX(dst) )
*ymax = SPG_CLIP_YMAX(dst);
}
/*==================================================================================
** Rotate by angle about pivot (px,py) scale by scale and place at
** position (qx,qy).
**
** Transformation matrix application (rotated coords "R"):
**
** / rx \ / cos(theta) sin(theta) \ / dx \
** | | = | | | |
** \ ry / \ -sin(theta) cos(theta) / \ dy /
**
** => rx = cos(theta) dx + sin(theta) dy
** ry = cos(theta) dy - sin(theta) dx
** but represented as a fixed-point float using integer math
**
** Developed with the help from Terry Hancock (hancock@earthlink.net)
**
**==================================================================================*/
// First we need some macros to handle different bpp
// I'm sorry about this...
#define TRANSFORM(UintXX, DIV) \
Sint32 const src_pitch=src->pitch/DIV; \
Sint32 const dst_pitch=dst->pitch/DIV; \
UintXX const *src_row = (UintXX *)src->pixels; \
UintXX *dst_row; \
Uint32 col;\
\
for (y=ymin; y<=ymax; y++){ /* Changed from y<ymax to y<=ymax Edge fix 7-13-08*/\
dy = y - qy; \
\
sx = (Sint32)(ctdx + stx*dy + mx); /* Compute source anchor points */ \
sy = (Sint32)(cty*dy - stdx + my); \
\
/* Calculate pointer to dst surface */ \
dst_row = (UintXX *)dst->pixels + y*dst_pitch; \
\
for (x=xmin; x<=xmax; x++){ /* Changed from x<xmax to x<=xmax Edge fix 7-13-08*/\
rx=(Sint16)(sx >> 13); /* Convert from fixed-point */ \
ry=(Sint16)(sy >> 13)+1; /* Added +1 Edge fix 7-13-08*/\
/* Make sure the source pixel is actually in the source image. */ \
if( (rx>=sxmin) && (rx<=sxmax) && (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 == 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) == 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) == 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) == 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;
-#ifdef PS3
+#if SDL_VERSION_ATLEAST(1, 3, 0)
/* Hack for the ps3 because it doesn't have src->format->colorkey.
* we know that paintown always uses 255,0,255 for the colorkey
* so we just hack it in here.
*/
int colorkey = SDL_MapRGB(src->format, 255, 0, 255);
#else
int colorkey = src->format->colorkey;
#endif
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;
-#ifdef PS3
+#if SDL_VERSION_ATLEAST(1, 3, 0)
int colorkey = SDL_MapRGB(src->format, 255, 0, 255);
#else
int colorkey = src->format->colorkey;
#endif
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;
-#ifndef PS3
+#if !SDL_VERSION_ATLEAST(1, 3, 0)
dest->format->alpha = src->format->alpha;
dest->format->colorkey = src->format->colorkey;
#endif
SPG_Fill(dest,bgColor); //Set background color
SPG_TransformX(src, dest, angle, xscale, yscale, 0, 0, qx, qy, flags);
return dest;
}
//==================================================================================
// Rotate using texture mapping
//==================================================================================
SDL_Rect spg_transform_tmap(SDL_Surface *src, SDL_Surface *dst, float angle, float xscale, float yscale, Uint16 qx, Uint16 qy)
{
float a=(SPG_CLIP_XMAX(src) - SPG_CLIP_XMIN(src))/2.0f;
float b=(SPG_CLIP_YMAX(src) - SPG_CLIP_YMIN(src))/2.0f;
float cosv, sinv;
//Get an exact value if possible
if(angle == 0.0f || angle == 360.0f){
cosv=1; sinv=0;
}
else if(angle == 90.0f){
cosv=0; sinv=1;
}
else if(angle == 180.0f){
cosv=-1; sinv=0;
}
else if(angle == 270.0f){
cosv=0; sinv=-1;
}
else{ //Oh well
if(spg_usedegrees)
angle *= RADPERDEG; /* Convert to radians. */
cosv=cos(angle); sinv=sin(angle);
}
//Precalculate as much as possible
float acosv=a*cosv*xscale, bcosv=b*cosv*yscale;
float asinv=a*sinv*xscale, bsinv=b*sinv*yscale;
/* Do the math */
Sint16 xt[4],yt[4];
xt[0] = (Sint16)((-acosv+bsinv)+qx);
yt[0] = (Sint16)((-asinv-bcosv)+qy);
xt[1] = (Sint16)((acosv+bsinv)+qx);
yt[1] = (Sint16)((asinv-bcosv)+qy);
xt[2] = (Sint16)((-acosv-bsinv)+qx);
yt[2] = (Sint16)((-asinv+bcosv)+qy);
xt[3] = (Sint16)((acosv-bsinv)+qx);
yt[3] = (Sint16)((asinv+bcosv)+qy);
//Use a texture mapped rectangle
SPG_QuadTex(dst,xt[0],yt[0],xt[1],yt[1],xt[2],yt[2],xt[3],yt[3],src, SPG_CLIP_XMIN(src),SPG_CLIP_YMIN(src), SPG_CLIP_XMAX(src),SPG_CLIP_YMIN(src), SPG_CLIP_XMIN(src),SPG_CLIP_YMAX(src), SPG_CLIP_XMAX(src),SPG_CLIP_YMAX(src));
//Or maybe two trigons...
//SPG_TexturedTrigon(dest,xt[0],yt[0],xt[1],yt[1],xt[2],yt[2],src, SPG_CLIP_XMIN(src),SPG_CLIP_YMIN(src), SPG_CLIP_XMAX(src),SPG_CLIP_YMIN(src), SPG_CLIP_XMIN(src),SPG_CLIP_YMAX(src));
//SPG_TexturedTrigon(dest,xt[3],yt[3],xt[1],yt[1],xt[2],yt[2],src, SPG_CLIP_XMAX(src),SPG_CLIP_YMAX(src), SPG_CLIP_XMAX(src),SPG_CLIP_YMIN(src), SPG_CLIP_XMIN(src),SPG_CLIP_YMAX(src));
//For debug
//SPG_Trigon(dest,xt[0],yt[0],xt[1],yt[1],xt[2],yt[2],SDL_MapRGB(dest->format,255,0,0));
//SPG_Trigon(dest,xt[3],yt[3],xt[1],yt[1],xt[2],yt[2],SDL_MapRGB(dest->format,0,255,0));
Sint16 xmax=xt[0], xmin=xt[0];
xmax= (xmax>xt[1])? xmax : xt[1];
xmin= (xmin<xt[1])? xmin : xt[1];
xmax= (xmax>xt[2])? xmax : xt[2];
xmin= (xmin<xt[2])? xmin : xt[2];
xmax= (xmax>xt[3])? xmax : xt[3];
xmin= (xmin<xt[3])? xmin : xt[3];
Sint16 ymax=yt[0], ymin=yt[0];
ymax= (ymax>yt[1])? ymax : yt[1];
ymin= (ymin<yt[1])? ymin : yt[1];
ymax= (ymax>yt[2])? ymax : yt[2];
ymin= (ymin<yt[2])? ymin : yt[2];
ymax= (ymax>yt[3])? ymax : yt[3];
ymin= (ymin<yt[3])? ymin : yt[3];
SDL_Rect r;
r.x=xmin; r.y=ymin; r.w=xmax-xmin+1; r.h=ymax-ymin+1;
return r;
}
SDL_Surface* SPG_Rotate(SDL_Surface *src, float angle, Uint32 bgColor)
{
SDL_Surface *dest;
/* Create the destination surface*/
int max = (int)( sqrt( (src->h*src->h/2 + src->w*src->w/2) + 1 ) );
dest=SDL_AllocSurface(SDL_SWSURFACE, max, max, src->format->BitsPerPixel, src->format->Rmask, src->format->Gmask, src->format->Bmask, src->format->Amask );
if(!dest)
{SPG_Error("SPG_Rotate could not allocate enough memory");return NULL;}
SDL_FillRect(dest, NULL, bgColor);
SPG_TransformX(src, dest, angle, 1.0f, 1.0f, src->w/2, src->h/2, dest->w/2, dest->h/2, 0);
return dest;
}
SDL_Surface* SPG_RotateAA(SDL_Surface *src, float angle, Uint32 bgColor)
{
SDL_Surface *dest;
/* Create the destination surface*/
int max = (int)( sqrt( (src->h*src->h/2 + src->w*src->w/2) + 1 ) );
dest=SDL_AllocSurface(SDL_SWSURFACE, max, max, src->format->BitsPerPixel, src->format->Rmask, src->format->Gmask, src->format->Bmask, src->format->Amask );
if(!dest)
{SPG_Error("SPG_RotateAA could not allocate enough memory"); return NULL;}
SDL_FillRect(dest, NULL, bgColor);
SPG_TransformX(src, dest, angle, 1.0f, 1.0f, src->w/2, src->h/2, dest->w/2, dest->h/2, SPG_TAA);
return dest;
}
diff --git a/util/sdl/sprig/SPG_surface.c b/util/sdl/sprig/SPG_surface.c
index b262eb88..5c4a751a 100644
--- a/util/sdl/sprig/SPG_surface.c
+++ b/util/sdl/sprig/SPG_surface.c
@@ -1,1225 +1,1225 @@
/*
SPriG - SDL Primitive Generator
by Jonathan Dearborn
Based on SGE: SDL Graphics Extension r030809
by Anders Lindström
*/
/*********************************************************************
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
*********************************************************************/
/*
* Some of this code is taken from the "Introduction to SDL" and
* John Garrison's PowerPak
*/
#include "sprig.h"
#include "sprig_common.h"
#include <math.h>
#include <string.h>
#include <stdarg.h>
/* Global used for SPG_EnableAutolock */
SPG_bool spg_autolock = 1;
void (*spg_blitfunc)(SDL_Surface*, SDL_Rect*, SDL_Surface*, SDL_Rect*) = NULL;
struct spg_uint8_node
{
Uint8 datum;
struct spg_uint8_node* next;
};
struct spg_uint16_node
{
Uint16 datum;
struct spg_uint16_node* next;
};
struct spg_bool_node
{
SPG_bool datum;
struct spg_bool_node* next;
};
struct spg_string_node
{
char* datum;
struct spg_string_node* next;
};
struct spg_uint16_node* spg_thickness_state = NULL;
extern Uint16 spg_thickness;
struct spg_uint8_node* spg_blend_state = NULL;
struct spg_bool_node* spg_aa_state = NULL;
struct spg_bool_node* spg_blit_surface_alpha_state = NULL;
struct spg_string_node* _spg_errors = NULL;
struct spg_string_node* _spg_errors_tail = NULL;
Uint16 _spg_numerrors = 0;
SPG_bool spg_useerrors = 0;
extern SPG_bool spg_makedirtyrects;
extern SPG_DirtyTable* spg_dirtytable_front;
void spg_pixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color);
void spg_pixelblend(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color, Uint8 alpha);
void spg_pixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color);
void spg_pixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color);
void spg_pixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color);
void spg_pixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color);
void spg_pixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color);
/**********************************************************************************/
/** Misc. functions **/
/**********************************************************************************/
void SPG_EnableAutolock(SPG_bool enable)
{ spg_autolock = enable;}
SPG_bool SPG_GetAutolock()
{ return spg_autolock;}
void SPG_PushThickness(Uint16 state)
{
struct spg_uint16_node* node = (struct spg_uint16_node*)malloc(sizeof(struct spg_uint16_node));
node->datum = state;
node->next = spg_thickness_state;
spg_thickness_state = node;
spg_thickness = state;
}
Uint16 SPG_PopThickness()
{
if(spg_thickness_state == NULL)
{
if(spg_useerrors)
SPG_Error("SPG_PopThickness popped an empty stack!");
spg_thickness = 1;
return 1;
}
struct spg_uint16_node* temp = spg_thickness_state;
spg_thickness = spg_thickness_state->datum;
spg_thickness_state = spg_thickness_state->next;
free(temp);
return spg_thickness;
}
Uint16 SPG_GetThickness()
{
return spg_thickness;
}
void SPG_PushBlend(Uint8 state)
{
struct spg_uint8_node* node = (struct spg_uint8_node*)malloc(sizeof(struct spg_uint8_node));
node->datum = state;
node->next = spg_blend_state;
spg_blend_state = node;
}
Uint8 SPG_PopBlend()
{
if(spg_blend_state == NULL)
{
if(spg_useerrors)
SPG_Error("SPG_PopBlend popped an empty stack!");
return 0;
}
struct spg_uint8_node* temp = spg_blend_state;
Uint8 result = spg_blend_state->datum;
spg_blend_state = spg_blend_state->next;
free(temp);
return result;
}
Uint8 SPG_GetBlend()
{
if(spg_blend_state == NULL)
{
// Without initialization, this overfills the stack.
//if(spg_useerrors)
//SPG_Error("SPG_GetBlend checked an empty stack!");
return 0;
}
return spg_blend_state->datum;
}
void SPG_PushAA(SPG_bool state)
{
struct spg_bool_node* node = (struct spg_bool_node*)malloc(sizeof(struct spg_bool_node));
node->datum = state;
node->next = spg_aa_state;
spg_aa_state = node;
}
SPG_bool SPG_PopAA()
{
if(spg_aa_state == NULL)
{
if(spg_useerrors)
SPG_Error("SPG_PopAA popped an empty stack!");
return 0;
}
struct spg_bool_node* temp = spg_aa_state;
SPG_bool result = spg_aa_state->datum;
spg_aa_state = spg_aa_state->next;
free(temp);
return result;
}
SPG_bool SPG_GetAA()
{
if(spg_aa_state == NULL)
{
// Without initialization, this overfills the stack.
//if(spg_useerrors)
//SPG_Error("SPG_GetAA checked an empty stack!");
return 0;
}
return spg_aa_state->datum;
}
void SPG_PushSurfaceAlpha(SPG_bool state)
{
struct spg_bool_node* node = (struct spg_bool_node*)malloc(sizeof(struct spg_bool_node));
node->datum = state;
node->next = spg_blit_surface_alpha_state;
spg_blit_surface_alpha_state = node;
}
SPG_bool SPG_PopSurfaceAlpha()
{
if(spg_blit_surface_alpha_state == NULL)
{
if(spg_useerrors)
SPG_Error("SPG_PopSurfaceAlpha popped an empty stack!");
return 0;
}
struct spg_bool_node* temp = spg_blit_surface_alpha_state;
SPG_bool result = spg_blit_surface_alpha_state->datum;
spg_blit_surface_alpha_state = spg_blit_surface_alpha_state->next;
free(temp);
return result;
}
SPG_bool SPG_GetSurfaceAlpha()
{
if(spg_blit_surface_alpha_state == NULL)
{
// Without initialization, this overfills the stack.
//if(spg_useerrors)
//SPG_Error("SPG_GetSurfaceAlpha checked an empty stack!");
return 0;
}
return spg_blit_surface_alpha_state->datum;
}
void SPG_Error(const char* err)
{
if(err == NULL || _spg_numerrors >= SPG_MAX_ERRORS)
return;
struct spg_string_node* node = (struct spg_string_node*)malloc(sizeof(struct spg_string_node));
node->datum = (char*)malloc(strlen(err)+20);
sprintf(node->datum, "%s at time %ums", err, SDL_GetTicks());
// push to front
//node->next = _spg_errors;
//_spg_errors = node;
// push to back
node->next = NULL;
if(_spg_errors == NULL || _spg_errors_tail == NULL)
_spg_errors = node;
else
_spg_errors_tail->next = node;
_spg_errors_tail = node;
_spg_numerrors++;
}
char* SPG_GetError()
{
if(_spg_numerrors == 0 || _spg_errors == NULL)
return NULL;
struct spg_string_node* temp = _spg_errors;
char* result = _spg_errors->datum;
_spg_errors = _spg_errors->next;
_spg_numerrors--;
free(temp);
return result;
}
Uint16 SPG_NumErrors()
{
return _spg_numerrors;
}
void SPG_EnableErrors(SPG_bool enable)
{
spg_useerrors = enable;
}
/*
* Get the smallest bounding box from two (SDL_Rect) rectangles
*/
void SPG_RectOR(const SDL_Rect rect1, const SDL_Rect rect2, SDL_Rect* dst_rect)
{
if(dst_rect == NULL)
return;
dst_rect->x = (rect1.x < rect2.x)? rect1.x : rect2.x;
dst_rect->y = (rect1.y < rect2.y)? rect1.y : rect2.y;
dst_rect->w = (rect1.x + rect1.w > rect2.x + rect2.w)? rect1.x + rect1.w - dst_rect->x : rect2.x + rect2.w - dst_rect->x;
dst_rect->h = (rect1.y + rect1.h > rect2.y + rect2.h)? rect1.y + rect1.h - dst_rect->y : rect2.y + rect2.h - dst_rect->y;
}
// Adapted from SDL_IntersectRect
SPG_bool SPG_RectAND(const SDL_Rect A, const SDL_Rect B, SDL_Rect* intersection)
{
int resX, resY, resW, resH;
int Amin, Amax, Bmin, Bmax;
// Horizontal intersection
Amin = A.x;
Amax = Amin + A.w;
Bmin = B.x;
Bmax = Bmin + B.w;
if(Bmin > Amin)
Amin = Bmin;
resX = Amin;
if(Bmax < Amax)
Amax = Bmax;
resW = Amax - Amin > 0 ? Amax - Amin : 0;
// Vertical intersection
Amin = A.y;
Amax = Amin + A.h;
Bmin = B.y;
Bmax = Bmin + B.h;
if(Bmin > Amin)
Amin = Bmin;
resY = Amin;
if(Bmax < Amax)
Amax = Bmax;
resH = Amax - Amin > 0 ? Amax - Amin : 0;
if(intersection != NULL)
{
intersection->x = resX;
intersection->y = resY;
intersection->w = resW;
intersection->h = resH;
}
return (resW && resH);
}
// Adapted from SDL_SetClipRect
void SPG_SetClip(SDL_Surface *surface, const SDL_Rect rect)
{
//SDL_Rect full_rect;
int Amin, Amax, Bmax;
if (!surface)
return;
// Set the clipping rectangle with the intersection of
// the given rect with the full surface.
// Horizontal intersection
Amin = rect.x;
Amax = Amin + rect.w;
Bmax = surface->w;
if(Amin < 0)
Amin = 0;
surface->clip_rect.x = Amin;
if(Bmax < Amax)
Amax = Bmax;
surface->clip_rect.w = Amax - Amin > 0 ? Amax - Amin : 0;
// Vertical intersection
Amin = rect.y;
Amax = Amin + rect.h;
Bmax = surface->h;
if(Amin < 0)
Amin = 0;
surface->clip_rect.y = Amin;
if(Bmax < Amax)
Amax = Bmax;
surface->clip_rect.h = Amax - Amin > 0 ? Amax - Amin : 0;
}
//==================================================================================
// Calculate y pitch offset
// (the y pitch offset is constant for the same y coord and surface)
//==================================================================================
Sint32 SPG_CalcYPitch(SDL_Surface *dest,Sint16 y)
{
if(y>=SPG_CLIP_YMIN(dest) && y<=SPG_CLIP_YMAX(dest)){
switch ( dest->format->BytesPerPixel ) {
case 1:
return y*dest->pitch;
break;
case 2:
return y*dest->pitch/2;
break;
case 3:
return y*dest->pitch;
break;
case 4:
return y*dest->pitch/4;
break;
}
}
return -1;
}
//==================================================================================
// Set pixel with precalculated y pitch offset
//==================================================================================
void SPG_pSetPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
{
if(x>=SPG_CLIP_XMIN(surface) && x<=SPG_CLIP_XMAX(surface) && ypitch>=0){
switch (surface->format->BytesPerPixel) {
case 1: { /* Assuming 8-bpp */
*((Uint8 *)surface->pixels + ypitch + x) = color;
}
break;
case 2: { /* Probably 15-bpp or 16-bpp */
*((Uint16 *)surface->pixels + ypitch + x) = color;
}
break;
case 3: { /* Slow 24-bpp mode, usually not used */
/* Gack - slow, but endian correct */
Uint8 *pix = (Uint8 *)surface->pixels + ypitch + x*3;
*(pix+surface->format->Rshift/8) = color>>surface->format->Rshift;
*(pix+surface->format->Gshift/8) = color>>surface->format->Gshift;
*(pix+surface->format->Bshift/8) = color>>surface->format->Bshift;
*(pix+surface->format->Ashift/8) = color>>surface->format->Ashift;
}
break;
case 4: { /* Probably 32-bpp */
*((Uint32 *)surface->pixels + ypitch + x) = color;
}
break;
}
}
}
//==================================================================================
// Get pixel
//==================================================================================
Uint32 SPG_GetPixel(SDL_Surface *surface, Sint16 x, Sint16 y)
{
if(x<0 || x>=surface->w || y<0 || y>=surface->h)
{
if(spg_useerrors)
SPG_Error("SPG_GetPixel was used out of the surface bounds");
return 0;
}
switch (surface->format->BytesPerPixel) {
case 1: { /* Assuming 8-bpp */
return *((Uint8 *)surface->pixels + y*surface->pitch + x);
}
break;
case 2: { /* Probably 15-bpp or 16-bpp */
return *((Uint16 *)surface->pixels + y*surface->pitch/2 + x);
}
break;
case 3: { /* Slow 24-bpp mode, usually not used */
Uint8 *pix;
int shift;
Uint32 color=0;
pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
shift = surface->format->Rshift;
color = *(pix+shift/8)<<shift;
shift = surface->format->Gshift;
color|= *(pix+shift/8)<<shift;
shift = surface->format->Bshift;
color|= *(pix+shift/8)<<shift;
shift = surface->format->Ashift;
color|= *(pix+shift/8)<<shift;
return color;
}
break;
case 4: { /* Probably 32-bpp */
return *((Uint32 *)surface->pixels + y*surface->pitch/4 + x);
}
break;
}
return 0;
}
/**********************************************************************************/
/** Block functions **/
/**********************************************************************************/
//==================================================================================
// The SPG_write_block* functions copies the given block (a surface line) directly
// to the surface. This is *much* faster then using the put pixel functions to
// update a line. The block consist of Surface->w (the width of the surface) numbers
// of color values. Note the difference in byte size for the block elements for
// different color depths. 24 bpp is slow and not included!
//==================================================================================
// See sprig_inline.h
// SDL's clipping
SDL_Rect* SPG_BlitClip(SDL_Surface* source, SDL_Rect* srect, SDL_Surface* dest, SDL_Rect* drect)
{
// Clip rects
SDL_Rect fulldst;
int srcx, srcy, w, h;
/* If the destination rectangle is NULL, use the entire dest surface */
if ( drect == NULL ) {
fulldst.x = fulldst.y = 0;
fulldst.w = dest->w;
fulldst.h = dest->h;
drect = &fulldst;
}
/* clip the source rectangle to the source surface */
if(srect) {
int maxw, maxh;
srcx = srect->x;
w = srect->w;
if(srcx < 0) {
w += srcx;
drect->x -= srcx;
srcx = 0;
}
maxw = source->w - srcx;
if(maxw < w)
w = maxw;
srcy = srect->y;
h = srect->h;
if(srcy < 0) {
h += srcy;
drect->y -= srcy;
srcy = 0;
}
maxh = source->h - srcy;
if(maxh < h)
h = maxh;
} else {
srcx = srcy = 0;
w = source->w;
h = source->h;
}
/* clip the destination rectangle against the clip rectangle */
{
SDL_Rect *clip = &dest->clip_rect;
int dx, dy;
dx = clip->x - drect->x;
if(dx > 0) {
w -= dx;
drect->x += dx;
srcx += dx;
}
dx = drect->x + w - clip->x - clip->w;
if(dx > 0)
w -= dx;
dy = clip->y - drect->y;
if(dy > 0) {
h -= dy;
drect->y += dy;
srcy += dy;
}
dy = drect->y + h - clip->y - clip->h;
if(dy > 0)
h -= dy;
}
if(w <= 0 || h <= 0)
return NULL;
SDL_Rect* result = (SDL_Rect*)malloc(sizeof(SDL_Rect));
result->x = srcx;
result->y = srcy;
result->w = drect->w = w;
result->h = drect->h = h;
return result;
}
void SPG_BlendBlit(SDL_Surface* source, SDL_Rect* srect, SDL_Surface* dest, SDL_Rect* drect)
{
int lowSX, highSX, lowSY, highSY;
if(srect)
{
lowSX = srect->x;
highSX = srect->x + srect->w;
lowSY = srect->y;
highSY = srect->y + srect->h;
}
else
{
lowSX = 0;
highSX = dest->w;
lowSY = 0;
highSY = dest->h;
}
int lowDX, highDX, lowDY, highDY;
if(drect)
{
lowDX = drect->x;
highDX = drect->x + drect->w;
lowDY = drect->y;
highDY = drect->y + drect->h;
}
else
{
lowDX = 0;
highDX = dest->w;
lowDY = 0;
highDY = dest->h;
}
-#ifndef PS3
+#if !SDL_VERSION_ATLEAST(1, 3, 0)
// Get the per-surface alpha
Uint8 perSAlpha = source->format->alpha;
// Ready the recycling loop variables
int sx = 0, sy = 0, dx = 0, dy = 0;
Uint32 color;
Uint8 r;
Uint8 g;
Uint8 b;
Uint8 a;
/*if ( spg_lock(surface) < 0 )
return;
if ( spg_lock(dest) < 0 )
return;*/
SPG_bool ncolorkeyed = !(source->flags & SDL_SRCCOLORKEY);
Uint32 colorkey = source->format->colorkey;
// Go through the rect we made
for (sx = lowSX, sy = lowSY, dx = lowDX, dy = lowDY; sy < highSY;)
{
// Get the source color
color = SPG_GetPixel(source, sx, sy);
SDL_GetRGBA(color, source->format, &r, &g, &b, &a);
// Combine per-surface and per-pixel alpha
if(SPG_GetSurfaceAlpha())
a = (Uint8)(a*(perSAlpha)/255.0);
// Convert color to dest color
color = SDL_MapRGB(dest->format, r, g, b);
// If not a colorkeyed color, then draw the pixel (blending done in put pixel function)
if(ncolorkeyed || color != colorkey)
spg_pixelblend(dest, dx, dy, color, a);
// Increment here so we can use the auto test on dy
sx++;
dx++;
// Check sx bound to move on to the next horizontal line
if (sx >= highSX)
{
sx = lowSX;
sy++;
dx = lowDX;
dy++;
}
}
#endif
/*spg_unlock(surface);
spg_unlock(dest);*/
if(spg_makedirtyrects)
{
SDL_Rect rect;
rect.x = lowDX;
rect.y = lowDY;
rect.w = highDX - lowDX;
rect.h = highDY - lowDY;
// Clip it to the screen
SPG_DirtyClip(dest, &rect);
SPG_DirtyAddTo(spg_dirtytable_front, &rect);
}
}
// SDL's clipping
int SPG_Blit(SDL_Surface* source, SDL_Rect* srect, SDL_Surface* dest, SDL_Rect* drect)
{
/* Make sure the surfaces aren't locked */
if ( ! source || ! dest ) {
SDL_SetError("SPG_Blit was passed a NULL surface");
return -1;
}
if ( source->locked || dest->locked ) {
SDL_SetError("SPG_Blit was passed a locked surface");
return -1;
}
srect = SPG_BlitClip(source, srect, dest, drect);
if(spg_blitfunc == NULL)
spg_blitfunc = SPG_BlendBlit;
spg_blitfunc(source, srect, dest, drect);
free(srect);
return 0;
}
void SPG_SetBlit(void (*blitfn)(SDL_Surface*, SDL_Rect*, SDL_Surface*, SDL_Rect*))
{
spg_blitfunc = blitfn;
}
void (*SPG_GetBlit())(SDL_Surface*, SDL_Rect*, SDL_Surface*, SDL_Rect*)
{
return spg_blitfunc;
}
// Returns a new surface that is a copy of the dest surface but with
// the color value replaced by the values on the src surface.
SDL_Surface* SPG_ReplaceColor(SDL_Surface* src, SDL_Rect* srcrect, SDL_Surface* dest, SDL_Rect* destrect, Uint32 color)
{
if(src == NULL || dest == NULL)
return NULL;
-#ifndef PS3
+#if !SDL_VERSION_ATLEAST(1, 3, 0)
// Save per-surface alpha
Uint32 srcAlpha = src->flags & SDL_SRCALPHA;
Uint32 destAlpha = dest->flags & SDL_SRCALPHA;
// ... and disable blending.
SDL_SetAlpha(src, 0, src->format->alpha);
SDL_SetAlpha(dest, 0, dest->format->alpha);
// Save colorkey info
Uint32 destCK = dest->format->colorkey;
Uint32 destCKflag = dest->flags & SDL_SRCCOLORKEY;
// ... and set the key to the desired color.
SPG_SetColorkey(dest, color);
// srcrect != NULL: Take piece of src and use it (looks like placing piece on top of dest)
// destrect != NULL: Move src somewhere before blitting
SDL_Surface* temp = SDL_CreateRGBSurface(SDL_SWSURFACE, dest->w, dest->h, dest->format->BitsPerPixel,
dest->format->Rmask, dest->format->Gmask, dest->format->Bmask, dest->format->Amask);
SDL_BlitSurface(src, srcrect, temp, destrect); // BG color is always BLACK and TRANSPARENT...
SDL_BlitSurface(dest, NULL, temp, NULL);
// Restore stuff
SDL_SetColorKey(dest, destCKflag, destCK);
SDL_SetAlpha(src, srcAlpha, src->format->alpha);
SDL_SetAlpha(dest, destAlpha, dest->format->alpha);
return temp;
#else
return NULL;
#endif
}
/**********************************************************************************/
/** Palette functions **/
/**********************************************************************************/
// 8-bit palettes
// Returns an 8-bit rainbow palette with 256 colors.
// Code adapted from SDL_DitherColors in SDL_pixels.c
SDL_Color* SPG_ColorPalette()
{
SDL_Color* colors = (SDL_Color*)malloc(sizeof(SDL_Color)*256);
int i;
for(i = 0; i < 256; i++) {
int r, g, b;
// map each bit field to the full [0, 255] interval,
//so 0 is mapped to (0, 0, 0) and 255 to (255, 255, 255)
r = i & 0xe0;
r |= r >> 3 | r >> 6;
colors[i].r = r;
g = (i << 3) & 0xe0;
g |= g >> 3 | g >> 6;
colors[i].g = g;
b = i & 0x3;
b |= b << 2;
b |= b << 4;
colors[i].b = b;
}
return colors;
}
// Returns an 8-bit black and white (grayscale) palette with 256 colors.
SDL_Color* SPG_GrayPalette()
{
SDL_Color* colors = (SDL_Color*)malloc(sizeof(SDL_Color)*256);
int i;
for(i = 0; i < 256; i++) {
colors[i].r = i;
colors[i].g = i;
colors[i].b = i;
}
return colors;
}
SDL_Surface* SPG_CreateSurface8(Uint32 flags, Uint16 width, Uint16 height)
{
SDL_Surface* result = SDL_CreateRGBSurface(flags, width, height, 8, 0, 0, 0, 0);
// Try to use existing palette...
SDL_Surface* videoSurf = SDL_GetVideoSurface();
if(videoSurf != NULL && videoSurf->format->BitsPerPixel == 8)
{
SDL_SetColors(result, videoSurf->format->palette->colors, 0, videoSurf->format->palette->ncolors);
}
else // else create one
{
SDL_Color* p = SPG_ColorPalette();
SDL_SetColors(result, p, 0, 256);
free(p);
}
return result;
}
//returns the closest index into the palette for a given r,g,b color
// Adapted from Meetul Kinarivala, SDL mailing list, 2001
Uint32 SPG_FindPaletteColor(SDL_Palette* palette, Uint8 r, Uint8 g, Uint8 b)
{
SDL_Color* colors = palette->colors;
int Distance, MinDistance = 0xFFFFFF; //init to large value
Uint32 index = 0;
int i;
//find index with minimum spatial distance to given r,g,b
for (i = 0; i < palette->ncolors; ++i)
{
// d = r^2 + g^2 + b^2
Distance = ((int)(colors[i].r)-(int)(r))*((int)(colors[i].r)-(int)(r))
+((int)(colors[i].g)-(int)(g))*((int)(colors[i].g)-(int)(g))
+((int)(colors[i].b)-(int)(b))*((int)(colors[i].b)-(int)(b));
if (MinDistance > Distance)
{
MinDistance = Distance;
index = i;
if(MinDistance == 0)
break; //color match !!
}
}
return index;
}
//converts any surface -> 8 bit indexed, using shared palette
//quality optimized but slow
//returns NULL on error
// Adapted from Meetul Kinarivala, SDL mailing list, 2001
SDL_Surface* SPG_PalettizeSurface(SDL_Surface* surface, SDL_Palette* palette)
{
if(surface == NULL || palette == NULL)
return NULL;
SDL_Surface* result = SDL_CreateRGBSurface(surface->flags, surface->w, surface->h, 8, 0, 0, 0, 0);
if(result == NULL)
return NULL;
int x, y;
Uint8 r, g, b;
for (y=0; y < surface->h; ++y)
{
for (x=0; x < surface->w; ++x)
{
SDL_GetRGB(SPG_GetPixel(surface, x, y), surface->format, &r, &g, &b);
SPG_Pixel(result, x, y, SPG_FindPaletteColor(palette, r, g, b));
}
}
return result;
}
// 32-bit palettes
//==================================================================================
// Fades from (sR,sG,sB) to (dR,dG,dB), puts result in ctab[start] to ctab[stop]
//==================================================================================
void SPG_FadedPalette32(SDL_PixelFormat* format, Uint32 color1, Uint32 color2, Uint32* colorArray, Uint16 startIndex, Uint16 stopIndex)
{
Uint8 sR, sG, sB, dR, dG, dB;
SDL_GetRGB(color1, format, &sR, &sG, &sB);
SDL_GetRGB(color2, format, &dR, &dG, &dB);
// (sR,sG,sB) and (dR,dG,dB) are two points in space (the RGB cube).
/* The vector for the straight line */
int v[3];
v[0]=(int)dR-(int)sR; v[1]=(int)dG-(int)sG; v[2]=(int)dB-(int)sB;
/* Ref. point */
int x0=sR, y0=sG, z0=sB;
// The line's equation is:
// x= x0 + v[0] * t
// y= y0 + v[1] * t
// z= z0 + v[2] * t
//
// (x,y,z) will travel between the two points when t goes from 0 to 1.
int i = startIndex;
float step = 1.0f/((stopIndex+1)-startIndex);
float t;
for(t=0.0f; t<=1.0f && i<=stopIndex ; t+=step){
colorArray[i++]=SDL_MapRGB(format, (Uint8)(x0+v[0]*t), (Uint8)(y0+v[1]*t), (Uint8)(z0+v[2]*t) );
}
}
//==================================================================================
// Fades from (sR,sG,sB,sA) to (dR,dG,dB,dA), puts result in ctab[start] to ctab[stop]
//==================================================================================
void SPG_FadedPalette32Alpha(SDL_PixelFormat* format, Uint32 color1, Uint8 alpha1, Uint32 color2, Uint8 alpha2, Uint32* colorArray, Uint16 startIndex, Uint16 stopIndex)
{
Uint8 sR, sG, sB, dR, dG, dB;
SDL_GetRGB(color1, format, &sR, &sG, &sB);
SDL_GetRGB(color2, format, &dR, &dG, &dB);
// (sR,sG,sB,sA) and (dR,dG,dB,dA) are two points in hyperspace (the RGBA hypercube).
/* The vector for the straight line */
int v[4];
v[0]=(int)dR-(int)sR; v[1]=(int)dG-(int)sG; v[2]=(int)dB-(int)sB; v[3]=(int)alpha2-(int)alpha1;
/* Ref. point */
int x0=sR, y0=sG, z0=sB, w0=alpha1;
// The line's equation is:
// x= x0 + v[0] * t
// y= y0 + v[1] * t
// z= z0 + v[2] * t
// w= w0 + v[3] * t
//
// (x,y,z,w) will travel between the two points when t goes from 0 to 1.
int i = startIndex;
float step = 1.0f/((stopIndex+1)-startIndex);
float t;
for(t=0.0f; t<=1.0f && i<=stopIndex ; t+=step)
colorArray[i++]=SDL_MapRGBA(format, (Uint8)(x0+v[0]*t), (Uint8)(y0+v[1]*t), (Uint8)(z0+v[2]*t), (Uint8)(w0+v[3]*t));
}
//==================================================================================
// Copies a nice rainbow palette to the color table (ctab[start] to ctab[stop]).
// You must also set the intensity of the palette (0-dark 255-bright)
//==================================================================================
void SPG_RainbowPalette32(SDL_PixelFormat* format, Uint32* colorArray, Uint8 intensity, Uint16 startIndex, Uint16 stopIndex)
{
intensity = 255 - intensity;
int slice=(int)((stopIndex-startIndex)/6.0f);
Uint32 red = SDL_MapRGB(format, 255, intensity, intensity),
yellow = SDL_MapRGB(format, 255, 255, intensity),
green = SDL_MapRGB(format, intensity, 255, intensity),
teal = SDL_MapRGB(format, intensity, 255, 255),
blue = SDL_MapRGB(format, intensity, intensity, 255),
purple = SDL_MapRGB(format, 255, intensity, 255);
/* R-Y */
SPG_FadedPalette32(format, red, yellow, colorArray, startIndex, startIndex+slice);
/* Y-G */
SPG_FadedPalette32(format, yellow, green, colorArray, startIndex+slice+1, startIndex+2*slice);
/* G-T */
SPG_FadedPalette32(format, green, teal, colorArray, startIndex+2*slice+1, startIndex+3*slice);
/* T-B */
SPG_FadedPalette32(format, teal, blue, colorArray, startIndex+3*slice+1, startIndex+4*slice);
/* B-P */
SPG_FadedPalette32(format, blue, purple, colorArray, startIndex+4*slice+1, startIndex+5*slice);
/* P-R */
SPG_FadedPalette32(format, purple, red, colorArray, startIndex+5*slice+1, stopIndex);
}
//==================================================================================
// Copies a B&W palette to the color table (ctab[start] to ctab[stop]).
//==================================================================================
void SPG_GrayPalette32(SDL_PixelFormat* format, Uint32* colorArray, Uint16 startIndex, Uint16 stopIndex)
{
SPG_FadedPalette32(format, SDL_MapRGB(format, 0,0,0), SDL_MapRGB(format, 255,255,255), colorArray, startIndex, stopIndex);
}
/**********************************************************************************/
/** Color filling functions **/
/**********************************************************************************/
//==================================================================================
// SPG_FloodFill: Fast non-recursive flood fill
//
// Algorithm originally written by
// Paul Heckbert, 13 Sept 1982, 28 Jan 1987
//==================================================================================
/* horizontal segment of scan line y */
typedef struct seg{
Sint16 y, xl, xr, dy;
}seg;
#define MAXSTACK 1000 /* max depth of stack */
#define PUSH(Y, XL, XR, DY){\
if (sp<stack+MAXSTACK && Y+(DY)>=SPG_CLIP_YMIN(dst) && Y+(DY)<=SPG_CLIP_YMAX(dst)){\
sp->y = Y;\
sp->xl = XL;\
sp->xr = XR;\
sp->dy = DY;\
sp++;\
}\
}
#define POP(Y, XL, XR, DY){\
sp--;\
DY = sp->dy;\
Y = sp->y + sp->dy;\
XL = sp->xl;\
XR = sp->xr;\
}
/*
* set the pixel at (x,y) and all of its 4-connected neighbors
* with the same pixel value to the new pixel color.
* A 4-connected neighbor is a pixel above, below, left, or right of a pixel.
*/
// First a generic (slow) version and then 8/16/32 bpp versions
void _FloodFillX(SDL_Surface *dst, Sint16 x, Sint16 y, Uint32 color)
{
Sint16 l, x1, x2, dy;
Uint32 oc; /* old pixel color */
seg stack[MAXSTACK], *sp = stack; /* stack of filled segments */
if (x<SPG_CLIP_XMIN(dst) || x>SPG_CLIP_XMAX(dst) || y<SPG_CLIP_YMIN(dst) || y>SPG_CLIP_YMAX(dst))
return;
oc = SPG_GetPixel(dst, x,y); /* read color at seed point */
if (oc == color)
return;
PUSH(y, x, x, 1); /* needed in some cases */
PUSH(y+1, x, x, -1); /* seed segment (popped 1st) */
while (sp>stack) {
/* pop segment off stack and fill a neighboring scan line */
POP(y, x1, x2, dy);
/*
* segment of scan line y-dy for x1<=x<=x2 was previously filled,
* now explore adjacent pixels in scan line y
*/
for (x=x1; x>=SPG_CLIP_XMIN(dst); x--){
if( SPG_GetPixel(dst, x,y) != oc )
break;
spg_pixel(dst, x, y, color);
}
if (x>=x1)
goto skip;
l = x+1;
if (l<x1)
PUSH(y, l, x1-1, -dy); /* leak on left? */
x = x1+1;
do {
for (; x<=SPG_CLIP_XMAX(dst); x++){
if( SPG_GetPixel(dst, x,y) != oc )
break;
spg_pixel(dst, x, y, color);
}
PUSH(y, l, x-1, dy);
if (x>x2+1)
PUSH(y, x2+1, x-1, -dy); /* leak on right? */
skip:
for (x++; x<=x2; x++)
if( SPG_GetPixel(dst, x,y) == oc )
break;
l = x;
} while (x<=x2);
}
}
/* Macro for 8/16/32 bpp */
#define DO_FILL(UintXX, label)\
{\
Sint16 l, x1, x2, dy;\
Uint32 oc; /* old pixel color */\
seg stack[MAXSTACK], *sp = stack; /* stack of filled segments */\
Uint16 pitch = dst->pitch/dst->format->BytesPerPixel;\
UintXX *row = (UintXX*)dst->pixels + y*pitch;\
UintXX *pixel = row + x;\
\
if (x<SPG_CLIP_XMIN(dst) || x>SPG_CLIP_XMAX(dst) || y<SPG_CLIP_YMIN(dst) || y>SPG_CLIP_YMAX(dst))\
return;\
\
oc = *pixel; /* read color at seed point */\
\
if (oc == color)\
return;\
\
PUSH(y, x, x, 1); /* needed in some cases */\
PUSH(y+1, x, x, -1); /* seed segment (popped 1st) */\
\
while (sp>stack) {\
/* pop segment off stack and fill a neighboring scan line */\
POP(y, x1, x2, dy);\
row = (UintXX*)dst->pixels + y*pitch;\
pixel = row + x1;\
\
/*\
* segment of scan line y-dy for x1<=x<=x2 was previously filled,
* now explore adjacent pixels in scan line y
*/\
for (x=x1; x>=SPG_CLIP_XMIN(dst) && *pixel == oc; x--, pixel--)\
*pixel = color;\
\
if (x>=x1)\
goto label;\
\
l = x+1;\
if (l<x1)\
PUSH(y, l, x1-1, -dy); /* leak on left? */\
\
x = x1+1;\
pixel = row + x;\
\
do {\
for (; x<=SPG_CLIP_XMAX(dst) && *pixel == oc; x++, pixel++)\
*pixel = color;\
\
PUSH(y, l, x-1, dy);\
\
if (x>x2+1)\
PUSH(y, x2+1, x-1, -dy); /* leak on right? */\
label:\
pixel++;\
\
for (x++; x<=x2 && *pixel != oc; x++, pixel++);\
\
l = x;\
} while (x<=x2);\
}\
}
// Wrapper function
void SPG_FloodFill(SDL_Surface *dst, Sint16 x, Sint16 y, Uint32 color)
{
if ( spg_lock(dst) < 0 )
{
if(spg_useerrors)
SPG_Error("SPG_FloodFill could not lock surface");
return;
}
switch (dst->format->BytesPerPixel) {
case 1: /* Assuming 8-bpp */
DO_FILL(Uint8, skip8)
break;
case 2: /* Probably 15-bpp or 16-bpp */
DO_FILL(Uint16, skip16)
break;
case 3: /* Slow 24-bpp mode, usually not used */
_FloodFillX(dst, x,y, color);
break;
case 4: /* Probably 32-bpp */
DO_FILL(Uint32, skip32)
break;
}
spg_unlock(dst);
}
diff --git a/util/thread.cpp b/util/thread.cpp
index 6550f25f..718354ac 100644
--- a/util/thread.cpp
+++ b/util/thread.cpp
@@ -1,389 +1,389 @@
#include "thread.h"
namespace Util{
namespace Thread{
LockObject::LockObject(){
initializeLock(&lock);
initializeCondition(&condition);
// Global::debug(0) << "Created lock " << lock << std::endl;
// Global::debug(0) << "Created condition " << condition << std::endl;
}
int LockObject::acquire() const {
/* quick hack to get around annoying constness */
return acquireLock((Lock*) &lock);
}
int LockObject::release() const {
return releaseLock((Lock*) &lock);
}
void LockObject::wait() const {
int ok = 1;
while (ok != 0){
/* if conditionWait succeeds then ok will be 0 */
ok = conditionWait((Condition*) &condition, (Lock*) &lock);
}
}
void LockObject::wait(volatile bool & check) const {
int ok = 0;
/* only wait if check is false. if so then keep waiting until the condition
* was successful as well.
*/
while (!check || ok != 0){
if (ok != 0){
// Global::debug(0) << "Wait failed: " << SDL_GetError() << std::endl;
}
ok = conditionWait((Condition*) &condition, (Lock*) &lock);
}
}
void LockObject::signal() const {
conditionSignal((Condition*) &condition);
}
void LockObject::lockAndSignal(volatile bool & check, bool what) const {
acquire();
check = what;
signal();
release();
}
LockObject::~LockObject(){
destroyLock(&lock);
destroyCondition(&condition);
}
ScopedLock::ScopedLock(const LockObject & lock):
lock(lock){
lock.acquire();
}
ScopedLock::~ScopedLock(){
lock.release();
}
bool isUninitialized(Id thread){
return thread == uninitializedValue;
}
ThreadObject::ThreadObject(void * data, void * (function)(void * arg)):
data(data),
function(function),
thread(uninitializedValue){
}
bool ThreadObject::start(){
if (thread == uninitializedValue){
return createThread(&thread, NULL, (Thread::ThreadFunction) function, data);
} else {
return false;
}
}
ThreadObject::~ThreadObject(){
if (thread != uninitializedValue){
joinThread(thread);
thread = uninitializedValue;
}
}
#if defined(USE_SDL) && !defined(USE_NACL)
Id uninitializedValue = NULL;
void initializeLock(Lock * lock){
*lock = SDL_CreateMutex();
}
int acquireLock(Lock * lock){
return SDL_LockMutex(*lock);
}
int releaseLock(Lock * lock){
return SDL_UnlockMutex(*lock);
}
void destroyLock(Lock * lock){
SDL_DestroyMutex(*lock);
}
void initializeCondition(Condition * condition){
*condition = SDL_CreateCond();
if (condition == NULL){
Global::debug(0) << "Could not create condition" << std::endl;
}
}
void destroyCondition(Condition * condition){
SDL_DestroyCond(*condition);
}
int conditionWait(Condition * condition, Lock * lock){
return SDL_CondWait(*condition, *lock);
}
int conditionSignal(Condition * condition){
return SDL_CondBroadcast(*condition);
}
/*
void initializeSemaphore(Semaphore * semaphore, unsigned int value){
*semaphore = SDL_CreateSemaphore(value);
}
void destroySemaphore(Semaphore * semaphore){
SDL_DestroySemaphore(*semaphore);
}
void semaphoreDecrease(Semaphore * semaphore){
SDL_SemWait(*semaphore);
}
void semaphoreIncrease(Semaphore * semaphore){
SDL_SemPost(*semaphore);
}
*/
bool createThread(Id * thread, void * attributes, ThreadFunction function, void * arg){
*thread = SDL_CreateThread(function, arg);
return *thread != NULL;
}
void joinThread(Id thread){
if (!isUninitialized(thread)){
SDL_WaitThread(thread, NULL);
}
}
void cancelThread(Id thread){
-#ifndef PS3
+#if !SDL_VERSION_ATLEAST(1, 3, 0)
SDL_KillThread(thread);
#endif
}
#elif USE_ALLEGRO5
Id uninitializedValue = 0;
void initializeLock(Lock * lock){
*lock = al_create_mutex();
}
int acquireLock(Lock * lock){
al_lock_mutex(*lock);
return 0;
}
int releaseLock(Lock * lock){
al_unlock_mutex(*lock);
return 0;
}
void initializeCondition(Condition * condition){
*condition = al_create_cond();
}
void destroyCondition(Condition * condition){
al_destroy_cond(*condition);
}
int conditionWait(Condition * condition, Lock * lock){
al_wait_cond(*condition, *lock);
return 0;
}
int conditionSignal(Condition * condition){
al_broadcast_cond(*condition);
return 0;
}
struct AllegroThreadStuff{
AllegroThreadStuff(const ThreadFunction & function, void * arg):
function(function),
arg(arg){
}
ThreadFunction function;
void * arg;
};
static void * allegro_start_thread(ALLEGRO_THREAD * self, void * _stuff){
AllegroThreadStuff * stuff = (AllegroThreadStuff*) _stuff;
ThreadFunction function = stuff->function;
void * arg = stuff->arg;
delete stuff;
return function(arg);
}
bool createThread(Id * thread, void * attributes, ThreadFunction function, void * arg){
AllegroThreadStuff * stuff = new AllegroThreadStuff(function, arg);
*thread = al_create_thread(allegro_start_thread, stuff);
if (*thread != NULL){
al_start_thread(*thread);
return true;
} else {
delete stuff;
return false;
}
}
void joinThread(Id thread){
if (!isUninitialized(thread)){
al_join_thread(thread, NULL);
}
}
void cancelThread(Id thread){
al_destroy_thread(thread);
}
void destroyLock(Lock * lock){
al_destroy_mutex(*lock);
}
#else
Id uninitializedValue = 0;
void initializeLock(Lock * lock){
pthread_mutex_init(lock, NULL);
}
int acquireLock(Lock * lock){
return pthread_mutex_lock(lock);
}
int releaseLock(Lock * lock){
return pthread_mutex_unlock(lock);
}
void initializeCondition(Condition * condition){
pthread_cond_init(condition, NULL);
}
void destroyCondition(Condition * condition){
pthread_cond_destroy(condition);
}
int conditionWait(Condition * condition, Lock * lock){
return pthread_cond_wait(condition, lock);
}
int conditionSignal(Condition * condition){
return pthread_cond_broadcast(condition);
}
#if 0
void initializeSemaphore(Semaphore * semaphore, unsigned int value){
sem_init(semaphore, 0, value);
}
void destroySemaphore(Semaphore * semaphore){
/* nothing */
}
void semaphoreDecrease(Semaphore * semaphore){
sem_wait(semaphore);
}
void semaphoreIncrease(Semaphore * semaphore){
sem_post(semaphore);
}
#endif
bool createThread(Id * thread, void * attributes, ThreadFunction function, void * arg){
return pthread_create(thread, (pthread_attr_t*) attributes, function, arg) == 0;
}
void joinThread(Id thread){
if (!isUninitialized(thread)){
pthread_join(thread, NULL);
}
}
void cancelThread(Id thread){
/* FIXME: cancel is not implemented for libogc, find another way.
* thread suspend/resume is there, though.
*/
#if !defined(WII) && !defined(USE_NACL)
pthread_cancel(thread);
#endif
}
void destroyLock(Lock * lock){
/* nothing */
}
#endif
}
WaitThread::WaitThread():
done(false){
Thread::initializeLock(&doneLock);
}
WaitThread::WaitThread(Thread::ThreadFunction thread, void * arg){
Thread::initializeLock(&doneLock);
start(thread, arg);
}
static void * do_thread(void * arg){
WaitThread * thread = (WaitThread *) arg;
thread->doRun();
return NULL;
}
void WaitThread::doRun(){
this->function(this->arg);
Thread::acquireLock(&doneLock);
this->done = true;
Thread::releaseLock(&doneLock);
}
void WaitThread::start(Thread::ThreadFunction thread, void * arg){
done = false;
this->arg = arg;
this->function = thread;
Thread::createThread(&this->thread, NULL, (Thread::ThreadFunction) do_thread, this);
}
bool WaitThread::isRunning(){
Thread::acquireLock(&doneLock);
bool what = done;
Thread::releaseLock(&doneLock);
return what;
}
void WaitThread::kill(){
Thread::cancelThread(thread);
Thread::joinThread(thread);
}
WaitThread::~WaitThread(){
/* FIXME: Should we join the thread? */
/* pthread_join(thread); */
Thread::joinThread(thread);
}
ThreadBoolean::ThreadBoolean(volatile bool & what, Thread::Lock & lock):
what(what),
lock(lock){
}
bool ThreadBoolean::get(){
Thread::acquireLock(&lock);
bool b = what;
Thread::releaseLock(&lock);
return b;
}
void ThreadBoolean::set(bool value){
Thread::acquireLock(&lock);
what = value;
Thread::releaseLock(&lock);
}
}
diff --git a/util/thread.h b/util/thread.h
index 4fca4a78..0207e960 100644
--- a/util/thread.h
+++ b/util/thread.h
@@ -1,290 +1,291 @@
#ifndef _paintown_thread_h
#define _paintown_thread_h
/* FIXME: NACL should be able to use SDL threads but they are broken
* for some reason. SDL is implemented in terms of pthreads anyway
* so for now just use the native pthreads implementation.
*/
#if defined(USE_SDL) && !defined(USE_NACL)
+#include <SDL.h>
#include <SDL_thread.h>
#include <SDL_mutex.h>
#elif USE_ALLEGRO5
#include <allegro5/allegro5.h>
#else
#include <pthread.h>
// #include <semaphore.h>
#endif
#include "exceptions/exception.h"
#include "load_exception.h"
#include "token_exception.h"
#include "mugen/exception.h"
// #include "funcs.h"
#include "debug.h"
namespace Util{
/* Either uses pthreads or SDL_thread */
namespace Thread{
#ifdef USE_SDL
typedef SDL_mutex* Lock;
typedef SDL_Thread* Id;
typedef int (*ThreadFunction)(void*);
typedef SDL_cond* Condition;
// typedef SDL_semaphore* Semaphore;
#elif USE_ALLEGRO5
typedef ALLEGRO_MUTEX* Lock;
typedef ALLEGRO_THREAD* Id;
typedef void * (*ThreadFunction)(void*);
typedef ALLEGRO_COND* Condition;
// typedef SDL_semaphore* Semaphore;
#else
typedef pthread_mutex_t Lock;
typedef pthread_t Id;
typedef pthread_cond_t Condition;
// typedef sem_t Semaphore;
typedef void * (*ThreadFunction)(void*);
#endif
extern Id uninitializedValue;
bool isUninitialized(Id thread);
void initializeLock(Lock * lock);
void initializeCondition(Condition * condition);
void destroyCondition(Condition * condition);
int conditionWait(Condition * condition, Lock * lock);
int conditionSignal(Condition * condition);
/*
void initializeSemaphore(Semaphore * semaphore, unsigned int value);
void destroySemaphore(Semaphore * semaphore);
void semaphoreDecrease(Semaphore * semaphore);
void semaphoreIncrease(Semaphore * semaphore);
*/
int acquireLock(Lock * lock);
int releaseLock(Lock * lock);
void destroyLock(Lock * lock);
bool createThread(Id * thread, void * attributes, ThreadFunction function, void * arg);
void joinThread(Id thread);
void cancelThread(Id thread);
/* wraps a Lock in a c++ class */
class LockObject{
public:
LockObject();
int acquire() const;
int release() const;
Lock & getLock(){
return lock;
}
/* wait until check is true.
* you MUST acquire the lock before calling this function */
void wait(volatile bool & check) const;
/* just until we are signaled
* you MUST acquire the lock before calling this function */
void wait() const;
/* you MUST acquire the lock before calling this function */
void signal() const;
/* gets the lock, sets the boolean, and signals the condition
* you MUST NOT acquire the lock before calling this function
*/
void lockAndSignal(volatile bool & check, bool what) const;
virtual ~LockObject();
Lock lock;
Condition condition;
};
/* acquires/releases the lock in RAII fashion */
class ScopedLock{
public:
ScopedLock(const LockObject & lock);
~ScopedLock();
private:
const LockObject & lock;
};
class ThreadObject{
public:
ThreadObject(void * data, void * (function)(void * arg));
/* true if the thread was started, false otherwise */
virtual bool start();
virtual ~ThreadObject();
protected:
void * data;
void * (*function)(void * arg);
Id thread;
};
}
class WaitThread{
public:
/* does not start a new thread yet */
WaitThread();
/* starts a thread */
WaitThread(Thread::ThreadFunction thread, void * arg);
/* starts a thread */
void start(Thread::ThreadFunction thread, void * arg);
bool isRunning();
void kill();
virtual ~WaitThread();
public:
/* actually runs the thread */
void doRun();
protected:
Thread::Lock doneLock;
Thread::Id thread;
volatile bool done;
void * arg;
Thread::ThreadFunction function;
};
/* wraps a boolean with lock/unlock while checking/setting it */
class ThreadBoolean{
public:
ThreadBoolean(volatile bool & what, Thread::Lock & lock);
bool get();
void set(bool value);
protected:
volatile bool & what;
Thread::Lock & lock;
};
/* Computes stuff in a separate thread and gives it back when you ask for it.
* As soon as the future is created a thread will start executing and compute
* whatever it is that the class is supposed to do. You can then call `get'
* on the future object to get the result. If the thread is still executing
* then `get' will block until the future completes. If the future has already
* completed then `get' will return immediately with the computed value.
* The use case is computing something that has to be used later:
* Future future; // might take a while to compute
* do_stuff_that_takes_a_while(); // future might finish sometime in here
* Object o = future.get(); // future is already done
*
* TODO: handle exceptions
*/
template<class X>
class Future{
protected:
/* WARNING: hack to find out the type of the exception */
/*
enum ExceptionType{
None,
Load,
Token,
Base,
Mugen
};
*/
public:
Future():
thing(0),
thread(Thread::uninitializedValue),
done(false),
exception(NULL){
/* future will increase the count */
// Thread::initializeSemaphore(&future, 0);
// future.acquire();
}
virtual ~Future(){
if (Thread::isUninitialized(thread)){
Thread::joinThread(thread);
}
// Thread::destroySemaphore(&future);
delete exception;
}
virtual X get(){
X out;
Exception::Base * failed = NULL;
future.acquire();
future.wait(done);
// Thread::semaphoreDecrease(&future);
if (exception != NULL){
failed = exception;
// exception->throwSelf();
}
out = thing;
// Thread::semaphoreIncrease(&future);
future.release();
if (failed){
failed->throwSelf();
}
return out;
}
virtual void start(){
if (!Thread::createThread(&thread, NULL, (Thread::ThreadFunction) runit, this)){
Global::debug(0) << "Could not create future thread. Blocking until its done" << std::endl;
runit(this);
// throw Exception::Base(__FILE__, __LINE__);
}
}
protected:
bool isDone(){
Thread::ScopedLock scoped(future);
return done;
}
static void * runit(void * arg){
Future<X> * me = (Future<X>*) arg;
try{
me->compute();
} catch (const LoadException & load){
me->exception = new LoadException(load);
} catch (const TokenException & t){
me->exception = new TokenException(t);
} catch (const MugenException & m){
me->exception = new MugenException(m);
} catch (const Exception::Base & base){
me->exception = new Exception::Base(base);
}
me->future.lockAndSignal(me->done, true);
/*
me->future.acquire();
me->done = true;
me->future.signal();
me->future.release();
*/
// Thread::semaphoreIncrease(&me->future);
return NULL;
}
virtual void set(X x){
this->thing = x;
}
virtual void compute() = 0;
X thing;
Thread::Id thread;
Thread::LockObject future;
volatile bool done;
/* if any exceptions occur, throw them from `get' */
Exception::Base * exception;
};
}
#endif

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jun 11, 10:02 AM (3 w, 5 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
68260
Default Alt Text
(299 KB)

Event Timeline