310 lines
7.3 KiB
C++
310 lines
7.3 KiB
C++
|
#include <SDL.h>
|
||
|
#include "screen.h"
|
||
|
#include "exceptions.h"
|
||
|
#include "unicode.h"
|
||
|
|
||
|
|
||
|
Screen::Screen()
|
||
|
{
|
||
|
screen = NULL;
|
||
|
mouseImage = NULL;
|
||
|
mouseSave = NULL;
|
||
|
mouseVisible = false;
|
||
|
regionsList = NULL;
|
||
|
maxRegionsList = 0;
|
||
|
}
|
||
|
|
||
|
Screen::~Screen()
|
||
|
{
|
||
|
SDL_SetCursor(cursor);
|
||
|
if (mouseImage) SDL_FreeSurface(mouseImage);
|
||
|
if (mouseSave) SDL_FreeSurface(mouseSave);
|
||
|
if (regionsList) free(regionsList);
|
||
|
}
|
||
|
|
||
|
|
||
|
const VideoMode Screen::getVideoMode() const
|
||
|
{
|
||
|
return VideoMode(screen->w, screen->h, screen->format->BitsPerPixel, fullScreen);
|
||
|
}
|
||
|
|
||
|
|
||
|
void Screen::setMode(const VideoMode& mode)
|
||
|
{
|
||
|
fullScreen = mode.isFullScreen();
|
||
|
|
||
|
int flags = SDL_SWSURFACE /*| SDL_OPENGL*/;
|
||
|
if (fullScreen)
|
||
|
flags = flags | SDL_FULLSCREEN;
|
||
|
screen = SDL_SetVideoMode(mode.getWidth(), mode.getHeight(), mode.getBpp(), flags);
|
||
|
if (! screen)
|
||
|
throw Exception(L"Couldn't set video mode: " +
|
||
|
fromMbcs((SDL_GetError())));
|
||
|
}
|
||
|
|
||
|
|
||
|
std::vector<VideoMode> Screen::getFullScreenModes() const
|
||
|
{
|
||
|
std::vector<VideoMode> modes;
|
||
|
return modes;
|
||
|
}
|
||
|
|
||
|
|
||
|
int Screen::getWidth() const
|
||
|
{
|
||
|
if (screen)
|
||
|
return screen->w;
|
||
|
else
|
||
|
throw Exception(L"No video mode selected");
|
||
|
}
|
||
|
|
||
|
|
||
|
int Screen::getHeight() const
|
||
|
{
|
||
|
if (screen)
|
||
|
return screen->h;
|
||
|
else
|
||
|
throw Exception(L"No video mode selected");
|
||
|
}
|
||
|
|
||
|
void Screen::centerMouse()
|
||
|
{
|
||
|
if (screen)
|
||
|
SDL_WarpMouse(screen->w / 2, screen->h / 2);
|
||
|
else
|
||
|
throw Exception(L"No video mode selected");
|
||
|
}
|
||
|
|
||
|
void Screen::setMouseImage(SDL_Surface *image)
|
||
|
{
|
||
|
if (mouseImage) {
|
||
|
SDL_FreeSurface(mouseImage);
|
||
|
mouseImage = NULL;
|
||
|
}
|
||
|
if (mouseSave) {
|
||
|
SDL_FreeSurface(mouseSave);
|
||
|
mouseSave = NULL;
|
||
|
}
|
||
|
|
||
|
if (! image) return;
|
||
|
|
||
|
mouseImage = SDL_DisplayFormat(image);
|
||
|
if (! mouseImage)
|
||
|
throw Exception(L"Error creating surface");
|
||
|
//mouseSave = SDL_DisplayFormat(image);
|
||
|
mouseSave = SDL_CreateRGBSurface(SDL_HWSURFACE | SDL_SRCCOLORKEY,
|
||
|
image->w, image->h, screen->format->BitsPerPixel,
|
||
|
screen->format->Rmask, screen->format->Gmask,
|
||
|
screen->format->Bmask, screen->format->Amask);
|
||
|
if (! mouseSave) {
|
||
|
SDL_FreeSurface(mouseImage);
|
||
|
throw Exception(L"Error creating buffer surface");
|
||
|
}
|
||
|
SDL_SetColorKey(mouseImage, SDL_SRCCOLORKEY,
|
||
|
SDL_MapRGB(mouseImage->format, 0, 0, 0));
|
||
|
}
|
||
|
|
||
|
|
||
|
void Screen::hideMouse()
|
||
|
{
|
||
|
if (! mouseVisible)
|
||
|
return;
|
||
|
|
||
|
if (! niceCursor) {
|
||
|
mouseVisible = false;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (mouseSave) {
|
||
|
SDL_Rect src = { 0, 0, mouseSave->w, mouseSave->h };
|
||
|
SDL_Rect dst = { saveX, saveY, mouseSave->w, mouseSave->h };
|
||
|
if (src.w > 0) {
|
||
|
SDL_BlitSurface(mouseSave, &src, screen, &dst);
|
||
|
addRegionToUpdate(dst.x, dst.y, dst.w, dst.h);
|
||
|
}
|
||
|
}
|
||
|
mouseVisible = false;
|
||
|
}
|
||
|
|
||
|
void Screen::showMouse()
|
||
|
{
|
||
|
if (mouseVisible)
|
||
|
return;
|
||
|
|
||
|
if (! niceCursor) {
|
||
|
mouseVisible = true;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (mouseImage && mouseSave) {
|
||
|
int x, y;
|
||
|
SDL_GetMouseState(&x, &y);
|
||
|
saveX = x;
|
||
|
saveY = y;
|
||
|
SDL_Rect src = { 0, 0, mouseSave->w, mouseSave->h };
|
||
|
SDL_Rect dst = { x, y, mouseImage->w, mouseImage->h };
|
||
|
if (src.w > 0) {
|
||
|
SDL_BlitSurface(screen, &dst, mouseSave, &src);
|
||
|
SDL_BlitSurface(mouseImage, &src, screen, &dst);
|
||
|
addRegionToUpdate(dst.x, dst.y, dst.w, dst.h);
|
||
|
}
|
||
|
}
|
||
|
mouseVisible = true;
|
||
|
}
|
||
|
|
||
|
void Screen::updateMouse()
|
||
|
{
|
||
|
hideMouse();
|
||
|
showMouse();
|
||
|
}
|
||
|
|
||
|
void Screen::flush()
|
||
|
{
|
||
|
if (! regions.size()) return;
|
||
|
|
||
|
if (! regionsList) {
|
||
|
regionsList = (SDL_Rect*)malloc(sizeof(SDL_Rect) * regions.size());
|
||
|
if (! regionsList) {
|
||
|
regions.clear();
|
||
|
throw Exception(L"Error allocating regions buffer");
|
||
|
}
|
||
|
maxRegionsList = regions.size();
|
||
|
} else {
|
||
|
if (maxRegionsList < (int)regions.size()) {
|
||
|
SDL_Rect *r = (SDL_Rect*)realloc(regionsList,
|
||
|
sizeof(SDL_Rect) * regions.size());
|
||
|
if (! r) {
|
||
|
regions.clear();
|
||
|
free(regionsList);
|
||
|
throw Exception(L"Error incrementing regions buffer");
|
||
|
}
|
||
|
regionsList = r;
|
||
|
maxRegionsList = regions.size();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int j = 0;
|
||
|
for (std::list<SDL_Rect>::iterator i = regions.begin();
|
||
|
i != regions.end(); i++, j++)
|
||
|
regionsList[j] = *i;
|
||
|
|
||
|
SDL_UpdateRects(screen, regions.size(), regionsList);
|
||
|
regions.clear();
|
||
|
}
|
||
|
|
||
|
|
||
|
void Screen::addRegionToUpdate(int x, int y, int w, int h)
|
||
|
{
|
||
|
if (((x >= getWidth()) || (y >= getHeight())) || (0 >= w) || (0 >= h))
|
||
|
return;
|
||
|
if ((x + w < 0) || (y + h < 0))
|
||
|
return;
|
||
|
if (x + w > getWidth())
|
||
|
w = getWidth() - x;
|
||
|
if (y + h > getHeight())
|
||
|
h = getHeight() - y;
|
||
|
if (0 > x) {
|
||
|
w = w + x;
|
||
|
x = 0;
|
||
|
}
|
||
|
if (0 > y) {
|
||
|
h = h + y;
|
||
|
y = 0;
|
||
|
}
|
||
|
SDL_Rect r = { x, y, w, h };
|
||
|
regions.push_back(r);
|
||
|
}
|
||
|
|
||
|
|
||
|
void Screen::setPixel(int x, int y, int r, int g, int b)
|
||
|
{
|
||
|
SDL_LockSurface(screen);
|
||
|
int bpp = screen->format->BytesPerPixel;
|
||
|
Uint32 pixel = SDL_MapRGB(screen->format, r, g, b);
|
||
|
/* Here p is the address to the pixel we want to set */
|
||
|
Uint8 *p = (Uint8*)screen->pixels + y * screen->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;
|
||
|
}
|
||
|
SDL_UnlockSurface(screen);
|
||
|
}
|
||
|
|
||
|
|
||
|
void Screen::draw(int x, int y, SDL_Surface *tile)
|
||
|
{
|
||
|
SDL_Rect src = { 0, 0, tile->w, tile->h };
|
||
|
SDL_Rect dst = { x, y, tile->w, tile->h };
|
||
|
SDL_BlitSurface(tile, &src, screen, &dst);
|
||
|
}
|
||
|
|
||
|
void Screen::setCursor(bool nice)
|
||
|
{
|
||
|
if (nice == niceCursor)
|
||
|
return;
|
||
|
|
||
|
bool oldVisible = mouseVisible;
|
||
|
if (mouseVisible)
|
||
|
hideMouse();
|
||
|
niceCursor = nice;
|
||
|
|
||
|
if (niceCursor)
|
||
|
SDL_SetCursor(emptyCursor);
|
||
|
else
|
||
|
SDL_SetCursor(cursor);
|
||
|
|
||
|
if (oldVisible)
|
||
|
showMouse();
|
||
|
}
|
||
|
|
||
|
void Screen::initCursors()
|
||
|
{
|
||
|
cursor = SDL_GetCursor();
|
||
|
Uint8 t = 0;
|
||
|
emptyCursor = SDL_CreateCursor(&t, &t, 8, 1, 0, 0);
|
||
|
}
|
||
|
|
||
|
void Screen::doneCursors()
|
||
|
{
|
||
|
if (niceCursor)
|
||
|
SDL_SetCursor(cursor);
|
||
|
SDL_FreeCursor(emptyCursor);
|
||
|
}
|
||
|
|
||
|
SDL_Surface* Screen::createSubimage(int x, int y, int width, int height)
|
||
|
{
|
||
|
SDL_Surface *s = SDL_CreateRGBSurface(SDL_HWSURFACE | SDL_SRCCOLORKEY,
|
||
|
width, height, screen->format->BitsPerPixel,
|
||
|
screen->format->Rmask, screen->format->Gmask,
|
||
|
screen->format->Bmask, screen->format->Amask);
|
||
|
if (! s)
|
||
|
throw Exception(L"Error creating buffer surface");
|
||
|
SDL_Rect src = { x, y, width, height };
|
||
|
SDL_Rect dst = { 0, 0, width, height };
|
||
|
SDL_BlitSurface(screen, &src, s, &dst);
|
||
|
return s;
|
||
|
}
|
||
|
|