Root/src/surface.cpp

1/***************************************************************************
2 * Copyright (C) 2006 by Massimiliano Torromeo *
3 * massimiliano.torromeo@gmail.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
21#include "surface.h"
22
23#include "debug.h"
24#include "imageio.h"
25#include "surfacecollection.h"
26#include "utilities.h"
27
28#include <SDL_gfxPrimitives.h>
29
30#include <iostream>
31
32using namespace std;
33
34RGBAColor strtorgba(const string &strColor) {
35    RGBAColor c = {0,0,0,255};
36    c.r = constrain( strtol( strColor.substr(0,2).c_str(), NULL, 16 ), 0, 255 );
37    c.g = constrain( strtol( strColor.substr(2,2).c_str(), NULL, 16 ), 0, 255 );
38    c.b = constrain( strtol( strColor.substr(4,2).c_str(), NULL, 16 ), 0, 255 );
39    c.a = constrain( strtol( strColor.substr(6,2).c_str(), NULL, 16 ), 0, 255 );
40    return c;
41}
42
43Surface *Surface::openOutputSurface(int width, int height, int bitsperpixel) {
44    SDL_ShowCursor(SDL_DISABLE);
45    SDL_Surface *raw = SDL_SetVideoMode(
46        width, height, bitsperpixel, SDL_HWSURFACE | SDL_DOUBLEBUF);
47    return raw ? new Surface(raw, false) : NULL;
48}
49
50Surface *Surface::emptySurface(int width, int height) {
51    SDL_Surface *raw = SDL_CreateRGBSurface(
52        SDL_SWSURFACE, width, height, 32, 0, 0, 0, 0);
53    if (!raw) return NULL;
54    SDL_FillRect(raw, NULL, SDL_MapRGB(raw->format, 0, 0, 0));
55    return new Surface(raw, true);
56}
57
58Surface *Surface::loadImage(const string &img, const string &skin) {
59    string skinpath;
60    if (!skin.empty() && !img.empty() && img[0]!='/')
61      skinpath = SurfaceCollection::getSkinFilePath(skin, img);
62    else
63      skinpath = img;
64
65    SDL_Surface *raw = loadPNG(skinpath);
66    if (!raw) {
67        ERROR("Couldn't load surface '%s'\n", img.c_str());
68        return NULL;
69    }
70
71    return new Surface(raw, true);
72}
73
74Surface::Surface(SDL_Surface *raw_, bool freeWhenDone_)
75    : raw(raw_)
76    , freeWhenDone(freeWhenDone_)
77{
78    halfW = raw->w/2;
79    halfH = raw->h/2;
80}
81
82Surface::Surface(Surface *s) {
83    raw = SDL_ConvertSurface(s->raw, s->raw->format, SDL_SWSURFACE);
84    // Note: A bug in SDL_ConvertSurface() leaves the per-surface alpha
85    // undefined when converting from RGBA to RGBA. This can cause
86    // problems if the surface is later converted to a format without
87    // an alpha channel, such as the display format.
88    raw->format->alpha = s->raw->format->alpha;
89    freeWhenDone = true;
90    halfW = raw->w/2;
91    halfH = raw->h/2;
92}
93
94Surface::~Surface() {
95    if (freeWhenDone) {
96        SDL_FreeSurface(raw);
97    }
98}
99
100void Surface::convertToDisplayFormat() {
101    SDL_Surface *newSurface = SDL_DisplayFormat(raw);
102    if (newSurface) {
103        if (freeWhenDone) {
104            SDL_FreeSurface(raw);
105        }
106        raw = newSurface;
107        freeWhenDone = true;
108    }
109}
110
111void Surface::flip() {
112    SDL_Flip(raw);
113}
114
115bool Surface::blit(SDL_Surface *destination, int x, int y, int w, int h, int a) const {
116    if (destination == NULL || a==0) return false;
117
118    SDL_Rect src = { 0, 0, static_cast<Uint16>(w), static_cast<Uint16>(h) };
119    SDL_Rect dest;
120    dest.x = x;
121    dest.y = y;
122    if (a>0 && a!=raw->format->alpha)
123        SDL_SetAlpha(raw, SDL_SRCALPHA|SDL_RLEACCEL, a);
124    return SDL_BlitSurface(raw, (w==0 || h==0) ? NULL : &src, destination, &dest);
125}
126bool Surface::blit(Surface *destination, int x, int y, int w, int h, int a) const {
127    return blit(destination->raw,x,y,w,h,a);
128}
129
130bool Surface::blitCenter(SDL_Surface *destination, int x, int y, int w, int h, int a) const {
131    int oh, ow;
132    if (w==0) ow = halfW; else ow = min(halfW,w/2);
133    if (h==0) oh = halfH; else oh = min(halfH,h/2);
134    return blit(destination,x-ow,y-oh,w,h,a);
135}
136bool Surface::blitCenter(Surface *destination, int x, int y, int w, int h, int a) const {
137    return blitCenter(destination->raw,x,y,w,h,a);
138}
139
140bool Surface::blitRight(SDL_Surface *destination, int x, int y, int w, int h, int a) const {
141    if (!w) w = raw->w;
142    return blit(destination,x-min(raw->w,w),y,w,h,a);
143}
144bool Surface::blitRight(Surface *destination, int x, int y, int w, int h, int a) const {
145    if (!w) w = raw->w;
146    return blitRight(destination->raw,x,y,w,h,a);
147}
148
149int Surface::box(Sint16 x, Sint16 y, Uint16 w, Uint16 h, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
150    return boxRGBA(raw, x, y, x + w - 1, y + h - 1, r, g, b, a);
151}
152int Surface::box(Sint16 x, Sint16 y, Uint16 w, Uint16 h, Uint8 r, Uint8 g, Uint8 b) {
153    SDL_Rect re = { x, y, w, h };
154    return SDL_FillRect(raw, &re, SDL_MapRGBA(raw->format, r, g, b, 255));
155}
156int Surface::box(Sint16 x, Sint16 y, Uint16 w, Uint16 h, RGBAColor c) {
157    return box(x, y, w, h, c.r, c.g, c.b, c.a);
158}
159int Surface::box(SDL_Rect re, RGBAColor c) {
160    return boxRGBA(
161        raw, re.x, re.y, re.x + re.w - 1, re.y + re.h - 1, c.r, c.g, c.b, c.a
162        );
163}
164
165int Surface::rectangle(Sint16 x, Sint16 y, Uint16 w, Uint16 h, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
166    return rectangleRGBA(raw, x, y, x + w - 1, y + h - 1, r, g, b, a);
167}
168int Surface::rectangle(Sint16 x, Sint16 y, Uint16 w, Uint16 h, RGBAColor c) {
169    return rectangle(x, y, w, h, c.r, c.g, c.b, c.a);
170}
171int Surface::rectangle(SDL_Rect re, RGBAColor c) {
172    return rectangle(re.x, re.y, re.w, re.h, c.r, c.g, c.b, c.a);
173}
174
175int Surface::hline(Sint16 x, Sint16 y, Uint16 w, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
176    return hlineRGBA(raw, x, x + w - 1, y, r, g, b, a);
177}
178
179void Surface::clearClipRect() {
180    SDL_SetClipRect(raw,NULL);
181}
182
183void Surface::setClipRect(int x, int y, int w, int h) {
184    SDL_Rect rect = {
185        static_cast<Sint16>(x), static_cast<Sint16>(y),
186        static_cast<Uint16>(w), static_cast<Uint16>(h)
187    };
188    setClipRect(rect);
189}
190
191void Surface::setClipRect(SDL_Rect rect) {
192    SDL_SetClipRect(raw,&rect);
193}
194
195bool Surface::blit(Surface *destination, SDL_Rect container, Font::HAlign halign, Font::VAlign valign) const {
196    switch (halign) {
197    case Font::HAlignLeft:
198        break;
199    case Font::HAlignCenter:
200        container.x += container.w/2-halfW;
201        break;
202    case Font::HAlignRight:
203        container.x += container.w-raw->w;
204        break;
205    }
206
207    switch (valign) {
208    case Font::VAlignTop:
209        break;
210    case Font::VAlignMiddle:
211        container.y += container.h/2-halfH;
212        break;
213    case Font::VAlignBottom:
214        container.y += container.h-raw->h;
215        break;
216    }
217
218    return blit(destination,container.x,container.y);
219}
220

Archive Download this file



interactive