einstein/cpp-source/utils.cpp
2015-11-03 15:56:09 +01:00

420 lines
9.8 KiB
C++

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <math.h>
#include <wchar.h>
//#ifndef WIN32
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
//#endif
#include <fstream>
#include "utils.h"
#include "main.h"
#include "unicode.h"
#include "sound.h"
int getCornerPixel(SDL_Surface *surface)
{
SDL_LockSurface(surface);
int bpp = surface->format->BytesPerPixel;
Uint8 *p = (Uint8*)surface->pixels;
int pixel = 0;
switch (bpp) {
case 1: pixel = *p; break;
case 2: pixel = *(Uint16 *)p; break;
case 3:
if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
pixel = p[0] << 16 | p[1] << 8 | p[2];
else
pixel = p[0] | p[1] << 8 | p[2] << 16;
break;
case 4: pixel = *(Uint32 *)p; break;
default: pixel = 0; /* shouldn't happen, but avoids warnings */
}
SDL_UnlockSurface(surface);
return pixel;
}
SDL_Surface* loadImage(const std::wstring &name, bool transparent)
{
int size;
void *bmp;
bmp = resources->getRef(name, size);
if (! bmp)
throw Exception(name + L" is not found");
SDL_RWops *op = SDL_RWFromMem(bmp, size);
SDL_Surface *s = SDL_LoadBMP_RW(op, 0);
SDL_FreeRW(op);
resources->delRef(bmp);
if (! s)
throw Exception(L"Error loading " + name);
SDL_Surface *screenS = SDL_DisplayFormat(s);
SDL_FreeSurface(s);
if (! screenS)
throw Exception(L"Error translating to screen format " + name);
if (transparent)
SDL_SetColorKey(screenS, SDL_SRCCOLORKEY, getCornerPixel(screenS));
return screenS;
}
#ifdef WIN32
#include <sys/timeb.h>
struct timezone { };
int gettimeofday(struct timeval* tp, int* /*tz*/)
{
struct timeb tb;
ftime(&tb);
tp->tv_sec = tb.time;
tp->tv_usec = 1000*tb.millitm;
return 0;
}
int gettimeofday(struct timeval* tp, struct timezone* /*tz*/)
{
return gettimeofday(tp, (int*)NULL);
}
#endif
int gettimeofday(struct timeval* tp)
{
#ifdef WIN32
return gettimeofday(tp, (int*)NULL);
#else
struct timezone tz;
return gettimeofday(tp, &tz);
#endif
}
void drawWallpaper(const std::wstring &name)
{
SDL_Surface *tile = loadImage(name);
SDL_Rect src = { 0, 0, tile->w, tile->h };
SDL_Rect dst = { 0, 0, tile->w, tile->h };
for (int y = 0; y < screen.getHeight(); y += tile->h)
for (int x = 0; x < screen.getWidth(); x += tile->w) {
dst.x = x;
dst.y = y;
SDL_BlitSurface(tile, &src, screen.getSurface(), &dst);
}
SDL_FreeSurface(tile);
}
void setPixel(SDL_Surface *s, int x, int y, int r, int g, int b)
{
int bpp = s->format->BytesPerPixel;
Uint32 pixel = SDL_MapRGB(s->format, r, g, b);
/* Here p is the address to the pixel we want to set */
Uint8 *p = (Uint8*)s->pixels + y * s->pitch + x * bpp;
switch (bpp) {
case 1:
*p = pixel;
break;
case 2:
*(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;
}
}
void getPixel(SDL_Surface *surface, int x, int y,
Uint8 *r, Uint8 *g, Uint8 *b)
{
int bpp = surface->format->BytesPerPixel;
/* Here p is the address to the pixel we want to retrieve */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
Uint32 pixel;
switch (bpp) {
case 1: pixel = *p; break;
case 2: pixel = *(Uint16 *)p; break;
case 3:
if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
pixel = p[0] << 16 | p[1] << 8 | p[2];
else
pixel = p[0] | p[1] << 8 | p[2] << 16;
break;
case 4: pixel = *(Uint32 *)p; break;
default: pixel = 0; /* shouldn't happen, but avoids warnings */
}
SDL_GetRGB(pixel, surface->format, r, g, b);
}
static int gammaTable[256];
static double lastGamma = -1.0;
void adjustBrightness(SDL_Surface *image, int x, int y, double k)
{
if (lastGamma != k) {
for (int i = 0; i <= 255; i++) {
gammaTable[i] = (int)(255.0 * pow((double)i / 255.0, 1.0 / k) + 0.5);
if (gammaTable[i] > 255)
gammaTable[i] = 255;
}
lastGamma = k;
}
Uint8 r, g, b;
getPixel(image, x, y, &r, &g, &b);
setPixel(image, x, y, gammaTable[r], gammaTable[g], gammaTable[b]);
}
SDL_Surface* adjustBrightness(SDL_Surface *image, double k, bool transparent)
{
if (lastGamma != k) {
for (int i = 0; i <= 255; i++) {
gammaTable[i] = (int)(255.0 * pow((double)i / 255.0, 1.0 / k) + 0.5);
if (gammaTable[i] > 255)
gammaTable[i] = 255;
}
lastGamma = k;
}
SDL_Surface *s = SDL_DisplayFormat(image);
if (! s)
throw Exception(L"Error converting image to display format");
SDL_LockSurface(s);
Uint8 r, g, b;
for (int j = 0; j < s->h; j++)
for (int i = 0; i < s->w; i++) {
getPixel(s, i, j, &r, &g, &b);
setPixel(s, i, j, gammaTable[r], gammaTable[g], gammaTable[b]);
}
SDL_UnlockSurface(s);
if (transparent)
SDL_SetColorKey(s, SDL_SRCCOLORKEY, getCornerPixel(s));
return s;
}
class CenteredBitmap: public Widget
{
private:
SDL_Surface *tile;
int x, y;
public:
CenteredBitmap(const std::wstring &fileName) {
tile = loadImage(fileName);
x = (screen.getWidth() - tile->w) / 2;
y = (screen.getHeight() - tile->h) / 2;
};
virtual ~CenteredBitmap() {
SDL_FreeSurface(tile);
};
virtual void draw() {
screen.draw(x, y, tile);
screen.addRegionToUpdate(x, y, tile->w, tile->h);
};
};
void showWindow(Area *parentArea, const std::wstring &fileName)
{
Area area;
area.add(parentArea);
area.add(new CenteredBitmap(fileName));
area.add(new AnyKeyAccel());
area.run();
sound->play(L"click.wav");
}
bool isInRect(int evX, int evY, int x, int y, int w, int h)
{
return ((evX >= x) && (evX < x + w) && (evY >= y) && (evY < y + h));
}
std::wstring secToStr(int time)
{
int hours = time / 3600;
int v = time - hours * 3600;
int minutes = v / 60;
int seconds = v - minutes * 60;
wchar_t buf[50];
#ifdef WIN32
swprintf(buf, L"%02i:%02i:%02i", hours, minutes, seconds);
#else
swprintf(buf, 50, L"%02i:%02i:%02i", hours, minutes, seconds);
#endif
return buf;
}
void showMessageWindow(Area *parentArea, const std::wstring &pattern,
int width, int height, Font *font, int r, int g, int b,
const std::wstring &msg)
{
Area area;
int x = (screen.getWidth() - width) / 2;
int y = (screen.getHeight() - height) / 2;
area.add(parentArea);
area.add(new Window(x, y, width, height, pattern, 6));
area.add(new Label(font, x, y, width, height, Label::ALIGN_CENTER,
Label::ALIGN_MIDDLE, r, g, b, msg));
area.add(new AnyKeyAccel());
area.run();
sound->play(L"click.wav");
}
void drawBevel(SDL_Surface *s, int left, int top, int width, int height,
bool raised, int size)
{
double k, f, kAdv, fAdv;
if (raised) {
k = 2.6;
f = 0.1;
kAdv = -0.2;
fAdv = 0.1;
} else {
f = 2.6;
k = 0.1;
fAdv = -0.2;
kAdv = 0.1;
}
for (int i = 0; i < size; i++) {
for (int j = i; j < height - i - 1; j++)
adjustBrightness(s, left + i, top + j, k);
for (int j = i; j < width - i; j++)
adjustBrightness(s, left + j, top + i, k);
for (int j = i+1; j < height - i; j++)
adjustBrightness(s, left + width - i - 1, top + j, f);
for (int j = i; j < width - i - 1; j++)
adjustBrightness(s, left + j, top + height - i - 1, f);
k += kAdv;
f += fAdv;
}
}
//#ifndef WIN32
void ensureDirExists(const std::wstring &fileName)
{
std::string s(toMbcs(fileName));
struct stat buf;
if (! stat(s.c_str(), &buf)) {
if (! S_ISDIR(buf.st_mode))
unlink(s.c_str());
else
return;
}
#ifndef WIN32
mkdir(s.c_str(), S_IRUSR | S_IWUSR | S_IXUSR);
#else
mkdir(s.c_str());
#endif
}
/*#else
void ensureDirExists(const std::wstring &fileName)
{
PORT ME!
}
#endif*/
int readInt(std::istream &stream)
{
if (stream.fail())
throw Exception(L"Error reading string");
unsigned char buf[4];
stream.read((char*)buf, 4);
if (stream.fail())
throw Exception(L"Error reading string");
return buf[0] + buf[1] * 256 + buf[2] * 256 * 256 +
buf[3] * 256 * 256 * 256;
}
std::wstring readString(std::istream &stream)
{
std::string str;
char c;
if (stream.fail())
throw Exception(L"Error reading string");
c = stream.get();
while (c && (! stream.fail())) {
str += c;
c = stream.get();
}
if (stream.fail())
throw Exception(L"Error reading string");
return fromUtf8(str);
}
void writeInt(std::ostream &stream, int v)
{
unsigned char b[4];
int i, ib;
for (i = 0; i < 4; i++) {
ib = v & 0xFF;
v = v >> 8;
b[i] = ib;
}
stream.write((char*)&b, 4);
}
void writeString(std::ostream &stream, const std::wstring &value)
{
std::string s(toUtf8(value));
stream.write(s.c_str(), s.length() + 1);
}
int readInt(unsigned char *buf)
{
return buf[0] + buf[1] * 256 + buf[2] * 256 * 256 +
buf[3] * 256 * 256 * 256;
}