Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
115 KB
Referenced Files
None
Subscribers
None
diff --git a/util/funcs.cpp b/util/funcs.cpp
index 56e11f1d..470bf493 100644
--- a/util/funcs.cpp
+++ b/util/funcs.cpp
@@ -1,358 +1,362 @@
#ifdef USE_ALLEGRO
#include <allegro.h>
#endif
#ifdef USE_SDL
#include <SDL.h>
#endif
#ifdef USE_ALLEGRO5
#include <allegro5/allegro.h>
#endif
#include "funcs.h"
#include "debug.h"
#include <vector>
#include <string>
#include <string.h>
#include <algorithm>
#include "file-system.h"
#include "graphics/bitmap.h"
#include "font.h"
#include "init.h"
#include <sstream>
#include "file-system.h"
#include <math.h>
#ifndef USE_ALLEGRO
/* FIXME: move this to the filesystem module */
#include "sfl/sfl.h"
#include "sfl/sflfile.h"
#endif
#ifndef WINDOWS
#include <unistd.h>
#endif
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
using namespace std;
/* remove this once cmake and scons properly set DATA_PATH */
#ifndef DATA_PATH
#define DATA_PATH "data"
#endif
/* the build system should define DATA_PATH */
static string dataPath = DATA_PATH;
const double Util::pi = 3.14159265358979323846;
double Util::radians(double degree){
return degree * pi / 180.0;
}
+double Util::degrees(double radians){
+ return radians * 180.0 / pi;
+}
+
/*
inline int rnd( int q ){
if ( q <= 0 ) return 0;
return (int)( rand() % q );
}
*/
int Util::max(int a, int b){
if (a>b){
return a;
}
return b;
}
double Util::min(double a, double b){
if (a < b){
return a;
}
return b;
}
double Util::max(double a, double b){
if (a > b){
return a;
}
return b;
}
/*
int Util::min(int a, int b){
if (a<b){
return a;
}
return b;
}
*/
int Util::clamp(int value, int min, int max){
return Util::min(Util::max(value, min), max);
}
double Util::clamp(double value, double min, double max){
return Util::min(Util::max(value, min), max);
}
int Util::rnd( int q, int min, int range ){
return q - min + rnd( range );
}
int Util::rnd( int min, int max ){
return rnd( max - min ) + min;
}
/* sleep for `x' milliseconds */
void Util::rest( int x ){
#ifdef USE_ALLEGRO
::rest(x);
#endif
#ifdef USE_SDL
SDL_Delay(x);
#endif
#ifdef USE_ALLEGRO5
al_rest((double) x / 1000.0);
#endif
}
void Util::restSeconds(double x){
Util::rest((int)(x * 1000));
}
#if 0
bool Util::checkVersion(int version){
if (version == Global::getVersion()){
return true;
}
/* when an incompatible version is made, add a check here, like
* version < getVersion(3, 5)
* would mean any client below version 3.5 is incompatible.
*
* assume versions of client's greater than ourself is compatible, but
* this may not be true. There is no way to check this.
*/
if (version < 0){
return false;
}
return true;
}
#endif
void Util::setDataPath( const string & str ){
dataPath = str;
}
Filesystem::AbsolutePath Util::getDataPath2(){
return Filesystem::AbsolutePath(dataPath + "/");
}
/* FIXME: remove this method */
bool Util::exists( const string & file ){
return Storage::instance().exists(Filesystem::AbsolutePath(file));
/*
#ifdef USE_ALLEGRO
return ::exists(file.c_str()) != 0;
#else
return file_exists(file.c_str());
#endif
*/
}
/*
vector<Filesystem::AbsolutePath> Util::getFiles(const Filesystem::AbsolutePath & dataPath, const string & find){
return Filesystem::getFiles(dataPath, find);
}
*/
string Util::trim(const std::string & str){
string s;
size_t startpos = str.find_first_not_of(" \t");
size_t endpos = str.find_last_not_of(" \t");
// if all spaces or empty return an empty string
if ((string::npos == startpos) ||
(string::npos == endpos)){
return "";
} else {
return str.substr(startpos, endpos-startpos+1);
}
return str;
}
/* makes the first letter of a string upper case */
string Util::upcase(std::string str){
if ( str.length() > 0 && (str[0] >= 'a' && str[0] <= 'z') ){
str[0] = str[0] - 'a' + 'A';
}
return str;
}
static int lowerCase(int c){
return tolower(c);
}
static int upperCase(int c){
return toupper(c);
}
string Util::upperCaseAll(std::string str){
std::transform(str.begin(), str.end(), str.begin(), upperCase);
return str;
}
string Util::lowerCaseAll(std::string str){
std::transform(str.begin(), str.end(), str.begin(), lowerCase);
/*
for (unsigned int i = 0; i < str.length(); i++){
if (str[0] >= 'A' && str[0] <= 'Z'){
str[0] = str[0] - 'A' + 'a';
}
}
*/
return str;
}
/*Gets the minimum of three values*/
static int minimum(int a,int b,int c){
int min=a;
if(b<min)
min=b;
if(c<min)
min=c;
return min;
}
/* Compute levenshtein distance between s and t
* from: http://www.merriampark.com/ldc.htm
*/
static int levenshtein_distance(const char *s, const char *t){
//Step 1
int k,i,j,n,m,cost,distance;
int * d;
n=strlen(s);
m=strlen(t);
if(n!=0&&m!=0){
d = (int*) malloc((sizeof(int))*(m+1)*(n+1));
m++;
n++;
//Step 2
for(k=0;k<n;k++)
d[k]=k;
for(k=0;k<m;k++)
d[k*n]=k;
//Step 3 and 4
for(i=1;i<n;i++)
for(j=1;j<m;j++)
{
//Step 5
if(s[i-1]==t[j-1])
cost=0;
else
cost=1;
//Step 6
d[j*n+i]=minimum(d[(j-1)*n+i]+1,d[j*n+i-1]+1,d[(j-1)*n+i-1]+cost);
}
distance=d[n*m-1];
free(d);
return distance;
} else {
return -1; //a negative return value means that one or both strings are empty.
}
}
int Util::levenshtein(const std::string & str1, const std::string & str2){
return levenshtein_distance(str1.c_str(), str2.c_str());
}
void Util::limitPrintf(char * buffer, int size, const char * format, va_list args){
#ifdef USE_ALLEGRO
uvszprintf(buffer, size, format, args);
#else
vsnprintf(buffer, size, format, args);
#endif
}
/*
#ifndef WINDOWS
int Util::getPipe(int files[2]){
#ifdef PS3
return 0;
#else
return pipe(files);
#endif
}
#endif
*/
void Util::showError(const Graphics::Bitmap & screen, const Exception::Base & exception, const string & info){
screen.BlitFromScreen(0, 0);
Graphics::Bitmap error(screen.getWidth() - 100, screen.getHeight() - 100);
error.fill(Graphics::darken(Graphics::makeColor(160, 0, 0), 3));
error.border(1, 2, Graphics::makeColor(240, 0, 0));
const Font & font = Font::getDefaultFont(17, 17);
int y = 10;
std::ostringstream out;
out << info;
out << " " << exception.getTrace();
Global::debug(0) << out.str() << std::endl;
font.printfWrap(10, 10, Graphics::makeColor(240, 240, 240), error, error.getWidth() - 20, out.str(), 0);
Graphics::Bitmap::transBlender(0, 0, 0, 220);
error.translucent().draw(50, 50, screen);
screen.BlitToScreen();
}
void Util::showError(const Exception::Base & exception, const std::string & info){
Graphics::Bitmap screen(*Graphics::screenParameter.current());
showError(screen, exception, info);
}
static double twoDigits(double x){
return (int) (x * 100) / 100.0;
}
string Util::niceSize(unsigned long size){
const char sizes[] = {'b', 'k', 'm', 'g', 't'};
double real = size;
for (unsigned int i = 0; i < sizeof(sizes) / sizeof(const char); i++){
if (real > 1024){
real /= 1024.0;
} else {
ostringstream in;
in << twoDigits(real) << sizes[i];
return in.str();
}
}
ostringstream in;
in << twoDigits(real) << "t";
return in.str();
}
std::string Util::join(const std::vector<std::string> & list, const std::string & middle){
ostringstream out;
bool first = true;
for (std::vector<std::string>::const_iterator it = list.begin(); it != list.end(); it++){
if (!first){
out << middle;
}
out << *it;
first = false;
}
return out.str();
}
double Util::distance(double x1, double y1, double x2, double y2){
double xs = x1 - x2;
double ys = y1 - y2;
return sqrt(xs * xs + ys * ys);
}
diff --git a/util/funcs.h b/util/funcs.h
index 5f18b829..ab59c3e8 100644
--- a/util/funcs.h
+++ b/util/funcs.h
@@ -1,109 +1,110 @@
#ifndef _paintown_funcs_h
#define _paintown_funcs_h
#include <stdlib.h>
#include <vector>
#include <string>
#include <stdarg.h>
#include "regex.h"
#include "file-system.h"
namespace Exception{
class Base;
}
namespace Graphics{
class Bitmap;
}
namespace Util{
extern const double pi;
/* returns a number between 0 and q-1. you will never get `q'. if
* you wanted to get `q' then pass in q+1
*/
inline int rnd( int q ){
if (q <= 0){
return 0;
}
return (int)(rand() % q);
}
// std::vector< std::string > getFiles(const Filesystem::AbsolutePath & dataPath, const std::string & find );
double radians(double degree);
+double degrees(double radians);
Filesystem::AbsolutePath getDataPath2();
void setDataPath( const std::string & str );
bool exists( const std::string & file );
/* check that `version' is compatible with this program, mostly used
* for network clients.
*/
// bool checkVersion(int version);
/* return a random number + some range between min/max */
int rnd( int q, int min, int max );
int max(int a, int b);
inline int min(int a, int b){
if (a<b){
return a;
}
return b;
}
double min(double a, double b);
double max(double a, double b);
double distance(double x1, double y1, double x2, double y2);
int clamp(int value, int min, int max);
double clamp(double value, double min, double max);
/* return a number between min/max */
int rnd( int min, int max );
/* rest in milliseconds */
void rest( int x );
/* rest in seconds */
void restSeconds(double x);
std::string trim(const std::string & str);
/* only upper cases the first letter of a string */
std::string upcase(std::string str);
/* lower cases the entire string */
std::string lowerCaseAll(std::string str);
/* upper cases the entire string */
std::string upperCaseAll(std::string str);
/* convert a size in bytes into human readable form.
* 234823592 = 223.94m
*/
std::string niceSize(unsigned long size);
int levenshtein(const std::string & str1, const std::string & str2);
// int getPipe(int files[2]);
void limitPrintf(char * buffer, int size, const char * format, va_list args);
void showError(const Graphics::Bitmap & screen, const Exception::Base & exception, const std::string & info);
/* will create a screen of size GFX_X, GFX_Y */
void showError(const Exception::Base & exception, const std::string & info);
std::string join(const std::vector<std::string> & list, const std::string & middle);
}
#endif
diff --git a/util/graphics/bitmap.h b/util/graphics/bitmap.h
index 0c35d74a..b5ecc1d8 100644
--- a/util/graphics/bitmap.h
+++ b/util/graphics/bitmap.h
@@ -1,617 +1,618 @@
#ifndef _paintown_bitmap_h_
#define _paintown_bitmap_h_
#include "../exceptions/exception.h"
#include "../pointer.h"
#include "../parameter.h"
#include <string>
#include <vector>
#include <iostream>
#ifdef USE_ALLEGRO
#include "allegro/bitmap.h"
#endif
#ifdef USE_SDL
#include "sdl/bitmap.h"
#endif
#ifdef USE_ALLEGRO5
#include "allegro5/bitmap.h"
#endif
#if !defined(USE_ALLEGRO) && !defined(USE_SDL) && !defined(USE_ALLEGRO5)
#error No backend specified. Define one of USE_ALLEGRO, USE_SDL, or USE_ALLEGRO5
#endif
namespace Storage{
class File;
}
namespace Graphics{
enum ImageFormat{
FormatPNG,
FormatBMP,
FormatJPG,
FormatPCX,
FormatTGA,
FormatTIF,
FormatXPM,
FormatGIF,
FormatUnknown
};
ImageFormat identifyImage(const unsigned char * data, int length);
class TranslucentBitmap;
class LitBitmap;
class Bitmap;
extern Util::Parameter<Bitmap*> screenParameter;
extern const int SPRITE_NORMAL;
extern const int SPRITE_LIT;
extern const int SPRITE_TRANS;
extern const int SPRITE_NO_FLIP;
extern const int SPRITE_V_FLIP;
extern const int SPRITE_H_FLIP;
/*
extern int SCALE_X;
extern int SCALE_Y;
*/
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;
};
/* create a color from components */
Color makeColor(int r, int g, int b);
Color darken(Color color, double factor);
void hsvToRGB( float h, float s, float v, int * r, int * g, int * b );
int setGfxModeText();
int setGfxModeFullscreen( int x, int y );
int setGfxModeWindowed( int x, int y );
int setGraphicsMode(int mode, int width, int height);
/* get color components */
int getRed(Color x);
int getBlue(Color x);
int getGreen(Color x);
Color MaskColor();
enum QualityFilter{
NoFilter,
HqxFilter,
XbrFilter
};
QualityFilter qualityFilterName(const std::string & type);
class Bitmap{
private:
/* these constructors don't really matter, get rid of them at some point */
Bitmap( const Bitmap & copy, int sx, int sy, double accuracy );
Bitmap( const char * load_file, int sx, int sy, double accuracy );
public:
/* equivalent to a GPU shader */
class Filter{
public:
virtual Color filter(Color pixel) const = 0;
virtual ~Filter(){
}
};
/* default constructor makes 10x10 bitmap */
Bitmap();
Bitmap( int x, int y );
Bitmap( const char * load_file );
Bitmap(const char * data, int length);
Bitmap( const std::string & load_file );
Bitmap( const char * load_file, int sx, int sy );
/* Load a bitmap from an abstract file */
Bitmap(Storage::File & file);
/* 4/24/2010: remove this at some point */
#ifdef USE_ALLEGRO
explicit Bitmap( BITMAP * who, bool deep_copy = false );
#endif
#ifdef USE_SDL
explicit Bitmap(SDL_Surface * who, bool deep_copy = false );
#endif
#ifdef USE_ALLEGRO5
explicit Bitmap(ALLEGRO_BITMAP * who, bool deep_copy = false );
#endif
Bitmap( const Bitmap & copy, bool deep_copy = false );
Bitmap( const Bitmap & copy, int sx, int sy );
Bitmap( const Bitmap & copy, int x, int y, int width, int height );
virtual ~Bitmap();
virtual TranslucentBitmap translucent() const;
/* will call transBlender() with the supplied values for you */
virtual TranslucentBitmap translucent(int red, int green, int blue, int alpha) const;
virtual LitBitmap lit() const;
virtual void save( const std::string & str ) const;
Bitmap & operator=( const Bitmap & );
virtual void load( const std::string & str );
virtual int getWidth() const;
virtual int getHeight() const;
/*
inline const int getWidth() const{
return getBitmap()->w;
}
inline const int getHeight() const{
return getBitmap()->h;
}
*/
/*
inline const int getWidth() const{
return my_bitmap->w;
}
inline const int getHeight() const{
return my_bitmap->h;
}
*/
void detach();
/* replace all pixels that have value `original' with `replaced' */
void replaceColor(const Color & original, const Color & replaced);
void set8BitMaskColor(const Color & color);
Color get8BitMaskColor();
/* Blend between source pixel and destination pixel.
* Source and dest should be 0-255.
* source = 64, dest = 128
* pixel = source_pixel * source / 255 + dest_pixel * dest / 255
*/
static void alphaBlender(int source, int dest);
static void transBlender( int r, int g, int b, int a );
static void multiplyBlender( int r, int g, int b, int a );
static void dissolveBlender( int r, int g, int b, int a );
static void addBlender( int r, int g, int b, int a );
static void burnBlender( int r, int g, int b, int a );
static void colorBlender( int r, int g, int b, int a );
static void differenceBlender( int r, int g, int b, int a );
static void dodgeBlender( int r, int g, int b, int a );
static void hueBlender( int r, int g, int b, int a );
static void luminanceBlender( int r, int g, int b, int a );
static void invertBlender( int r, int g, int b, int a );
static void screenBlender( int r, int g, int b, int a );
/* for testing */
static void setFakeGraphicsMode(int width, int height);
/* clean up any remaining state */
static void shutdown();
// static void drawingMode( int type );
virtual Color blendColor(const Color & input) const;
/* sets the blend state. try not to use these function unless
* absolutely necessary.
*/
virtual void startDrawing() const;
virtual void endDrawing() const;
void acquire();
void release();
void updateOnResize();
/* Resizes the bitmap and stretches the old pixels to the new bitmap */
void resize(const int width, const int height);
/* Just resizes the bitmap without copying pixels */
void updateSize(const int width, const int height);
/* Makes this bitmap the same as the parameter.
* Width/height is copied and then a Blit is called.
*/
void copy(const Bitmap & him);
void debugSelf() const;
/* convert to a grey scale version */
virtual Bitmap greyScale();
virtual void triangle( int x1, int y1, int x2, int y2, int x3, int y3, Color color ) const;
/* draws an equilateral triangle centered at (x,y) pointing at `angle'
* where each side has `size' pixels using the color.
*/
virtual void equilateralTriangle(int x, int y, int angle, int size, Color color) const;
virtual void ellipse( int x, int y, int rx, int ry, Color color ) const;
virtual void ellipseFill( int x, int y, int rx, int ry, Color color ) const;
virtual void light(int x, int y, int width, int height, int start_y, int focus_alpha, int edge_alpha, int focus_color, Color edge_color) const;
virtual void applyTrans(const Color color) const;
virtual void border( int min, int max, Color color ) const;
virtual void rectangle( int x1, int y1, int x2, int y2, Color color ) const;
virtual void rectangleFill( int x1, int y1, int x2, int y2, Color color ) const;
virtual void circleFill( int x, int y, int radius, Color color ) const;
virtual void circle( int x, int y, int radius, Color color ) const;
virtual void circle(int x, int y, int radius, int thickness, Color color) const;
virtual void line( const int x1, const int y1, const int x2, const int y2, const Color color ) const;
virtual void floodfill( const int x, const int y, const Color color ) const;
virtual void horizontalLine( const int x1, const int y, const int x2, const Color color ) const;
virtual void hLine( const int x1, const int y, const int x2, const Color color ) const;
virtual void vLine( const int y1, const int x, const int y2, const Color color ) const;
virtual void polygon( const int * verts, const int nverts, const Color color ) const;
virtual void arc(const int x, const int y, const double ang1, const double ang2, const int radius, const Color color ) const;
virtual void arcFilled(const int x, const int y, const double ang1, const double ang2, const int radius, const Color color ) const;
/* x/y is in the center of the bitmap */
virtual void drawCenter(const int x, const int y, const Bitmap & where) const;
virtual void draw(const int x, const int y, const Bitmap & where) const;
virtual void draw(const int x, const int y, Filter * filter, const Bitmap & where) const;
virtual void draw(const int x, const int y, const int startWidth, const int startHeight, const int width, const int height, const Bitmap & where) const;
virtual void draw(const int x, const int y, const int startWidth, const int startHeight, const int width, const int height, Filter * filter, const Bitmap & where) const;
virtual void drawCharacter( const int x, const int y, const int color, const int background, const Bitmap & where ) const;
/* flip horizontally */
virtual void drawHFlip(const int x, const int y, const Bitmap & where) const;
virtual void drawHFlip(const int x, const int y, Filter * filter, const Bitmap & where) const;
virtual void drawHFlip(const int x, const int y, const int startWidth, const int startHeight, const int width, const int height, const Bitmap & where) const;
virtual void drawHFlip(const int x, const int y, const int startWidth, const int startHeight, const int width, const int height, Filter * filter, const Bitmap & where) const;
/* flip vertically */
virtual void drawVFlip( const int x, const int y, const Bitmap & where ) const;
virtual void drawVFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const;
/* flip horizontal and vertical */
virtual void drawHVFlip( const int x, const int y, const Bitmap & where ) const;
virtual void drawHVFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const;
// virtual void drawTrans( const int x, const int y, const Bitmap & where ) const;
// virtual void drawTrans( const int x, const int y, Filter * filter, const Bitmap & where ) const;
// virtual void drawTransHFlip( const int x, const int y, const Bitmap & where ) const;
// virtual void drawTransHFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const;
// virtual void drawTransVFlip( const int x, const int y, const Bitmap & where ) const;
// virtual void drawTransVFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const;
// virtual void drawTransHVFlip( const int x, const int y, const Bitmap & where ) const;
// virtual void drawTransHVFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const;
virtual void drawMask( const int x, const int y, const Bitmap & where );
virtual void drawStretched( const int x, const int y, const int new_width, const int new_height, const Bitmap & who ) const;
virtual void drawStretched(const Bitmap & who) const;
/* middle of the bitmap is at x, y */
virtual void drawRotateCenter(const int x, const int y, const int angle, const Bitmap & where);
/* upper left hand corner is at x, y*/
virtual void drawRotate(const int x, const int y, const int angle, const Bitmap & where);
virtual void drawPivot( const int centerX, const int centerY, const int x, const int y, const int angle, const Bitmap & where );
virtual void drawPivot( const int centerX, const int centerY, const int x, const int y, const int angle, const double scale, const Bitmap & where );
/* Stretch using the hqx algorithm */
virtual void StretchHqx(const Bitmap & where) const;
virtual void StretchHqx(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;
/* Xbr is defined here:
* http://board.byuu.org/viewtopic.php?f=10&t=2248
*/
virtual void StretchXbr(const Bitmap & where) const;
virtual void StretchXbr(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;
/* Just copies pixels (fast) */
virtual void Stretch(const Bitmap & where) const;
virtual void 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;
virtual void StretchBy2( const Bitmap & where );
virtual void StretchBy4( const Bitmap & where );
virtual void Blit( const std::string & xpath ) const;
virtual void Blit( const Bitmap & where ) const;
virtual void Blit( const int x, const int y, const Bitmap & where ) const;
virtual void Blit( const int mx, const int my, const int wx, const int wy, const Bitmap & where ) const;
virtual void Blit( const int mx, const int my, const int width, const int height, const int wx, const int wy, const Bitmap & where ) const;
virtual void BlitMasked( const int mx, const int my, const int width, const int height, const int wx, const int wy, const Bitmap & where ) const;
virtual void BlitToScreen() const;
virtual void BlitAreaToScreen(const int upper_left_x, const int upper_left_y) const;
virtual void BlitToScreen(const int upper_left_x, const int upper_left_y) const;
virtual void BlitFromScreen(const int x, const int y) const;
void roundRect(int radius, int x1, int y1, int x2, int y2, Color color) const;
void roundRectFill(int radius, int x1, int y1, int x2, int y2, Graphics::Color color) const;
virtual void drawShadow(Bitmap & where, int x, int y, int intensity, Color color, double scale, bool facingRight) const;
/* returned a scaled version of this bitmap of the given dimensions */
virtual Bitmap scaleTo(const int width, const int height) const;
/* scale the image by the given ratios, i.e: a ratio of 1 means do nothing.
* less than 1 will make it smaller and larger than 1 will make it larger.
*/
virtual Bitmap scaleBy(const double widthRatio, const double heightRatio) const;
/* try to call Global::getScreenWidth/Height() instead of these directly */
static int getScreenWidth();
static int getScreenHeight();
virtual void fill(Color color) const;
virtual void clear() const;
inline void clearToMask() const{
this->fill(MaskColor());
}
bool getError();
inline const Util::ReferenceCount<BitmapData> & getData() const {
return data;
}
inline Util::ReferenceCount<BitmapData> getData(){
return data;
}
void setData(Util::ReferenceCount<BitmapData> data){
this->data = data;
}
virtual void readLine( std::vector<Color> & vec, int y );
Color getPixel( const int x, const int y ) const;
/* lock video bitmap to memory */
void lock() const;
void lock(int x, int y, int width, int height) const;
void unlock() const;
/* true if the point is within the bounds of the bitmap */
bool inRange(int x, int y) const;
/* uses _putpixel16 underneath which ignores translucent behavior */
void putPixel( int x, int y, Color col ) const;
/* respects the current trans mode */
virtual void putPixelNormal(int x, int y, Color col) const;
/*
inline int getPixel( int x, int y ) const{
if ( x >= 0 && x < my_bitmap->w && y >= 0 && y <= my_bitmap->h )
return _getpixel16( my_bitmap, x, y );
return -1;
}
inline void putPixel( int x, int y, int col ) const{
if ( x >= 0 && x < my_bitmap->w && y >= 0 && y <= my_bitmap->h )
_putpixel16( my_bitmap, x, y, col );
}
*/
void setClipRect( int x1, int y1, int x2, int y2 ) const;
void getClipRect( int & x1, int & y1, int & x2, int & y2 ) const;
inline const std::string & getPath() const{
return path;
}
/* produce a temporary bitmap that is not guaranteed to be preserved
* after your function returns. do *not* hold references to this bitmap
* and if you make a temporary bitmap, do *not* call functions that
* might also make temporary bitmaps.
*/
static Bitmap temporaryBitmap(int w, int h);
static Bitmap temporaryBitmap2(int w, int h);
/* call this method to delete all temporary bitmaps.
* don't call this unless you know what you are doing
*/
static void cleanupTemporaryBitmaps();
static double getScale();
/*
* Convert color values between the HSV and RGB color spaces. The RGB values
* range from 0 to 255, hue is from 0 to 360, and saturation and value are
* from 0 to 1.
*/
static void rgbToHSV(int r, int g, int b, float * h, float * s, float * v);
/* convert cymk to rgb. values should be in the range 0-255 */
static void cymkToRGB(int c, int y, int m, int k, int * r, int * g, int * b);
/* Add two RGB16 colors together
* r = c1.r + c2.r
* g = c1.g + c2.g
* b = c1.b + c2.b
*/
static int addColor( int color1, int color2 );
/*
inline static int makeColor( int r, int g, int b ){
return makecol16( r, g, b );
}
*/
// static const int MaskColor = MASK_COLOR_16;
/*
static const int MODE_TRANS;
static const int MODE_SOLID;
*/
#ifdef USE_ALLEGRO5
void convertToVideo();
#endif
protected:
/* release a reference count, and possibly destroy data */
// void releaseInternalBitmap();
/* really destroy private data */
// void destroyPrivateData();
/*
inline void setBitmap( BITMAP * bitmap ){
if ( bitmap == NULL ){
std::cout << "*FATAL* Setting null bitmap" << std::endl;
}
_my_bitmap = bitmap;
}
*/
void loadFromMemory(const char * data, int length);
void internalLoadFile( const char * load_file );
/* implementation specific data */
Util::ReferenceCount<BitmapData> data;
// int * own;
bool mustResize;
// bool own;
bool error;
std::string path;
static Bitmap * temporary_bitmap;
static Bitmap * temporary_bitmap2;
Color bit8MaskColor;
/* only used by allegro5 for now */
int width, height;
};
/* 8-bit bitmap that supports a palette */
class PaletteBitmap: public Bitmap {
public:
PaletteBitmap();
virtual ~PaletteBitmap();
protected:
Color palette[256];
};
Bitmap memoryPCX(unsigned char * const data, const int length, const bool mask = true);
/* creates a bitmap that can be used as a buffer for the screen.
* on opengl/allegro5 systems this will return the current backbuffer
*/
Bitmap * getScreenBuffer();
void blend_palette(Color * pal, int mp, Color sc, Color ec);
// bool sameColors(Color color1, Color color2);
class LitBitmap: public Bitmap {
public:
LitBitmap( const Bitmap & b );
LitBitmap();
virtual ~LitBitmap();
using Bitmap::draw;
virtual void draw(const int x, const int y, const Bitmap & where) const;
virtual void draw(const int x, const int y, Filter * filter, const Bitmap & where ) const;
using Bitmap::drawHFlip;
virtual void drawHFlip( const int x, const int y, const Bitmap & where ) const;
virtual void drawHFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const;
using Bitmap::drawVFlip;
virtual void drawVFlip( const int x, const int y, const Bitmap & where ) const;
virtual void drawVFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const;
using Bitmap::drawHVFlip;
virtual void drawHVFlip( const int x, const int y, const Bitmap & where ) const;
virtual void drawHVFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const;
};
class StretchedBitmap: public Bitmap {
public:
StretchedBitmap(int width, int height, const Bitmap & where, QualityFilter filter = NoFilter);
void finish();
void start();
virtual int getWidth() const;
virtual int getHeight() const;
virtual double getScaleWidth() const;
virtual double getScaleHeight() const;
protected:
double width;
double height;
double scale_x, scale_y;
const Bitmap & where;
const QualityFilter filter;
Bitmap scaleToFilter;
};
class TranslatedBitmap: public Bitmap {
public:
TranslatedBitmap(int x, int y, const Bitmap & where);
using Bitmap::BlitToScreen;
virtual void BlitToScreen() const;
virtual ~TranslatedBitmap();
public:
int x, y;
};
class TranslucentBitmap: public Bitmap {
public:
TranslucentBitmap(const Bitmap & b);
TranslucentBitmap();
virtual ~TranslucentBitmap();
virtual Color blendColor(const Color & color) const;
virtual void startDrawing() const;
virtual void endDrawing() const;
virtual void putPixelNormal(int x, int y, Color col) const;
virtual void rectangleFill(int x1, int y1, int x2, int y2, Color color) const;
virtual void rectangle(int x1, int y1, int x2, int y2, Color color) const;
virtual void fill(Color color) const;
virtual void line( const int x1, const int y1, const int x2, const int y2, const Color color ) const;
virtual void hLine( const int x1, const int y, const int x2, const Color color ) const;
virtual void arc(const int x, const int y, const double ang1, const double ang2, const int radius, const Color color) const;
virtual void arcFilled(const int x, const int y, const double ang1, const double ang2, const int radius, const Color color ) const;
virtual void circleFill( int x, int y, int radius, Color color ) const;
virtual void ellipse( int x, int y, int rx, int ry, Color color ) const;
+ virtual void ellipseFill( int x, int y, int rx, int ry, Color color ) const;
using Bitmap::draw;
virtual void draw(const int x, const int y, const Bitmap & where) const;
virtual void draw(const int x, const int y, Filter * filter, const Bitmap & where) const;
// virtual void draw(const int x, const int y, const int startWidth, const int startHeight, const int width, const int height, const Bitmap & where) const;
// virtual void draw(const int x, const int y, const int startWidth, const int startHeight, const int width, const int height, Filter * filter, const Bitmap & where) const;
using Bitmap::drawHFlip;
virtual void drawHFlip(const int x, const int y, const Bitmap & where) const;
virtual void drawHFlip(const int x, const int y, Filter * filter, const Bitmap & where) const;
// virtual void drawHFlip(const int x, const int y, const int startWidth, const int startHeight, const int width, const int height, const Bitmap & where) const;
// virtual void drawHFlip(const int x, const int y, const int startWidth, const int startHeight, const int width, const int height, Filter * filter, const Bitmap & where) const;
virtual void drawVFlip( const int x, const int y, const Bitmap & where ) const;
virtual void drawVFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const;
virtual void drawHVFlip( const int x, const int y, const Bitmap & where ) const;
virtual void drawHVFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const;
};
}
#endif
diff --git a/util/graphics/sdl/bitmap.cpp b/util/graphics/sdl/bitmap.cpp
index 853de97c..ad9380ac 100644
--- a/util/graphics/sdl/bitmap.cpp
+++ b/util/graphics/sdl/bitmap.cpp
@@ -1,2357 +1,2362 @@
#include "util/funcs.h"
#include "util/debug.h"
#include "util/system.h"
#include "util/init.h"
#include "hqx.h"
#include "xbr.h"
#include "sprig/sprig.h"
#include "stretch/SDL_stretch.h"
#include <SDL.h>
#include "image/SDL_image.h"
#include "image/IMG_savepng.h"
#include <math.h>
#include "util/exceptions/exception.h"
#include <string>
#include <sstream>
namespace Graphics{
static const int WINDOWED = 0;
static const int FULLSCREEN = 1;
/* bits per pixel */
static int SCREEN_DEPTH = 16;
static SDL_Surface * screen;
static SDL_PixelFormat format565;
/* FIXME: try to get rid of these two variables */
/*
static int SCALE_X;
static int SCALE_Y;
*/
typedef unsigned int (*blender)(unsigned int color1, unsigned int color2, unsigned int alpha);
/* taken from allegro 4.2: src/colblend.c, _blender_trans16 */
/* this function performs a psuedo-SIMD operation on the pixel
* components in RGB 5-6-5 format. To get this to work for some
* other format probably all that needs to happen is to change
* the 0x7E0F81F constant to something else. 5-5-5:
* binary: 0011 1110 000 0111 1100 0001 1111
* hex: 0x174076037
*/
static inline unsigned int transBlender(unsigned int x, unsigned int y, unsigned int n){
unsigned long result;
if (n)
n = (n + 1) / 8;
/* hex: 0x7E0F81F
* binary: 0111 1110 0000 1111 1000 0001 1111
*/
x = ((x & 0xFFFF) | (x << 16)) & 0x7E0F81F;
y = ((y & 0xFFFF) | (y << 16)) & 0x7E0F81F;
result = ((x - y) * n / 32 + y) & 0x7E0F81F;
return ((result & 0xFFFF) | (result >> 16));
}
static inline unsigned int multiplyBlender(unsigned int x, unsigned int y, unsigned int n){
Uint8 redX = 0;
Uint8 greenX = 0;
Uint8 blueX = 0;
SDL_GetRGB(x, &format565, &redX, &greenX, &blueX);
Uint8 redY = 0;
Uint8 greenY = 0;
Uint8 blueY = 0;
SDL_GetRGB(y, &format565, &redY, &greenY, &blueY);
int r = redX * redY / 256;
int g = greenX * greenY / 256;
int b = blueX * blueY / 256;
return transBlender(makeColor(r, g, b), y, n);
}
static inline unsigned int alphaBlender(unsigned int x, unsigned int y, unsigned int n){
Uint8 source = n >> 8;
Uint8 dest = n & 0xff;
/*
unsigned long result;
x = ((x & 0xFFFF) | (x << 16)) & 0x7E0F81F;
y = ((y & 0xFFFF) | (y << 16)) & 0x7E0F81F;
result = ((x * source / 255) + (y * dest / 255)) & 0x7E0F81F;
return ((result & 0xFFFF) | (result >> 16));
*/
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 * dest + redX * source) / 256;
int g = (greenY * dest + greenX * source) / 256;
int b = (blueY * dest + blueX * source) / 256;
r = Util::min(r, 255);
g = Util::min(g, 255);
b = Util::min(b, 255);
// return transBlender(makeColor(r, g, b), y, dest);
return makeColor(r, g, b);
// return y;
}
static inline unsigned int addBlender(unsigned int x, unsigned int y, unsigned int n){
Uint8 redX = 0;
Uint8 greenX = 0;
Uint8 blueX = 0;
SDL_GetRGB(x, &format565, &redX, &greenX, &blueX);
Uint8 redY = 0;
Uint8 greenY = 0;
Uint8 blueY = 0;
SDL_GetRGB(y, &format565, &redY, &greenY, &blueY);
int r = redY + redX * n / 256;
int g = greenY + greenX * n / 256;
int b = blueY + blueX * n / 256;
r = Util::min(r, 255);
g = Util::min(g, 255);
b = Util::min(b, 255);
return makeColor(r, g, b);
}
static inline int iabs(int x){
return x < 0 ? -x : x;
}
static inline unsigned int differenceBlender(unsigned int x, unsigned int y, unsigned int n){
Uint8 redX = 0;
Uint8 greenX = 0;
Uint8 blueX = 0;
SDL_GetRGB(x, &format565, &redX, &greenX, &blueX);
Uint8 redY = 0;
Uint8 greenY = 0;
Uint8 blueY = 0;
SDL_GetRGB(y, &format565, &redY, &greenY, &blueY);
// int r = iabs(redY - redX);
// int g = iabs(greenY - greenX);
// int b = iabs(blueY - blueX);
int r = redY - redX;
int g = greenY - greenX;
int b = blueY - blueX;
if (r < 0){
r = 0;
}
if (g < 0){
g = 0;
}
if (b < 0){
b = 0;
}
return transBlender(makeColor(r, g, b), y, n);
}
static inline unsigned int burnBlender(unsigned int x, unsigned int y, unsigned int n){
Uint8 redX = 0;
Uint8 greenX = 0;
Uint8 blueX = 0;
SDL_GetRGB(x, &format565, &redX, &greenX, &blueX);
Uint8 redY = 0;
Uint8 greenY = 0;
Uint8 blueY = 0;
SDL_GetRGB(y, &format565, &redY, &greenY, &blueY);
int r = redX - redY;
int g = greenX - greenY;
int b = blueX - blueY;
if (r < 0){
r = 0;
}
if (g < 0){
g = 0;
}
if (b < 0){
g = 0;
}
return transBlender(makeColor(r, g, b), y, n);
}
static inline unsigned int noBlender(unsigned int a, unsigned int b, unsigned int c){
return a;
}
struct BlendingData{
BlendingData():
red(0), green(0), blue(0), alpha(0), currentBlender(noBlender){}
int red, green, blue, alpha;
blender currentBlender;
};
BitmapData::~BitmapData(){
if (surface != NULL && destroy){
SDL_FreeSurface(surface);
}
}
static BlendingData globalBlend;
// static int drawingMode = Bitmap::MODE_SOLID;
/*
static int drawingAlpha(){
if (drawingMode == Bitmap::MODE_SOLID){
return 255;
}
if (drawingMode == Bitmap::MODE_TRANS){
return globalBlend.alpha;
}
return 255;
}
*/
static void paintown_applyTrans16(SDL_Surface * dst, const int color);
static void paintown_replace16(SDL_Surface * dst, const int original, const int replace);
static void paintown_draw_sprite_ex16(SDL_Surface * dst, SDL_Surface * src, long long dx, long long dy, int mode, int flip, Bitmap::Filter * filter);
static void paintown_draw_sprite_filter_ex16(SDL_Surface * dst, SDL_Surface * src, long long x, long long y, Bitmap::Filter * filter);
static void paintown_light16(SDL_Surface * dst, const int x, const int y, int width, int height, const int start_y, const int focus_alpha, const int edge_alpha, const int focus_color, const int edge_color);
int MaskColor(){
static int mask = makeColor(255, 0, 255);
return mask;
}
static SDL_Surface * optimizedSurface(SDL_Surface * in){
/* SDL_DisplayFormat will return 0 if a graphics context is not set,
* like if a test is running instead of the real game.
*/
// SDL_Surface * out = SDL_DisplayFormat(in);
SDL_Surface * out = SDL_ConvertSurface(in, &format565, SDL_SWSURFACE);
if (out == NULL){
// out = SDL_CreateRGBSurface(SDL_SWSURFACE, in->w, in->h, in->format->BitsPerPixel, 0, 0, 0, 0);
out = SDL_CreateRGBSurface(SDL_SWSURFACE, in->w, in->h, SCREEN_DEPTH, format565.Rmask, format565.Gmask, format565.Bmask, format565.Amask);
if (out == NULL){
std::ostringstream out;
out << "Could not create RGB surface of size " << in->w << ", " << in->h << ". Memory usage: " << System::memoryUsage();
throw BitmapException(__FILE__, __LINE__, out.str());
}
SDL_Rect source;
SDL_Rect destination;
source.w = in->w;
source.h = in->h;
source.x = 0;
source.y = 0;
destination.w = in->w;
destination.h = in->h;
destination.x = 0;
destination.y = 0;
SDL_BlitSurface(in, &source, out, &destination);
}
return out;
}
static Bitmap * Scaler = NULL;
BitmapData::BitmapData(SDL_Surface * surface):
surface(surface),
destroy(true){
setSurface(surface);
}
void BitmapData::setSurface(SDL_Surface * surface){
this->surface = surface;
clip_left = 0;
clip_top = 0;
if (surface){
clip_right = surface->w;
clip_bottom = surface->h;
} else {
clip_right = 0;
clip_bottom = 0;
}
}
Bitmap::Bitmap():
mustResize(false),
bit8MaskColor(0){
int width = 1;
int height = 1;
SDL_Surface * surface = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, SCREEN_DEPTH, format565.Rmask, format565.Gmask, format565.Bmask, format565.Amask);
setData(Util::ReferenceCount<BitmapData>(new BitmapData(surface)));
}
Bitmap::Bitmap(const char * data, int length):
mustResize(false),
bit8MaskColor(0){
loadFromMemory(data, length);
}
Bitmap::Bitmap(SDL_Surface * who, bool deep_copy):
mustResize(false),
bit8MaskColor(0){
if (deep_copy){
SDL_Surface * surface = SDL_CreateRGBSurface(SDL_SWSURFACE, who->w, who->h, SCREEN_DEPTH, format565.Rmask, format565.Gmask, format565.Bmask, format565.Amask);
SDL_Rect source;
SDL_Rect destination;
source.w = surface->w;
source.h = surface->h;
source.x = 0;
source.y = 0;
destination.w = surface->w;
destination.h = surface->h;
destination.x = 0;
destination.y = 0;
SDL_BlitSurface(who, &source, surface, &destination);
setData(Util::ReferenceCount<BitmapData>(new BitmapData(surface)));
} else {
setData(Util::ReferenceCount<BitmapData>(new BitmapData(who)));
}
}
Bitmap::Bitmap(int w, int h):
mustResize(false),
bit8MaskColor(0){
if (w < 1){
w = 1;
}
if (h < 1){
h = 1;
}
SDL_Surface * surface = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, SCREEN_DEPTH, format565.Rmask, format565.Gmask, format565.Bmask, format565.Amask);
if (surface == NULL){
std::ostringstream out;
out << "Could not create surface with dimensions " << w << ", " << h;
throw BitmapException(__FILE__, __LINE__, out.str());
}
setData(Util::ReferenceCount<BitmapData>(new BitmapData(surface)));
}
Bitmap::Bitmap( const char * load_file ):
mustResize(false),
bit8MaskColor(0){
internalLoadFile(load_file);
}
Bitmap::Bitmap( const std::string & load_file ):
mustResize(false){
internalLoadFile(load_file.c_str());
}
Bitmap::Bitmap( const char * load_file, int sx, int sy ):
mustResize(false),
bit8MaskColor(0){
Bitmap temp(load_file);
SDL_Surface * surface = SDL_CreateRGBSurface(SDL_SWSURFACE, sx, sy, SCREEN_DEPTH, format565.Rmask, format565.Gmask, format565.Bmask, format565.Amask);
setData(Util::ReferenceCount<BitmapData>(new BitmapData(surface)));
temp.Stretch(*this);
}
/* unused */
Bitmap::Bitmap( const char * load_file, int sx, int sy, double accuracy ):
mustResize(false),
bit8MaskColor(0){
throw BitmapException(__FILE__, __LINE__, "Unimplemented constructor");
}
Bitmap::Bitmap( const Bitmap & copy, bool deep_copy):
mustResize(false),
bit8MaskColor(copy.bit8MaskColor){
if (deep_copy){
SDL_Surface * who = copy.getData()->getSurface();
SDL_Surface * surface = SDL_CreateRGBSurface(SDL_SWSURFACE, who->w, who->h, SCREEN_DEPTH, format565.Rmask, format565.Gmask, format565.Bmask, format565.Amask);
SDL_Rect source;
SDL_Rect destination;
source.w = surface->w;
source.h = surface->h;
source.x = 0;
source.y = 0;
destination.w = surface->w;
destination.h = surface->h;
destination.x = 0;
destination.y = 0;
SDL_BlitSurface(who, &source, surface, &destination);
setData(Util::ReferenceCount<BitmapData>(new BitmapData(surface)));
} else {
setData(copy.getData());
}
}
Bitmap::Bitmap( const Bitmap & copy, int sx, int sy ):
mustResize(false),
bit8MaskColor(copy.bit8MaskColor){
/* TODO */
}
Bitmap::Bitmap( const Bitmap & copy, int sx, int sy, double accuracy ):
mustResize(false),
bit8MaskColor(copy.bit8MaskColor){
/* TODO */
}
void Bitmap::loadFromMemory(const char * data, int length){
SDL_RWops * ops = SDL_RWFromConstMem(data, length);
SDL_Surface * loaded = IMG_Load_RW(ops, 1);
if (loaded){
setData(Util::ReferenceCount<BitmapData>(new BitmapData(optimizedSurface(loaded))));
SDL_FreeSurface(loaded);
} else {
std::ostringstream out;
out << "Could not load surface from memory " << (void*) data << " length " << length;
throw BitmapException(__FILE__, __LINE__, out.str());
}
}
static inline Uint8* computeOffset(SDL_Surface * surface, int x, int y){
int bpp = surface->format->BytesPerPixel;
return ((Uint8*)surface->pixels) + y * surface->pitch + x * bpp;
}
Bitmap::Bitmap( const Bitmap & copy, int x, int y, int width, int height ):
mustResize(false),
bit8MaskColor(copy.bit8MaskColor){
path = copy.getPath();
SDL_Surface * his = copy.getData()->getSurface();
if (x < 0)
x = 0;
if (y < 0)
y = 0;
if (width + x > his->w )
width = his->w - x;
if (height + y > his->h)
height = his->h - y;
SDL_Surface * sub = SDL_CreateRGBSurfaceFrom(computeOffset(his, x, y), width, height, SCREEN_DEPTH, his->pitch, format565.Rmask, format565.Gmask, format565.Bmask, format565.Amask);
setData(Util::ReferenceCount<BitmapData>(new BitmapData(sub)));
}
void Bitmap::internalLoadFile(const char * path){
this->path = path;
SDL_Surface * loaded = IMG_Load(path);
if (loaded){
setData(Util::ReferenceCount<BitmapData>(new BitmapData(optimizedSurface(loaded))));
SDL_FreeSurface(loaded);
} else {
std::ostringstream out;
out << "Could not load file '" << path << "'";
throw BitmapException(__FILE__, __LINE__, out.str());
}
}
int Bitmap::getWidth() const {
if (getData()->getSurface() != NULL){
return getData()->getSurface()->w;
}
return 0;
}
int Bitmap::getHeight() const {
if (getData()->getSurface() != NULL){
return getData()->getSurface()->h;
}
return 0;
}
int getRed(int c){
Uint8 red = 0;
Uint8 green = 0;
Uint8 blue = 0;
SDL_GetRGB(c, &format565, &red, &green, &blue);
return red;
}
int getBlue(int c){
Uint8 red = 0;
Uint8 green = 0;
Uint8 blue = 0;
SDL_GetRGB(c, &format565, &red, &green, &blue);
return blue;
}
int getGreen(int c){
Uint8 red = 0;
Uint8 green = 0;
Uint8 blue = 0;
SDL_GetRGB(c, &format565, &red, &green, &blue);
return green;
}
int makeColor(int red, int blue, int green){
return SDL_MapRGB(&format565, red, blue, green);
}
void initializeExtraStuff(){
/* this is as good a place as any to initialize our format */
format565.palette = 0;
format565.BitsPerPixel = 16;
format565.BytesPerPixel = 2;
format565.Rloss = 3;
format565.Gloss = 2;
format565.Bloss = 3;
format565.Aloss = 0;
format565.Rshift = 11;
format565.Gshift = 5;
format565.Bshift = 0;
format565.Ashift = 0;
format565.Rmask = 63488;
format565.Gmask = 2016;
format565.Bmask = 31;
format565.Amask = 0;
#if !SDL_VERSION_ATLEAST(1, 3, 0)
format565.colorkey = 0;
format565.alpha = 255;
#endif
}
/* This code isn't used but leave it here for reference */
#ifdef PS3
#include <rsx/rsx.h>
#include <sysutil/video.h>
void getNativePs3Resolution(int * width, int * height){
videoState state;
videoGetState(0,0,&state);
videoResolution resolution;
videoGetResolution(state.displayMode.resolution, &resolution);
*height = resolution.height;
/* preserve 640x480 aspect ratio */
*width = (int)((*height) * 1.33333);
}
#endif
int setGraphicsMode(int mode, int width, int height){
initializeExtraStuff();
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 <<
#if !SDL_VERSION_ATLEAST(1, 3, 0)
" colorkey: " << (int) screen->format->colorkey <<
" alpha: " << (int) screen->format->alpha << std::endl;
#else
std::endl;
#endif
/*
SCALE_X = width;
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 (width != 0 && height != 0){
Screen = new Bitmap(screen);
/* don't destroy the screen */
Screen->getData()->destroy = false;
/* Scaler is re-used as the screen buffer so don't destroy it */
if (Scaler == NULL){
Scaler = new Bitmap(width, height);
} else {
Scaler->updateSize(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;
}
Bitmap * getScreenBuffer(){
return Scaler;
}
void Bitmap::shutdown(){
delete Screen;
Screen = NULL;
delete Scaler;
Scaler = NULL;
}
void Bitmap::addBlender( int r, int g, int b, int a ){
globalBlend.red = r;
globalBlend.green = g;
globalBlend.blue = b;
globalBlend.alpha = a;
globalBlend.currentBlender = Graphics::addBlender;
}
void Bitmap::multiplyBlender( int r, int g, int b, int a ){
globalBlend.red = r;
globalBlend.green = g;
globalBlend.blue = b;
globalBlend.alpha = a;
globalBlend.currentBlender = Graphics::multiplyBlender;
}
void Bitmap::differenceBlender( int r, int g, int b, int a ){
globalBlend.red = r;
globalBlend.green = g;
globalBlend.blue = b;
globalBlend.alpha = a;
globalBlend.currentBlender = Graphics::differenceBlender;
}
void Bitmap::burnBlender(int r, int g, int b, int a){
globalBlend.red = r;
globalBlend.green = g;
globalBlend.blue = b;
globalBlend.alpha = a;
globalBlend.currentBlender = Graphics::burnBlender;
}
int setGfxModeText(){
/* TODO */
return 0;
}
int setGfxModeFullscreen(int x, int y){
return setGraphicsMode(FULLSCREEN, x, y);
}
int setGfxModeWindowed( int x, int y ){
return setGraphicsMode(WINDOWED, x, y);
}
/*
void Bitmap::drawingMode(int type){
Graphics::drawingMode = type;
}
*/
void Bitmap::alphaBlender(int source, int dest){
globalBlend.red = 0;
globalBlend.green = 0;
globalBlend.blue = 0;
/* Shove values into alpha */
if (source > 255){
source = 255;
}
if (dest > 255){
dest = 255;
}
globalBlend.alpha = ((source & 0xff) << 8) + (dest & 0xff);
globalBlend.currentBlender = Graphics::alphaBlender;
}
void Bitmap::transBlender( int r, int g, int b, int a ){
globalBlend.red = r;
globalBlend.green = g;
globalBlend.blue = b;
globalBlend.alpha = a;
globalBlend.currentBlender = Graphics::transBlender;
}
void Bitmap::setClipRect( int x1, int y1, int x2, int y2 ) const {
SDL_Rect area;
area.x = x1;
area.y = y1;
area.w = x2 - x1;
area.h = y2 - y1;
SDL_SetClipRect(getData()->getSurface(), &area);
SDL_GetClipRect(getData()->getSurface(), &area);
getData()->setClip(area.x, area.y, area.x + area.w, area.y + area.h);
}
void Bitmap::getClipRect(int & x1, int & y1, int & x2, int & y2) const {
const Util::ReferenceCount<BitmapData> & data = getData();
x1 = data->clip_left;
y1 = data->clip_top;
x2 = data->clip_right;
y2 = data->clip_bottom;
}
static void doPutPixel(SDL_Surface * surface, int x, int y, int pixel, bool translucent){
if (SDL_MUSTLOCK(surface)){
SDL_LockSurface(surface);
}
int bpp = surface->format->BytesPerPixel;
/* Here p is the address to the pixel we want to set */
Uint8 *p = computeOffset(surface, x, y);
switch(bpp) {
case 1:
*p = pixel;
break;
case 2:
if (translucent){
*(Uint16 *)p = globalBlend.currentBlender(pixel, *(Uint16*)p, globalBlend.alpha);
} else {
*(Uint16 *)p = pixel;
}
break;
case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
p[0] = (pixel >> 16) & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = pixel & 0xff;
} else {
p[0] = pixel & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = (pixel >> 16) & 0xff;
}
break;
case 4:
*(Uint32 *)p = pixel;
break;
}
if (SDL_MUSTLOCK(surface)){
SDL_UnlockSurface(surface);
}
}
void Bitmap::putPixel(int x, int y, int pixel) const {
/* clip it */
if (getData()->isClipped(x, y)){
return;
}
SDL_Surface * surface = getData()->getSurface();
doPutPixel(surface, x, y, pixel, false);
}
void Bitmap::putPixelNormal(int x, int y, int col) const {
putPixel(x, y, col);
}
void TranslucentBitmap::putPixelNormal(int x, int y, int color) const {
if (getData()->isClipped(x, y)){
return;
}
SDL_Surface * surface = getData()->getSurface();
doPutPixel(surface, x, y, color, true);
}
bool Bitmap::getError(){
/* TODO */
return false;
}
void Bitmap::rectangle( int x1, int y1, int x2, int y2, int color ) const {
SPG_Rect(getData()->getSurface(), x1, y1, x2, y2, color);
}
void TranslucentBitmap::rectangle( int x1, int y1, int x2, int y2, int color ) const {
int alpha = globalBlend.alpha;
SPG_RectBlend(getData()->getSurface(), x1, y1, x2, y2, color, alpha);
}
void Bitmap::rectangleFill( int x1, int y1, int x2, int y2, int color ) const {
SPG_RectFilled(getData()->getSurface(), x1, y1, x2, y2, color);
}
void TranslucentBitmap::rectangleFill(int x1, int y1, int x2, int y2, int color) const {
int alpha = globalBlend.alpha;
SPG_RectFilledBlend(getData()->getSurface(), x1, y1, x2, y2, color, alpha);
}
+
+void TranslucentBitmap::ellipseFill( int x, int y, int rx, int ry, Color color ) const {
+ int alpha = globalBlend.alpha;
+ SPG_EllipseFilledBlend(getData()->getSurface(), x, y, rx, ry, color, alpha);
+}
void Bitmap::circleFill(int x, int y, int radius, int color) const {
SPG_CircleFilled(getData()->getSurface(), x, y, radius, color);
/*
if (Graphics::drawingMode == MODE_SOLID){
SPG_CircleFilled(getData().getSurface(), x, y, radius, color);
} else if (Graphics::drawingMode == MODE_TRANS){
int alpha = globalBlend.alpha;
SPG_CircleFilledBlend(getData().getSurface(), x, y, radius, color, alpha);
}
*/
}
void TranslucentBitmap::circleFill(int x, int y, int radius, int color) const {
int alpha = globalBlend.alpha;
SPG_CircleFilledBlend(getData()->getSurface(), x, y, radius, color, alpha);
}
void Bitmap::circle(int x, int y, int radius, int color) const {
// Uint8 red, green, blue;
// SDL_GetRGB(color, getData().getSurface()->format, &red, &green, &blue);
// int alpha = 255;
SPG_Circle(getData()->getSurface(), x, y, radius, color);
/*
if (Graphics::drawingMode == MODE_SOLID){
SPG_Circle(getData()->getSurface(), x, y, radius, color);
} else if (Graphics::drawingMode == MODE_TRANS){
int alpha = globalBlend.alpha;
SPG_CircleBlend(getData()->getSurface(), x, y, radius, color, alpha);
}
*/
// circleRGBA(getData().getSurface(), x, y, radius, red, green, blue, alpha);
}
extern "C" unsigned short spg_thickness;
void Bitmap::circle(int x, int y, int radius, int thickness, int color) const {
int old = spg_thickness;
spg_thickness = thickness;
SPG_Circle(getData()->getSurface(), x, y, radius, color);
spg_thickness = old;
}
void Bitmap::line( const int x1, const int y1, const int x2, const int y2, const int color ) const {
SPG_Line(getData()->getSurface(), x1, y1, x2, y2, color);
/*
if (Graphics::drawingMode == MODE_SOLID){
SPG_Line(getData().getSurface(), x1, y1, x2, y2, color);
} else if (Graphics::drawingMode == MODE_TRANS){
int alpha = globalBlend.alpha;
SPG_LineBlend(getData().getSurface(), x1, y1, x2, y2, color, alpha);
}
*/
}
void TranslucentBitmap::line(const int x1, const int y1, const int x2, const int y2, const int color ) const {
int alpha = globalBlend.alpha;
SPG_LineBlend(getData()->getSurface(), x1, y1, x2, y2, color, alpha);
}
void Bitmap::draw(const int x, const int y, const Bitmap & where) const {
if (getData()->getSurface() != NULL){
paintown_draw_sprite_ex16(where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_NORMAL, SPRITE_NO_FLIP, NULL);
/*
SDL_SetColorKey(getData().getSurface(), SDL_SRCCOLORKEY, makeColor(255, 0, 255));
Blit(x, y, where);
*/
}
}
void Bitmap::drawHFlip(const int x, const int y, const Bitmap & where) const {
paintown_draw_sprite_ex16( where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_NORMAL, SPRITE_H_FLIP, NULL);
}
void Bitmap::drawHFlip(const int x, const int y, Filter * filter, const Bitmap & where) const {
paintown_draw_sprite_ex16( where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_NORMAL, SPRITE_H_FLIP, filter);
}
void Bitmap::drawVFlip( const int x, const int y, const Bitmap & where ) const {
paintown_draw_sprite_ex16(where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_NORMAL, SPRITE_V_FLIP, NULL);
}
void Bitmap::drawVFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const {
paintown_draw_sprite_ex16(where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_NORMAL, SPRITE_V_FLIP, filter);
}
void Bitmap::drawHVFlip( const int x, const int y, const Bitmap & where ) const {
paintown_draw_sprite_ex16(where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_NORMAL, SPRITE_V_FLIP | SPRITE_H_FLIP, NULL);
}
void Bitmap::drawHVFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const {
paintown_draw_sprite_ex16(where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_NORMAL, SPRITE_V_FLIP | SPRITE_H_FLIP, filter);
}
void TranslucentBitmap::draw(const int x, const int y, const Bitmap & where) const {
paintown_draw_sprite_ex16(where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_TRANS, SPRITE_NO_FLIP, NULL);
}
void TranslucentBitmap::draw( const int x, const int y, Filter * filter, const Bitmap & where ) const {
paintown_draw_sprite_ex16(where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_TRANS, SPRITE_NO_FLIP, filter);
}
void TranslucentBitmap::drawHFlip( const int x, const int y, const Bitmap & where ) const {
paintown_draw_sprite_ex16(where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_TRANS, SPRITE_H_FLIP, NULL);
}
void TranslucentBitmap::drawHFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const {
paintown_draw_sprite_ex16(where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_TRANS, SPRITE_H_FLIP, filter);
}
void TranslucentBitmap::drawVFlip( const int x, const int y, const Bitmap & where ) const {
paintown_draw_sprite_ex16(where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_TRANS, SPRITE_V_FLIP, NULL);
}
void TranslucentBitmap::drawVFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const {
paintown_draw_sprite_ex16(where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_TRANS, SPRITE_V_FLIP, filter);
}
void TranslucentBitmap::drawHVFlip( const int x, const int y, const Bitmap & where ) const {
paintown_draw_sprite_ex16(where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_TRANS, SPRITE_V_FLIP | SPRITE_H_FLIP, NULL);
}
void TranslucentBitmap::drawHVFlip( const int x, const int y, Filter * filter,const Bitmap & where ) const {
paintown_draw_sprite_ex16(where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_TRANS, SPRITE_V_FLIP | SPRITE_H_FLIP, filter);
}
void Bitmap::drawStretched( const int x, const int y, const int new_width, const int new_height, const Bitmap & who ) const {
if (getData()->getSurface() != NULL){
SDL_SetColorKey(getData()->getSurface(), SDL_SRCCOLORKEY, makeColor(255, 0, 255));
SDL_Surface * src = getData()->getSurface();
SDL_Surface * dst = who.getData()->getSurface();
int myWidth = src->w;
int myHeight = src->h;
int hisWidth = new_width;
int hisHeight = new_height;
int useX = x;
int useY = y;
int myX = 0;
int myY = 0;
float xscale = (float) hisWidth / (float) myWidth;
float yscale = (float) hisHeight / (float) myHeight;
/* sprig wont do the clipping right, if you start drawing from a negative offset
* sprig will do nothing.
*/
if (useX < 0){
useX = 0;
myX = -x / xscale;
}
if (useY < 0){
useY = 0;
myY = -y / yscale;
}
SPG_TransformX(src, dst, 0, xscale, yscale, myX, myY, useX, useY, SPG_TCOLORKEY);
}
}
static void doBlit(SDL_Surface * mine, const int mx, const int my, const int width, const int height, const int wx, const int wy, const Bitmap & where ){
SDL_Rect source;
SDL_Rect destination;
source.w = width;
source.h = height;
source.x = mx;
source.y = my;
destination.w = width;
destination.h = height;
destination.x = wx;
destination.y = wy;
SDL_BlitSurface(mine, &source, where.getData()->getSurface(), &destination);
}
void Bitmap::Blit( const int mx, const int my, const int width, const int height, const int wx, const int wy, const Bitmap & where ) const {
SDL_SetColorKey(getData()->getSurface(), 0, MaskColor());
doBlit(getData()->getSurface(), mx, my, width, height, wx, wy, where);
/* FIXME: this is a hack, maybe put a call here for the other bitmap to update stuff
* like where->Blitted()
*/
if (&where == Screen){
SDL_Flip(Screen->getData()->getSurface());
}
}
void Bitmap::BlitMasked( const int mx, const int my, const int width, const int height, const int wx, const int wy, const Bitmap & where ) const {
SDL_SetColorKey(getData()->getSurface(), SDL_SRCCOLORKEY, MaskColor());
doBlit(getData()->getSurface(),mx, my, width, height, wx, wy, where);
/* FIXME: this is a hack, maybe put a call here for the other bitmap to update stuff
* like where->Blitted()
*/
if (&where == Screen){
SDL_Flip(Screen->getData()->getSurface());
}
}
void Bitmap::BlitToScreen(const int upper_left_x, const int upper_left_y) const {
if (getWidth() != Screen->getWidth() || getHeight() != Screen->getHeight()){
/*
this->Blit( upper_left_x, upper_left_y, *Buffer );
Buffer->Stretch(*Scaler);
Scaler->Blit(0, 0, 0, 0, *Screen);
*/
this->Stretch(*Scaler, 0, 0, getWidth(), getHeight(), upper_left_x, upper_left_y, Scaler->getWidth(), Scaler->getHeight());
Scaler->Blit(0, 0, 0, 0, *Screen);
} else {
this->Blit( upper_left_x, upper_left_y, *Screen );
}
/*
if ( Scaler == NULL ){
this->Blit( upper_left_x, upper_left_y, *Screen );
} else {
this->Blit( upper_left_x, upper_left_y, *Buffer );
Buffer->Stretch(*Scaler);
Scaler->Blit(0, 0, 0, 0, *Screen);
}
*/
// SDL_Flip(Screen->getData().getSurface());
// SDL_UpdateRect(Screen->getData().getSurface(), 0, 0, Screen->getWidth(), Screen->getHeight());
}
void Bitmap::BlitAreaToScreen(const int upper_left_x, const int upper_left_y) const {
this->Blit(upper_left_x, upper_left_y, *Screen);
#if 0
if (Scaler != NULL && false){
/*
double mult_x = (double) Scaler->getWidth() / (double) SCALE_X;
double mult_y = (double) Scaler->getHeight() / (double) SCALE_Y;
*/
double mult_x = 1;
double mult_y = 1;
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);
}
#endif
}
/*
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::StretchXbr(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 * source = subSource.getData()->getSurface();
SDL_Surface * destination = subDestination.getData()->getSurface();
if (SDL_MUSTLOCK(source)){
SDL_LockSurface(source);
}
if (SDL_MUSTLOCK(destination)){
SDL_LockSurface(destination);
}
if (sourceWidth * 4 == destWidth && sourceHeight * 4 == destHeight){
xbr::xbr4x(source, destination);
} else if (sourceWidth * 3 == destWidth && sourceHeight * 3 == destHeight){
xbr::xbr3x(source, destination);
} else if (sourceWidth * 2 == destWidth && sourceHeight * 2 == destHeight){
xbr::xbr2x(source, destination);
} else {
if (SDL_MUSTLOCK(source)){
SDL_UnlockSurface(source);
}
if (SDL_MUSTLOCK(destination)){
SDL_UnlockSurface(destination);
}
subSource.Stretch(subDestination);
return;
}
if (SDL_MUSTLOCK(source)){
SDL_UnlockSurface(source);
}
if (SDL_MUSTLOCK(destination)){
SDL_UnlockSurface(destination);
}
}
void Bitmap::StretchHqx(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 * source = subSource.getData()->getSurface();
SDL_Surface * destination = subDestination.getData()->getSurface();
if (SDL_MUSTLOCK(source)){
SDL_LockSurface(source);
}
if (SDL_MUSTLOCK(destination)){
SDL_LockSurface(destination);
}
if (sourceWidth * 4 == destWidth && sourceHeight * 4 == destHeight){
hqx::hq4x(source, destination);
} else if (sourceWidth * 3 == destWidth && sourceHeight * 3 == destHeight){
hqx::hq3x(source, destination);
} else if (sourceWidth * 2 == destWidth && sourceHeight * 2 == destHeight){
hq2x::hq2x(source, destination);
} else {
if (SDL_MUSTLOCK(source)){
SDL_UnlockSurface(source);
}
if (SDL_MUSTLOCK(destination)){
SDL_UnlockSurface(destination);
}
subSource.Stretch(subDestination);
return;
}
if (SDL_MUSTLOCK(source)){
SDL_UnlockSurface(source);
}
if (SDL_MUSTLOCK(destination)){
SDL_UnlockSurface(destination);
}
}
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 {
/* TODO: if souceWidth == destWidth && souceHeight == destHeight then
* just do a normal blit. check if sdl already does this optimization
*/
if (destWidth <= 0 || destHeight <= 0 ||
sourceWidth <= 0 || sourceHeight <= 0){
return;
}
Bitmap subSource(*this, sourceX, sourceY, sourceWidth, sourceHeight);
Bitmap subDestination(where, destX, destY, destWidth, destHeight);
SDL_Surface * src = subSource.getData()->getSurface();
SDL_Surface * dst = subDestination.getData()->getSurface();
if (SDL_MUSTLOCK(src)){
SDL_LockSurface(src);
}
if (SDL_MUSTLOCK(dst)){
SDL_LockSurface(dst);
}
SDL_StretchSurfaceRect(src, NULL, dst, NULL);
if (SDL_MUSTLOCK(src)){
SDL_UnlockSurface(src);
}
if (SDL_MUSTLOCK(dst)){
SDL_UnlockSurface(dst);
}
/*
SDL_Surface * src = getData().getSurface();
SDL_Surface * dst = where.getData().getSurface();
*/
/*
float xscale = (float) destWidth / (float) sourceWidth;
float yscale = (float) destHeight / (float) sourceHeight;
SDL_SetColorKey(src, 0, MaskColor());
SPG_TransformX(src, dst, 0, xscale, yscale, sourceX, sourceY, destX, destY, SPG_NONE);
*/
/*
SDL_Rect source;
SDL_Rect destination;
source.x = sourceX;
source.y = sourceY;
source.w = sourceWidth;
source.h = sourceHeight;
destination.x = destX;
destination.y = destY;
destination.w = destWidth;
destination.h = destHeight;
// SDL_StretchSurfaceRect(getData().getSurface(), &source, where.getData().getSurface(), &destination);
SDL_Surface * src = getData().getSurface();
SDL_Surface * dst = where.getData().getSurface();
if (SDL_MUSTLOCK(src)){
SDL_LockSurface(src);
}
if (SDL_MUSTLOCK(dst)){
SDL_LockSurface(dst);
}
SDL_StretchSurfaceRect(src, &source, dst, &destination);
if (SDL_MUSTLOCK(src)){
SDL_UnlockSurface(src);
}
if (SDL_MUSTLOCK(dst)){
SDL_UnlockSurface(dst);
}
*/
}
void Bitmap::save(const std::string & str) const {
/* always saves as a png for now */
IMG_SavePNG(str.c_str(), getData()->getSurface(), IMG_COMPRESS_DEFAULT);
}
void Bitmap::triangle( int x1, int y1, int x2, int y2, int x3, int y3, int color ) const {
SPG_TrigonFilled(getData()->getSurface(), x1, y1, x2, y2, x3, y3, color);
/*
if (Graphics::drawingMode == MODE_SOLID){
SPG_TrigonFilled(getData()->getSurface(), x1, y1, x2, y2, x3, y3, color);
} else if (Graphics::drawingMode == MODE_TRANS){
int alpha = globalBlend.alpha;
SPG_TrigonFilledBlend(getData()->getSurface(), x1, y1, x2, y2, x3, y3, color, alpha);
}
*/
}
void Bitmap::ellipse( int x, int y, int rx, int ry, int color ) const {
SPG_Ellipse(getData()->getSurface(), x, y, rx, ry, color);
/*
if (Graphics::drawingMode == MODE_SOLID){
SPG_Ellipse(getData()->getSurface(), x, y, rx, ry, color);
} else if (Graphics::drawingMode == MODE_TRANS){
int alpha = globalBlend.alpha;
SPG_EllipseBlend(getData()->getSurface(), x, y, rx, ry, color, alpha);
}
*/
}
void TranslucentBitmap::ellipse( int x, int y, int rx, int ry, int color ) const {
int alpha = globalBlend.alpha;
SPG_EllipseBlend(getData()->getSurface(), x, y, rx, ry, color, alpha);
}
void Bitmap::ellipseFill( int x, int y, int rx, int ry, int color ) const {
SPG_EllipseFilled(getData()->getSurface(), x, y, rx, ry, color);
}
void Bitmap::light(int x, int y, int width, int height, int start_y, int focus_alpha, int edge_alpha, int focus_color, int edge_color) const {
paintown_light16(getData()->getSurface(), x, y, width, height, start_y, focus_alpha, edge_alpha, focus_color, edge_color);
}
void Bitmap::applyTrans(const int color) const {
paintown_applyTrans16(getData()->getSurface(), color);
}
void Bitmap::floodfill( const int x, const int y, const int color ) const {
SPG_FloodFill(getData()->getSurface(), x, y, color);
}
/*
void Bitmap::horizontalLine( const int x1, const int y, const int x2, const int color ) const {
SPG_LineH(getData().getSurface(), x1, y, x2, color);
}
*/
void Bitmap::hLine( const int x1, const int y, const int x2, const int color ) const {
SPG_LineH(getData()->getSurface(), x1, y, x2, color);
}
void TranslucentBitmap::hLine( const int x1, const int y, const int x2, const int color ) const {
int alpha = globalBlend.alpha;
SPG_LineHBlend(getData()->getSurface(), x1, y, x2, color, alpha);
}
void Bitmap::vLine( const int y1, const int x, const int y2, const int color ) const {
SPG_LineV(getData()->getSurface(), x, y1, y2, color);
}
void Bitmap::polygon( const int * verts, const int nverts, const int color ) const {
SPG_Point * points = new SPG_Point[nverts];
for (int i = 0; i < nverts; i++){
points[i].x = verts[i*2];
points[i].y = verts[i*2+1];
}
SPG_PolygonFilled(getData()->getSurface(), nverts, points, color);
delete[] points;
}
static const double RAD_TO_DEG = 180.0/Util::pi;
static const double DEG_TO_RAD = Util::pi/180.0;
static double toDegrees(double radians){
return RAD_TO_DEG * radians;
}
static const double arcPhase = -Util::pi / 2;
/* 0 = right. pi/2 = up. pi = left. 3pi/2 = down */
void Bitmap::arc(const int x, const int y, const double ang1, const double ang2, const int radius, const int color ) const {
SPG_Arc(getData()->getSurface(), x, y, radius, toDegrees(ang1 + arcPhase), toDegrees(ang2 + arcPhase), color);
}
void Bitmap::arcFilled(const int x, const int y, const double ang1, const double ang2, const int radius, const int color ) const {
SPG_ArcFilled(getData()->getSurface(), x, y, radius, toDegrees(ang1 + arcPhase), toDegrees(ang2 + arcPhase), color);
}
void TranslucentBitmap::arc(const int x, const int y, const double ang1, const double ang2, const int radius, const int color ) const {
int alpha = globalBlend.alpha;
SPG_ArcBlend(getData()->getSurface(), x, y, radius, toDegrees(ang1 + arcPhase), toDegrees(ang2 + arcPhase), color, alpha);
}
void TranslucentBitmap::arcFilled(const int x, const int y, const double ang1, const double ang2, const int radius, const int color ) const {
int alpha = globalBlend.alpha;
SPG_ArcFilledBlend(getData()->getSurface(), x, y, radius, toDegrees(ang1 + arcPhase), toDegrees(ang2 + arcPhase), color, alpha);
}
void Bitmap::fill(int color) const {
SDL_Rect area;
area.x = 0;
area.y = 0;
area.w = getWidth();
area.h = getHeight();
SDL_FillRect(getData()->getSurface(), &area, color);
}
/*
void TranslucentBitmap::fill(int color) const {
rectangleFill(0, 0, getWidth(), getHeight(), color);
}
*/
void Bitmap::drawCharacter( const int x, const int y, const int color, const int background, const Bitmap & where ) const {
/* TODO */
}
void Bitmap::drawRotate( const int x, const int y, const int angle, const Bitmap & where ){
SDL_SetColorKey(getData()->getSurface(), SDL_SRCCOLORKEY, MaskColor());
SDL_Surface * src = getData()->getSurface();
SDL_Surface * dst = where.getData()->getSurface();
SPG_TransformX(src, dst, angle, 1, 1, 0, 0, x, y, SPG_TCOLORKEY);
}
/* I'm not really sure whats going on here but we need to negate the angle */
static int fixAngle(int angle){
return -angle;
}
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, fixAngle(angle), 1, 1, centerX, centerY, x, y, SPG_TCOLORKEY);
}
void Bitmap::drawPivot( const int centerX, const int centerY, const int x, const int y, const int angle, const double scale, const Bitmap & where ){
SDL_SetColorKey(getData()->getSurface(), SDL_SRCCOLORKEY, MaskColor());
SDL_Surface * src = getData()->getSurface();
SDL_Surface * dst = where.getData()->getSurface();
SPG_TransformX(src, dst, angle, scale, scale, centerX, centerY, x, y, SPG_TCOLORKEY);
}
void Bitmap::replaceColor(const Color & original, const Color & replaced){
paintown_replace16(getData()->getSurface(), original, replaced);
}
static SDL_Color pcxMaskColor(unsigned char * data, const int length){
if (length >= 769){
if (data[length - 768 - 1] == 12){
unsigned char * palette = &data[length - 768];
unsigned char red = palette[0];
unsigned char green = palette[1];
unsigned char blue = palette[2];
SDL_Color color;
color.r = red;
color.g = green;
color.b = blue;
return color;
}
}
SDL_Color color;
color.r = 255;
color.g = 255;
color.b = 255;
return color;
}
struct PCXheader {
Uint8 Manufacturer;
Uint8 Version;
Uint8 Encoding;
Uint8 BitsPerPixel;
Sint16 Xmin, Ymin, Xmax, Ymax;
Sint16 HDpi, VDpi;
Uint8 Colormap[48];
Uint8 Reserved;
Uint8 NPlanes;
Sint16 BytesPerLine;
Sint16 PaletteInfo;
Sint16 HscreenSize;
Sint16 VscreenSize;
Uint8 Filler[54];
};
static SDL_Surface * fast_load_pcx(unsigned char * const memory, const unsigned int length){
int start;
struct PCXheader pcxh;
Uint32 Rmask;
Uint32 Gmask;
Uint32 Bmask;
Uint32 Amask;
SDL_Surface *surface = NULL;
int width, height;
int y, bpl;
Uint8 *row, *buf = NULL;
const char *error = NULL;
int bits, src_bits;
Uint8 * data = memory;
if (length < sizeof(pcxh)){
goto done;
}
memcpy(&pcxh, data, sizeof(pcxh));
data += sizeof(pcxh);
pcxh.Xmin = SDL_SwapLE16(pcxh.Xmin);
pcxh.Ymin = SDL_SwapLE16(pcxh.Ymin);
pcxh.Xmax = SDL_SwapLE16(pcxh.Xmax);
pcxh.Ymax = SDL_SwapLE16(pcxh.Ymax);
pcxh.BytesPerLine = SDL_SwapLE16(pcxh.BytesPerLine);
/* Create the surface of the appropriate type */
width = (pcxh.Xmax - pcxh.Xmin) + 1;
height = (pcxh.Ymax - pcxh.Ymin) + 1;
Rmask = Gmask = Bmask = Amask = 0;
src_bits = pcxh.BitsPerPixel * pcxh.NPlanes;
if((pcxh.BitsPerPixel == 1 && pcxh.NPlanes >= 1 && pcxh.NPlanes <= 4)
|| (pcxh.BitsPerPixel == 8 && pcxh.NPlanes == 1)) {
bits = 8;
} else if(pcxh.BitsPerPixel == 8 && pcxh.NPlanes == 3) {
bits = 24;
if (SDL_BYTEORDER == SDL_LIL_ENDIAN){
Rmask = 0x000000FF;
Gmask = 0x0000FF00;
Bmask = 0x00FF0000;
} else {
Rmask = 0xFF0000;
Gmask = 0x00FF00;
Bmask = 0x0000FF;
}
} else {
error = "unsupported PCX format";
goto done;
}
surface = SDL_AllocSurface(SDL_SWSURFACE, width, height,
bits, Rmask, Gmask, Bmask, Amask);
if ( surface == NULL )
goto done;
bpl = pcxh.NPlanes * pcxh.BytesPerLine;
if (bpl > surface->pitch) {
error = "bytes per line is too large (corrupt?)";
}
buf = (Uint8*) malloc(bpl);
row = (Uint8*) surface->pixels;
for ( y=0; y<surface->h; ++y ) {
/* decode a scan line to a temporary buffer first */
int i, count = 0;
Uint8 *dst = (src_bits == 8) ? row : buf;
if (pcxh.Encoding == 0){
if (bpl + data - memory < length){
memcpy(dst, data, bpl);
data += bpl;
} else {
error = "file truncated";
goto done;
}
} else {
Uint8 ch = 0;
for (i = 0; i < bpl; i++) {
if (!count) {
if (data - memory >= length){
error = "file truncated";
goto done;
} else {
ch = *data;
data += 1;
}
if ((ch & 0xc0) == 0xc0){
count = ch & 0x3f;
if (data - memory >= length){
error = "file truncated";
goto done;
} else {
ch = *data;
data += 1;
}
} else
count = 1;
}
dst[i] = ch;
count--;
}
}
if (src_bits <= 4){
/* expand planes to 1 byte/pixel */
Uint8 *src = buf;
int plane;
for(plane = 0; plane < pcxh.NPlanes; plane++) {
int i, j, x = 0;
for(i = 0; i < pcxh.BytesPerLine; i++) {
Uint8 byte = *src++;
for(j = 7; j >= 0; j--) {
unsigned bit = (byte >> j) & 1;
/* skip padding bits */
if (i * 8 + j >= width)
continue;
row[x++] |= bit << plane;
}
}
}
} else if(src_bits == 24) {
/* de-interlace planes */
Uint8 *src = buf;
int plane;
for(plane = 0; plane < pcxh.NPlanes; plane++) {
int x;
dst = row + plane;
for(x = 0; x < width; x++) {
*dst = *src++;
dst += pcxh.NPlanes;
}
}
}
row += surface->pitch;
}
if(bits == 8) {
SDL_Color *colors = surface->format->palette->colors;
int nc = 1 << src_bits;
int i;
surface->format->palette->ncolors = nc;
if(src_bits == 8) {
/* look for a 256-colour palette */
while (data - memory < length && *data != 12){
data += 1;
}
data += 1;
if (data - memory >= length){
goto done;
}
for (i = 0; i < 256; i++) {
colors[i].r = *data; data += 1;
colors[i].g = *data; data += 1;
colors[i].b = *data; data += 1;
}
} else {
for(i = 0; i < nc; i++) {
colors[i].r = pcxh.Colormap[i * 3];
colors[i].g = pcxh.Colormap[i * 3 + 1];
colors[i].b = pcxh.Colormap[i * 3 + 2];
}
}
}
done:
free(buf);
if (error){
if (surface){
SDL_FreeSurface(surface);
surface = NULL;
}
}
return surface;
}
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 * pcx = fast_load_pcx(data, length);
if (pcx == NULL){
std::ostringstream out;
out << "Could not load PCX file from " << (void*) data << " length " << length;
throw BitmapException(__FILE__, __LINE__, out.str());
}
SDL_Surface * display = optimizedSurface(pcx);
Bitmap out(display, false);
if (pcx->format->BitsPerPixel == 8){
#if SDL_VERSION_ATLEAST(1, 3, 0)
SDL_Color color = pcxMaskColor(data, length);
#else
SDL_Color color = pcx->format->palette->colors[pcx->format->colorkey];
#endif
int bad = makeColor(color.r, color.g, color.b);
out.set8BitMaskColor(bad);
// int mask = MaskColor();
// out.replaceColor(bad, mask);
}
SDL_FreeSurface(pcx);
// SDL_FreeSurface(display);
// out.floodfill(0, 0, makeColor(255, 0, 255));
return out;
}
int Bitmap::getPixel( const int x, const int y ) const {
return SPG_GetPixel(getData()->getSurface(), x, y);
}
void Bitmap::readLine( std::vector< int > & line, int y ){
for (int x = 0; x < getWidth(); x++){
line.push_back(getPixel(x, y));
}
}
void Bitmap::StretchBy2( const Bitmap & where ){
/* TODO */
}
void Bitmap::StretchBy4( const Bitmap & where ){
/* TODO */
}
void Bitmap::draw(const int x, const int y, Filter * filter, const Bitmap & where) const {
// paintown_draw_sprite_filter_ex16(where.getData().getSurface(), getData().getSurface(), x, y, filter);
paintown_draw_sprite_ex16(where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_NORMAL, SPRITE_NO_FLIP, filter);
}
void LitBitmap::draw( const int x, const int y, const Bitmap & where ) const {
paintown_draw_sprite_ex16( where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_LIT, SPRITE_NO_FLIP, NULL);
}
void LitBitmap::draw( const int x, const int y, Filter * filter, const Bitmap & where ) const {
paintown_draw_sprite_ex16( where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_LIT, SPRITE_NO_FLIP, filter);
}
void LitBitmap::drawHFlip( const int x, const int y, const Bitmap & where ) const {
paintown_draw_sprite_ex16( where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_LIT, SPRITE_H_FLIP, NULL);
}
void LitBitmap::drawHFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const {
paintown_draw_sprite_ex16( where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_LIT, SPRITE_H_FLIP, filter);
}
void LitBitmap::drawVFlip( const int x, const int y, const Bitmap & where ) const {
paintown_draw_sprite_ex16( where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_LIT, SPRITE_V_FLIP, NULL);
}
void LitBitmap::drawVFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const {
paintown_draw_sprite_ex16( where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_LIT, SPRITE_V_FLIP, filter);
}
void LitBitmap::drawHVFlip( const int x, const int y, const Bitmap & where ) const {
paintown_draw_sprite_ex16( where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_LIT, SPRITE_V_FLIP | SPRITE_H_FLIP, NULL);
}
void LitBitmap::drawHVFlip( const int x, const int y, Filter * filter, const Bitmap & where ) const {
paintown_draw_sprite_ex16( where.getData()->getSurface(), getData()->getSurface(), x, y, SPRITE_LIT, SPRITE_V_FLIP | SPRITE_H_FLIP, filter);
}
/*
#define PAINTOWN_DLS_BLENDER BLENDER_FUNC
#define PAINTOWN_DTS_BLENDER BLENDER_FUNC
#define PAINTOWN_MAKE_DLS_BLENDER(a) _blender_func16
#define PAINTOWN_MAKE_DTS_BLENDER() _blender_func16
#define PAINTOWN_PIXEL_PTR unsigned short*
#define PAINTOWN_OFFSET_PIXEL_PTR(p,x) ((PAINTOWN_PIXEL_PTR) (p) + (x))
#define PAINTOWN_INC_PIXEL_PTR(p) ((p)++)
#define PAINTOWN_INC_PIXEL_PTR_EX(p,d) ((p) += d)
#define PAINTOWN_GET_MEMORY_PIXEL(p) (*(p))
#define PAINTOWN_IS_SPRITE_MASK(b,c) ((unsigned long) (c) == (unsigned long) MASK_COLOR)
#define PAINTOWN_DLSX_BLEND(b,n) ((*(b))(_blender_col_16, (n), globalBlend.alpha))
#define PAINTOWN_GET_PIXEL(p) *((unsigned short *) (p))
#define PAINTOWN_DTS_BLEND(b,o,n) ((*(b))((n), (o), globalBlend.alpha))
#define PAINTOWN_PUT_PIXEL(p,c) (*((unsigned short *) p) = (c))
#define PAINTOWN_PUT_MEMORY_PIXEL(p,c) (*(p) = (c))
#define PAINTOWN_SET_ALPHA(a) (globalBlend.alpha = (a))
*/
static void paintown_applyTrans16(SDL_Surface * dst, const int color){
int y1 = 0;
int y2 = dst->h;
int x1 = 0;
int x2 = dst->w - 1;
y1 = dst->clip_rect.y;
y2 = dst->clip_rect.y + dst->clip_rect.h;
x1 = dst->clip_rect.x;
x2 = dst->clip_rect.x + dst->clip_rect.w;
int bpp = dst->format->BytesPerPixel;
unsigned int mask = makeColor(255, 0, 255);
for (int y = y1; y < y2; y++) {
Uint8 * sourceLine = computeOffset(dst, x1, y);
for (int x = x2 - 1; x >= x1; sourceLine += bpp, x--) {
unsigned long sourcePixel = *(Uint16*) sourceLine;
if (!(sourcePixel == mask)){
sourcePixel = globalBlend.currentBlender(color, sourcePixel, globalBlend.alpha);
*(Uint16 *)sourceLine = sourcePixel;
}
}
}
}
static void paintown_replace16(SDL_Surface * dst, const int original, const int replace){
int y1 = 0;
int y2 = dst->h;
int x1 = 0;
int x2 = dst->w - 1;
y1 = dst->clip_rect.y;
y2 = dst->clip_rect.y + dst->clip_rect.h;
x1 = dst->clip_rect.x;
x2 = dst->clip_rect.x + dst->clip_rect.w;
int bpp = dst->format->BytesPerPixel;
/* Attempted manual unrolling. Gcc can optimize the naive loop below better
* than this unrolling attempt.
*/
/*
for (int y = y1; y < y2; y += 4){
switch (y2 - y1){
case 1 : {
Uint8 * source1 = computeOffset(dst, x1, y);
for (int x = x2 - 1; x >= x1; source1 += bpp, x--) {
unsigned long sourcePixel = *(Uint16*) source1;
if ((int) sourcePixel == original){
*(Uint16 *)source1 = replace;
}
}
break;
}
case 2 : {
Uint8 * source1 = computeOffset(dst, x1, y);
Uint8 * source2 = computeOffset(dst, x1, y + 1);
for (int x = x2 - 1; x >= x1; source1 += bpp, source2 += bpp, x--) {
unsigned long sourcePixel = *(Uint16*) source1;
unsigned long sourcePixel2 = *(Uint16*) source2;
if ((int) sourcePixel == original){
*(Uint16 *)source1 = replace;
}
if ((int) sourcePixel2 == original){
*(Uint16 *)source2 = replace;
}
}
break;
}
case 3 : {
Uint8 * source1 = computeOffset(dst, x1, y);
Uint8 * source2 = computeOffset(dst, x1, y + 1);
Uint8 * source3 = computeOffset(dst, x1, y + 2);
for (int x = x2 - 1; x >= x1; source1 += bpp, source2 += bpp, source3 += bpp, x--) {
unsigned long sourcePixel = *(Uint16*) source1;
unsigned long sourcePixel2 = *(Uint16*) source2;
unsigned long sourcePixel3 = *(Uint16*) source3;
if ((int) sourcePixel == original){
*(Uint16 *)source1 = replace;
}
if ((int) sourcePixel2 == original){
*(Uint16 *)source2 = replace;
}
if ((int) sourcePixel3 == original){
*(Uint16 *)source3 = replace;
}
}
break;
}
default:
case 4 : {
Uint8 * source1 = computeOffset(dst, x1, y);
Uint8 * source2 = computeOffset(dst, x1, y + 1);
Uint8 * source3 = computeOffset(dst, x1, y + 2);
Uint8 * source4 = computeOffset(dst, x1, y + 3);
for (int x = x2 - 1; x >= x1; source1 += bpp, source2 += bpp, source3 += bpp, source4 += bpp, x--) {
unsigned long sourcePixel = *(Uint16*) source1;
unsigned long sourcePixel2 = *(Uint16*) source2;
unsigned long sourcePixel3 = *(Uint16*) source3;
unsigned long sourcePixel4 = *(Uint16*) source4;
if ((int) sourcePixel == original){
*(Uint16 *)source1 = replace;
}
if ((int) sourcePixel2 == original){
*(Uint16 *)source2 = replace;
}
if ((int) sourcePixel3 == original){
*(Uint16 *)source3 = replace;
}
if ((int) sourcePixel4 == original){
*(Uint16 *)source4 = replace;
}
}
break;
}
}
}
*/
if (SDL_MUSTLOCK(dst)){
SDL_LockSurface(dst);
}
/* Another failed attempt at loop unrolling. */
/*
int y2_4 = y2 & (~3);
for (int y = y1; y < y2_4; y += 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--) {
Uint16 sourcePixel = *(Uint16*) source1;
Uint16 sourcePixel2 = *(Uint16*) source2;
Uint16 sourcePixel3 = *(Uint16*) source3;
Uint16 sourcePixel4 = *(Uint16*) source4;
if (sourcePixel == original){
*(Uint16 *)source1 = replace;
}
if (sourcePixel2 == original){
*(Uint16 *)source2 = replace;
}
if (sourcePixel3 == original){
*(Uint16 *)source3 = replace;
}
if (sourcePixel4 == original){
*(Uint16 *)source4 = replace;
}
}
}
for (int y = y2_4; y < y2; y++) {
Uint8 * sourceLine = computeOffset(dst, x1, y);
for (int x = x2 - 1; x >= x1; sourceLine += bpp, x--) {
Uint16 sourcePixel = *(Uint16*) sourceLine;
if (sourcePixel == original){
*(Uint16 *)sourceLine = replace;
}
}
}
*/
/* Original */
for (int y = y1; y < y2; y++){
Uint8 * sourceLine = computeOffset(dst, x1, y);
for (int x = x2 - 1; x >= x1; sourceLine += bpp, x--) {
Uint16 sourcePixel = *(Uint16*) sourceLine;
if (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, long long dx, long long 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*/ ) {
long long tmp;
tmp = dst->clip_rect.x - dx;
sxbeg = ((tmp < 0) ? 0 : tmp);
dxbeg = sxbeg + dx;
tmp = dst->clip_rect.x + dst->clip_rect.w - dx;
w = ((tmp > src->w) ? src->w : tmp) - sxbeg;
if (w <= 0)
return;
tmp = dst->clip_rect.y - dy;
sybeg = ((tmp < 0) ? 0 : tmp);
dybeg = sybeg + dy;
tmp = dst->clip_rect.y + dst->clip_rect.h - dy;
h = ((tmp > src->h) ? src->h : tmp) - sybeg;
if (h <= 0)
return;
}
unsigned int mask = makeColor(255, 0, 255);
int bpp = src->format->BytesPerPixel;
for (y = 0; y < h; y++) {
Uint8 * sourceLine = computeOffset(src, sxbeg, sybeg + y);
Uint8 * destLine = computeOffset(dst, dxbeg, dybeg + y * y_dir);
for (x = w - 1; x >= 0; sourceLine += bpp, destLine += bpp * x_dir, x--) {
unsigned long sourcePixel = *(Uint16*) sourceLine;
if (!(sourcePixel == mask)){
*(Uint16 *)destLine = filter->filter(sourcePixel);
} else {
*(Uint16 *)destLine = mask;
}
}
}
if (SDL_MUSTLOCK(dst)){
SDL_UnlockSurface(dst);
}
}
static void paintown_draw_sprite_ex16(SDL_Surface * dst, SDL_Surface * src, long long dx, long long dy, int mode, int flip, Bitmap::Filter * filter){
int x, y, w, h;
int x_dir = 1, y_dir = 1;
int dxbeg, dybeg;
int sxbeg, sybeg;
/*
PAINTOWN_DLS_BLENDER lit_blender;
PAINTOWN_DTS_BLENDER trans_blender;
*/
/*
ASSERT(dst);
ASSERT(src);
*/
if (SDL_MUSTLOCK(src)){
SDL_LockSurface(src);
}
if (SDL_MUSTLOCK(dst)){
SDL_LockSurface(dst);
}
if ( flip & SPRITE_V_FLIP ){
y_dir = -1;
}
if ( flip & SPRITE_H_FLIP ){
x_dir = -1;
}
if (true /* dst->clip*/ ) {
long long tmp;
tmp = dst->clip_rect.x - dx;
sxbeg = ((tmp < 0) ? 0 : tmp);
dxbeg = sxbeg + dx;
tmp = dst->clip_rect.x + dst->clip_rect.w - dx;
w = ((tmp > src->w) ? src->w : tmp) - sxbeg;
if (w <= 0)
return;
if ( flip & SPRITE_H_FLIP ){
/* use backward drawing onto dst */
sxbeg = src->w - (sxbeg + w);
dxbeg += w - 1;
}
tmp = dst->clip_rect.y - dy;
sybeg = ((tmp < 0) ? 0 : tmp);
dybeg = sybeg + dy;
tmp = dst->clip_rect.y + dst->clip_rect.h - dy;
h = ((tmp > src->h) ? src->h : tmp) - sybeg;
if (h <= 0)
return;
if ( flip & SPRITE_V_FLIP ){
/* use backward drawing onto dst */
sybeg = src->h - (sybeg + h);
dybeg += h - 1;
}
} else {
w = src->w;
h = src->h;
sxbeg = 0;
sybeg = 0;
dxbeg = dx;
if ( flip & SPRITE_H_FLIP ){
dxbeg = dx + w - 1;
}
dybeg = dy;
if ( flip & SPRITE_V_FLIP ){
dybeg = dy + h - 1;
}
}
/*
lit_blender = PAINTOWN_MAKE_DLS_BLENDER(0);
trans_blender = PAINTOWN_MAKE_DTS_BLENDER();
*/
#if 0
if (dst->id & (BMP_ID_VIDEO | BMP_ID_SYSTEM)) {
bmp_select(dst);
switch (mode){
case Bitmap::SPRITE_NORMAL : {
for (y = 0; y < h; y++) {
PAINTOWN_PIXEL_PTR s = PAINTOWN_OFFSET_PIXEL_PTR(src->line[sybeg + y], sxbeg);
PAINTOWN_PIXEL_PTR d = PAINTOWN_OFFSET_PIXEL_PTR(bmp_write_line(dst, dybeg + y * y_dir), dxbeg);
for (x = w - 1; x >= 0; PAINTOWN_INC_PIXEL_PTR(s), PAINTOWN_INC_PIXEL_PTR_EX(d,x_dir), x--) {
unsigned long c = PAINTOWN_GET_MEMORY_PIXEL(s);
if (!PAINTOWN_IS_SPRITE_MASK(src, c)) {
PAINTOWN_PUT_PIXEL(d, c);
}
}
}
break;
}
case Bitmap::SPRITE_LIT : {
for (y = 0; y < h; y++) {
PAINTOWN_PIXEL_PTR s = PAINTOWN_OFFSET_PIXEL_PTR(src->line[sybeg + y], sxbeg);
PAINTOWN_PIXEL_PTR d = PAINTOWN_OFFSET_PIXEL_PTR(bmp_write_line(dst, dybeg + y * y_dir), dxbeg);
for (x = w - 1; x >= 0; PAINTOWN_INC_PIXEL_PTR(s), PAINTOWN_INC_PIXEL_PTR_EX(d,x_dir), x--) {
unsigned long c = PAINTOWN_GET_MEMORY_PIXEL(s);
if (!PAINTOWN_IS_SPRITE_MASK(src, c)) {
c = PAINTOWN_DLSX_BLEND(lit_blender, c);
PAINTOWN_PUT_PIXEL(d, c);
}
}
}
break;
}
case Bitmap::SPRITE_TRANS : {
for (y = 0; y < h; y++) {
PAINTOWN_PIXEL_PTR s = PAINTOWN_OFFSET_PIXEL_PTR(src->line[sybeg + y], sxbeg);
PAINTOWN_PIXEL_PTR d = PAINTOWN_OFFSET_PIXEL_PTR(bmp_write_line(dst, dybeg + y * y_dir), dxbeg);
for (x = w - 1; x >= 0; PAINTOWN_INC_PIXEL_PTR(s), PAINTOWN_INC_PIXEL_PTR_EX(d,x_dir), x--) {
unsigned long c = PAINTOWN_GET_MEMORY_PIXEL(s);
if (!PAINTOWN_IS_SPRITE_MASK(src, c)) {
c = PAINTOWN_DTS_BLEND(trans_blender, PAINTOWN_GET_PIXEL(d), c);
PAINTOWN_PUT_PIXEL(d, c);
}
}
}
break;
}
}
#xendif
for (y = 0; y < h; y++) {
PAINTOWN_PIXEL_PTR s = PAINTOWN_OFFSET_PIXEL_PTR(src->line[sybeg + y], sxbeg);
/* flipped if y_dir is -1 */
PAINTOWN_PIXEL_PTR d = PAINTOWN_OFFSET_PIXEL_PTR(bmp_write_line(dst, dybeg + y * y_dir), dxbeg);
/* d is incremented by x_dir, -1 if flipped */
for (x = w - 1; x >= 0; PAINTOWN_INC_PIXEL_PTR(s), PAINTOWN_INC_PIXEL_PTR_EX(d,x_dir), x--) {
unsigned long c = PAINTOWN_GET_MEMORY_PIXEL(s);
if (!PAINTOWN_IS_SPRITE_MASK(src, c)) {
switch( mode ){
case Bitmap::SPRITE_NORMAL : break;
case Bitmap::SPRITE_LIT : {
c = PAINTOWN_DLSX_BLEND(lit_blender, c);
break;
}
case Bitmap::SPRITE_TRANS : {
c = PAINTOWN_DTS_BLEND(trans_blender, PAINTOWN_GET_PIXEL(d), c);
break;
}
}
PAINTOWN_PUT_PIXEL(d, c);
}
}
}
bmp_unwrite_line(dst);
}
else {
#endif
{
switch (mode){
case SPRITE_NORMAL : {
unsigned int mask = makeColor(255, 0, 255);
int bpp = src->format->BytesPerPixel;
for (y = 0; y < h; y++) {
Uint8 * sourceLine = computeOffset(src, sxbeg, sybeg + y);
Uint8 * destLine = computeOffset(dst, dxbeg, dybeg + y * y_dir);
for (x = w - 1; x >= 0; sourceLine += bpp, destLine += bpp * x_dir, x--) {
unsigned long sourcePixel = *(Uint16*) sourceLine;
if (!(sourcePixel == mask)){
// unsigned int destPixel = *(Uint16*) destLine;
// sourcePixel = globalBlend.currentBlender(destPixel, sourcePixel, globalBlend.alpha);
if (filter != NULL){
*(Uint16 *)destLine = filter->filter(sourcePixel);
} else {
*(Uint16 *)destLine = sourcePixel;
}
}
}
}
break;
}
case SPRITE_LIT : {
int bpp = src->format->BytesPerPixel;
int litColor = makeColor(globalBlend.red, globalBlend.green, globalBlend.blue);
unsigned int mask = makeColor(255, 0, 255);
for (y = 0; y < h; y++) {
Uint8 * sourceLine = computeOffset(src, sxbeg, sybeg + y);
Uint8 * destLine = computeOffset(dst, dxbeg, dybeg + y * y_dir);
for (x = w - 1; x >= 0; sourceLine += bpp, destLine += bpp * x_dir, x--) {
unsigned long sourcePixel = *(Uint16*) sourceLine;
if (!(sourcePixel == mask)){
// unsigned int destPixel = *(Uint16*) destLine;
if (filter != NULL){
sourcePixel = globalBlend.currentBlender(litColor, filter->filter(sourcePixel), globalBlend.alpha);
*(Uint16 *)destLine = sourcePixel;
} else {
sourcePixel = globalBlend.currentBlender(litColor, sourcePixel, globalBlend.alpha);
*(Uint16 *)destLine = sourcePixel;
}
}
}
}
break;
}
case SPRITE_TRANS : {
int bpp = src->format->BytesPerPixel;
unsigned int mask = makeColor(255, 0, 255);
for (y = 0; y < h; y++) {
Uint8 * sourceLine = computeOffset(src, sxbeg, sybeg + y);
Uint8 * destLine = computeOffset(dst, dxbeg, dybeg + y * y_dir);
for (x = w - 1; x >= 0; sourceLine += bpp, destLine += bpp * x_dir, x--) {
unsigned long sourcePixel = *(Uint16*) sourceLine;
if (!(sourcePixel == mask)){
unsigned int destPixel = *(Uint16*) destLine;
if (filter != NULL){
sourcePixel = globalBlend.currentBlender(filter->filter(sourcePixel), destPixel, globalBlend.alpha);
*(Uint16 *)destLine = sourcePixel;
} else {
sourcePixel = globalBlend.currentBlender(sourcePixel, destPixel, globalBlend.alpha);
*(Uint16 *)destLine = sourcePixel;
}
}
}
}
break;
}
default : { break; }
}
#if 0
for (y = 0; y < h; y++) {
PAINTOWN_PIXEL_PTR s = PAINTOWN_OFFSET_PIXEL_PTR(src->line[sybeg + y], sxbeg);
PAINTOWN_PIXEL_PTR d = PAINTOWN_OFFSET_PIXEL_PTR(bmp_write_line(dst, dybeg + y * y_dir), dxbeg);
for (x = w - 1; x >= 0; PAINTOWN_INC_PIXEL_PTR(s), PAINTOWN_INC_PIXEL_PTR_EX(d,x_dir), x--) {
unsigned long c = PAINTOWN_GET_MEMORY_PIXEL(s);
if (!PAINTOWN_IS_SPRITE_MASK(src, c)) {
switch( mode ){
case Bitmap::SPRITE_NORMAL : break;
case Bitmap::SPRITE_LIT : {
c = PAINTOWN_DLSX_BLEND(lit_blender, c);
break;
}
case Bitmap::SPRITE_TRANS : {
c = PAINTOWN_DTS_BLEND(trans_blender, PAINTOWN_GET_PIXEL(d), c);
break;
}
}
PAINTOWN_PUT_MEMORY_PIXEL(d, c);
}
}
}
#endif
}
if (SDL_MUSTLOCK(src)){
SDL_UnlockSurface(src);
}
if (SDL_MUSTLOCK(dst)){
SDL_UnlockSurface(dst);
}
}
/* ultra special-case for drawing a light (like from a lamp).
* center of light is x,y and shines in a perfect isosolese triangle.
*/
static void paintown_light16(SDL_Surface * dst, const int x, const int y, int width, int height, const int start_y, const int focus_alpha, const int edge_alpha, const int focus_color, const int edge_color){
if (width > dst->w){
width = dst->w;
}
if (height > dst->h){
height = dst->h;
}
int dxbeg = x - width;
int x_dir = 1;
unsigned char * alphas = new unsigned char[width];
int * colors = new int[width];
for (int i = 0; i < width; i++){
alphas[i] = (unsigned char)((double)(edge_alpha - focus_alpha) * (double)i / (double)width + focus_alpha);
}
blend_palette(colors, width, focus_color, edge_color);
if (SDL_MUSTLOCK(dst)){
SDL_LockSurface(dst);
}
int min_y, max_y, min_x, max_x;
min_y = dst->clip_rect.y;
max_y = dst->clip_rect.y + dst->clip_rect.h - 1;
min_x = dst->clip_rect.x;
max_x = dst->clip_rect.x + dst->clip_rect.w - 1;
int dybeg = y;
/* tan(theta) = y / x */
double xtan = (double) height / (double) width;
int bpp = dst->format->BytesPerPixel;
for (int sy = start_y; sy < height; sy++) {
if (dybeg + sy < min_y || dybeg + sy > max_y){
continue;
}
/* x = y / tan(theta) */
int top_width = (int)((double) sy / xtan);
if (top_width == 0){
continue;
}
dxbeg = x - top_width;
Uint8* line = computeOffset(dst, dxbeg, dybeg + y);
for (int sx = -top_width; sx <= top_width; line += x_dir * bpp, sx++) {
if (sx + x < min_x || sx + x > max_x){
continue;
}
unsigned long c = *(Uint16*) line;
/* TODO:
* converting to a double and calling fabs is overkill, just
* write an integer abs() function.
*/
int sx_abs = (int) fabs((double) sx);
int alphaUse = alphas[sx_abs];
int color = colors[sx_abs];
c = globalBlend.currentBlender(color, c, alphaUse);
*(Uint16*) line = c;
}
}
delete[] alphas;
delete[] colors;
if (SDL_MUSTLOCK(dst)){
SDL_UnlockSurface(dst);
}
}
}
#include "../software-renderer/bitmap.cpp"

File Metadata

Mime Type
text/x-diff
Expires
Sat, Jun 20, 7:46 PM (1 w, 1 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
72991
Default Alt Text
(115 KB)

Event Timeline