1
/*
2
 *  The Mana World
3
 *  Copyright (C) 2004  The Mana World Development Team
4
 *
5
 *  This file is part of The Mana World.
6
 *
7
 *  This program is free software; you can redistribute it and/or modify
8
 *  it under the terms of the GNU General Public License as published by
9
 *  the Free Software Foundation; either version 2 of the License, or
10
 *  any later version.
11
 *
12
 *  This program is distributed in the hope that it will be useful,
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 *  GNU General Public License for more details.
16
 *
17
 *  You should have received a copy of the GNU General Public License
18
 *  along with this program; if not, write to the Free Software
19
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
 */
21
22
#include <cassert>
23
24
#include "graphics.h"
25
#include "log.h"
26
27
#include "resources/image.h"
28
#include "resources/imageloader.h"
29
30
Graphics::Graphics():
31
    mScreen(0)
32
{
33
}
34
35
Graphics::~Graphics()
36
{
37
    _endDraw();
38
}
39
40
bool Graphics::setVideoMode(int w, int h, int bpp, bool fs, bool hwaccel)
41
{
42
    logger->log("Setting video mode %dx%d %s",
43
            w, h, fs ? "fullscreen" : "windowed");
44
45
    logger->log("Bits per pixel: %d", bpp);
46
47
    int displayFlags = SDL_ANYFORMAT;
48
49
    mFullscreen = fs;
50
    mHWAccel = hwaccel;
51
52
    if (fs)
53
        displayFlags |= SDL_FULLSCREEN;
54
55
    if (hwaccel)
56
        displayFlags |= SDL_HWSURFACE | SDL_DOUBLEBUF;
57
    else
58
        displayFlags |= SDL_SWSURFACE;
59
60
    mScreen = SDL_SetVideoMode(w, h, bpp, displayFlags);
61
62
    if (!mScreen)
63
        return false;
64
65
    char videoDriverName[64];
66
67
    if (SDL_VideoDriverName(videoDriverName, 64))
68
        logger->log("Using video driver: %s", videoDriverName);
69
    else
70
        logger->log("Using video driver: unknown");
71
72
    const SDL_VideoInfo *vi = SDL_GetVideoInfo();
73
74
    logger->log("Possible to create hardware surfaces: %s",
75
            ((vi->hw_available) ? "yes" : "no"));
76
    logger->log("Window manager available: %s",
77
            ((vi->wm_available) ? "yes" : "no"));
78
    logger->log("Accelerated hardware to hardware blits: %s",
79
            ((vi->blit_hw) ? "yes" : "no"));
80
    logger->log("Accelerated hardware to hardware colorkey blits: %s",
81
            ((vi->blit_hw_CC) ? "yes" : "no"));
82
    logger->log("Accelerated hardware to hardware alpha blits: %s",
83
            ((vi->blit_hw_A) ? "yes" : "no"));
84
    logger->log("Accelerated software to hardware blits: %s",
85
            ((vi->blit_sw) ? "yes" : "no"));
86
    logger->log("Accelerated software to hardware colorkey blits: %s",
87
            ((vi->blit_sw_CC) ? "yes" : "no"));
88
    logger->log("Accelerated software to hardware alpha blits: %s",
89
            ((vi->blit_sw_A) ? "yes" : "no"));
90
    logger->log("Accelerated color fills: %s",
91
            ((vi->blit_fill) ? "yes" : "no"));
92
    logger->log("Available video memory: %d", vi->video_mem);
93
94
    setTarget(mScreen);
95
96
    return true;
97
}
98
99
bool Graphics::setFullscreen(bool fs)
100
{
101
    if (mFullscreen == fs)
102
        return true;
103
104
    return setVideoMode(mScreen->w, mScreen->h,
105
            mScreen->format->BitsPerPixel, fs, mHWAccel);
106
}
107
108
int Graphics::getWidth() const
109
{
110
    return mScreen->w;
111
}
112
113
int Graphics::getHeight() const
114
{
115
    return mScreen->h;
116
}
117
118
bool Graphics::drawImage(Image *image, int x, int y)
119
{
120
    if (image)
121
        return drawImage(image, 0, 0, x, y, image->mBounds.w, image->mBounds.h);
122
    else
123
        return false;
124
}
125
126
bool Graphics::drawRescaledImage(Image *image, int srcX, int srcY,
127
                               int dstX, int dstY,
128
                               int width, int height,
129
                               int desiredWidth, int desiredHeight,
130
                               bool useColor)
131
{
132
    // Check that preconditions for blitting are met.
133
    if (!mScreen || !image) return false;
134
    if (!image->mSDLSurface) return false;
135
136
    Image *tmpImage = image->SDLgetScaledImage(desiredWidth, desiredHeight);
137
    bool returnValue = false;
138
139
    if (!tmpImage) return false;
140
    if (!tmpImage->mSDLSurface) return false;
141
142
    dstX += mClipStack.top().xOffset;
143
    dstY += mClipStack.top().yOffset;
144
145
    srcX += image->mBounds.x;
146
    srcY += image->mBounds.y;
147
148
    SDL_Rect dstRect;
149
    SDL_Rect srcRect;
150
    dstRect.x = dstX; dstRect.y = dstY;
151
    srcRect.x = srcX; srcRect.y = srcY;
152
    srcRect.w = width;
153
    srcRect.h = height;
154
155
    returnValue = !(SDL_BlitSurface(tmpImage->mSDLSurface, &srcRect, mScreen, &dstRect) < 0);
156
157
    delete tmpImage;
158
159
    return returnValue;
160
}
161
162
bool Graphics::drawImage(Image *image, int srcX, int srcY, int dstX, int dstY,
163
                         int width, int height, bool)
164
{
165
    // Check that preconditions for blitting are met.
166
    if (!mScreen || !image) return false;
167
    if (!image->mSDLSurface) return false;
168
169
    dstX += mClipStack.top().xOffset;
170
    dstY += mClipStack.top().yOffset;
171
172
    srcX += image->mBounds.x;
173
    srcY += image->mBounds.y;
174
175
    SDL_Rect dstRect;
176
    SDL_Rect srcRect;
177
    dstRect.x = dstX; dstRect.y = dstY;
178
    srcRect.x = srcX; srcRect.y = srcY;
179
    srcRect.w = width;
180
    srcRect.h = height;
181
182
    return !(SDL_BlitSurface(image->mSDLSurface, &srcRect, mScreen, &dstRect) < 0);
183
}
184
185
void Graphics::drawImage(gcn::Image const *image, int srcX, int srcY,
186
                         int dstX, int dstY, int width, int height)
187
{
188
    ProxyImage const *srcImage =
189
        dynamic_cast< ProxyImage const * >(image);
190
    assert(srcImage);
191
    drawImage(srcImage->getImage(), srcX, srcY, dstX, dstY, width, height, true);
192
}
193
194
void Graphics::drawImagePattern(Image *image, int x, int y, int w, int h)
195
{
196
    // Check that preconditions for blitting are met.
197
    if (!mScreen || !image) return;
198
    if (!image->mSDLSurface) return;
199
200
    const int iw = image->getWidth();
201
    const int ih = image->getHeight();
202
203
    if (iw == 0 || ih == 0) return;
204
205
    for (int py = 0; py < h; py += ih)     // Y position on pattern plane
206
    {
207
        int dh = (py + ih >= h) ? h - py : ih;
208
        int srcY = image->mBounds.y;
209
        int dstY = y + py + mClipStack.top().yOffset;
210
211
        for (int px = 0; px < w; px += iw) // X position on pattern plane
212
        {
213
            int dw = (px + iw >= w) ? w - px : iw;
214
            int srcX = image->mBounds.x;
215
            int dstX = x + px + mClipStack.top().xOffset;
216
217
            SDL_Rect dstRect;
218
            SDL_Rect srcRect;
219
            dstRect.x = dstX; dstRect.y = dstY;
220
            srcRect.x = srcX; srcRect.y = srcY;
221
            srcRect.w = dw;   srcRect.h = dh;
222
223
            SDL_BlitSurface(image->mSDLSurface, &srcRect, mScreen, &dstRect);
224
        }
225
    }
226
}
227
228
void Graphics::drawRescaledImagePattern(Image *image, int x, int y,
229
               int w, int h, int scaledWidth, int scaledHeight)
230
{
231
    // Check that preconditions for blitting are met.
232
    if (!mScreen || !image) return;
233
    if (!image->mSDLSurface) return;
234
235
    if (scaledHeight == 0 || scaledWidth == 0) return;
236
237
    Image *tmpImage = image->SDLgetScaledImage(scaledWidth, scaledHeight);
238
    if (!tmpImage) return;
239
240
    const int iw = tmpImage->getWidth();
241
    const int ih = tmpImage->getHeight();
242
243
    if (iw == 0 || ih == 0) return;
244
245
    for (int py = 0; py < h; py += ih)     // Y position on pattern plane
246
    {
247
        int dh = (py + ih >= h) ? h - py : ih;
248
        int srcY = tmpImage->mBounds.y;
249
        int dstY = y + py + mClipStack.top().yOffset;
250
251
        for (int px = 0; px < w; px += iw) // X position on pattern plane
252
        {
253
            int dw = (px + iw >= w) ? w - px : iw;
254
            int srcX = tmpImage->mBounds.x;
255
            int dstX = x + px + mClipStack.top().xOffset;
256
257
            SDL_Rect dstRect;
258
            SDL_Rect srcRect;
259
            dstRect.x = dstX; dstRect.y = dstY;
260
            srcRect.x = srcX; srcRect.y = srcY;
261
            srcRect.w = dw;   srcRect.h = dh;
262
263
            SDL_BlitSurface(tmpImage->mSDLSurface, &srcRect, mScreen, &dstRect);
264
        }
265
    }
266
267
    delete tmpImage;
268
}
269
270
void Graphics::drawImageRect(int x, int y, int w, int h,
271
                             Image *topLeft, Image *topRight,
272
                             Image *bottomLeft, Image *bottomRight,
273
                             Image *top, Image *right,
274
                             Image *bottom, Image *left,
275
                             Image *center)
276
{
277
    pushClipArea(gcn::Rectangle(x, y, w, h));
278
279
    // Draw the center area
280
    drawImagePattern(center,
281
            topLeft->getWidth(), topLeft->getHeight(),
282
            w - topLeft->getWidth() - topRight->getWidth(),
283
            h - topLeft->getHeight() - bottomLeft->getHeight());
284
285
    // Draw the sides
286
    drawImagePattern(top,
287
            left->getWidth(), 0,
288
            w - left->getWidth() - right->getWidth(), top->getHeight());
289
    drawImagePattern(bottom,
290
            left->getWidth(), h - bottom->getHeight(),
291
            w - left->getWidth() - right->getWidth(),
292
            bottom->getHeight());
293
    drawImagePattern(left,
294
            0, top->getHeight(),
295
            left->getWidth(),
296
            h - top->getHeight() - bottom->getHeight());
297
    drawImagePattern(right,
298
            w - right->getWidth(), top->getHeight(),
299
            right->getWidth(),
300
            h - top->getHeight() - bottom->getHeight());
301
302
    // Draw the corners
303
    drawImage(topLeft, 0, 0);
304
    drawImage(topRight, w - topRight->getWidth(), 0);
305
    drawImage(bottomLeft, 0, h - bottomLeft->getHeight());
306
    drawImage(bottomRight,
307
            w - bottomRight->getWidth(),
308
            h - bottomRight->getHeight());
309
310
    popClipArea();
311
}
312
313
void Graphics::drawImageRect(int x, int y, int w, int h,
314
                             const ImageRect &imgRect)
315
{
316
    drawImageRect(x, y, w, h,
317
            imgRect.grid[0], imgRect.grid[2], imgRect.grid[6], imgRect.grid[8],
318
            imgRect.grid[1], imgRect.grid[5], imgRect.grid[7], imgRect.grid[3],
319
            imgRect.grid[4]);
320
}
321
322
void Graphics::updateScreen()
323
{
324
    SDL_Flip(mScreen);
325
}
326
327
SDL_Surface *Graphics::getScreenshot()
328
{
329
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
330
    int rmask = 0xff000000;
331
    int gmask = 0x00ff0000;
332
    int bmask = 0x0000ff00;
333
#else
334
    int rmask = 0x000000ff;
335
    int gmask = 0x0000ff00;
336
    int bmask = 0x00ff0000;
337
#endif
338
    int amask = 0x00000000;
339
340
    SDL_Surface *screenshot = SDL_CreateRGBSurface(SDL_SWSURFACE, mScreen->w,
341
            mScreen->h, 24, rmask, gmask, bmask, amask);
342
343
    SDL_BlitSurface(mScreen, NULL, screenshot, NULL);
344
345
    return screenshot;
346
}