2
* Copyright (C) 2002-2004, 2007-2010 by the Widelands Development Team
4
* This program is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU General Public License
6
* as published by the Free Software Foundation; either version 2
7
* of the License, or (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24
#include "sdl_surface.h"
26
SDLSurface::~SDLSurface() {
28
SDL_FreeSurface(m_surface);
31
void SDLSurface::set_sdl_surface(SDL_Surface & surface)
34
SDL_FreeSurface(m_surface);
41
const SDL_PixelFormat & SDLSurface::format() const {
43
return *m_surface->format;
46
uint8_t * SDLSurface::get_pixels() const {
50
static_cast<uint8_t *>(m_surface->pixels)
52
m_offsy * m_surface->pitch
54
m_offsx * m_surface->format->BytesPerPixel;
57
void SDLSurface::lock(LockMode) {
58
if (SDL_MUSTLOCK(m_surface))
59
SDL_LockSurface(m_surface);
62
void SDLSurface::unlock(UnlockMode) {
63
if (SDL_MUSTLOCK(m_surface))
64
SDL_UnlockSurface(m_surface);
67
uint32_t SDLSurface::get_pixel(uint32_t x, uint32_t y) {
75
// Locking not needed: reading only
76
const Uint8 bytes_per_pixel = m_surface->format->BytesPerPixel;
78
static_cast<Uint8 *>(m_surface->pixels) +
79
y * m_surface->pitch + x * bytes_per_pixel;
81
switch (bytes_per_pixel) {
83
return *pix; // Maybe needed for save_png.
85
return *reinterpret_cast<const Uint16 *>(pix);
86
case 3: //Needed for save_png.
87
// We can not dereference a pointer to a size 4 object in this case
88
// since that would casue a read beyond the end of the block pointed to
89
// by m_surface. Furthermore it would not be properly aligned to a 4
92
// Suppose that the image is 2 * 2 pixels. Then m_surface points to a
93
// block of size 2 * 2 * 3 = 12. The values for the last pixel are at
94
// m_surface[9], m_surface[10] and m_surface[11]. But m_surface[12] is
95
// beyond the end of the block, so we can not read 4 bytes starting at
96
// m_surface[9] (even if unaligned access is allowed).
98
// Therefore we read the 3 bytes separately and get the result by
99
// shifting the values. It is alignment safe.
100
return pix[0] << 0x00 | pix[1] << 0x08 | pix[2] << 0x10;
102
return *reinterpret_cast<const Uint32 *>(pix);
106
return 0; // Should never be here
109
void SDLSurface::set_pixel(uint32_t x, uint32_t y, const Uint32 clr) {
113
if (x >= get_w() || y >= get_h())
117
if (SDL_MUSTLOCK(m_surface))
118
SDL_LockSurface(m_surface);
120
const Uint8 bytes_per_pixel = m_surface->format->BytesPerPixel;
122
static_cast<Uint8 *>(m_surface->pixels) +
123
y * m_surface->pitch + x * bytes_per_pixel;
124
switch (bytes_per_pixel) {
125
case 2: *reinterpret_cast<Uint16 *>(pix) = static_cast<Uint16>(clr); break;
126
case 4: *reinterpret_cast<Uint32 *>(pix) = clr; break;
129
if (SDL_MUSTLOCK(m_surface))
130
SDL_UnlockSurface(m_surface);
133
void SDLSurface::set_subwin(const Rect& r) {
140
void SDLSurface::unset_subwin() {
149
Draws the outline of a rectangle
152
void SDLSurface::draw_rect(const Rect& rc, const RGBColor clr) {
158
const uint32_t color = clr.map(format());
160
const Point bl = rc.bottom_right() - Point(1, 1);
162
for (int32_t x = rc.x + 1; x < bl.x; ++x) {
163
set_pixel(x, rc.y, color);
164
set_pixel(x, bl.y, color);
166
for (int32_t y = rc.y; y <= bl.y; ++y) {
167
set_pixel(rc.x, y, color);
168
set_pixel(bl.x, y, color);
175
Draws a filled rectangle
178
void SDLSurface::fill_rect(const Rect& rc, const RGBAColor clr) {
184
const uint32_t color = clr.map(format());
187
static_cast<Sint16>(rc.x), static_cast<Sint16>(rc.y),
188
static_cast<Uint16>(rc.w), static_cast<Uint16>(rc.h)
190
SDL_FillRect(m_surface, &r, color);
196
Change the brightness of the given rectangle
197
This function is slow as hell.
199
* This function is a possible point to optimize on
200
slow system. It takes a lot of cpu time atm and is
201
not needed. It is used by the ui_basic stuff to
205
void SDLSurface::brighten_rect(const Rect& rc, const int32_t factor) {
213
const Point bl = rc.bottom_right();
215
lock(Surface::Lock_Normal);
217
if (m_surface->format->BytesPerPixel == 4)
219
for (int32_t y = rc.y; y < bl.y; ++y)
220
for (int32_t x = rc.x; x < bl.x; ++x)
224
static_cast<Uint8 *>(m_surface->pixels) +
225
(y + m_offsy) * m_surface->pitch + (x + m_offsx) * 4;
227
uint32_t const clr = *reinterpret_cast<const Uint32 *>(pix);
229
SDL_GetRGB(clr, m_surface->format, &gr, &gg, &gb);
230
int16_t r = gr + factor;
231
int16_t g = gg + factor;
232
int16_t b = gb + factor;
241
*reinterpret_cast<Uint32 *>(pix) =
242
SDL_MapRGB(m_surface->format, r, g, b);
244
} else if (m_surface->format->BytesPerPixel == 2) {
245
for (int32_t y = rc.y; y < bl.y; ++y)
246
for (int32_t x = rc.x; x < bl.x; ++x)
249
static_cast<Uint8 *>(m_surface->pixels) +
250
(y + m_offsy) * m_surface->pitch + (x + m_offsx) * 2;
252
uint32_t const clr = *reinterpret_cast<const Uint16 *>(pix);
254
SDL_GetRGB(clr, m_surface->format, &gr, &gg, &gb);
255
int16_t r = gr + factor;
256
int16_t g = gg + factor;
257
int16_t b = gb + factor;
266
*reinterpret_cast<Uint16 *>(pix) =
267
SDL_MapRGB(m_surface->format, r, g, b);
270
unlock(Surface::Unlock_Update);
273
#define draw_pixel(p, r, clr) \
275
((p).x >= (r).x and (p).x < static_cast<int32_t>((r).x + (r).w) and \
276
(p).y >= (r).y and (p).y < static_cast<int32_t>((r).y + (r).h)) \
277
set_pixel((p).x, (p).y, (clr).map(format())) \
280
* This functions draws a (not horizontal or vertical)
281
* line in the target, using Bresenham's algorithm
283
* This function could be faster by using direct pixel
284
* access instead of the set_pixel() function
286
void SDLSurface::draw_line(int32_t x1, int32_t y1, int32_t x2, int32_t y2,
287
const RGBColor& color, uint8_t width)
289
int32_t dx = x2 - x1; /* the horizontal distance of the line */
290
int32_t dy = y2 - y1; /* the vertical distance of the line */
291
const uint32_t dxabs = abs(dx);
292
const uint32_t dyabs = abs(dy);
293
int32_t sdx = dx < 0 ? -1 : 1;
294
int32_t sdy = dy < 0 ? -1 : 1;
295
uint32_t x = dyabs / 2;
296
uint32_t y = dxabs / 2;
299
set_pixel(p.x, p.y, color.map(format()));
301
if (dxabs >= dyabs) // the line is more horizontal than vertical
302
for (uint32_t i = 0; i < dxabs; ++i) {
311
for (int32_t w = 0; w < width; ++w) {
312
set_pixel(p.x, p.y + w, color.map(format()));
315
else // the line is more vertical than horizontal
316
for (uint32_t i = 0; i < dyabs; ++i) {
325
for (int32_t w = 0; w < width; ++w) {
326
set_pixel(p.x + w, p.y, color.map(format()));
332
void SDLSurface::blit
333
(const Point& dst, const IPicture* src, const Rect& srcrc, Composite cm)
335
const SDLSurface* sdlsurf = static_cast<const SDLSurface*>(src);
337
static_cast<Sint16>(srcrc.x), static_cast<Sint16>(srcrc.y),
338
static_cast<Uint16>(srcrc.w), static_cast<Uint16>(srcrc.h)
341
static_cast<Sint16>(dst.x), static_cast<Sint16>(dst.y),
347
if (cm == CM_Solid || cm == CM_Copy) {
348
alpha = sdlsurf->get_sdl_surface()->flags & SDL_SRCALPHA;
349
alphaval = sdlsurf->get_sdl_surface()->format->alpha;
350
SDL_SetAlpha(sdlsurf->get_sdl_surface(), 0, 0);
353
SDL_BlitSurface(sdlsurf->get_sdl_surface(), &srcrect, m_surface, &dstrect);
355
if (cm == CM_Solid || cm == CM_Copy) {
356
SDL_SetAlpha(sdlsurf->get_sdl_surface(), alpha?SDL_SRCALPHA:0, alphaval);