Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
177 KB
Referenced Files
None
Subscribers
None
diff --git a/util/sdl/bitmap.cpp b/util/sdl/bitmap.cpp
index 5d073f04..9eff2f47 100644
--- a/util/sdl/bitmap.cpp
+++ b/util/sdl/bitmap.cpp
@@ -1,1896 +1,1925 @@
#include "../bitmap.h"
#include "../lit_bitmap.h"
#include "../trans-bitmap.h"
#include "../funcs.h"
#include "../../util/debug.h"
#include "../system.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>
class BitmapException: public Exception::Base {
public:
BitmapException(const std::string & file, int line, const std::string & reason):
Base(file, line),
reason(reason){
}
BitmapException(const BitmapException & copy):
Base(copy),
reason(copy.reason){
}
virtual void throwSelf() const {
throw *this;
}
virtual ~BitmapException() throw () {
}
protected:
virtual const std::string getReason() const {
return reason;
}
std::string reason;
};
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(Bitmap::makeColor(r, g, b), y, n);
}
static inline unsigned int addBlender(unsigned int x, unsigned int y, unsigned int n){
Uint8 redX = 0;
Uint8 greenX = 0;
Uint8 blueX = 0;
SDL_GetRGB(x, &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 Bitmap::makeColor(r, g, b);
}
static inline int iabs(int x){
return x < 0 ? -x : x;
}
static inline unsigned int differenceBlender(unsigned int x, unsigned int y, unsigned int n){
Uint8 redX = 0;
Uint8 greenX = 0;
Uint8 blueX = 0;
SDL_GetRGB(x, &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(Bitmap::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(Bitmap::makeColor(r, g, b), y, n);
}
static inline unsigned int noBlender(unsigned int a, unsigned int b, unsigned int c){
return a;
}
struct BlendingData{
BlendingData():
red(0), green(0), blue(0), alpha(0), currentBlender(noBlender){}
int red, green, blue, alpha;
blender currentBlender;
};
static BlendingData globalBlend;
static int drawingMode = Bitmap::MODE_SOLID;
static int drawingAlpha(){
switch (::drawingMode){
case Bitmap::MODE_SOLID : return 255;
case Bitmap::MODE_TRANS : return globalBlend.alpha;
default : return 255;
}
}
static void paintown_applyTrans16(SDL_Surface * dst, const int color);
static void paintown_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 Bitmap::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;
}
Bitmap * Bitmap::Screen = NULL;
static Bitmap * Scaler = NULL;
static Bitmap * Buffer = NULL;
void BitmapData::setSurface(SDL_Surface * surface){
this->surface = surface;
clip_left = 0;
clip_top = 0;
if (surface){
clip_right = surface->w;
clip_bottom = surface->h;
} else {
clip_right = 0;
clip_bottom = 0;
}
}
Bitmap::Bitmap():
own(NULL),
mustResize(false),
bit8MaskColor(0){
/* TODO */
}
Bitmap::Bitmap(const char * data, int length):
own(NULL),
mustResize(false),
bit8MaskColor(0){
SDL_RWops * ops = SDL_RWFromConstMem(data, length);
SDL_Surface * loaded = IMG_Load_RW(ops, 1);
if (loaded){
getData().setSurface(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());
}
own = new int;
*own = 1;
}
Bitmap::Bitmap(SDL_Surface * who, bool deep_copy):
own(NULL),
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);
getData().setSurface(surface);
own = new int;
*own = 1;
} else {
getData().setSurface(who);
}
}
Bitmap::Bitmap(int w, int h):
mustResize(false),
bit8MaskColor(0){
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());
}
getData().setSurface(surface);
own = new int;
*own = 1;
}
Bitmap::Bitmap( const char * load_file ):
own(NULL),
mustResize(false),
bit8MaskColor(0){
internalLoadFile(load_file);
}
Bitmap::Bitmap( const std::string & load_file ):
own(NULL),
mustResize(false){
internalLoadFile(load_file.c_str());
}
Bitmap::Bitmap( const char * load_file, int sx, int sy ):
own(NULL),
mustResize(false),
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);
getData().setSurface(surface);
own = new int;
*own = 1;
temp.Stretch(*this);
}
/* unused */
Bitmap::Bitmap( const char * load_file, int sx, int sy, double accuracy ):
own(NULL),
mustResize(false),
bit8MaskColor(0){
throw BitmapException(__FILE__, __LINE__, "Unimplemented constructor");
}
Bitmap::Bitmap( const Bitmap & copy, bool deep_copy):
own(NULL),
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);
getData().setSurface(surface);
own = new int;
*own = 1;
} else {
getData().setSurface(copy.getData().getSurface());
own = copy.own;
if (own){
*own += 1;
}
}
}
Bitmap::Bitmap( const Bitmap & copy, int sx, int sy ):
own(NULL),
mustResize(false),
bit8MaskColor(copy.bit8MaskColor){
/* TODO */
}
Bitmap::Bitmap( const Bitmap & copy, int sx, int sy, double accuracy ):
own(NULL),
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 ):
own(NULL),
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);
getData().setSurface(sub);
own = new int;
*own = 1;
}
void Bitmap::internalLoadFile(const char * path){
this->path = path;
SDL_Surface * loaded = IMG_Load(path);
if (loaded){
getData().setSurface(optimizedSurface(loaded));
SDL_FreeSurface(loaded);
} else {
std::ostringstream out;
out << "Could not load file '" << path << "'";
throw BitmapException(__FILE__, __LINE__, out.str());
}
own = new int;
*own = 1;
}
int Bitmap::getWidth() const {
if (getData().getSurface() != NULL){
return getData().getSurface()->w;
}
return 0;
}
int Bitmap::getHeight() const {
if (getData().getSurface() != NULL){
return getData().getSurface()->h;
}
return 0;
}
int Bitmap::getRed(int c){
Uint8 red = 0;
Uint8 green = 0;
Uint8 blue = 0;
SDL_GetRGB(c, &format565, &red, &green, &blue);
return red;
}
int Bitmap::getBlue(int c){
Uint8 red = 0;
Uint8 green = 0;
Uint8 blue = 0;
SDL_GetRGB(c, &format565, &red, &green, &blue);
return blue;
}
int Bitmap::getGreen(int c){
Uint8 red = 0;
Uint8 green = 0;
Uint8 blue = 0;
SDL_GetRGB(c, &format565, &red, &green, &blue);
return green;
}
int Bitmap::makeColor(int red, int blue, int green){
return SDL_MapRGB(&format565, red, blue, green);
}
void Bitmap::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
format565.colorkey = 0;
format565.alpha = 255;
#endif
}
int Bitmap::setGraphicsMode(int mode, int width, int height){
initializeExtraStuff();
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
" 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);
Scaler = new Bitmap(width, height);
/*
if ( width != 0 && height != 0 && (width != SCALE_X || height != SCALE_Y) ){
Scaler = new Bitmap(width, height);
Buffer = new Bitmap(SCALE_X, SCALE_Y);
}
*/
}
for (std::vector<Bitmap*>::iterator it = needResize.begin(); it != needResize.end(); it++){
Bitmap * who = *it;
who->resize(width, height);
}
return 0;
}
void Bitmap::shutdown(){
delete Screen;
Screen = NULL;
delete Scaler;
Scaler = NULL;
delete Buffer;
Buffer = NULL;
}
void Bitmap::addBlender( int r, int g, int b, int a ){
globalBlend.red = r;
globalBlend.green = g;
globalBlend.blue = b;
globalBlend.alpha = a;
globalBlend.currentBlender = ::addBlender;
}
void Bitmap::multiplyBlender( int r, int g, int b, int a ){
globalBlend.red = r;
globalBlend.green = g;
globalBlend.blue = b;
globalBlend.alpha = a;
globalBlend.currentBlender = ::multiplyBlender;
}
void Bitmap::differenceBlender( int r, int g, int b, int a ){
globalBlend.red = r;
globalBlend.green = g;
globalBlend.blue = b;
globalBlend.alpha = a;
globalBlend.currentBlender = ::differenceBlender;
}
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 = ::burnBlender;
}
Bitmap & Bitmap::operator=(const Bitmap & copy){
releaseInternalBitmap();
path = copy.getPath();
getData().setSurface(copy.getData().getSurface());
// own = false;
own = copy.own;
if (own)
*own += 1;
return *this;
}
int Bitmap::setGfxModeText(){
/* TODO */
return 0;
}
int Bitmap::setGfxModeFullscreen(int x, int y){
return setGraphicsMode(FULLSCREEN, x, y);
}
int Bitmap::setGfxModeWindowed( int x, int y ){
return setGraphicsMode(WINDOWED, x, y);
}
void Bitmap::drawingMode(int type){
::drawingMode = type;
}
void Bitmap::transBlender( int r, int g, int b, int a ){
globalBlend.red = r;
globalBlend.green = g;
globalBlend.blue = b;
globalBlend.alpha = a;
globalBlend.currentBlender = ::transBlender;
}
void Bitmap::setClipRect( int x1, int y1, int x2, int y2 ) const {
SDL_Rect area;
area.x = x1;
area.y = y1;
area.w = x2 - x1;
area.h = y2 - y1;
SDL_SetClipRect(getData().getSurface(), &area);
SDL_GetClipRect(getData().getSurface(), &area);
getData().setClip(area.x, area.y, area.x + area.w, area.y + area.h);
}
void Bitmap::getClipRect(int & x1, int & y1, int & x2, int & y2) const {
x1 = getData().clip_left;
y1 = getData().clip_top;
x2 = getData().clip_right;
y2 = getData().clip_bottom;
}
void Bitmap::destroyPrivateData(){
SDL_FreeSurface(getData().getSurface());
}
static void doPutPixel(SDL_Surface * surface, int x, int y, int pixel, bool translucent){
if (SDL_MUSTLOCK(surface)){
SDL_LockSurface(surface);
}
int bpp = surface->format->BytesPerPixel;
/* Here p is the address to the pixel we want to set */
Uint8 *p = computeOffset(surface, x, y);
switch(bpp) {
case 1:
*p = pixel;
break;
case 2:
if (translucent){
*(Uint16 *)p = globalBlend.currentBlender(pixel, *(Uint16*)p, globalBlend.alpha);
} else {
*(Uint16 *)p = pixel;
}
break;
case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
p[0] = (pixel >> 16) & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = pixel & 0xff;
} else {
p[0] = pixel & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = (pixel >> 16) & 0xff;
}
break;
case 4:
*(Uint32 *)p = pixel;
break;
}
if (SDL_MUSTLOCK(surface)){
SDL_UnlockSurface(surface);
}
}
void Bitmap::putPixel(int x, int y, int pixel) const {
/* clip it */
if (getData().isClipped(x, y)){
return;
}
SDL_Surface * surface = getData().getSurface();
doPutPixel(surface, x, y, pixel, false);
}
void Bitmap::putPixelNormal(int x, int y, int col) const {
putPixel(x, y, col);
}
void TranslucentBitmap::putPixelNormal(int x, int y, int color) const {
if (getData().isClipped(x, y)){
return;
}
SDL_Surface * surface = getData().getSurface();
doPutPixel(surface, x, y, color, true);
}
bool Bitmap::getError(){
/* TODO */
return false;
}
void Bitmap::rectangle( int x1, int y1, int x2, int y2, int color ) const {
SPG_Rect(getData().getSurface(), x1, y1, x2, y2, color);
}
void TranslucentBitmap::rectangle( int x1, int y1, int x2, int y2, int color ) const {
int alpha = globalBlend.alpha;
SPG_RectBlend(getData().getSurface(), x1, y1, x2, y2, color, alpha);
}
void Bitmap::rectangleFill( int x1, int y1, int x2, int y2, int color ) const {
SPG_RectFilled(getData().getSurface(), x1, y1, x2, y2, color);
}
void TranslucentBitmap::rectangleFill(int x1, int y1, int x2, int y2, int color) const {
int alpha = globalBlend.alpha;
SPG_RectFilledBlend(getData().getSurface(), x1, y1, x2, y2, color, alpha);
}
void Bitmap::circleFill(int x, int y, int radius, int color) const {
switch (::drawingMode){
case MODE_SOLID : {
SPG_CircleFilled(getData().getSurface(), x, y, radius, color);
break;
}
case MODE_TRANS : {
int alpha = globalBlend.alpha;
SPG_CircleFilledBlend(getData().getSurface(), x, y, radius, color, alpha);
break;
}
}
}
void 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;
switch (::drawingMode){
case MODE_SOLID : {
SPG_Circle(getData().getSurface(), x, y, radius, color);
break;
}
case MODE_TRANS : {
int alpha = globalBlend.alpha;
SPG_CircleBlend(getData().getSurface(), x, y, radius, color, alpha);
break;
}
}
// circleRGBA(getData().getSurface(), x, y, radius, red, green, blue, alpha);
}
void Bitmap::line( const int x1, const int y1, const int x2, const int y2, const int color ) const {
switch (::drawingMode){
case MODE_SOLID : {
SPG_Line(getData().getSurface(), x1, y1, x2, y2, color);
break;
}
case MODE_TRANS : {
int alpha = globalBlend.alpha;
SPG_LineBlend(getData().getSurface(), x1, y1, x2, y2, color, alpha);
break;
}
}
}
void Bitmap::draw(const int x, const int y, const Bitmap & where) const {
if (getData().getSurface() != NULL){
paintown_draw_sprite_ex16(where.getData().getSurface(), getData().getSurface(), x, y, Bitmap::SPRITE_NORMAL, Bitmap::SPRITE_NO_FLIP, 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, Bitmap::SPRITE_NORMAL, Bitmap::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, Bitmap::SPRITE_NORMAL, Bitmap::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, Bitmap::SPRITE_NORMAL, Bitmap::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, Bitmap::SPRITE_NORMAL, Bitmap::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, Bitmap::SPRITE_NORMAL, Bitmap::SPRITE_V_FLIP | Bitmap::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, Bitmap::SPRITE_NORMAL, Bitmap::SPRITE_V_FLIP | Bitmap::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, Bitmap::SPRITE_TRANS, Bitmap::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, Bitmap::SPRITE_TRANS, Bitmap::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, Bitmap::SPRITE_TRANS, Bitmap::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, Bitmap::SPRITE_TRANS, Bitmap::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, Bitmap::SPRITE_TRANS, Bitmap::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, Bitmap::SPRITE_TRANS, Bitmap::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, Bitmap::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, Bitmap::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);
}
}
void Bitmap::Blit( const Bitmap & where ) const {
Blit(0, 0, where);
}
void Bitmap::Blit( const int x, const int y, const Bitmap & where ) const {
Blit(0, 0, x, y, where);
}
void Bitmap::Blit( const int mx, const int my, const int wx, const int wy, const Bitmap & where ) const {
Blit(mx, my, getWidth(), getHeight(), wx, wy, where);
}
static void doBlit(SDL_Surface * mine, const int mx, const int my, const int width, const int height, const int wx, const int wy, const Bitmap & where ){
SDL_Rect source;
SDL_Rect destination;
source.w = width;
source.h = height;
source.x = mx;
source.y = my;
destination.w = width;
destination.h = height;
destination.x = wx;
destination.y = wy;
SDL_BlitSurface(mine, &source, where.getData().getSurface(), &destination);
}
void Bitmap::Blit( const int mx, const int my, const int width, const int height, const int wx, const int wy, const Bitmap & where ) const {
SDL_SetColorKey(getData().getSurface(), 0, MaskColor());
doBlit(getData().getSurface(), mx, my, width, height, wx, wy, where);
/* FIXME: this is a hack, maybe put a call here for the other bitmap to update stuff
* like where->Blitted()
*/
if (&where == Screen){
SDL_Flip(Screen->getData().getSurface());
}
}
void Bitmap::BlitMasked( const int mx, const int my, const int width, const int height, const int wx, const int wy, const Bitmap & where ) const {
SDL_SetColorKey(getData().getSurface(), SDL_SRCCOLORKEY, MaskColor());
doBlit(getData().getSurface(),mx, my, width, height, wx, wy, where);
/* FIXME: this is a hack, maybe put a call here for the other bitmap to update stuff
* like where->Blitted()
*/
if (&where == Screen){
SDL_Flip(Screen->getData().getSurface());
}
}
void Bitmap::BlitToScreen(const int upper_left_x, const int upper_left_y) const {
if (getWidth() != Screen->getWidth() || getHeight() != Screen->getHeight()){
/*
this->Blit( upper_left_x, upper_left_y, *Buffer );
Buffer->Stretch(*Scaler);
Scaler->Blit(0, 0, 0, 0, *Screen);
*/
this->Stretch(*Scaler, 0, 0, getWidth(), getHeight(), upper_left_x, upper_left_y, Scaler->getWidth(), Scaler->getHeight());
Scaler->Blit(0, 0, 0, 0, *Screen);
} else {
this->Blit( upper_left_x, upper_left_y, *Screen );
}
/*
if ( Scaler == NULL ){
this->Blit( upper_left_x, upper_left_y, *Screen );
} else {
this->Blit( upper_left_x, upper_left_y, *Buffer );
Buffer->Stretch(*Scaler);
Scaler->Blit(0, 0, 0, 0, *Screen);
}
*/
// SDL_Flip(Screen->getData().getSurface());
// SDL_UpdateRect(Screen->getData().getSurface(), 0, 0, Screen->getWidth(), Screen->getHeight());
}
void Bitmap::BlitAreaToScreen(const int upper_left_x, const int upper_left_y) const {
if ( Scaler != NULL ){
double mult_x = (double) Scaler->getWidth() / (double) SCALE_X;
double mult_y = (double) Scaler->getHeight() / (double) SCALE_Y;
int x = (int)(upper_left_x * mult_x);
int y = (int)(upper_left_y * mult_y);
int w = (int)(this->getWidth() * mult_x);
int h = (int)(this->getHeight() * mult_y);
// printf("ux %d uy %d uw %d uh %d. x %d y %d w %d h %d\n", upper_left_x, upper_left_y, getWidth(), getHeight(), x, y, w, h );
this->Stretch( *Scaler, 0, 0, this->getWidth(), this->getHeight(), x, y, w, h );
Bitmap tmp(*Scaler, x, y, w, h );
tmp.Blit( x, y, *Screen );
// Scaler->Blit( x, y, w, h, *Screen );
} else {
this->Blit( upper_left_x, upper_left_y, *Screen );
}
}
void Bitmap::Stretch( const Bitmap & where ) const {
if (getWidth() == where.getWidth() && getHeight() == where.getHeight()){
Blit(where);
} else {
Stretch(where, 0, 0, getWidth(), getHeight(), 0, 0, where.getWidth(), where.getHeight());
}
}
void Bitmap::Stretch( const Bitmap & where, const int sourceX, const int sourceY, const int sourceWidth, const int sourceHeight, const int destX, const int destY, const int destWidth, const int destHeight ) const {
+ 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 {
switch (::drawingMode){
case MODE_SOLID : {
SPG_TrigonFilled(getData().getSurface(), x1, y1, x2, y2, x3, y3, color);
break;
}
case MODE_TRANS : {
int alpha = globalBlend.alpha;
SPG_TrigonFilledBlend(getData().getSurface(), x1, y1, x2, y2, x3, y3, color, alpha);
break;
}
}
}
void Bitmap::ellipse( int x, int y, int rx, int ry, int color ) const {
switch (::drawingMode){
case MODE_SOLID : {
SPG_Ellipse(getData().getSurface(), x, y, rx, ry, color);
break;
}
case MODE_TRANS : {
int alpha = globalBlend.alpha;
SPG_EllipseBlend(getData().getSurface(), x, y, rx, ry, color, alpha);
break;
}
}
}
void 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;
}
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, ang1, ang2, color);
}
void Bitmap::fill(int color) const {
SDL_Rect area;
area.x = 0;
area.y = 0;
area.w = getWidth();
area.h = getHeight();
SDL_FillRect(getData().getSurface(), &area, color);
}
/*
void TranslucentBitmap::fill(int color) const {
rectangleFill(0, 0, getWidth(), getHeight(), color);
}
*/
int Bitmap::darken( int color, double factor ){
int r = (int)((double)getRed(color) / factor);
int g = (int)((double)getGreen(color) / factor);
int b = (int)((double)getBlue(color) / factor);
return makeColor(r, g, b);
}
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(int original, int replaced){
paintown_replace16(getData().getSurface(), original, replaced);
}
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);
#ifndef PS3
if (pcx->format->BitsPerPixel == 8){
SDL_Color color = pcx->format->palette->colors[pcx->format->colorkey];
int bad = makeColor(color.r, color.g, color.b);
out.set8BitMaskColor(bad);
// int mask = MaskColor();
// out.replaceColor(bad, mask);
}
#endif
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, Bitmap::SPRITE_NORMAL, Bitmap::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, Bitmap::SPRITE_LIT, Bitmap::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, Bitmap::SPRITE_LIT, Bitmap::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, Bitmap::SPRITE_LIT, Bitmap::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, Bitmap::SPRITE_LIT, Bitmap::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, Bitmap::SPRITE_LIT, Bitmap::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, Bitmap::SPRITE_LIT, Bitmap::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 = Bitmap::makeColor(255, 0, 255);
for (int y = y1; y < y2; y++) {
Uint8 * sourceLine = computeOffset(dst, x1, y);
for (int x = x2 - 1; x >= x1; sourceLine += bpp, x--) {
unsigned long sourcePixel = *(Uint16*) sourceLine;
if (!(sourcePixel == mask)){
sourcePixel = globalBlend.currentBlender(color, sourcePixel, globalBlend.alpha);
*(Uint16 *)sourceLine = sourcePixel;
}
}
}
}
static void paintown_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 = Bitmap::makeColor(255, 0, 255);
int bpp = src->format->BytesPerPixel;
for (y = 0; y < h; y++) {
Uint8 * sourceLine = computeOffset(src, sxbeg, sybeg + y);
Uint8 * destLine = computeOffset(dst, dxbeg, dybeg + y * y_dir);
for (x = w - 1; x >= 0; sourceLine += bpp, destLine += bpp * x_dir, x--) {
unsigned long sourcePixel = *(Uint16*) sourceLine;
if (!(sourcePixel == mask)){
*(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 & Bitmap::SPRITE_V_FLIP ){
y_dir = -1;
}
if ( flip & Bitmap::SPRITE_H_FLIP ){
x_dir = -1;
}
if (true /* dst->clip*/ ) {
int tmp;
tmp = dst->clip_rect.x - dx;
sxbeg = ((tmp < 0) ? 0 : tmp);
dxbeg = sxbeg + dx;
tmp = dst->clip_rect.x + dst->clip_rect.w - dx;
w = ((tmp > src->w) ? src->w : tmp) - sxbeg;
if (w <= 0)
return;
if ( flip & Bitmap::SPRITE_H_FLIP ){
/* use backward drawing onto dst */
sxbeg = src->w - (sxbeg + w);
dxbeg += w - 1;
}
tmp = dst->clip_rect.y - dy;
sybeg = ((tmp < 0) ? 0 : tmp);
dybeg = sybeg + dy;
tmp = dst->clip_rect.y + dst->clip_rect.h - dy;
h = ((tmp > src->h) ? src->h : tmp) - sybeg;
if (h <= 0)
return;
if ( flip & Bitmap::SPRITE_V_FLIP ){
/* use backward drawing onto dst */
sybeg = src->h - (sybeg + h);
dybeg += h - 1;
}
} else {
w = src->w;
h = src->h;
sxbeg = 0;
sybeg = 0;
dxbeg = dx;
if ( flip & Bitmap::SPRITE_H_FLIP ){
dxbeg = dx + w - 1;
}
dybeg = dy;
if ( flip & Bitmap::SPRITE_V_FLIP ){
dybeg = dy + h - 1;
}
}
/*
lit_blender = PAINTOWN_MAKE_DLS_BLENDER(0);
trans_blender = PAINTOWN_MAKE_DTS_BLENDER();
*/
#if 0
if (dst->id & (BMP_ID_VIDEO | BMP_ID_SYSTEM)) {
bmp_select(dst);
switch (mode){
case Bitmap::SPRITE_NORMAL : {
for (y = 0; y < h; y++) {
PAINTOWN_PIXEL_PTR s = PAINTOWN_OFFSET_PIXEL_PTR(src->line[sybeg + y], sxbeg);
PAINTOWN_PIXEL_PTR d = PAINTOWN_OFFSET_PIXEL_PTR(bmp_write_line(dst, dybeg + y * y_dir), dxbeg);
for (x = w - 1; x >= 0; PAINTOWN_INC_PIXEL_PTR(s), PAINTOWN_INC_PIXEL_PTR_EX(d,x_dir), x--) {
unsigned long c = PAINTOWN_GET_MEMORY_PIXEL(s);
if (!PAINTOWN_IS_SPRITE_MASK(src, c)) {
PAINTOWN_PUT_PIXEL(d, c);
}
}
}
break;
}
case Bitmap::SPRITE_LIT : {
for (y = 0; y < h; y++) {
PAINTOWN_PIXEL_PTR s = PAINTOWN_OFFSET_PIXEL_PTR(src->line[sybeg + y], sxbeg);
PAINTOWN_PIXEL_PTR d = PAINTOWN_OFFSET_PIXEL_PTR(bmp_write_line(dst, dybeg + y * y_dir), dxbeg);
for (x = w - 1; x >= 0; PAINTOWN_INC_PIXEL_PTR(s), PAINTOWN_INC_PIXEL_PTR_EX(d,x_dir), x--) {
unsigned long c = PAINTOWN_GET_MEMORY_PIXEL(s);
if (!PAINTOWN_IS_SPRITE_MASK(src, c)) {
c = PAINTOWN_DLSX_BLEND(lit_blender, c);
PAINTOWN_PUT_PIXEL(d, c);
}
}
}
break;
}
case Bitmap::SPRITE_TRANS : {
for (y = 0; y < h; y++) {
PAINTOWN_PIXEL_PTR s = PAINTOWN_OFFSET_PIXEL_PTR(src->line[sybeg + y], sxbeg);
PAINTOWN_PIXEL_PTR d = PAINTOWN_OFFSET_PIXEL_PTR(bmp_write_line(dst, dybeg + y * y_dir), dxbeg);
for (x = w - 1; x >= 0; PAINTOWN_INC_PIXEL_PTR(s), PAINTOWN_INC_PIXEL_PTR_EX(d,x_dir), x--) {
unsigned long c = PAINTOWN_GET_MEMORY_PIXEL(s);
if (!PAINTOWN_IS_SPRITE_MASK(src, c)) {
c = PAINTOWN_DTS_BLEND(trans_blender, PAINTOWN_GET_PIXEL(d), c);
PAINTOWN_PUT_PIXEL(d, c);
}
}
}
break;
}
}
#xendif
for (y = 0; y < h; y++) {
PAINTOWN_PIXEL_PTR s = PAINTOWN_OFFSET_PIXEL_PTR(src->line[sybeg + y], sxbeg);
/* flipped if y_dir is -1 */
PAINTOWN_PIXEL_PTR d = PAINTOWN_OFFSET_PIXEL_PTR(bmp_write_line(dst, dybeg + y * y_dir), dxbeg);
/* d is incremented by x_dir, -1 if flipped */
for (x = w - 1; x >= 0; PAINTOWN_INC_PIXEL_PTR(s), PAINTOWN_INC_PIXEL_PTR_EX(d,x_dir), x--) {
unsigned long c = PAINTOWN_GET_MEMORY_PIXEL(s);
if (!PAINTOWN_IS_SPRITE_MASK(src, c)) {
switch( mode ){
case Bitmap::SPRITE_NORMAL : break;
case Bitmap::SPRITE_LIT : {
c = PAINTOWN_DLSX_BLEND(lit_blender, c);
break;
}
case Bitmap::SPRITE_TRANS : {
c = PAINTOWN_DTS_BLEND(trans_blender, PAINTOWN_GET_PIXEL(d), c);
break;
}
}
PAINTOWN_PUT_PIXEL(d, c);
}
}
}
bmp_unwrite_line(dst);
}
else {
#endif
{
switch (mode){
case Bitmap::SPRITE_NORMAL : {
unsigned int mask = Bitmap::makeColor(255, 0, 255);
int bpp = src->format->BytesPerPixel;
for (y = 0; y < h; y++) {
Uint8 * sourceLine = computeOffset(src, sxbeg, sybeg + y);
Uint8 * destLine = computeOffset(dst, dxbeg, dybeg + y * y_dir);
for (x = w - 1; x >= 0; sourceLine += bpp, destLine += bpp * x_dir, x--) {
unsigned long sourcePixel = *(Uint16*) sourceLine;
if (!(sourcePixel == mask)){
// unsigned int destPixel = *(Uint16*) destLine;
// sourcePixel = globalBlend.currentBlender(destPixel, sourcePixel, globalBlend.alpha);
if (filter != NULL){
*(Uint16 *)destLine = filter->filter(sourcePixel);
} else {
*(Uint16 *)destLine = sourcePixel;
}
}
}
}
break;
}
case Bitmap::SPRITE_LIT : {
int bpp = src->format->BytesPerPixel;
int litColor = Bitmap::makeColor(globalBlend.red, globalBlend.green, globalBlend.blue);
unsigned int mask = Bitmap::makeColor(255, 0, 255);
for (y = 0; y < h; y++) {
Uint8 * sourceLine = computeOffset(src, sxbeg, sybeg + y);
Uint8 * destLine = computeOffset(dst, dxbeg, dybeg + y * y_dir);
for (x = w - 1; x >= 0; sourceLine += bpp, destLine += bpp * x_dir, x--) {
unsigned long sourcePixel = *(Uint16*) sourceLine;
if (!(sourcePixel == mask)){
// unsigned int destPixel = *(Uint16*) destLine;
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 Bitmap::SPRITE_TRANS : {
int bpp = src->format->BytesPerPixel;
unsigned int mask = Bitmap::makeColor(255, 0, 255);
for (y = 0; y < h; y++) {
Uint8 * sourceLine = computeOffset(src, sxbeg, sybeg + y);
Uint8 * destLine = computeOffset(dst, dxbeg, dybeg + y * y_dir);
for (x = w - 1; x >= 0; sourceLine += bpp, destLine += bpp * x_dir, x--) {
unsigned long sourcePixel = *(Uint16*) sourceLine;
if (!(sourcePixel == mask)){
unsigned int destPixel = *(Uint16*) destLine;
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);
}
Util::blend_palette(colors, width, focus_color, edge_color);
if (SDL_MUSTLOCK(dst)){
SDL_LockSurface(dst);
}
int min_y, max_y, min_x, max_x;
min_y = dst->clip_rect.y;
max_y = dst->clip_rect.y + dst->clip_rect.h - 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);
}
}
diff --git a/util/sdl/stretch/SDL_stretch.h b/util/sdl/stretch/SDL_stretch.h
new file mode 100644
index 00000000..5c0ea6de
--- /dev/null
+++ b/util/sdl/stretch/SDL_stretch.h
@@ -0,0 +1,88 @@
+/*
+ SDL_stretch - Stretch Functions For The Simple DirectMedia Layer
+ Copyright (C) 2003 Guido Draheim
+
+ 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Guido Draheim, guidod@gmx.de
+*/
+
+#ifndef _SDL_stretch_h
+#define _SDL_stretch_h
+
+#include "SDL_video.h"
+#ifndef _SDL_video_h
+#include <SDL/SDL_video.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef DECLSPEC
+#define DECLSPEC
+#endif
+
+/** Perform a stretch blit between two surfaces of the same format.
+ * NOTE: This function is not safe to call from multiple threads!
+ *
+ * This function will stretch a srcrect smoothly to the full area of
+ * the dst surface. If no srcrect is given then the full area of the
+ * src surface is stretched smoothly to the full dst surface. The
+ * dstrect is ignored always.
+ *
+ * This function will also watch for a clip rectangle on the src
+ * surface. This may speed up handling in your programs by creating
+ * a larger src surface with an associated viewframe, and the srcrect
+ * argument needs not be recomputed.
+ */
+extern DECLSPEC int
+SDL_StretchSurfaceRect(SDL_Surface *src, SDL_Rect *srcrect,
+ SDL_Surface *dst, SDL_Rect *dstrect);
+/** Perform a stretch blit between two surfaces of the same format.
+ * NOTE: This function is not safe to call from multiple threads!
+ *
+ * This function will stretch a srcrect smoothly to the full area of
+ * the dst surface. If no srcrect is given then the full area of the
+ * src surface is stretched smoothly to the full dst surface. The
+ * dstrect is ignored always.
+ *
+ * Remember that this is the inverse meaning, the main SDL lib will
+ * ignore the srcrect and only watch for the dstrect if any.
+ */
+extern DECLSPEC int
+SDL_StretchSurfaceBlit(SDL_Surface *src, SDL_Rect *srcrect,
+ SDL_Surface *dst, SDL_Rect *dstrect);
+/**
+ * This function will stretch to 150%. This is not only a fast function
+ * but it is also safe to call from multiple threads. If the srcrect
+ * is given then only that rect is copied. Otherwise the full src
+ * surface is copied to the full dst surface. The dstrect is ignored.
+ */
+extern DECLSPEC int
+SDL_StretchSurface_23(SDL_Surface *src, SDL_Rect *srcrect,
+ SDL_Surface *dst, SDL_Rect *dstrect);
+
+/**
+ * return some informative information.
+ */
+extern DECLSPEC char*
+SDL_StretchInfo(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/util/sdl/stretch/SDL_stretchasm.h b/util/sdl/stretch/SDL_stretchasm.h
new file mode 100644
index 00000000..d2441456
--- /dev/null
+++ b/util/sdl/stretch/SDL_stretchasm.h
@@ -0,0 +1,102 @@
+/*
+ SDL_stretch - Stretch Functions For The Simple DirectMedia Layer
+ Copyright (C) 2003 Guido Draheim
+
+ 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Guido Draheim, guidod@gmx.de
+*/
+
+#ifndef _SDL_STRETCHASM_IMPLEMENTATION_
+#define _SDL_STRETCHASM_IMPLEMENTATION_
+
+/* development header - do not use */
+
+#if (defined(WIN32) && !defined(_M_ALPHA) && !defined(_WIN32_WCE))
+#define SDL_STRETCH_I386
+#define SDL_STRETCH_MASM
+#define SDL_STRETCH_USE_ASM
+#endif
+
+#if defined(__i386__) && defined(__GNUC__)
+#define SDL_STRETCH_I386
+#define SDL_STRETCH_GAS
+#define SDL_STRETCH_USE_ASM
+#endif
+
+#if defined(__x86_64__) && defined(__GNUC__)
+#define SDL_STRETCH_X86_64
+#define SDL_STRETCH_GAS
+#define SDL_STRETCH_USE_ASM
+#endif
+
+#if defined SDL_STRETCH_I386 && defined SDL_STRETCH_MASM
+#define SDL_STRETCH_CALL(code, srcp, dstp) \
+__asm {\
+ push edi ;\
+ push esi ;\
+ mov edi, dstp ;\
+ mov esi, srcp ;\
+ call dword ptr code ;\
+ pop esi ;\
+ pop edi ;\
+}
+#endif
+
+#if defined SDL_STRETCH_X86_64 && defined SDL_STRETCH_MASM
+#define SDL_STRETCH_CALL(code, srcp, dstp) \
+__asm {\
+ push rdi ;\
+ push rsi ;\
+ mov rdi, dstp ;\
+ mov rsi, srcp ;\
+ call qword ptr code ;\
+ pop rsi ;\
+ pop rdi ;\
+}
+#endif
+
+#if defined SDL_STRETCH_I386 && defined SDL_STRETCH_GAS
+#define SDL_STRETCH_CALL(code, srcp, dstp) \
+__asm__ __volatile__ ("call *%%eax" \
+ :: "S" (dstp), "D" (srcp), "a" (code));
+#endif
+
+#if defined SDL_STRETCH_X86_64 && defined SDL_STRETCH_GAS
+#define SDL_STRETCH_CALL(code, srcp, dstp) \
+__asm__ __volatile__ ("call *%%rax" \
+ :: "S" (dstp), "D" (srcp), "a" (code));
+#endif
+
+#if defined USE_ASM_STRETCH && ! defined SDL_STRETCH_USE_ASM
+#define SDL_STRETCH_USE_ASM 1
+#endif
+
+#if defined SDL_STRETCH_DISABLE_ASM
+#undef SDL_STRETCH_USE_ASM
+#undef SDL_STRETCH_CALL
+#endif
+
+#if defined SDL_STRETCH_USE_INTERPRETED_CODE
+#undef SDL_STRETCH_CALL
+#endif
+
+#if defined SDL_STRETCH_I386 || defined WIN32 || !defined SDL_STRETCH_CALL
+#define SDL_STRETCH_DATA_EXECUTABLE
+#else
+#define SDL_STRETCH_DATA_NOEXEC
+#endif
+
+#endif
diff --git a/util/sdl/stretch/SDL_stretchcode.h b/util/sdl/stretch/SDL_stretchcode.h
new file mode 100644
index 00000000..f8d06c3d
--- /dev/null
+++ b/util/sdl/stretch/SDL_stretchcode.h
@@ -0,0 +1,103 @@
+/*
+ SDL_stretch - Stretch Functions For The Simple DirectMedia Layer
+ Copyright (C) 2003 Guido Draheim
+
+ 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Guido Draheim, guidod@gmx.de
+*/
+
+#ifndef _SDL_STRETCHCODE_IMPLEMENTATION_
+#define _SDL_STRETCHCODE_IMPLEMENTATION_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* development header - do not use */
+
+#define SDL_STRETCHCODE_BUFFERSIZE 8192
+
+/**
+ * TheRowStretchCode is a shared buffer between Stretch-routines that
+ * use no extra buffer-argument. You should call SDL_SetRowStretchCode
+ * to fill this internal buffer and set a "call"-operation for your target
+ * cpu to execute this static buffer. That is done for effiency
+ * as the RowStretch is often called in a tight loop for each Row
+ * in a rectengular stretch and it is best to not use a variable
+ * argument with an indirect call or a function call that would
+ * build up a callframe and release that callframe later.
+ *
+ * If you do not need that effiency, use PutRowStretchCode and RunRowStretchCode
+ * which are also good in a multithreading environment. To allocate a new buffer
+ * for usage with Put/Run you can use the NewRowStretchCode routine which is
+ * also used on NX machines (e.g. AMD64) where the data segment is set to be
+ * not-executable (in that case it will allocate from heap and use mprotect).
+ * if the argument is 0 then a buffer of the default size is allocated. If the
+ * buffer allocation (or mprotect) fails it will return NULL and SDL_SetError.
+ */
+extern unsigned char* SDL_GetRowStretchCode(void);
+
+/** => SDL_GetRowStretchCode */
+extern unsigned char* SDL_NewRowStretchCode(unsigned size);
+
+/**
+ * The SetRowStretchCode is a wrapper around PutRowStretchCode that
+ * uses the Adress and Size of the shared SDL_TheRowStretchCode buffer.
+ * The PutRowStretchCode will fill the given buffer with an assembler
+ * stream that should be called with SDL_RunRowStretchCode. The
+ * assembler stream is usually faster as all the scale decisions are
+ * done in advance of the execution. This helps when a RunCode is
+ * done multiple times with the same src_w/dst_w/bpp pair. All the
+ * pixel-get and pixel-set calls are unrolled in that buffer. Therefore,
+ * the buffer should be big enough - as a rule of thumb use a buffer
+ * of size (src_w+dst_w)*5
+ *
+ * If PutCode or SetCode fails, a NULL is returned and SDL_SetError.
+ * Otherwise, the start adress of the machine code buffer is returned,
+ * which is also the input argument of PutCode and RunCode.
+ */
+unsigned char* SDL_SetRowStretchCode(int src_w, int dst_w, int bpp);
+/** => SDL_SetRowStretchCode */
+unsigned char* SDL_PutRowStretchCode(unsigned char* buffer, int buflen,
+ int src_w, int dst_w, int bpp);
+/** => SDL_SetRowStretchCode */
+void SDL_RunRowStretchCode(unsigned char* buffer,
+ unsigned char* src,
+ unsigned char* dst);
+
+/** => SDL_SetRowStretchCode
+ * If SDL_SetRowStretchCode fails, this function must be used instead.
+ * This function and its cousins are singular routines that work in
+ * a tight loop to scale a single row. The number specifies the
+ * byte-width of each pixel (it is not a bit-width!).
+ */
+void SDL_StretchRow1(Uint8 *src, int src_w, Uint8 *dst, int dst_w);
+/** => SDL_SetRowStretchCode */
+void SDL_StretchRow2(Uint16 *src, int src_w, Uint16 *dst, int dst_w);
+/** => SDL_SetRowStretchCode */
+void SDL_StretchRow3(Uint8 *src, int src_w, Uint8 *dst, int dst_w);
+/** => SDL_SetRowStretchCode */
+void SDL_StretchRow4(Uint32 *src, int src_w, Uint32 *dst, int dst_w);
+
+/**
+ * return some informative information.
+ */
+extern char* SDL_StretchRowInfo(void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/util/sdl/stretch/config.h b/util/sdl/stretch/config.h
new file mode 100644
index 00000000..3f811f54
--- /dev/null
+++ b/util/sdl/stretch/config.h
@@ -0,0 +1,60 @@
+/* src/config.h. Generated from config.h.in by configure. */
+/* src/config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#define LT_OBJDIR ".libs/"
+
+/* Name of package */
+#define PACKAGE "SDL_stretch"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "0.3.1"
diff --git a/util/sdl/stretch/sdlscreen.c b/util/sdl/stretch/sdlscreen.c
new file mode 100644
index 00000000..a1df98fe
--- /dev/null
+++ b/util/sdl/stretch/sdlscreen.c
@@ -0,0 +1,376 @@
+/*
+ SDL_stretch - Stretch Functions For The Simple DirectMedia Layer
+ Copyright (C) 2003 Guido Draheim
+
+ 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Guido Draheim, guidod@gmx.de
+*/
+
+/* these will fill the target surface completely */
+
+/****************************************************
+ *
+ * WARNING: these routines are not used anymore.
+ * (they will not be part of the normal library)
+ *
+ ****************************************************
+ */
+
+#ifdef SAVE_RCSID
+static char rcsid =
+ "@(#) $Id: sdstretch.c $";
+#endif
+
+#include "SDL/SDL_error.h"
+#include "SDL/SDL_video.h"
+#include "SDL_stretch.h"
+#include "SDL_stretchcode.h"
+#include "SDL_stretchasm.h"
+#include "SDL_stretchtest.hh"
+
+#define PRERUN 0
+
+
+/* Perform a stretch blit between two surfaces of the same format.
+ NOTE: This function is not safe to call from multiple threads!
+*/
+int SDL_StretchSurfaceBlitTo(SDL_Surface *src, SDL_Rect *srcrect,
+ SDL_Surface *dst, SDL_Rect *dstrect)
+{
+ int i = 0;
+ int src_row, dst_row;
+ SDL_Rect full_src;
+ /* SDL_Rect full_dst; */
+# if defined SDL_STRETCH_USE_ASM
+ unsigned char* code = 0;
+# endif
+ const int bpp = dst->format->BytesPerPixel;
+ auto int dest_w = srcrect->w * dst->w / src->w;
+ auto int dest_x = srcrect->x * dst->w / src->w;
+
+ if ( src->format->BitsPerPixel != dst->format->BitsPerPixel ) {
+ SDL_SetError("Only works with same format surfaces");
+ return(-1);
+ }
+
+ /* Verify the blit rectangles */
+ if ( srcrect ) {
+ if ( (srcrect->x < 0) || (srcrect->y < 0) ||
+ ((srcrect->x+srcrect->w) > src->w) ||
+ ((srcrect->y+srcrect->h) > src->h) ) {
+ SDL_SetError("Invalid source blit rectangle");
+ return(-1);
+ }
+ } else {
+ full_src.x = 0;
+ full_src.y = 0;
+ full_src.w = src->w;
+ full_src.h = src->h;
+ srcrect = &full_src;
+ }
+
+# ifdef SDL_STRETCH_USE_ASM
+ /* Write the opcodes for this stretch */
+ /* if ( (bpp != 3) */
+ code = SDL_SetRowStretchCode(srcrect->w, dest_w, bpp);
+# endif
+
+
+ if (PRERUN) /* let the compiler do the dead-code removal */
+ { /* Pre-Run the stretch blit (the invisible lines) */
+ src_row = 0;
+ dst_row = 0;
+ while (1)
+ {
+ if (src_row >= srcrect->y) break;
+ dst_row++; i += src->h;
+ if (i < dst->h) continue;
+ do { i -= dst->h; src_row++; } while (i >= dst->h);
+ }
+ }else
+ { /* or compute the resulting dst_row and i-fraction directly: */
+ src_row = srcrect->y;
+ dst_row = ((src_row * dst->h)+(src->h-1)) / src->h;
+ i = (dst_row * src->h - src_row * dst->h ) % dst->h;
+ if (i < 0) i += dst->h;
+ }
+
+ if (dstrect) { /*returnvalue*/
+ dstrect->y = dst_row;
+ dstrect->x = dest_x;
+ dstrect->w = dest_w;
+ }
+
+
+ while (src_row < srcrect->y + srcrect->h)
+ {
+ Uint8 *srcp, *dstp;
+ srcp = (Uint8 *)src->pixels + (src_row*src->pitch)
+ + (srcrect->x*bpp);
+ draw:
+ dstp = (Uint8 *)dst->pixels + (dst_row*dst->pitch)
+ + (dest_x*bpp);
+# ifdef SDL_STRETCH_USE_ASM
+ if (code)
+ {
+# if defined SDL_STRETCH_CALL
+ SDL_STRETCH_CALL(code, srcp, dstp);
+# else
+ SDL_RunRowStretchCode(code, srcp, dstp);
+# endif
+ }else
+# endif /*USE_ASM*/
+ {
+ switch (bpp) {
+ case 1:
+ SDL_StretchRow1(srcp, srcrect->w, dstp, dest_w);
+ break;
+ case 2:
+ SDL_StretchRow2((Uint16 *)srcp, srcrect->w,
+ (Uint16 *)dstp, dest_w);
+ break;
+ case 3:
+ SDL_StretchRow3(srcp, srcrect->w, dstp, dest_w);
+ break;
+ case 4:
+ SDL_StretchRow4((Uint32 *)srcp, srcrect->w,
+ (Uint32 *)dstp, dest_w);
+ break;
+ }
+ }
+
+ dst_row++; i += src->h;
+ if (dst_row == dst->h) break; /*oops*/
+ if (i < dst->h) goto draw; /* draw the line again */
+ do { i -= dst->h; src_row++; } while (i >= dst->h);
+ }
+
+ if (dstrect) dstrect->h = dst_row - dstrect->y; /*returnvalue*/
+
+ return(0);
+}
+
+/* ------------------------------------------------------------------------ */
+
+#define OPTIMIZED 1
+
+#if defined SDL_STRETCH_USE_ASM && defined OPTIMIZED
+static int SDL_StretchFastBlitTo(
+ unsigned char* code,
+ int dst_row, int src_row,
+ SDL_Surface* dst, SDL_Surface* src,
+ SDL_Rect* rect, SDL_Rect* clip, int dest_x, int i)
+{
+ const int bpp = src->format->BytesPerPixel;
+ Uint8 *srcp = (Uint8 *)src->pixels + (src_row*src->pitch) + (rect->x*bpp);
+ Uint8 *srcE = (Uint8 *)src->pixels + ((rect->y + rect->h)
+ *src->pitch) + (rect->x*bpp);
+ Uint8 *dstp = (Uint8 *)dst->pixels + (dst_row*dst->pitch) + (dest_x*bpp);
+// Uint8* dstE = (Uint8 *)dst->pixels + (dst->h*dst->pitch) + (dest_x*bpp);
+
+ while (srcp < srcE)
+ {
+ draws:
+# if defined SDL_STRETCH_CALL
+ SDL_STRETCH_CALL(code, srcp, dstp)
+# else
+ SDL_RunRowStretchCode(code, srcp, dstp);
+# endif
+ dstp += dst->pitch; i += clip->h;
+ // if (dstp == dstE) break; /*oops*/
+ if (i < dst->h) goto draws; /* draw the line again */
+ do { i -= dst->h; srcp += src->pitch; } while (i >= dst->h);
+ }
+ return dst_row;
+}
+#endif
+
+#define DEBUGSIZES 0
+#define DEBUGSIZES_ (src->h != dst->h)
+
+/* Perform a stretch blit between two surfaces of the same format.
+ NOTE: This function is not safe to call from multiple threads!
+*/
+int SDL_StretchSurfaceRectTo(SDL_Surface *src, SDL_Rect *srcrect,
+ SDL_Surface *dst, SDL_Rect *dstrect)
+{
+ int i = 0;
+ int src_row, dst_row;
+ int dest_x, dest_w;
+ SDL_Rect rect;
+ SDL_Rect clip;
+# if defined SDL_STRETCH_USE_ASM
+ unsigned char* code = 0;
+# endif
+ const int bpp = src->format->BytesPerPixel;
+
+ if ( src->format->BitsPerPixel != dst->format->BitsPerPixel ) {
+ SDL_SetError("Only works with same format surfaces");
+ return(-1);
+ }
+
+ /* Verify the blit rectangles */
+ if ( srcrect ) {
+ rect = *srcrect;
+#if 0
+ clip.x = clip.y = 0; clip.h = src->h; clip.w = src->w;
+#else
+ clip = src->clip_rect;
+
+ if (rect.x > clip.x + clip.w ||
+ rect.x + rect.w < clip.x ||
+ rect.y > clip.y + clip.h ||
+ rect.y + rect.h < clip.y) return 1;
+ if (rect.x < clip.x) { rect.w -= clip.x-rect.x; rect.x = clip.x; }
+ if (rect.w > clip.x + clip.w - rect.x)
+ rect.w = clip.x + clip.w - rect.x;
+ if (rect.y < clip.y) { rect.h -= clip.y-rect.y; rect.y = clip.y; }
+ if (rect.h > clip.y + clip.h - rect.y)
+ rect.h = clip.y + clip.h - rect.y;
+#endif
+ if (! rect.h || !rect.w) return 1;
+ } else {
+ rect.x = 0;
+ rect.y = 0;
+ rect.w = src->w;
+ rect.h = src->h;
+ clip = rect;
+ }
+
+ if (DEBUGSIZES)
+ fprintf (stderr, "[%i/%i][%i+%i/%i+%i][%i+%i/%i+%i]\n",
+ src->w,src->h,
+ clip.x,clip.w,clip.y,clip.h,
+ rect.x,rect.w,rect.y,rect.h);
+
+ dest_w = rect.w * dst->w / clip.w;
+ dest_x = (rect.x-clip.x) * dst->w / clip.w;
+
+# ifdef SDL_STRETCH_USE_ASM
+ /* Write the opcodes for this stretch */
+ /* if ( (bpp != 3) */
+ code = SDL_SetRowStretchCode(rect.w, dest_w, bpp);
+# endif
+
+ if (PRERUN) /* let the compiler do the dead-code removal */
+ { /* Pre-Run the stretch blit (the invisible lines) */
+ src_row = clip.y;
+ dst_row = 0;
+ while (1)
+ {
+ if (src_row >= rect.y) break;
+ dst_row++; i += clip.h;
+ if (i < dst->h) continue;
+ do { i -= dst->h; src_row++; } while (i >= dst->h);
+ }
+ }else
+ { /* or compute the resulting dst_row and i-fraction directly: */
+ src_row = rect.y - clip.y;
+ dst_row = ((src_row * dst->h)+(clip.h-1)) / clip.h;
+ i = (dst_row * clip.h - src_row * dst->h ) % dst->h;
+ if (i < 0) i += dst->h;
+ }
+
+ if (dstrect) {
+ dstrect->y = dst_row;
+ dstrect->x = dest_x;
+ dstrect->w = dest_w;
+ }
+
+ if (DEBUGSIZES)
+ fprintf (stderr, "[%i/%i][%i+%i/%i+%i][%i+%i/%i+%i]"
+ " -> [%i/%i][%i+%i/%i+?]\n",
+ src->w,src->h,
+ clip.x,clip.w,clip.y,clip.h,
+ rect.x,rect.w,rect.y,rect.h,
+ dst->w,dst->h,
+ dest_x,dest_w,dst_row);
+
+# ifdef SDL_STRETCH_USE_ASM
+ if (code)
+ {
+# ifdef OPTIMIZED
+ dst_row = SDL_StretchFastBlitTo(code, dst_row, src_row, dst, src, &rect, &clip, dest_x,i);
+# else
+ while (src_row < rect.y + rect.h)
+ {
+ Uint8 *srcp, *dstp;
+ srcp = (Uint8 *)src->pixels + (src_row*src->pitch)
+ + (rect.x*bpp);
+ draws:
+ dstp = (Uint8 *)dst->pixels + (dst_row*dst->pitch)
+ + (dest_x*bpp);
+# ifdef SDL_STRETCH_CALL
+ SDL_STRETCH_CALL(code, srcp, dstp);
+# else
+ SDL_RunRowStretchCode(code, srcp, dstp);
+# endif
+ dst_row++; i += clip.h;
+ if (dst_row == dst->h) break; /*oops*/
+ if (i < dst->h) goto draws; /* draw the line again */
+ do { i -= dst->h; src_row++; } while (i >= dst->h);
+ }
+# endif
+ }else
+# endif /*USE_ASM*/
+ {
+ while (src_row < rect.y + rect.h)
+ {
+ Uint8 *srcp, *dstp;
+ srcp = (Uint8 *)src->pixels + (src_row*src->pitch)
+ + (rect.x*bpp);
+ draw:
+ dstp = (Uint8 *)dst->pixels + (dst_row*dst->pitch)
+ + (dest_x*bpp);
+
+ if (DEBUGSIZES) fprintf(stderr, ".");
+ switch (bpp) {
+ case 1:
+ SDL_StretchRow1(srcp, rect.w, dstp, dest_w);
+ break;
+ case 2:
+ SDL_StretchRow2((Uint16 *)srcp, rect.w,
+ (Uint16 *)dstp, dest_w);
+ break;
+ case 3:
+ SDL_StretchRow3(srcp, rect.w, dstp, dest_w);
+ break;
+ case 4:
+ SDL_StretchRow4((Uint32 *)srcp, rect.w,
+ (Uint32 *)dstp, dest_w);
+ break;
+ }
+
+ dst_row++; i += clip.h;
+ if (dst_row == dst->h) break; /*oops*/
+ if (i < dst->h) goto draw; /* draw the line again */
+ do { i -= dst->h; src_row++; } while (i >= dst->h);
+ }
+ }
+
+ if (dstrect) dstrect->h = dst_row - dstrect->y; /*returnvalue*/
+
+ if (DEBUGSIZES)
+ fprintf (stderr, "[%i/%i][%i+%i/%i+%i][%i+%i/%i+%i]"
+ " -> [%i/%i][%i+%i/?..%i]\n",
+ src->w,src->h,
+ clip.x,clip.w,clip.y,clip.h,
+ rect.x,rect.w,rect.y,rect.h,
+ dst->w,dst->h,
+ dest_x,dest_w,dst_row);
+
+ return(0);
+}
diff --git a/util/sdl/stretch/sdlstretch.c b/util/sdl/stretch/sdlstretch.c
new file mode 100644
index 00000000..5701691a
--- /dev/null
+++ b/util/sdl/stretch/sdlstretch.c
@@ -0,0 +1,382 @@
+/*
+ SDL_stretch - Stretch Functions For The Simple DirectMedia Layer
+ Copyright (C) 2003 Guido Draheim
+
+ 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Guido Draheim, guidod@gmx.de
+*/
+
+#ifdef SAVE_RCSID
+static char rcsid =
+ "@(#) $Id: sdstretch.c $";
+#endif
+
+#include "SDL/SDL_error.h"
+#include "SDL/SDL_video.h"
+#include "SDL_stretch.h"
+#include "SDL_stretchcode.h"
+#include "SDL_stretchasm.h"
+
+#define PRERUN 0
+
+
+/* Perform a stretch blit between two surfaces of the same format.
+ NOTE: This function is not safe to call from multiple threads!
+*/
+int SDL_StretchSurfaceBlit(SDL_Surface *src, SDL_Rect *srcrect,
+ SDL_Surface *dst, SDL_Rect *dstrect)
+{
+ int i = 0;
+ int src_row, dst_row;
+ SDL_Rect rect;
+# if defined SDL_STRETCH_USE_ASM
+ unsigned char* code = 0;
+# endif
+ const int bpp = dst->format->BytesPerPixel;
+ auto int dest_w;
+ auto int dest_x;
+
+ if ( src->format->BitsPerPixel != dst->format->BitsPerPixel ) {
+ SDL_SetError("Only works with same format surfaces");
+ return(-1);
+ }
+
+ /* Verify the blit rectangles */
+ if ( srcrect ) {
+ if ( (srcrect->x < 0) || (srcrect->y < 0) ||
+ ((srcrect->x+srcrect->w) > src->w) ||
+ ((srcrect->y+srcrect->h) > src->h) ) {
+ SDL_SetError("Invalid source blit rectangle");
+ return(-1);
+ }
+ } else {
+ rect.x = 0;
+ rect.y = 0;
+ rect.w = src->w;
+ rect.h = src->h;
+ srcrect = &rect;
+ }
+
+ dest_w = srcrect->w * dst->w / src->w;
+ dest_x = srcrect->x * dst->w / src->w;
+
+# ifdef SDL_STRETCH_USE_ASM
+ /* Write the opcodes for this stretch */
+ /* if ( (bpp != 3) */
+ code = SDL_SetRowStretchCode(srcrect->w, dest_w, bpp);
+# endif
+
+
+ if (PRERUN) /* let the compiler do the dead-code removal */
+ { /* Pre-Run the stretch blit (the invisible lines) */
+ src_row = 0;
+ dst_row = 0;
+ while (1)
+ {
+ if (src_row >= srcrect->y) break;
+ dst_row++; i += src->h;
+ if (i < dst->h) continue;
+ do { i -= dst->h; src_row++; } while (i >= dst->h);
+ }
+ }else
+ { /* or compute the resulting dst_row and i-fraction directly: */
+ src_row = srcrect->y;
+ dst_row = ((src_row * dst->h)+(src->h-1)) / src->h;
+ i = (dst_row * src->h - src_row * dst->h ) % dst->h;
+ if (i < 0) i += dst->h;
+ }
+
+ if (dstrect) { /*returnvalue*/
+ dstrect->y = dst_row;
+ dstrect->x = dest_x;
+ dstrect->w = dest_w;
+ }
+
+
+ while (src_row < srcrect->y + srcrect->h)
+ {
+ Uint8 *srcp, *dstp;
+ srcp = (Uint8 *)src->pixels
+ + (src_row*src->pitch)
+ + (srcrect->x*bpp);
+ draw:
+ dstp = (Uint8 *)dst->pixels
+ + (dst_row*dst->pitch)
+ + (dest_x*bpp);
+# ifdef SDL_STRETCH_USE_ASM
+ if (code)
+ {
+# ifdef SDL_STRETCH_CALL
+ SDL_STRETCH_CALL(code, srcp, dstp);
+# else
+ SDL_RunRowStretchCode(code, srcp, dstp);
+# endif
+ }else
+# endif /*USE_ASM*/
+ {
+ switch (bpp) {
+ case 1:
+ SDL_StretchRow1(srcp, srcrect->w, dstp, dest_w);
+ break;
+ case 2:
+ SDL_StretchRow2((Uint16 *)srcp, srcrect->w,
+ (Uint16 *)dstp, dest_w);
+ break;
+ case 3:
+ SDL_StretchRow3(srcp, srcrect->w, dstp, dest_w);
+ break;
+ case 4:
+ SDL_StretchRow4((Uint32 *)srcp, srcrect->w,
+ (Uint32 *)dstp, dest_w);
+ break;
+ }
+ }
+
+ dst_row++; i += src->h;
+ if (dst_row == dst->h) break; /*oops*/
+ if (i < dst->h) goto draw; /* draw the line again */
+ do { i -= dst->h; src_row++; } while (i >= dst->h);
+ }
+
+ if (dstrect) dstrect->h = dst_row - dstrect->y; /*returnvalue*/
+
+ return(0);
+}
+
+/* ------------------------------------------------------------------------ */
+
+#define OPTIMIZED 1
+
+#if defined SDL_STRETCH_USE_ASM && defined OPTIMIZED
+static int SDL_StretchFastBlit(unsigned char* code,
+ int dst_row, int src_row,
+ SDL_Surface* dst, SDL_Surface* src,
+ SDL_Rect* rect, SDL_Rect* clip, int dest_x, int i)
+{
+ const int bpp = src->format->BytesPerPixel;
+ Uint8 *srcp = (Uint8 *)src->pixels
+ + (src_row*src->pitch)
+ + (rect->x*bpp);
+ Uint8 *srcE = (Uint8 *)src->pixels
+ + ((rect->y + rect->h) * src->pitch)
+ + (rect->x*bpp);
+ Uint8 *dstp = (Uint8 *)dst->pixels
+ + (dst_row*dst->pitch)
+ + (dest_x*bpp);
+// Uint8* dstE = (Uint8 *)dst->pixels + (dst->h*dst->pitch) + (dest_x*bpp);
+
+ while (srcp < srcE)
+ {
+ draws:
+# ifdef SDL_STRETCH_CALL
+ SDL_STRETCH_CALL(code, srcp, dstp);
+# else
+ SDL_RunRowStretchCode(code, srcp, dstp);
+# endif
+ dstp += dst->pitch; i += clip->h;
+ // if (dstp == dstE) break; /*oops*/
+ if (i < dst->h) goto draws; /* draw the line again */
+ do { i -= dst->h; srcp += src->pitch; } while (i >= dst->h);
+ }
+ return dst_row;
+}
+#endif
+
+#define DEBUGSIZES 0
+#define DEBUGSIZES_ (src->h != dst->h)
+
+/* Perform a stretch blit between two surfaces of the same format.
+ NOTE: This function is not safe to call from multiple threads!
+*/
+int SDL_StretchSurfaceRect(SDL_Surface *src, SDL_Rect *srcrect,
+ SDL_Surface *dst, SDL_Rect *dstrect)
+{
+ int i = 0;
+ int src_row, dst_row;
+ int dest_x, dest_w;
+ SDL_Rect rect;
+ SDL_Rect clip;
+# if defined SDL_STRETCH_USE_ASM
+ unsigned char* code = 0;
+# endif
+ const int bpp = src->format->BytesPerPixel;
+
+ if ( src->format->BitsPerPixel != dst->format->BitsPerPixel ) {
+ SDL_SetError("Only works with same format surfaces");
+ return(-1);
+ }
+
+ /* Verify the blit rectangles */
+ if ( srcrect ) {
+ rect = *srcrect;
+#if 0
+ clip.x = clip.y = 0; clip.h = src->h; clip.w = src->w;
+#else
+ clip = src->clip_rect;
+
+ if (rect.x > clip.x + clip.w ||
+ rect.x + rect.w < clip.x ||
+ rect.y > clip.y + clip.h ||
+ rect.y + rect.h < clip.y) return 1;
+ if (rect.x < clip.x) { rect.w -= clip.x-rect.x; rect.x = clip.x; }
+ if (rect.w > clip.x + clip.w - rect.x)
+ rect.w = clip.x + clip.w - rect.x;
+ if (rect.y < clip.y) { rect.h -= clip.y-rect.y; rect.y = clip.y; }
+ if (rect.h > clip.y + clip.h - rect.y)
+ rect.h = clip.y + clip.h - rect.y;
+#endif
+ if (! rect.h || !rect.w) return 1;
+ } else {
+ rect.x = 0;
+ rect.y = 0;
+ rect.w = src->w;
+ rect.h = src->h;
+ clip = rect;
+ }
+
+ if (DEBUGSIZES)
+ fprintf (stderr, "[%i/%i][%i+%i/%i+%i][%i+%i/%i+%i]\n",
+ src->w,src->h,
+ clip.x,clip.w,clip.y,clip.h,
+ rect.x,rect.w,rect.y,rect.h);
+
+ dest_w = rect.w * dst->w / clip.w;
+ dest_x = (rect.x-clip.x) * dst->w / clip.w;
+
+# ifdef SDL_STRETCH_USE_ASM
+ /* Write the opcodes for this stretch */
+ /* if ( (bpp != 3) */
+ code = SDL_SetRowStretchCode(rect.w, dest_w, bpp);
+# endif
+
+ if (PRERUN) /* let the compiler do the dead-code removal */
+ { /* Pre-Run the stretch blit (the invisible lines) */
+ src_row = clip.y;
+ dst_row = 0;
+ while (1)
+ {
+ if (src_row >= rect.y) break;
+ dst_row++; i += clip.h;
+ if (i < dst->h) continue;
+ do { i -= dst->h; src_row++; } while (i >= dst->h);
+ }
+ }else
+ { /* or compute the resulting dst_row and i-fraction directly: */
+ src_row = rect.y - clip.y;
+ dst_row = ((src_row * dst->h)+(clip.h-1)) / clip.h;
+ i = (dst_row * clip.h - src_row * dst->h ) % dst->h;
+ if (i < 0) i += dst->h;
+ }
+
+ if (dstrect) {
+ dstrect->y = dst_row;
+ dstrect->x = dest_x;
+ dstrect->w = dest_w;
+ }
+
+ if (DEBUGSIZES)
+ fprintf (stderr, "[%i/%i][%i+%i/%i+%i][%i+%i/%i+%i]"
+ " -> [%i/%i][%i+%i/%i+?]\n",
+ src->w,src->h,
+ clip.x,clip.w,clip.y,clip.h,
+ rect.x,rect.w,rect.y,rect.h,
+ dst->w,dst->h,
+ dest_x,dest_w,dst_row);
+
+#ifdef SDL_STRETCH_USE_ASM
+ if (code)
+ {
+# ifdef OPTIMIZED
+ dst_row = SDL_StretchFastBlit(code, dst_row, src_row, dst, src, &rect, &clip, dest_x,i);
+# else
+ while (src_row < rect.y + rect.h)
+ {
+ Uint8 *srcp, *dstp;
+ srcp = (Uint8 *)src->pixels
+ + (src_row*src->pitch)
+ + (rect.x*bpp);
+ draws:
+ dstp = (Uint8 *)dst->pixels
+ + (dst_row*dst->pitch)
+ + (dest_x*bpp);
+
+# ifdef SDL_STRETCH_CALL
+ SDL_STRETCH_CALL(code, srcp, dstp);
+# else
+ SDL_RunRowStretchCode(code, srcp, dstp);
+# endif
+ dst_row++; i += clip.h;
+ if (dst_row == dst->h) break; /*oops*/
+ if (i < dst->h) goto draws; /* draw the line again */
+ do { i -= dst->h; src_row++; } while (i >= dst->h);
+ }
+# endif
+ }else
+# endif /*USE_ASM*/
+ {
+ while (src_row < rect.y + rect.h)
+ {
+ Uint8 *srcp, *dstp;
+ srcp = (Uint8 *)src->pixels
+ + (src_row*src->pitch)
+ + (rect.x*bpp);
+ draw:
+ dstp = (Uint8 *)dst->pixels
+ + (dst_row*dst->pitch)
+ + (dest_x*bpp);
+
+ if (DEBUGSIZES) fprintf(stderr, ".");
+ switch (bpp) {
+ case 1:
+ SDL_StretchRow1(srcp, rect.w, dstp, dest_w);
+ break;
+ case 2:
+ SDL_StretchRow2((Uint16 *)srcp, rect.w,
+ (Uint16 *)dstp, dest_w);
+ break;
+ case 3:
+ SDL_StretchRow3(srcp, rect.w, dstp, dest_w);
+ break;
+ case 4:
+ SDL_StretchRow4((Uint32 *)srcp, rect.w,
+ (Uint32 *)dstp, dest_w);
+ break;
+ }
+
+ dst_row++; i += clip.h;
+ if (dst_row == dst->h) break; /*oops*/
+ if (i < dst->h) goto draw; /* draw the line again */
+ do { i -= dst->h; src_row++; } while (i >= dst->h);
+ }
+ }
+
+ if (dstrect) dstrect->h = dst_row - dstrect->y; /*returnvalue*/
+
+ if (DEBUGSIZES)
+ fprintf (stderr, "[%i/%i][%i+%i/%i+%i][%i+%i/%i+%i]"
+ " -> [%i/%i][%i+%i/?..%i]\n",
+ src->w,src->h,
+ clip.x,clip.w,clip.y,clip.h,
+ rect.x,rect.w,rect.y,rect.h,
+ dst->w,dst->h,
+ dest_x,dest_w,dst_row);
+
+ return(0);
+}
+
+char* SDL_StretchInfo(void) {
+ return SDL_StretchRowInfo();
+}
diff --git a/util/sdl/stretch/sdlstretch23.c b/util/sdl/stretch/sdlstretch23.c
new file mode 100644
index 00000000..d30868dc
--- /dev/null
+++ b/util/sdl/stretch/sdlstretch23.c
@@ -0,0 +1,2219 @@
+/*
+ SDL_stretch - Stretch Functions For The Simple DirectMedia Layer
+ Copyright (C) 2003 Guido Draheim
+
+ 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Guido Draheim, guidod@gmx.de
+*/
+
+/* routines that stretch by constant factor (3 / 2) = 150% */
+
+#ifdef SAVE_RCSID
+static char rcsid =
+ "@(#) $Id: sdstretch.c $";
+#endif
+
+#include "SDL/SDL_error.h"
+#include "SDL/SDL_video.h"
+#include "SDL_stretch.h"
+#include "SDL_stretchasm.h"
+
+#if 0
+/* the first part is for documentation only */
+
+/* Perform a stretch blit between two surfaces of the same format.
+ NOTE: This function is not safe to call from multiple threads!
+*/
+int SDL_StretchSurface_23(SDL_Surface *src, SDL_Rect *srcrect,
+ SDL_Surface *dst, SDL_Rect *dstrect)
+{
+ union { Uint8* b; Uint16* w; Uint32* x; } srcp, dstp, endp;
+ unsigned int srci, dsti;
+ SDL_Rect rect;
+ SDL_Rect clip;
+ const unsigned bpp = src->format->BytesPerPixel;
+
+ if ( src->format->BitsPerPixel != dst->format->BitsPerPixel ) {
+ SDL_SetError("Only works with same format surfaces");
+ return(-1);
+ }
+
+ /* Verify the source blit rectangle - copy good values to "rect",
+ * note that the input srcrect is clipped with the src->clip_rect
+ * and not just the src-surface borders.
+ */
+ if ( srcrect ) {
+ rect = *srcrect;
+#if 0 /* for debugging, you might want to assume good srcrect values */
+ clip.x = clip.y = 0; clip.h = src->h; clip.w = src->w;
+#else /* otherwise we test with the clprect as well */
+ clip = src->clip_rect;
+
+ if (rect.x > clip.x + clip.w ||
+ rect.x + rect.w < clip.x ||
+ rect.y > clip.y + clip.h ||
+ rect.y + rect.h < clip.y) return 1;
+ if (rect.x < clip.x) { rect.w -= clip.x-rect.x; rect.x = clip.x; }
+ if (rect.w > clip.x + clip.w - rect.x)
+ rect.w = clip.x + clip.w - rect.x;
+ if (rect.y < clip.y) { rect.h -= clip.y-rect.y; rect.y = clip.y; }
+ if (rect.h > clip.y + clip.h - rect.y)
+ rect.h = clip.y + clip.h - rect.y;
+#endif
+ if (! rect.h || !rect.w) return 1;
+ } else
+ { /* in the default however, we use srcrect == cliprect == src-screen */
+ rect.x = 0;
+ rect.y = 0;
+ rect.w = src->w;
+ rect.h = src->h;
+ clip = rect;
+ }
+
+ { /* and now compute the dest rect area - starting off with fixscaled */
+ int dest_x = (rect.x - clip.x) * 3 / 2;
+ int dest_y = (rect.y - clip.y) * 3 / 2;
+ int dest_w = rect.w * 3 / 2;
+ int dest_h = rect.h * 3 / 2;
+
+ /* great, so we have the dest measure from src according to the scale
+ * but we need to check if that is still inside the dst->clip_rect
+ * and possibly adapt the source rect for it to work. Items in
+ * comments represent what a dest-only oriented routine would do.
+ */
+
+ if (dest_x >= dst->clip_rect.x + dst->clip_rect.w ||
+ dest_y >= dst->clip_rect.y + dst->clip_rect.h ||
+ dest_x + dest_w <= dst->clip_rect.x ||
+ dest_y + dest_h <= dst->clip_rect.y) return 1;
+ if (dest_x < dst->clip_rect.x)
+ { /*dest_w -= dst->clip_rect.x - dest_x; dest_x = dst->clip_rect.x; */
+ rect.w = (dest_w - dst->clip_rect.x - dest_x) / 3;
+ rect.x += (dst->clip_rect.x - dest_x) / 3 * 2;
+ dest_w = rect.w * 3; rect.w *= 2; dest_x = dst->clip_rect.x; }
+ if (dest_w > dst->clip_rect.x + dst->clip_rect.w - dest_x)
+ { /*dest_w = dst->clip_rect.x + dst->clip_rect.w - dest_x; */
+ rect.w = (dst->clip_rect.x + dst->clip_rect.w - dest_x) / 3;
+ dest_w = rect.w * 3; rect.w *= 2; }
+ if (dest_y < dst->clip_rect.y)
+ { /*dest_h -= dst->clip_rect.y - dest_y; dest_y = dst->clip_rect.y; */
+ rect.h = (dest_h - dst->clip_rect.y - dest_y) / 3;
+ rect.y += (dst->clip_rect.y - dest_y) / 3 * 2;
+ dest_h = rect.h * 3; rect.h *= 2; dest_y = dst->clip_rect.y; }
+ if (dest_h > dst->clip_rect.y + dst->clip_rect.h - dest_y)
+ { /*dest_h = dst->clip_rect.y + dst->clip_rect.h - dest_y; */
+ rect.h = (dst->clip_rect.y + dst->clip_rect.h - dest_y) / 3;
+ dest_h = rect.h * 3; rect.h *= 2; }
+ if (!dest_h || !dest_w || !rect.h || !rect.w) return 1;
+
+ if (dstrect) { /* inform the caller of the */
+ dstrect->y = dest_y; /* computed results - if the */
+ dstrect->x = dest_x; /* "dst" surface is actually */
+ dstrect->w = dest_w; /* the user screen then one can */
+ dstrect->h = dest_h; /* just use Update(dst,dstret) */
+ }
+
+ /* these computations happen to be the same for all bitdepths */
+ dstp.b = (Uint8*)dst->pixels +
+ (dst->pitch*dest_y) + (bpp*dest_x);
+ srcp.b = (Uint8*)src->pixels +
+ (src->pitch*rect.y) + (bpp*rect.x);
+ endp.b = srcp.b +
+ src->pitch*rect.h;
+ srci = src->pitch - (bpp*rect.w);
+ dsti = dst->pitch - (bpp*dest_w);
+ }
+
+ switch (bpp) /* the copy operations shall be as tight as possible */
+ { /* to let all values be in cpu registers and the */
+ case 4: /* complete series in the pipeline instruction cache */
+ do {
+ int count = rect.w / 2;
+ do {
+ *dstp.x++ = *srcp.x;
+ *dstp.x++ = *srcp.x++;
+ *dstp.x++ = *srcp.x++;
+ } while (--count != 0);
+ srcp.b += srci;
+ dstp.b += dsti;
+ } while (srcp.b != endp.b);
+ break;
+ case 3:
+ do {
+ int count = rect.w / 2;
+ do {
+ *dstp.b++ = *srcp.b++;
+ *dstp.w++ = *srcp.w; srcp.b--;
+ *dstp.w++ = *srcp.w++;
+ *dstp.x++ = *srcp.x++;
+ } while (--count != 0);
+ srcp.b += srci;
+ dstp.b += dsti;
+ } while (srcp.b != endp.b);
+ break;
+ case 2:
+ do {
+ int count = rect.w / 2;
+ do {
+ *dstp.w++ = *srcp.w;
+ *dstp.w++ = *srcp.w++;
+ *dstp.w++ = *srcp.w++;
+ } while (--count != 0);
+ srcp.b += srci;
+ dstp.b += dsti;
+ } while (srcp.b != endp.b);
+ break;
+ case 1:
+ do {
+ int count = rect.w / 2;
+ do {
+ *dstp.b++ = *srcp.b;
+ *dstp.b++ = *srcp.b++;
+ *dstp.b++ = *srcp.b++;
+ } while (--count != 0);
+ srcp.b += srci;
+ dstp.b += dsti;
+ } while (srcp.b != endp.b);
+ break;
+ }
+ return(0);
+}
+
+#elif 0
+/* the second part shows a nice optimization:
+ *
+ * we keep the rect.w and rect.h at halfsize - consequently,
+ * dest.w == 3 * rect.w and dest.h == 3 * src.w always - the
+ * copy-loops go in two src-lines -> three dst-lines anyway.
+ *
+ * and it does the fix the wrong behavior of the previous one,
+ * if you try it then you will see that it does scale correctly
+ * in the horizontal direction but the vertical does sometimes
+ * seem to get messed up. That is because we did not yet unroll
+ * the vertical part into being XY->XXY and instead it was kept
+ * as XYz->XYz i.e. it would copy a bit too much out of the
+ * source area instead of stretching it.
+ */
+
+
+/* Perform a stretch blit between two surfaces of the same format.
+ NOTE: This function is not safe to call from multiple threads!
+*/
+int SDL_StretchSurface_23(SDL_Surface *src, SDL_Rect *srcrect,
+ SDL_Surface *dst, SDL_Rect *dstrect)
+{
+ union { Uint8* b; Uint16* w; Uint32* x; } srcp, dstp, endp;
+ unsigned int srci, dsti;
+ SDL_Rect rect;
+ SDL_Rect clip;
+ const unsigned bpp = src->format->BytesPerPixel;
+
+ if ( src->format->BitsPerPixel != dst->format->BitsPerPixel ) {
+ SDL_SetError("Only works with same format surfaces");
+ return(-1);
+ }
+
+ /* Verify the blit rectangles */
+ if ( srcrect ) {
+ rect = *srcrect;
+#if 0
+ clip.x = clip.y = 0; clip.h = src->h; clip.w = src->w;
+#else
+ clip = src->clip_rect;
+
+ if (rect.x > clip.x + clip.w ||
+ rect.x + rect.w < clip.x ||
+ rect.y > clip.y + clip.h ||
+ rect.y + rect.h < clip.y) return 1;
+ if (rect.x < clip.x) { rect.w -= clip.x-rect.x; rect.x = clip.x; }
+ if (rect.w > clip.x + clip.w - rect.x)
+ rect.w = clip.x + clip.w - rect.x;
+ if (rect.y < clip.y) { rect.h -= clip.y-rect.y; rect.y = clip.y; }
+ if (rect.h > clip.y + clip.h - rect.y)
+ rect.h = clip.y + clip.h - rect.y;
+#endif
+ if (! rect.h || !rect.w) return 1;
+ rect.x /= 2; rect.w /= 2;
+ rect.y /= 2; rect.h /= 2;
+ clip.x /= 2; clip.w /= 2;
+ clip.y /= 2; clip.h /= 2;
+
+ } else {
+ rect.x = 0;
+ rect.y = 0;
+ rect.w = src->w / 2;
+ rect.h = src->h / 2;
+ clip = rect;
+ }
+
+ {
+ int dest_x = (rect.x - clip.x) * 3;
+ int dest_y = (rect.y - clip.y) * 3;
+ int dest_w = rect.w * 3;
+ int dest_h = rect.h * 3;
+
+ if (dest_x >= dst->clip_rect.x + dst->clip_rect.w ||
+ dest_y >= dst->clip_rect.y + dst->clip_rect.h ||
+ dest_x + dest_w <= dst->clip_rect.x ||
+ dest_y + dest_h <= dst->clip_rect.y) return 1;
+ if (dest_x < dst->clip_rect.x)
+ {
+ rect.w = (dest_w - dst->clip_rect.x - dest_x) / 3;
+ rect.x += (dst->clip_rect.x - dest_x) / 3;
+ dest_w = rect.w * 3; dest_x = dst->clip_rect.x; }
+ if (dest_w > dst->clip_rect.x + dst->clip_rect.w - dest_x)
+ {
+ rect.w = (dst->clip_rect.x + dst->clip_rect.w - dest_x) / 3;
+ dest_w = rect.w * 3; }
+ if (dest_y < dst->clip_rect.y)
+ {
+ rect.h = (dest_h - dst->clip_rect.y - dest_y) / 3;
+ rect.y += (dst->clip_rect.y - dest_y) / 3;
+ dest_h = rect.h * 3; dest_y = dst->clip_rect.y; }
+ if (dest_h > dst->clip_rect.y + dst->clip_rect.h - dest_y)
+ {
+ rect.h = (dst->clip_rect.y + dst->clip_rect.h - dest_y) / 3;
+ dest_h = rect.h * 3; }
+ if (!dest_h || !dest_w || !rect.h || !rect.w) return 1;
+
+ if (dstrect) { /*returnvalue*/
+ dstrect->y = dest_y;
+ dstrect->x = dest_x;
+ dstrect->w = dest_w;
+ dstrect->h = dest_h;
+ }
+
+ dstp.b = (Uint8*)dst->pixels +
+ (dst->pitch*dest_y) + (bpp*dest_x);
+ srcp.b = (Uint8*)src->pixels +
+ (src->pitch*rect.y*2) + (bpp*rect.x*2);
+ endp.b = srcp.b + src->pitch*rect.h*2;
+ srci = src->pitch - (bpp*rect.w*2);
+ dsti = dst->pitch - (bpp*dest_w);
+ }
+
+ switch (bpp) /* the copy operations shall be as tight as possible */
+ { /* to let all values be in cpu registers and the */
+ case 4: /* complete series in the pipeline instruction cache */
+ do {
+ int count = rect.w;
+ do {
+ *dstp.x++ = *srcp.x;
+ *dstp.x++ = *srcp.x++;
+ *dstp.x++ = *srcp.x++;
+ } while (--count != 0);
+ srcp.b -= rect.w*2*4;
+ dstp.b += dsti;
+ count = rect.w;
+ do {
+ *dstp.x++ = *srcp.x;
+ *dstp.x++ = *srcp.x++;
+ *dstp.x++ = *srcp.x++;
+ } while (--count != 0);
+ srcp.b += srci;
+ dstp.b += dsti;
+ count = rect.w;
+ do {
+ *dstp.x++ = *srcp.x;
+ *dstp.x++ = *srcp.x++;
+ *dstp.x++ = *srcp.x++;
+ } while (--count != 0);
+ srcp.b += srci;
+ dstp.b += dsti;
+ } while (srcp.b != endp.b);
+ break;
+ case 3:
+ do {
+ int count = rect.w;
+ do {
+ *dstp.b++ = *srcp.b++;
+ *dstp.w++ = *srcp.w; srcp.b--;
+ *dstp.w++ = *srcp.w++;
+ *dstp.x++ = *srcp.x++;
+ } while (--count != 0);
+ srcp.b -= rect.w*2*3;
+ dstp.b += dsti;
+ count = rect.w;
+ do {
+ *dstp.b++ = *srcp.b++;
+ *dstp.w++ = *srcp.w; srcp.b--;
+ *dstp.w++ = *srcp.w++;
+ *dstp.x++ = *srcp.x++;
+ } while (--count != 0);
+ srcp.b += srci;
+ dstp.b += dsti;
+ count = rect.w;
+ do {
+ *dstp.b++ = *srcp.b++;
+ *dstp.w++ = *srcp.w; srcp.b--;
+ *dstp.w++ = *srcp.w++;
+ *dstp.x++ = *srcp.x++;
+ } while (--count != 0);
+ srcp.b += srci;
+ dstp.b += dsti;
+ } while (srcp.b != endp.b);
+ break;
+ case 2:
+ do {
+ int count = rect.w;
+ do {
+ *dstp.w++ = *srcp.w;
+ *dstp.w++ = *srcp.w++;
+ *dstp.w++ = *srcp.w++;
+ } while (--count != 0);
+ srcp.b -= rect.w*2*2;
+ dstp.b += dsti;
+ count = rect.w;
+ do {
+ *dstp.w++ = *srcp.w;
+ *dstp.w++ = *srcp.w++;
+ *dstp.w++ = *srcp.w++;
+ } while (--count != 0);
+ srcp.b += srci;
+ dstp.b += dsti;
+ count = rect.w;
+ do {
+ *dstp.w++ = *srcp.w;
+ *dstp.w++ = *srcp.w++;
+ *dstp.w++ = *srcp.w++;
+ } while (--count != 0);
+ srcp.b += srci;
+ dstp.b += dsti;
+ } while (srcp.b != endp.b);
+ break;
+ case 1:
+ do {
+ int count = rect.w;
+ do {
+ *dstp.b++ = *srcp.b;
+ *dstp.b++ = *srcp.b++;
+ *dstp.b++ = *srcp.b++;
+ } while (--count != 0);
+ srcp.b -= rect.w*2*1;
+ dstp.b += dsti;
+ count = rect.w;
+ do {
+ *dstp.b++ = *srcp.b;
+ *dstp.b++ = *srcp.b++;
+ *dstp.b++ = *srcp.b++;
+ } while (--count != 0);
+ srcp.b += srci;
+ dstp.b += dsti;
+ count = rect.w;
+ do {
+ *dstp.b++ = *srcp.b;
+ *dstp.b++ = *srcp.b++;
+ *dstp.b++ = *srcp.b++;
+ } while (--count != 0);
+ srcp.b += srci;
+ dstp.b += dsti;
+ } while (srcp.b != endp.b);
+ break;
+ }
+ return(0);
+}
+
+
+#elif 0
+/* the third part shows two extra optimizations:
+ *
+ * (1) the i386 is a desperatly register-starved architecture
+ * and for the case of GNUC we say now where to store the
+ * copyloop variables and we even cut in some assembler snippets.
+ * (2) for that we better use copies of the srcp/dstp/endp pointers and
+ * therefore the initial computations can be done on Byte-pointers
+ * instead of the union-of-pointers as shown above for clarification.
+ *
+ * enough for UAE
+ */
+
+
+/* Perform a stretch blit between two surfaces of the same format.
+ NOTE: This function is not safe to call from multiple threads!
+*/
+int SDL_StretchSurface_23(SDL_Surface *src, SDL_Rect *srcrect,
+ SDL_Surface *dst, SDL_Rect *dstrect)
+{
+ Uint8 *srcp, *dstp, *endp;
+ unsigned int srci, dsti;
+ SDL_Rect rect;
+ SDL_Rect clip;
+ const unsigned bpp = src->format->BytesPerPixel;
+
+ if ( src->format->BitsPerPixel != dst->format->BitsPerPixel ) {
+ SDL_SetError("Only works with same format surfaces");
+ return(-1);
+ }
+
+ /* Verify the blit rectangles */
+ if ( srcrect ) {
+ rect = *srcrect;
+#if 0
+ clip.x = clip.y = 0; clip.h = src->h; clip.w = src->w;
+#else
+ clip = src->clip_rect;
+
+ if (rect.x > clip.x + clip.w ||
+ rect.x + rect.w < clip.x ||
+ rect.y > clip.y + clip.h ||
+ rect.y + rect.h < clip.y) return 1;
+ if (rect.x < clip.x) { rect.w -= clip.x-rect.x; rect.x = clip.x; }
+ if (rect.w > clip.x + clip.w - rect.x)
+ rect.w = clip.x + clip.w - rect.x;
+ if (rect.y < clip.y) { rect.h -= clip.y-rect.y; rect.y = clip.y; }
+ if (rect.h > clip.y + clip.h - rect.y)
+ rect.h = clip.y + clip.h - rect.y;
+#endif
+ if (! rect.h || !rect.w) return 1;
+ rect.x /= 2; rect.w /= 2;
+ rect.y /= 2; rect.h /= 2;
+ clip.x /= 2; clip.w /= 2;
+ clip.y /= 2; clip.h /= 2;
+
+ } else {
+ rect.x = 0;
+ rect.y = 0;
+ rect.w = src->w / 2;
+ rect.h = src->h / 2;
+ clip = rect;
+ }
+
+ {
+ int dest_x = (rect.x - clip.x) * 3;
+ int dest_y = (rect.y - clip.y) * 3;
+ int dest_w = rect.w * 3;
+ int dest_h = rect.h * 3;
+
+ if (dest_x >= dst->clip_rect.x + dst->clip_rect.w ||
+ dest_y >= dst->clip_rect.y + dst->clip_rect.h ||
+ dest_x + dest_w <= dst->clip_rect.x ||
+ dest_y + dest_h <= dst->clip_rect.y) return 1;
+ if (dest_x < dst->clip_rect.x)
+ {
+ rect.w = (dest_w - dst->clip_rect.x - dest_x) / 3;
+ rect.x += (dst->clip_rect.x - dest_x) / 3;
+ dest_w = rect.w * 3; dest_x = dst->clip_rect.x; }
+ if (dest_w > dst->clip_rect.x + dst->clip_rect.w - dest_x)
+ {
+ rect.w = (dst->clip_rect.x + dst->clip_rect.w - dest_x) / 3;
+ dest_w = rect.w * 3; }
+ if (dest_y < dst->clip_rect.y)
+ {
+ rect.h = (dest_h - dst->clip_rect.y - dest_y) / 3;
+ rect.y += (dst->clip_rect.y - dest_y) / 3;
+ dest_h = rect.h * 3; dest_y = dst->clip_rect.y; }
+ if (dest_h > dst->clip_rect.y + dst->clip_rect.h - dest_y)
+ {
+ rect.h = (dst->clip_rect.y + dst->clip_rect.h - dest_y) / 3;
+ dest_h = rect.h * 3; }
+ if (!dest_h || !dest_w || !rect.h || !rect.w) return 1;
+
+ if (dstrect) { /*returnvalue*/
+ dstrect->y = dest_y;
+ dstrect->x = dest_x;
+ dstrect->w = dest_w;
+ dstrect->h = dest_h;
+ }
+
+ dstp = (Uint8*)dst->pixels +
+ (dst->pitch*dest_y) + (bpp*dest_x);
+ srcp = (Uint8*)src->pixels +
+ (src->pitch*rect.y*2) + (bpp*rect.x*2);
+ endp = srcp + src->pitch*rect.h*2;
+ srci = src->pitch - (bpp*rect.w*2);
+ dsti = dst->pitch - (bpp*dest_w);
+ }
+
+#if defined __i386_ || defined __x86_64_
+#define ASM_i386
+#endif
+
+# if defined __GNUC__ && defined ASM_i386
+# define ECX __asm__("%ecx")
+# define ESI __asm__("%esi")
+# define EDI __asm__("%edi")
+# else
+# define ECX
+# define ESI
+# define EDI
+# endif
+
+ switch (bpp)
+ {
+ case 4:
+ {
+ register Uint32* dstP EDI = (Uint32*) dstp;
+ register Uint32* srcP ESI = (Uint32*) srcp;
+ do {
+ register int count ECX = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsl\n" "stosl\n" "stosl\n" "movsl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP -= rect.w*2;
+ dstP += dsti/4;
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsl\n" "stosl\n" "stosl\n" "movsl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci/4; /* gcc is clever enough to make */
+ dstP += dsti/4; /* it really a "ADD dsti, dstP" */
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsl\n" "stosl\n" "stosl\n" "movsl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci/4; /* gcc is clever enough to make */
+ dstP += dsti/4; /* it really a "ADD dsti, dstP" */
+ } while ((Uint8*)srcP != endp);
+ } break;
+ case 3:
+ {
+ register Uint8* dstP EDI = dstp;
+ register Uint8* srcP ESI = srcp;
+ do {
+ register int count ECX = rect.w;
+ do {
+ dstP[0] = srcP[0];
+ dstP[1] = srcP[1];
+ dstP[2] = srcP[2];
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsw\n" "movsl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP -= rect.w*2*3;
+ dstP += dsti;
+ count = rect.w;
+ do {
+ dstP[0] = srcP[0];
+ dstP[1] = srcP[1];
+ dstP[2] = srcP[2];
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsw\n" "movsl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci;
+ dstP += dsti;
+ count = rect.w;
+ do {
+ dstP[0] = srcP[0];
+ dstP[1] = srcP[1];
+ dstP[2] = srcP[2];
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsw\n" "movsl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci;
+ dstP += dsti;
+ } while ((Uint8*)srcP != endp);
+ } break;
+ case 2:
+ {
+ register Uint16* dstP EDI = (Uint16*) dstp;
+ register Uint16* srcP ESI = (Uint16*) srcp;
+ do {
+ register int count ECX = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsw\n" "stosw\n" "stosw\n" "movsw\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP -= rect.w*2;
+ dstP += dsti/2;
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsw\n" "stosw\n" "stosw\n" "movsw\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci/2; /* gcc is clever enough to make */
+ dstP += dsti/2; /* it really a "ADD dsti, dstP" */
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsw\n" "stosw\n" "stosw\n" "movsw\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci/2; /* gcc is clever enough to make */
+ dstP += dsti/2; /* it really a "ADD dsti, dstP" */
+ } while ((Uint8*)srcP != endp);
+ } break;
+ case 1:
+ {
+ register Uint8* dstP EDI = dstp;
+ register Uint8* srcP ESI = srcp;
+ do {
+ register int count ECX = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsb\n" "stosb\n" "stosb\n" "movsb\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcp -= rect.w*2;
+ dstp += dsti;
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsb\n" "stosb\n" "stosb\n" "movsb\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcp += srci;
+ dstp += dsti;
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsb\n" "stosb\n" "stosb\n" "movsb\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcp += srci;
+ dstp += dsti;
+ } while ((Uint8*)srcP != endp);
+ } break;
+ }
+ return 0;
+}
+
+
+#elif 1
+/* a pentium-specific one: using PREFETCH - use with Athlon or Piii only.
+ *
+ * PREFETCHn prefetch into cache (Intel 24547112.pdf, page 649)
+ * MOVNTI store dword using nontemporal hint (page 516)
+ * generally, noticable effect is only seen with PREFETCHnta and MOVNTI
+ * for memcpy implementations. However, in SDL we do often blit to a
+ * surface that will also be used right away, so it is fine to keep it
+ * in a (distant cache).
+ */
+
+
+/* Perform a stretch blit between two surfaces of the same format.
+ NOTE: This function is not safe to call from multiple threads!
+*/
+int SDL_StretchSurface_23(SDL_Surface *src, SDL_Rect *srcrect,
+ SDL_Surface *dst, SDL_Rect *dstrect)
+{
+ Uint8 *srcp, *dstp, *endp;
+ unsigned int srci, dsti;
+ SDL_Rect rect;
+ SDL_Rect clip;
+ const unsigned bpp = src->format->BytesPerPixel;
+
+ if ( src->format->BitsPerPixel != dst->format->BitsPerPixel ) {
+ SDL_SetError("Only works with same format surfaces");
+ return(-1);
+ }
+
+ /* Verify the blit rectangles */
+ if ( srcrect ) {
+ rect = *srcrect;
+#if 0
+ clip.x = clip.y = 0; clip.h = src->h; clip.w = src->w;
+#else
+ clip = src->clip_rect;
+
+ if (rect.x > clip.x + clip.w ||
+ rect.x + rect.w < clip.x ||
+ rect.y > clip.y + clip.h ||
+ rect.y + rect.h < clip.y) return 1;
+ if (rect.x < clip.x) { rect.w -= clip.x-rect.x; rect.x = clip.x; }
+ if (rect.w > clip.x + clip.w - rect.x)
+ rect.w = clip.x + clip.w - rect.x;
+ if (rect.y < clip.y) { rect.h -= clip.y-rect.y; rect.y = clip.y; }
+ if (rect.h > clip.y + clip.h - rect.y)
+ rect.h = clip.y + clip.h - rect.y;
+#endif
+ if (! rect.h || !rect.w) return 1;
+ rect.x /= 2; rect.w /= 2;
+ rect.y /= 2; rect.h /= 2;
+ clip.x /= 2; clip.w /= 2;
+ clip.y /= 2; clip.h /= 2;
+
+ } else {
+ rect.x = 0;
+ rect.y = 0;
+ rect.w = src->w / 2;
+ rect.h = src->h / 2;
+ clip = rect;
+ }
+
+ {
+ int dest_x = (rect.x - clip.x) * 3;
+ int dest_y = (rect.y - clip.y) * 3;
+ int dest_w = rect.w * 3;
+ int dest_h = rect.h * 3;
+
+ if (dest_x >= dst->clip_rect.x + dst->clip_rect.w ||
+ dest_y >= dst->clip_rect.y + dst->clip_rect.h ||
+ dest_x + dest_w <= dst->clip_rect.x ||
+ dest_y + dest_h <= dst->clip_rect.y) return 1;
+ if (dest_x < dst->clip_rect.x)
+ {
+ rect.w = (dest_w - dst->clip_rect.x - dest_x) / 3;
+ rect.x += (dst->clip_rect.x - dest_x) / 3;
+ dest_w = rect.w * 3; dest_x = dst->clip_rect.x; }
+ if (dest_w > dst->clip_rect.x + dst->clip_rect.w - dest_x)
+ {
+ rect.w = (dst->clip_rect.x + dst->clip_rect.w - dest_x) / 3;
+ dest_w = rect.w * 3; }
+ if (dest_y < dst->clip_rect.y)
+ {
+ rect.h = (dest_h - dst->clip_rect.y - dest_y) / 3;
+ rect.y += (dst->clip_rect.y - dest_y) / 3;
+ dest_h = rect.h * 3; dest_y = dst->clip_rect.y; }
+ if (dest_h > dst->clip_rect.y + dst->clip_rect.h - dest_y)
+ {
+ rect.h = (dst->clip_rect.y + dst->clip_rect.h - dest_y) / 3;
+ dest_h = rect.h * 3; }
+ if (!dest_h || !dest_w || !rect.h || !rect.w) return 1;
+
+ if (dstrect) { /*returnvalue*/
+ dstrect->y = dest_y;
+ dstrect->x = dest_x;
+ dstrect->w = dest_w;
+ dstrect->h = dest_h;
+ }
+
+ dstp = (Uint8*)dst->pixels +
+ (dst->pitch*dest_y) + (bpp*dest_x);
+ srcp = (Uint8*)src->pixels +
+ (src->pitch*rect.y*2) + (bpp*rect.x*2);
+ endp = srcp + src->pitch*rect.h*2;
+ srci = src->pitch - (bpp*rect.w*2);
+ dsti = dst->pitch - (bpp*dest_w);
+ }
+
+# if defined __GNUC__ && defined ASM_i386
+# define ECX __asm__("%ecx")
+# define ESI __asm__("%esi")
+# define EDI __asm__("%edi")
+# else
+# define ECX
+# define ESI
+# define EDI
+# endif
+
+ switch (bpp)
+ {
+ case 4:
+ {
+ register Uint32* dstP EDI = (Uint32*) dstp;
+ register Uint32* srcP ESI = (Uint32*) srcp;
+ do {
+ register int count ECX = rect.w;
+# if defined __GNUC__ && defined ASM_i386
+ if (rect.w^(rect.w&255))
+ __asm__ __volatile__ ("prefetchnta 320(%0)\n"
+ :: "r" (srcP));
+# endif
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsl\n" "stosl\n" "stosl\n" "movsl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP -= rect.w*2;
+ dstP += dsti/4;
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsl\n" "stosl\n" "stosl\n" "movsl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci/4; /* gcc is clever enough to make */
+ dstP += dsti/4; /* it really a "ADD dsti, dstP" */
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsl\n" "stosl\n" "stosl\n" "movsl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci/4; /* gcc is clever enough to make */
+ dstP += dsti/4; /* it really a "ADD dsti, dstP" */
+ } while ((Uint8*)srcP != endp);
+ } break;
+ case 3:
+ {
+ register Uint8* dstP EDI = dstp;
+ register Uint8* srcP ESI = srcp;
+ do {
+ register int count ECX = rect.w;
+ do {
+ dstP[0] = srcP[0];
+ dstP[1] = srcP[1];
+ dstP[2] = srcP[2];
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsw\n" "movsl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP -= rect.w*2*3;
+ dstP += dsti;
+ count = rect.w;
+ do {
+ dstP[0] = srcP[0];
+ dstP[1] = srcP[1];
+ dstP[2] = srcP[2];
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsw\n" "movsl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci;
+ dstP += dsti;
+ count = rect.w;
+ do {
+ dstP[0] = srcP[0];
+ dstP[1] = srcP[1];
+ dstP[2] = srcP[2];
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsw\n" "movsl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci;
+ dstP += dsti;
+ } while ((Uint8*)srcP != endp);
+ } break;
+ case 2:
+ {
+ register Uint16* dstP EDI = (Uint16*) dstp;
+ register Uint16* srcP ESI = (Uint16*) srcp;
+# if defined __GNUC__ && defined ASM_i386
+ if (rect.w^(rect.w&255))
+ __asm__ __volatile__ ("prefetchnta 512(%0)\n"
+ :: "r" (srcP));
+# endif
+ do {
+ register int count ECX = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsw\n" "stosw\n" "stosw\n" "movsw\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP -= rect.w*2;
+ dstP += dsti/2;
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsw\n" "stosw\n" "stosw\n" "movsw\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci/2; /* gcc is clever enough to make */
+ dstP += dsti/2; /* it really a "ADD dsti, dstP" */
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsw\n" "stosw\n" "stosw\n" "movsw\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci/2; /* gcc is clever enough to make */
+ dstP += dsti/2; /* it really a "ADD dsti, dstP" */
+ } while ((Uint8*)srcP != endp);
+ } break;
+ case 1:
+ {
+ register Uint8* dstP EDI = dstp;
+ register Uint8* srcP ESI = srcp;
+ do {
+ register int count ECX = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsb\n" "stosb\n" "stosb\n" "movsb\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcp -= rect.w*2;
+ dstp += dsti;
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsb\n" "stosb\n" "stosb\n" "movsb\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcp += srci;
+ dstp += dsti;
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsb\n" "stosb\n" "stosb\n" "movsb\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcp += srci;
+ dstp += dsti;
+ } while ((Uint8*)srcP != endp);
+ } break;
+ }
+ return 0;
+}
+
+#elif 1
+
+/* that routine is not a perfect stretch either - hopefully you have
+ * already noticed it: we have implicitly cut everything to div-2,
+ * the src-start and src-width are all on even columns and rows and
+ * the stretch algorithm will always do XY -> XXY and never the way
+ * of the odd rows/columns with a XY -> XYY copy operation. If we
+ * want to fix it but still want to keep the copy-loop as short as
+ * ever possible then we need to make an outer switch of 4x4 = 16 cases
+ * given that src-x/src-y can be each even/odd (four combinations)
+ * and that src-w/src-h be each even/odd as well (four combinations).
+ * Along with four bytedepths, we would come out at 64 copy-loop
+ * definitions but in reality there are 128 copy-loops. Guess why.
+ * oddX
+ * only
+ */
+
+/* Perform a stretch blit between two surfaces of the same format.
+ NOTE: This function is not safe to call from multiple threads!
+*/
+int SDL_StretchSurface_23(SDL_Surface *src, SDL_Rect *srcrect,
+ SDL_Surface *dst, SDL_Rect *dstrect)
+{
+ Uint8 *srcp, *dstp, *endp;
+ unsigned int srci, dsti;
+ SDL_Rect rect;
+ SDL_Rect clip;
+ const unsigned bpp = src->format->BytesPerPixel;
+ Uint8 oddX = 0;
+
+ if ( src->format->BitsPerPixel != dst->format->BitsPerPixel ) {
+ SDL_SetError("Only works with same format surfaces");
+ return(-1);
+ }
+
+ /* Verify the blit rectangles */
+ if ( srcrect ) {
+ rect = *srcrect;
+#if 0
+ clip.x = clip.y = 0; clip.h = src->h; clip.w = src->w;
+#else
+ clip = src->clip_rect;
+
+ if (rect.x > clip.x + clip.w ||
+ rect.x + rect.w < clip.x ||
+ rect.y > clip.y + clip.h ||
+ rect.y + rect.h < clip.y) return 1;
+ if (rect.x < clip.x) { rect.w -= clip.x-rect.x; rect.x = clip.x; }
+ if (rect.w > clip.x + clip.w - rect.x)
+ rect.w = clip.x + clip.w - rect.x;
+ if (rect.y < clip.y) { rect.h -= clip.y-rect.y; rect.y = clip.y; }
+ if (rect.h > clip.y + clip.h - rect.y)
+ rect.h = clip.y + clip.h - rect.y;
+#endif
+ if (! rect.h || !rect.w) return 1;
+ oddX = rect.x&1;
+ rect.x /= 2;
+ rect.y /= 2;
+ rect.w /= 2;
+ rect.h /= 2;
+ } else {
+ rect.x = 0;
+ rect.y = 0;
+ rect.w = src->w / 2;
+ rect.h = src->h / 2;
+ clip = rect;
+ }
+
+ {
+ int dest_x = (rect.x - clip.x/2) * 3 + oddX;
+ int dest_y = (rect.y - clip.y/2) * 3;
+ int dest_w = rect.w * 3;
+ int dest_h = rect.h * 3;
+
+ if (dest_x >= dst->clip_rect.x + dst->clip_rect.w ||
+ dest_y >= dst->clip_rect.y + dst->clip_rect.h ||
+ dest_x + dest_w <= dst->clip_rect.x ||
+ dest_y + dest_h <= dst->clip_rect.y) return 1;
+ if (dest_x < dst->clip_rect.x)
+ {
+ rect.w = (dest_w - dst->clip_rect.x - dest_x) / 3;
+ rect.x += (dst->clip_rect.x - dest_x) / 3; oddX = 0;
+ dest_w = rect.w * 3; dest_x = dst->clip_rect.x; }
+ if (dest_w > dst->clip_rect.x + dst->clip_rect.w - dest_x)
+ {
+ rect.w = (dst->clip_rect.x + dst->clip_rect.w - dest_x) / 3;
+ dest_w = rect.w * 3; }
+ if (dest_y < dst->clip_rect.y)
+ {
+ rect.h = (dest_h - dst->clip_rect.y - dest_y) / 3;
+ rect.y += (dst->clip_rect.y - dest_y) / 3;
+ dest_h = rect.h * 3; dest_y = dst->clip_rect.y; }
+ if (dest_h > dst->clip_rect.y + dst->clip_rect.h - dest_y)
+ {
+ rect.h = (dst->clip_rect.y + dst->clip_rect.h - dest_y) / 3;
+ dest_h = rect.h * 3; }
+ if (!dest_h || !dest_w || !rect.h || !rect.w) return 1;
+
+ if (dstrect) { /*returnvalue*/
+ dstrect->y = dest_y;
+ dstrect->x = dest_x;
+ dstrect->w = dest_w;
+ dstrect->h = dest_h;
+ }
+
+ dstp = (Uint8*)dst->pixels +
+ (dst->pitch*dest_y) + (bpp*dest_x);
+ srcp = (Uint8*)src->pixels +
+ (src->pitch*rect.y*2) + (bpp*(rect.x*2+oddX));
+ endp = srcp + src->pitch*rect.h*2;
+ srci = src->pitch - (bpp*rect.w*2);
+ dsti = dst->pitch - (bpp*dest_w);
+ }
+
+# if defined __GNUC__ && defined ASM_i386
+# define ECX __asm__("%ecx")
+# define ESI __asm__("%esi")
+# define EDI __asm__("%edi")
+# else
+# define ECX
+# define ESI
+# define EDI
+# endif
+
+ if (oddX) goto odd_X_even_Y;
+
+ switch (bpp)
+ {
+ case 4:
+ {
+ register Uint32* dstP EDI = (Uint32*) dstp;
+ register Uint32* srcP ESI = (Uint32*) srcp;
+ do {
+ register int count ECX = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsl\n" "stosl\n" "stosl\n" "movsl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP -= rect.w*2;
+ dstP += dsti/4;
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsl\n" "stosl\n" "stosl\n" "movsl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci/4; /* gcc is clever enough to make */
+ dstP += dsti/4; /* it really a "ADD dsti, dstP" */
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsl\n" "stosl\n" "stosl\n" "movsl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci/4; /* gcc is clever enough to make */
+ dstP += dsti/4; /* it really a "ADD dsti, dstP" */
+ } while ((Uint8*)srcP != endp);
+ } break;
+ case 3:
+ {
+ register Uint8* dstP EDI = dstp;
+ register Uint8* srcP ESI = srcp;
+ do {
+ register int count ECX = rect.w;
+ do {
+ dstP[0] = srcP[0];
+ dstP[1] = srcP[1];
+ dstP[2] = srcP[2];
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsw\n" "movsl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP -= rect.w*2*3;
+ dstP += dsti;
+ count = rect.w;
+ do {
+ dstP[0] = srcP[0];
+ dstP[1] = srcP[1];
+ dstP[2] = srcP[2];
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsw\n" "movsl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci;
+ dstP += dsti;
+ count = rect.w;
+ do {
+ dstP[0] = srcP[0];
+ dstP[1] = srcP[1];
+ dstP[2] = srcP[2];
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsw\n" "movsl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci;
+ dstP += dsti;
+ } while ((Uint8*)srcP != endp);
+ } break;
+ case 2:
+ {
+ register Uint16* dstP EDI = (Uint16*) dstp;
+ register Uint16* srcP ESI = (Uint16*) srcp;
+ do {
+ register int count ECX = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsw\n" "stosw\n" "stosw\n" "movsw\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP -= rect.w*2;
+ dstP += dsti/2;
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsw\n" "stosw\n" "stosw\n" "movsw\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci/2; /* gcc is clever enough to make */
+ dstP += dsti/2; /* it really a "ADD dsti, dstP" */
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsw\n" "stosw\n" "stosw\n" "movsw\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci/2; /* gcc is clever enough to make */
+ dstP += dsti/2; /* it really a "ADD dsti, dstP" */
+ } while ((Uint8*)srcP != endp);
+ } break;
+ case 1:
+ {
+ register Uint8* dstP EDI = dstp;
+ register Uint8* srcP ESI = srcp;
+ do {
+ register int count ECX = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsb\n" "stosb\n" "stosb\n" "movsb\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcp -= rect.w*2;
+ dstp += dsti;
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsb\n" "stosb\n" "stosb\n" "movsb\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcp += srci;
+ dstp += dsti;
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsb\n" "stosb\n" "stosb\n" "movsb\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcp += srci;
+ dstp += dsti;
+ } while ((Uint8*)srcP != endp);
+ } break;
+ }
+ return 0;
+
+odd_X_even_Y:
+ switch (bpp)
+ {
+ case 4:
+ {
+ register Uint32* dstP EDI = (Uint32*) dstp;
+ register Uint32* srcP ESI = (Uint32*) srcp;
+ do {
+ register int count ECX = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsl\n" "lodsl\n" "stosl\n" "stosl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP -= rect.w*2;
+ dstP += dsti/4;
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsl\n" "lodsl\n" "stosl\n" "stosl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci/4; /* gcc is clever enough to make */
+ dstP += dsti/4; /* it really a "ADD dsti, dstP" */
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsl\n" "lodsl\n" "stosl\n" "stosl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci/4; /* gcc is clever enough to make */
+ dstP += dsti/4; /* it really a "ADD dsti, dstP" */
+ } while ((Uint8*)srcP != endp);
+ } break;
+ case 3:
+ {
+ register Uint8* dstP EDI = dstp;
+ register Uint8* srcP ESI = srcp;
+ do {
+ register int count ECX = rect.w;
+ do {
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ dstP[0] = srcP[0];
+ dstP[1] = srcP[1];
+ dstP[2] = srcP[2];
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ } while (--count != 0);
+ srcP -= rect.w*2*3;
+ dstP += dsti;
+ count = rect.w;
+ do {
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ dstP[0] = srcP[0];
+ dstP[1] = srcP[1];
+ dstP[2] = srcP[2];
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ } while (--count != 0);
+ srcP += srci;
+ dstP += dsti;
+ count = rect.w;
+ do {
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ dstP[0] = srcP[0];
+ dstP[1] = srcP[1];
+ dstP[2] = srcP[2];
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ } while (--count != 0);
+ srcP += srci;
+ dstP += dsti;
+ } while ((Uint8*)srcP != endp);
+ } break;
+ case 2:
+ {
+ register Uint16* dstP EDI = (Uint16*) dstp;
+ register Uint16* srcP ESI = (Uint16*) srcp;
+ do {
+ register int count ECX = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsw\n" "lodsw\n" "stosw\n" "stosw\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP -= rect.w*2;
+ dstP += dsti/2;
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsw\n" "lodsw\n" "stosw\n" "stosw\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci/2; /* gcc is clever enough to make */
+ dstP += dsti/2; /* it really a "ADD dsti, dstP" */
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsw\n" "lodsw\n" "stosw\n" "stosw\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci/2; /* gcc is clever enough to make */
+ dstP += dsti/2; /* it really a "ADD dsti, dstP" */
+ } while ((Uint8*)srcP != endp);
+ } break;
+ case 1:
+ {
+ register Uint8* dstP EDI = dstp;
+ register Uint8* srcP ESI = srcp;
+ do {
+ register int count ECX = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsb\n" "lodsb\n" "stosb\n" "stosb\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcp -= rect.w*2;
+ dstp += dsti;
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsb\n" "lodsb\n" "stosb\n" "stosb\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcp += srci;
+ dstp += dsti;
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsb\n" "lodsb\n" "stosb\n" "stosb\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcp += srci;
+ dstp += dsti;
+ } while ((Uint8*)srcP != endp);
+ } break;
+ }
+ return 0;
+}
+
+#elif 1
+
+/* that routine is not a perfect stretch either - hopefully you have
+ * already noticed it: we have implicitly cut everything to div-2,
+ * the src-start and src-width are all on even columns and rows and
+ * the stretch algorithm will always do XY -> XXY and never the way
+ * of the odd rows/columns with a XY -> XYY copy operation. If we
+ * want to fix it but still want to keep the copy-loop as short as
+ * ever possible then we need to make an outer switch of 4x4 = 16 cases
+ * given that src-x/src-y can be each even/odd (four combinations)
+ * and that src-w/src-h be each even/odd as well (four combinations).
+ * Along with four bytedepths, we would come out at 64 copy-loop
+ * definitions but in reality there are 128 copy-loops. Guess why.
+ * [[ ALL ]]
+ * unfinished
+ */
+
+/* Perform a stretch blit between two surfaces of the same format.
+ NOTE: This function is not safe to call from multiple threads!
+*/
+int SDL_StretchSurface_23(SDL_Surface *src, SDL_Rect *srcrect,
+ SDL_Surface *dst, SDL_Rect *dstrect)
+{
+ Uint8 *srcp, *dstp, *endp;
+ unsigned int srci, dsti;
+ SDL_Rect rect;
+ SDL_Rect clip;
+ const unsigned bpp = src->format->BytesPerPixel;
+ Uint8 kind = 0;
+
+ if ( src->format->BitsPerPixel != dst->format->BitsPerPixel ) {
+ SDL_SetError("Only works with same format surfaces");
+ return(-1);
+ }
+
+ if (0) fprintf(stderr,
+ "[%4i +%4i /%4i +%4i ] ->"
+ "[%4i+%4i/%4i+%4i]\n",
+ srcrect->x, srcrect->w,
+ srcrect->y, srcrect->h,
+ dst->clip_rect.x, dst->clip_rect.w,
+ dst->clip_rect.y, dst->clip_rect.h);
+
+ /* Verify the blit rectangles */
+ if ( srcrect ) {
+ rect = *srcrect;
+#if 0
+ clip.x = clip.y = 0; clip.h = src->h; clip.w = src->w;
+#else
+ clip = src->clip_rect;
+
+ if (rect.x > clip.x + clip.w ||
+ rect.x + rect.w < clip.x ||
+ rect.y > clip.y + clip.h ||
+ rect.y + rect.h < clip.y) return 1;
+ if (rect.x < clip.x) { rect.w -= clip.x-rect.x; rect.x = clip.x; }
+ if (rect.w > clip.x + clip.w - rect.x)
+ rect.w = clip.x + clip.w - rect.x;
+ if (rect.y < clip.y) { rect.h -= clip.y-rect.y; rect.y = clip.y; }
+ if (rect.h > clip.y + clip.h - rect.y)
+ rect.h = clip.y + clip.h - rect.y;
+#endif
+ if (! rect.h || !rect.w) return 1;
+ kind |= rect.x&1; rect.x /= 2; kind<<=1;
+ kind |= rect.y&1; rect.y /= 2; kind<<=1;
+ kind |= rect.w&1; rect.w /= 2; kind<<=1;
+ kind |= rect.h&1; rect.h /= 2;
+ } else {
+ rect.x = 0;
+ rect.y = 0; kind |= src->w&1; kind<<=1;
+ rect.w = src->w / 2; kind |= src->h&1;
+ rect.h = src->h / 2;
+ clip = rect;
+ }
+
+/* bitmasks */
+# define _H 1
+# define _W 2
+# define _Y 4
+# define _X 8
+/* shiftvals */
+# define _H_ 0
+# define _W_ 1
+# define _Y_ 2
+# define _X_ 3
+
+ {
+ int dest_x = (rect.x - clip.x/2) * 3;
+ int dest_y = (rect.y - clip.y/2) * 3;
+ int dest_w = rect.w * 3;
+ int dest_h = rect.h * 3;
+ if (0) fprintf(stderr,
+ "[%3i*2%c+%3i*2%c/%3i*2%c+%3i*2%c] ->"
+ "[%4i+%4i/%4i+%4i]\n",
+ rect.x,(kind&_X)?'>':'.',rect.w,(kind&_W)?'>':'.',
+ rect.y,(kind&_Y)?'>':'.',rect.h,(kind&_H)?'>':'.',
+ dest_x,dest_w, dest_y,dest_h);
+ switch(kind) /* a switch statement is not an if() - it turns */
+ { /* out to be a table lookup operation actually */
+ case _X|_Y|_W|_H: dest_h ++; /*>>*/
+ case _X|_Y|_W: dest_w ++; /*>>*/
+ case _X|_Y: dest_y ++; /*>>*/
+ case _X: dest_x ++; break;
+ case _Y|_W|_H: dest_h ++; /*>>*/
+ case _Y|_W: dest_w ++; /*>>*/
+ case _Y: dest_x ++; break;
+ case _W|_X: dest_x ++; goto case__W;
+ case _W|_H|_X: dest_x ++; /*>>*/
+ case _W|_H: dest_h ++; /*>>*/
+ case__W:
+ case _W: dest_w ++; break;
+ case _H|_Y: dest_y ++; goto case__H;
+ case _H|_X|_Y: dest_y ++; /*>>*/
+ case _H|_X: dest_x ++; /*>>*/
+ case__H:
+ case _H: dest_h ++; break;
+ case 0: break;
+ }
+ if (0) fprintf(stderr,
+ "[%3i*2%c+%3i*2%c/%3i*2%c+%3i*2%c] ->"
+ "[%4i+%4i/%4i+%4i] !\n",
+ rect.x,(kind&_X)?'>':'.',rect.w,(kind&_W)?'>':'.',
+ rect.y,(kind&_Y)?'>':'.',rect.h,(kind&_H)?'>':'.',
+ dest_x,dest_w, dest_y,dest_h);
+
+ if (dest_x >= dst->clip_rect.x + dst->clip_rect.w ||
+ dest_y >= dst->clip_rect.y + dst->clip_rect.h ||
+ dest_x + dest_w <= dst->clip_rect.x ||
+ dest_y + dest_h <= dst->clip_rect.y) return 1;
+ if (dest_x < dst->clip_rect.x)
+ {
+ rect.w = (dest_w - dst->clip_rect.x - dest_x) / 3;
+ rect.x += (dst->clip_rect.x - dest_x) / 3;
+ dest_w = rect.w * 3; dest_x = dst->clip_rect.x;
+ kind &= _X|_Y|_H; }
+ if (dest_w > dst->clip_rect.x + dst->clip_rect.w - dest_x)
+ {
+ rect.w = (dst->clip_rect.x + dst->clip_rect.w - dest_x) / 3;
+ dest_w = rect.w * 3;
+ kind &= _X|_Y|_H; }
+ if (dest_y < dst->clip_rect.y)
+ {
+ rect.h = (dest_h - dst->clip_rect.y - dest_y) / 3;
+ rect.y += (dst->clip_rect.y - dest_y) / 3;
+ dest_h = rect.h * 3; dest_y = dst->clip_rect.y;
+ kind &= _X|_Y|_W; }
+ if (dest_h > dst->clip_rect.y + dst->clip_rect.h - dest_y)
+ {
+ rect.h = (dst->clip_rect.y + dst->clip_rect.h - dest_y) / 3;
+ dest_h = rect.h * 3;
+ kind &= _X|_Y|_W; }
+ if (!dest_h || !dest_w || !rect.h || !rect.w) return 1;
+
+ if (dstrect) { /*returnvalue*/
+ dstrect->y = dest_y;
+ dstrect->x = dest_x;
+ dstrect->w = dest_w;
+ dstrect->h = dest_h;
+ }
+
+ if (0) fprintf(stderr,
+ "[%3i*2%c+%3i*2%c/%3i*2%c+%3i*2%c] ->"
+ "[%4i+%4i/%4i+%4i] !!\n",
+ rect.x,(kind&_X)?'>':'.',rect.w,(kind&_W)?'>':'.',
+ rect.y,(kind&_Y)?'>':'.',rect.h,(kind&_H)?'>':'.',
+ dest_x,dest_w, dest_y,dest_h);
+
+ dstp = (Uint8*)dst->pixels +
+ (dst->pitch*dest_y) + (bpp*dest_x);
+ srcp = (Uint8*)src->pixels +
+ (src->pitch*rect.y*2) + (bpp*rect.x*2);
+ endp = srcp + src->pitch*rect.h*2;
+ srci = src->pitch - (bpp*rect.w*2);
+ dsti = dst->pitch - (bpp*dest_w);
+ }
+
+# if defined __GNUC__ && defined ASM_i386
+# define ECX __asm__("%ecx")
+# define ESI __asm__("%esi")
+# define EDI __asm__("%edi")
+# else
+# define ECX
+# define ESI
+# define EDI
+# endif
+
+ if (kind&_X) goto odd_X_even_Y;
+
+ switch (bpp)
+ {
+ case 4:
+ {
+ register Uint32* dstP EDI = (Uint32*) dstp;
+ register Uint32* srcP ESI = (Uint32*) srcp;
+ do {
+ register int count ECX = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsl\n" "stosl\n" "stosl\n" "movsl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP -= rect.w*2;
+ dstP += dsti/4;
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsl\n" "stosl\n" "stosl\n" "movsl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci/4; /* gcc is clever enough to make */
+ dstP += dsti/4; /* it really a "ADD dsti, dstP" */
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsl\n" "stosl\n" "stosl\n" "movsl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci/4; /* gcc is clever enough to make */
+ dstP += dsti/4; /* it really a "ADD dsti, dstP" */
+ } while ((Uint8*)srcP != endp);
+ } break;
+ case 3:
+ {
+ register Uint8* dstP EDI = dstp;
+ register Uint8* srcP ESI = srcp;
+ do {
+ register int count ECX = rect.w;
+ do {
+ dstP[0] = srcP[0];
+ dstP[1] = srcP[1];
+ dstP[2] = srcP[2];
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsw\n" "movsl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP -= rect.w*2*3;
+ dstP += dsti;
+ count = rect.w;
+ do {
+ dstP[0] = srcP[0];
+ dstP[1] = srcP[1];
+ dstP[2] = srcP[2];
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsw\n" "movsl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci;
+ dstP += dsti;
+ count = rect.w;
+ do {
+ dstP[0] = srcP[0];
+ dstP[1] = srcP[1];
+ dstP[2] = srcP[2];
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsw\n" "movsl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci;
+ dstP += dsti;
+ } while ((Uint8*)srcP != endp);
+ } break;
+ case 2:
+ {
+ register Uint16* dstP EDI = (Uint16*) dstp;
+ register Uint16* srcP ESI = (Uint16*) srcp;
+ do {
+ register int count ECX = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsw\n" "stosw\n" "stosw\n" "movsw\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP -= rect.w*2;
+ dstP += dsti/2;
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsw\n" "stosw\n" "stosw\n" "movsw\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci/2; /* gcc is clever enough to make */
+ dstP += dsti/2; /* it really a "ADD dsti, dstP" */
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsw\n" "stosw\n" "stosw\n" "movsw\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci/2; /* gcc is clever enough to make */
+ dstP += dsti/2; /* it really a "ADD dsti, dstP" */
+ } while ((Uint8*)srcP != endp);
+ } break;
+ case 1:
+ {
+ register Uint8* dstP EDI = dstp;
+ register Uint8* srcP ESI = srcp;
+ do {
+ register int count ECX = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsb\n" "stosb\n" "stosb\n" "movsb\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcp -= rect.w*2;
+ dstp += dsti;
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsb\n" "stosb\n" "stosb\n" "movsb\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcp += srci;
+ dstp += dsti;
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("lodsb\n" "stosb\n" "stosb\n" "movsb\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcp += srci;
+ dstp += dsti;
+ } while ((Uint8*)srcP != endp);
+ } break;
+ }
+ return 0;
+
+odd_X_even_Y:
+ switch (bpp)
+ {
+ case 4:
+ {
+ register Uint32* dstP EDI = (Uint32*) dstp;
+ register Uint32* srcP ESI = (Uint32*) srcp;
+ do {
+ register int count ECX = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsl\n" "lodsl\n" "stosl\n" "stosl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP -= rect.w*2;
+ dstP += dsti/4;
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsl\n" "lodsl\n" "stosl\n" "stosl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci/4; /* gcc is clever enough to make */
+ dstP += dsti/4; /* it really a "ADD dsti, dstP" */
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsl\n" "lodsl\n" "stosl\n" "stosl\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci/4; /* gcc is clever enough to make */
+ dstP += dsti/4; /* it really a "ADD dsti, dstP" */
+ } while ((Uint8*)srcP != endp);
+ } break;
+ case 3:
+ {
+ register Uint8* dstP EDI = dstp;
+ register Uint8* srcP ESI = srcp;
+ do {
+ register int count ECX = rect.w;
+ do {
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ dstP[0] = srcP[0];
+ dstP[1] = srcP[1];
+ dstP[2] = srcP[2];
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ } while (--count != 0);
+ srcP -= rect.w*2*3;
+ dstP += dsti;
+ count = rect.w;
+ do {
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ dstP[0] = srcP[0];
+ dstP[1] = srcP[1];
+ dstP[2] = srcP[2];
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ } while (--count != 0);
+ srcP += srci;
+ dstP += dsti;
+ count = rect.w;
+ do {
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ dstP[0] = srcP[0];
+ dstP[1] = srcP[1];
+ dstP[2] = srcP[2];
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP++;
+ } while (--count != 0);
+ srcP += srci;
+ dstP += dsti;
+ } while ((Uint8*)srcP != endp);
+ } break;
+ case 2:
+ {
+ register Uint16* dstP EDI = (Uint16*) dstp;
+ register Uint16* srcP ESI = (Uint16*) srcp;
+ do {
+ register int count ECX = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsw\n" "lodsw\n" "stosw\n" "stosw\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP -= rect.w*2;
+ dstP += dsti/2;
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsw\n" "lodsw\n" "stosw\n" "stosw\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci/2; /* gcc is clever enough to make */
+ dstP += dsti/2; /* it really a "ADD dsti, dstP" */
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsw\n" "lodsw\n" "stosw\n" "stosw\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcP += srci/2; /* gcc is clever enough to make */
+ dstP += dsti/2; /* it really a "ADD dsti, dstP" */
+ } while ((Uint8*)srcP != endp);
+ } break;
+ case 1:
+ {
+ register Uint8* dstP EDI = dstp;
+ register Uint8* srcP ESI = srcp;
+ do {
+ register int count ECX = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsb\n" "lodsb\n" "stosb\n" "stosb\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcp -= rect.w*2;
+ dstp += dsti;
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsb\n" "lodsb\n" "stosb\n" "stosb\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcp += srci;
+ dstp += dsti;
+ count = rect.w;
+ do {
+# if defined __GNUC__ && defined ASM_i386
+ __asm__ __volatile__ ("movsb\n" "lodsb\n" "stosb\n" "stosb\n"
+ :: "S" (srcP), "D" (dstP) : "%eax");
+# else
+ *dstP++ = *srcP++;
+ *dstP++ = *srcP;
+ *dstP++ = *srcP++;
+# endif
+ } while (--count != 0);
+ srcp += srci;
+ dstp += dsti;
+ } while ((Uint8*)srcP != endp);
+ } break;
+ }
+ return 0;
+}
+
+#endif
+
+/* --------------------------------------------------------------------- */
+/* RowCode */
+/* --------------------------------------------------------------------- */
diff --git a/util/sdl/stretch/sdlstretchcode.c b/util/sdl/stretch/sdlstretchcode.c
new file mode 100644
index 00000000..bf929128
--- /dev/null
+++ b/util/sdl/stretch/sdlstretchcode.c
@@ -0,0 +1,381 @@
+/*
+ SDL_stretch - Stretch Functions For The Simple DirectMedia Layer
+ Copyright (C) 2003 Guido Draheim
+
+ 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.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Guido Draheim, guidod@gmx.de
+*/
+
+#ifdef SAVE_RCSID
+static char rcsid =
+ "@(#) $Id: sdlcode.c $";
+#endif
+
+#include "config.h"
+#include "SDL/SDL_error.h"
+#include "SDL/SDL_video.h"
+#include "SDL_stretchcode.h"
+#include "SDL_stretchasm.h"
+
+#ifdef SDL_STRETCH_DATA_NOEXEC
+#ifdef __unix__
+#include <unistd.h>
+#include <sys/mman.h>
+#endif
+#include <malloc.h>
+#endif
+
+#ifdef SDL_STRETCH_CALL
+#if defined SDL_STRETCH_I386 || defined SDL_STRETCH_X86_64
+/*
+ * in AMD64 "long mode" all traditional opcodes stay 32bit
+ * and 64bit cousins have to be encoded via REX prefixes.
+ * The only exception are PUSH/POP/RET opcodes that will
+ * implicitly be 64bit. This makes it so the following
+ * opcode settings work in both 32bit and 64bit mode but
+ * for one case: the "INCSI" bit series is dropped and used
+ * for the "REX" prefix opcodes in AMD64 long mode.
+ */
+#define iLOADSB 0xAC
+#define iLOADSW 0xAD
+#define iSTOSB 0xAA
+#define iSTOSW 0xAB
+#define iPUSHCX 0x51
+#define iPOPCX 0x59
+#define iINCSI 0x46
+#define iXCHGCXAX 0x91
+#define iPREFIX16 0x66
+#define iRET 0xC3
+/*
+ * does XCHG yield a fast register renaming on P >= P3 ?
+ */
+# define PREP_1BYTE(dst)
+# define PREP_2BYTE(dst)
+# define PREP_3BYTE(dst) { *dst++ = iPUSHCX; }
+# define PREP_4BYTE(dst)
+# define LOAD_1BYTE(dst) { *dst++ = iLOADSB; }
+# define LOAD_2BYTE(dst) { *dst++ = iPREFIX16; *dst++ = iLOADSW; }
+# define LOAD_3BYTE(dst) { *dst++ = iLOADSB; *dst++ = iXCHGCXAX; \
+ *dst++ = iPREFIX16; *dst++ = iLOADSW; }
+# define LOAD_4BYTE(dst) { *dst++ = iLOADSW; }
+# define STORE_1BYTE(dst) { *dst++ = iSTOSB; }
+# define STORE_2BYTE(dst) { *dst++ = iPREFIX16; *dst++ = iSTOSW; }
+# define STORE_3BYTE(dst) { *dst++ = iXCHGCXAX; *dst++ = iSTOSB; *dst++ = iXCHGCXAX; \
+ *dst++ = iPREFIX16; *dst++ = iSTOSW; }
+# define STORE_4BYTE(dst) { *dst++ = iSTOSW; }
+# define RETURN_1BYTE(dst) { *dst++ = iRET; }
+# define RETURN_2BYTE(dst) { *dst++ = iRET; }
+# define RETURN_3BYTE(dst) { *dst++ = iPOPCX; *dst++ = iRET; }
+# define RETURN_4BYTE(dst) { *dst++ = iRET; }
+# ifdef SDL_STRETCH_I386
+# define SKIP_1BYTE(dst) { *dst++ = iINCSI; }
+# define SKIP_2BYTE(dst) { *dst++ = iINCSI; *dst++ = iINCSI; }
+# define SKIP_3BYTE(dst) { *dst++ = iINCSI; *dst++ = iINCSI; *dst++ = iINCSI; }
+#endif
+#define HAVE_NATIVE_CODE
+#endif
+#endif
+
+/* ASM i386 */
+#ifndef HAVE_NATIVE_CODE
+#define PREP_1BYTE(dst)
+#define PREP_2BYTE(dst)
+#define PREP_3BYTE(dst)
+#define PREP_4BYTE(dst)
+#define LOAD_1BYTE(dst) { *dst++ = 001; }
+#define LOAD_2BYTE(dst) { *dst++ = 002; }
+#define LOAD_3BYTE(dst) { *dst++ = 003; }
+#define LOAD_4BYTE(dst) { *dst++ = 004; }
+#define STORE_1BYTE(dst) { *dst++ = 011; }
+#define STORE_2BYTE(dst) { *dst++ = 012; }
+#define STORE_3BYTE(dst) { *dst++ = 013; }
+#define STORE_4BYTE(dst) { *dst++ = 014; }
+#define RETURN_1BYTE(dst) { *dst++ = 0; }
+#define RETURN_2BYTE(dst) { *dst++ = 0; }
+#define RETURN_3BYTE(dst) { *dst++ = 0; }
+#define RETURN_4BYTE(dst) { *dst++ = 0; }
+#define HAVE_INTERPRETED_CODE
+#endif
+
+#ifndef SKIP_1BYTE
+#define SKIP_1BYTE(dst) LOAD_1BYTE(dst)
+#endif
+#ifndef SKIP_2BYTE
+#define SKIP_2BYTE(dst) LOAD_2BYTE(dst)
+#endif
+#ifndef SKIP_3BYTE
+#define SKIP_3BYTE(dst) LOAD_3BYTE(dst)
+#endif
+#ifndef SKIP_4BYTE
+#define SKIP_4BYTE(dst) LOAD_4BYTE(dst)
+#endif
+
+#ifdef SDL_STRETCH_DATA_NOEXEC
+unsigned char* SDL_TheRowStretchCode = NULL;
+#else
+unsigned char SDL_TheRowStretchCode[SDL_STRETCHCODE_BUFFERSIZE];
+#endif
+
+unsigned char* SDL_NewRowStretchCode (unsigned size) {
+ if (size == 0) size = SDL_STRETCHCODE_BUFFERSIZE;
+# if defined SDL_STRETCH_DATA_NOEXEC && defined __unix__
+ unsigned char* buffer = memalign(getpagesize(), SDL_STRETCHCODE_BUFFERSIZE);
+ if (-1 == mprotect(buffer, SDL_STRETCHCODE_BUFFERSIZE, PROT_READ|PROT_WRITE|PROT_EXEC)) {
+ free (buffer);
+ SDL_SetError("SDL_TheRowStretchCode - can not allocate and make executable");
+ return 0;
+ }
+# else
+ unsigned char* buffer = malloc(SDL_STRETCHCODE_BUFFERSIZE);
+# endif
+ return buffer;
+}
+
+unsigned char* SDL_GetRowStretchCode (void) {
+#ifdef SDL_STRETCH_DATA_NOEXEC
+ if (SDL_TheRowStretchCode == NULL) {
+ SDL_TheRowStretchCode = SDL_NewRowStretchCode(0);
+ }
+#endif
+ return SDL_TheRowStretchCode;
+}
+
+unsigned char* SDL_SetRowStretchCode (int src_w, int dst_w, int bpp)
+{
+#ifdef SDL_STRETCH_DATA_NOEXEC
+ if (SDL_TheRowStretchCode == NULL) {
+ SDL_TheRowStretchCode = SDL_GetRowStretchCode();
+ }
+#endif
+ return SDL_PutRowStretchCode(SDL_TheRowStretchCode,
+ sizeof(SDL_TheRowStretchCode),
+ src_w, dst_w, bpp);
+}
+
+/*
+ * The computed stretch code represents a kind of Bresenham x/y line
+ * algorithm where our stretching factor matches with the steepness.
+ */
+unsigned char* SDL_PutRowStretchCode(unsigned char* buf_ptr, int buf_len,
+ int src_w, int dst_w, int bpp)
+{
+ static struct {
+ int bpp;
+ int src_w;
+ int dst_w;
+ } last;
+
+ int i = 0; int w = dst_w; int src = 0;
+ unsigned char *buf = buf_ptr;
+ unsigned char *buf_end = buf + buf_len;
+
+ if (last.src_w == src_w && last.dst_w == dst_w && last.bpp == bpp)
+ { /* so, we do not need to regenerate the code buffer */
+ return 0;
+ }else{
+ last.src_w = src_w; last.dst_w = dst_w; last.bpp = bpp;
+ }
+
+ switch (bpp)
+ {
+ case 4:
+ PREP_4BYTE(buf);
+ while(src<src_w) {
+ LOAD_4BYTE(buf);
+ draw4:
+ STORE_4BYTE(buf);
+ --w; i += src_w;
+ if (! w) break;
+ if (buf >= buf_end) goto overflow;
+ if (i < dst_w) goto draw4;
+ i -= dst_w; src++;
+ while (i >= dst_w) { i -= dst_w; src++; SKIP_4BYTE(buf); }
+ };
+ RETURN_4BYTE(buf);
+ break;
+ case 3:
+ PREP_3BYTE(buf);
+ while(src<src_w) {
+ LOAD_3BYTE(buf);
+ draw3:
+ STORE_3BYTE(buf);
+ --w; i += src_w;
+ if (! w) break;
+ if (buf >= buf_end) goto overflow;
+ if (i < dst_w) goto draw3;
+ i -= dst_w; src++;
+ while (i >= dst_w) { i -= dst_w; src++; SKIP_3BYTE(buf); }
+ };
+ RETURN_3BYTE(buf);
+ break;
+ case 2:
+ PREP_2BYTE(buf);
+ while(src<src_w) {
+ LOAD_2BYTE(buf);
+ draw2:
+ STORE_2BYTE(buf);
+ --w; i += src_w;
+ if (! w) break;
+ if (buf >= buf_end) goto overflow;
+ if (i < dst_w) goto draw2;
+ i -= dst_w; src++;
+ while (i >= dst_w) { i -= dst_w; src++; SKIP_2BYTE(buf); }
+ };
+ RETURN_2BYTE(buf);
+ break;
+ case 1:
+ PREP_1BYTE(buf);
+ while(src<src_w) {
+ LOAD_1BYTE(buf);
+ draw1:
+ STORE_1BYTE(buf);
+ --w; i += src_w;
+ if (! w) break;
+ if (buf >= buf_end) goto overflow;
+ if (i < dst_w) goto draw1;
+ i -= dst_w; src++;
+ while (i >= dst_w) { i -= dst_w; src++; SKIP_1BYTE(buf); }
+ };
+ RETURN_1BYTE(buf);
+ break;
+ default:
+ SDL_SetError("ASM stretch of %d bytes isn't supported\n", bpp);
+ return 0;
+ }
+# if 0 /* debugging - gives a nice visual representation of the code */
+ *buf = 0; buf = SDL_TheRowStretchCode; fprintf (stderr,"\n");
+ while (*buf) {
+ fprintf(stderr,"%c", (*buf++)&0x7F);
+ if (! (((long)buf)&0x3F)) fprintf (stderr, "\n");
+ } fprintf(stderr,"(%iB=(%i->%i))\n", buf-SDL_TheRowStretchCode,
+ src_w, dst_w);
+# endif
+ return buf_ptr; /* SUCCESS */
+
+ overflow:
+ /* so, we did overflow - too late anyway */
+ SDL_SetError("Copy buffer overflow");
+ return 0;
+}
+
+
+void SDL_RunRowStretchCode(unsigned char* code,
+ unsigned char* srcp,
+ unsigned char* dstp)
+{
+# if defined HAVE_NATIVE_CODE && defined SDL_STRETCH_CALL
+ SDL_STRETCH_CALL(code, srcp, dstp);
+# elif defined HAVE_INTERPRETED_CODE
+ unsigned char a = 0, b = 0, c = 0, d= 0;
+ while (1) {
+ switch (*code++) {
+ case 014: *dstp++ = a;
+ case 013: *dstp++ = b;
+ case 012: *dstp++ = c;
+ case 011: *dstp++ = d;
+ break;
+ case 004: a = *srcp++;
+ case 003: b = *srcp++;
+ case 002: c = *srcp++;
+ case 001: d = *srcp++;
+ break;
+ default:
+ return;
+ }
+ }
+# else
+# error Need inline assembly for this compiler
+# endif
+}
+
+#define DEFINE_COPY_ROW(name, type) \
+void name(type *src, int src_w, type *dst, int dst_w) \
+{ \
+ int i = 0; \
+ int w = dst_w; \
+ type pixel = 0; \
+ type* src_max = src + src_w; \
+ \
+ while(src < src_max) { \
+ pixel = *src; \
+ draw: \
+ *dst++ = pixel; \
+ --w; i += src_w; \
+ if (! w) break; \
+ if (i < dst_w) goto draw; \
+ do { i -= dst_w; src++; } while (i >= dst_w);\
+ }; return; \
+}
+DEFINE_COPY_ROW(SDL_StretchRow1, Uint8)
+DEFINE_COPY_ROW(SDL_StretchRow2, Uint16)
+DEFINE_COPY_ROW(SDL_StretchRow4, Uint32)
+
+/* The ASM code has a hard time to handle 24-bpp stretch blits */
+void SDL_StretchRow3(Uint8 *src, int src_w, Uint8 *dst, int dst_w)
+{
+ int i = 0;
+ int w = dst_w;
+ Uint8 pixel [3];
+ Uint8* src_max = src + src_w;
+
+ while(src < src_max) {
+ pixel[0] = *src++;
+ pixel[1] = *src++;
+ pixel[2] = *src++;
+ draw:
+ *dst++ = pixel[0];
+ *dst++ = pixel[1];
+ *dst++ = pixel[2];
+ --w ; i += src_w;
+ if (! w) break;
+ if (i < dst_w) goto draw; /* draw same pixel again */
+ do { i -= dst_w; src+=3; } while (i >= dst_w);
+ }; return;
+}
+
+char* SDL_StretchRowInfo(void) {
+ return "sdlstretch"
+#ifdef SDL_STRETCH_I386
+ "-i386"
+#endif
+#ifdef SDL_STRETCH_X86_64
+ "-x86_64"
+#endif
+#ifdef HAVE_NATIVE_CODE
+ "-native"
+#endif
+#ifdef HAVE_INTERPRETED_CODE
+ "-interpreted"
+#endif
+#ifdef SDL_STRETCH_CALL
+ "-call"
+#endif
+#ifdef SDL_STRETCH_DATA_NOEXEC
+ "-noexec"
+#endif
+#ifdef SDL_STRETCH_DISABLE_ASM
+ "-disabledasm"
+#endif
+#ifdef SDL_STRETCH_USE_ASM
+ "-autodetectedasm"
+#endif
+#ifdef VERSION
+ "-" VERSION
+#else
+ "-X"
+#endif
+ ;
+}

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jun 11, 11:34 AM (3 w, 4 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
68793
Default Alt Text
(177 KB)

Event Timeline