-
-
Notifications
You must be signed in to change notification settings - Fork 991
/
utils.hpp
499 lines (427 loc) · 17.6 KB
/
utils.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
/*
Copyright (C) 2003 - 2016 by David White <dave@whitevine.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/** @file */
#ifndef SDL_UTILS_INCLUDED
#define SDL_UTILS_INCLUDED
#include "color_range.hpp"
#include "color.hpp"
#include "util.hpp"
#include <SDL.h>
#include <cstdlib>
#include <iosfwd>
#include <map>
#include <string>
SDL_Keycode sdl_keysym_from_name(const std::string& keyname);
class surface
{
public:
surface() : surface_(nullptr)
{}
surface(SDL_Surface* surf) : surface_(surf)
{}
surface(const surface& s) : surface_(s.get())
{
add_surface_ref(surface_);
}
~surface()
{
free_surface();
}
void assign(SDL_Surface* surf)
{
assign_surface_internal(surf);
}
void assign(const surface& s)
{
assign_surface_internal(s.get());
}
surface& operator=(const surface& s)
{
assign(s);
return *this;
}
operator SDL_Surface*() const { return surface_; }
SDL_Surface* get() const { return surface_; }
SDL_Surface* operator->() const { return surface_; }
bool null() const { return surface_ == nullptr; }
private:
static void add_surface_ref(SDL_Surface* surf)
{
if(surf) {
++surf->refcount;
}
}
void assign_surface_internal(SDL_Surface* surf)
{
add_surface_ref(surf); // Needs to be done before assignment to avoid corruption on "a = a;"
free_surface();
surface_ = surf;
}
void free_surface()
{
if(surface_) {
SDL_FreeSurface(surface_);
}
}
SDL_Surface* surface_;
};
bool operator<(const surface& a, const surface& b);
inline void sdl_blit(const surface& src, SDL_Rect* src_rect, surface& dst, SDL_Rect* dst_rect){
SDL_BlitSurface(src, src_rect, dst, dst_rect);
}
inline void sdl_copy_portion(const surface& screen, SDL_Rect* screen_rect, surface& dst, SDL_Rect* dst_rect){
SDL_SetSurfaceBlendMode(screen, SDL_BLENDMODE_NONE);
SDL_SetSurfaceBlendMode(dst, SDL_BLENDMODE_NONE);
SDL_BlitSurface(screen, screen_rect, dst, dst_rect);
SDL_SetSurfaceBlendMode(screen, SDL_BLENDMODE_BLEND);
}
/**
* This method blends a RGBA color. The method takes as input a surface,
* the RGB color to blend and a value specifying how much blending to apply.
* The blended color is returned.
* Caution: if you use a transparent color,
* make sure the resulting color is not equal to the transparent color.
*/
Uint32 blend_rgba(const surface& surf, unsigned char r, unsigned char g, unsigned char b,
unsigned char a, unsigned char drop);
/**
* Check that the surface is neutral bpp 32.
*
* The surface may have an empty alpha channel.
*
* @param surf The surface to test.
*
* @returns The status @c true if neutral, @c false if not.
*/
bool is_neutral(const surface& surf);
surface make_neutral_surface(const surface &surf);
surface create_neutral_surface(int w, int h);
/**
* Stretches a surface in the horizontal direction.
*
* The stretches a surface it uses the first pixel in the horizontal
* direction of the original surface and copies that to the destination.
* This means only the first column of the original is used for the destination.
* @param surf The source surface.
* @param w The width of the resulting surface.
* @param optimize Should the return surface be RLE optimized.
*
* @return An optimized surface.
* returned.
* @retval 0 Returned upon error.
* @retval surf Returned if w == surf->w, note this ignores the
* optimize flag.
*/
surface stretch_surface_horizontal(
const surface& surf, const unsigned w, const bool optimize = true);
/**
* Stretches a surface in the vertical direction.
*
* The stretches a surface it uses the first pixel in the vertical
* direction of the original surface and copies that to the destination.
* This means only the first row of the original is used for the destination.
* @param surf The source surface.
* @param h The height of the resulting surface.
* @param optimize Should the return surface be RLE optimized.
*
* @return An optimized surface.
* returned.
*
* @retval surf Returned if h == surf->h, note this ignores the
* optimize flag.
*/
surface stretch_surface_vertical(
const surface& surf, const unsigned h, const bool optimize = true);
/** Scale a surface using xBRZ algorithm
* @param surf The source surface
* @param z The scaling factor. Should be an integer 2-5 (1 is tolerated).
* @return The scaled (optimized) surface
*/
surface scale_surface_xbrz(const surface & surf, size_t z);
/** Scale a surface using the nearest neighbor algorithm (provided by xBRZ lib)
* @param surf The sources surface
* @param w The width of the resulting surface.
* @param h The height of the resulting surface.
* @return The rescaled surface.
*/
surface scale_surface_nn(const surface & surf, int w, int h);
/** Scale a surface
* @param surf The source surface.
* @param w The width of the resulting surface.
* @param h The height of the resulting surface.
* @param optimize Should the return surface be RLE optimized.
* @return A surface containing the scaled version of the source.
* @retval 0 Returned upon error.
* @retval surf Returned if w == surf->w and h == surf->h
* note this ignores the optimize flag.
*/
surface scale_surface(const surface &surf, int w, int h, bool optimize /*=true*/);
surface scale_surface(const surface &surf, int w, int h);
//commenting out the default parameter so that it is possible to make function pointers to the 3 parameter version
/** Scale a surface using modified nearest neighbour algorithm. Use only if
* preserving sharp edges is a priority (e.g. minimap).
* @param surf The source surface.
* @param w The width of the resulting surface.
* @param h The height of the resulting surface.
* @param optimize Should the return surface be RLE optimized.
* @return A surface containing the scaled version of the source.
* @retval 0 Returned upon error.
* @retval surf Returned if w == surf->w and h == surf->h
* note this ignores the optimize flag.
*/
surface scale_surface_sharp(const surface& surf, int w, int h, bool optimize=true);
/** Tile a surface
* @param surf The source surface.
* @param w The width of the resulting surface.
* @param h The height of the resulting surface.
* @param optimize Should the return surface be RLE optimized
* @return A surface containing the tiled version of the source.
* @retval 0 Returned upon error
* @retval surf Returned if w == surf->w and h == surf->h
* note this ignores the optimize flag.
*/
surface tile_surface(const surface &surf, int w, int h, bool optimize=true);
surface adjust_surface_color(const surface &surf, int r, int g, int b, bool optimize=true);
surface greyscale_image(const surface &surf, bool optimize=true);
surface monochrome_image(const surface &surf, const int threshold, bool optimize=true);
surface sepia_image(const surface &surf, bool optimize=true);
surface negative_image(const surface &surf, const int thresholdR, const int thresholdG, const int thresholdB, bool optimize=true);
surface alpha_to_greyscale(const surface & surf, bool optimize=true);
surface wipe_alpha(const surface & surf, bool optimize=true);
/** create an heavy shadow of the image, by blurring, increasing alpha and darkening */
surface shadow_image(const surface &surf, bool optimize=true);
enum channel { RED, GREEN, BLUE, ALPHA };
surface swap_channels_image(const surface& surf, channel r, channel g, channel b, channel a, bool optimize=true);
/**
* Recolors a surface using a map with source and converted palette values.
* This is most often used for team-coloring.
*
* @param surf The source surface.
* @param map_rgb Map of color values, with the keys corresponding to the
* source palette, and the values to the recolored palette.
* @param optimize Whether the new surface should be RLE encoded. Only
* useful when the source is not the screen and it is
* going to be used multiple times.
* @return A recolored surface, or a null surface if there are
* problems with the source.
*/
surface recolor_image(surface surf, const color_range_map& map_rgb, bool optimize=true);
surface brighten_image(const surface &surf, fixed_t amount, bool optimize=true);
/** Get a portion of the screen.
* Send nullptr if the portion is outside of the screen.
* @param surf The source surface.
* @param rect The portion of the source surface to copy.
* @return A surface containing the portion of the source.
* No RLE or Alpha bits are set.
* @retval 0 if error or the portion is outside of the surface.
*/
surface get_surface_portion(const surface &surf, SDL_Rect &rect);
void adjust_surface_alpha(surface& surf, fixed_t amount);
surface adjust_surface_alpha_add(const surface &surf, int amount, bool optimize=true);
surface adjust_surface_alpha_formula(const surface &surf, const std::string& formula, bool optimize=true);
/** Applies a mask on a surface. */
surface mask_surface(const surface &surf, const surface &mask, bool* empty_result = nullptr, const std::string& filename = std::string());
/** Check if a surface fit into a mask */
bool in_mask_surface(const surface &surf, const surface &mask);
/** Progressively reduce alpha of bottom part of the surface
* @param surf The source surface.
* @param depth The height of the bottom part in pixels
* @param alpha_base The alpha adjustment at the interface
* @param alpha_delta The alpha adjustment reduction rate by pixel depth
* @param optimize Optimize by converting to result to display
*/
surface submerge_alpha(const surface &surf, int depth, float alpha_base, float alpha_delta, bool optimize=true);
/**
* Light surf using lightmap
* @param surf The source surface.
* @param lightmap add/subtract this color to surf
* but RGB values are converted to (X-128)*2
* to cover the full (-256,256) spectrum.
* Should already be neutral
* @param optimize Whether the new surface should be RLE encoded.
*/
surface light_surface(const surface &surf, const surface &lightmap, bool optimize=true);
/** Cross-fades a surface. */
surface blur_surface(const surface &surf, int depth = 1, bool optimize=true);
/**
* Cross-fades a surface in place.
*
* @param surf The surface to blur, must be not optimized
* and have 32 bits per pixel.
* @param rect The part of the surface to blur.
* @param depth The depth of the blurring.
*/
void blur_surface(surface& surf, SDL_Rect rect, int depth = 1);
/**
* Cross-fades a surface with alpha channel.
*
* @todo FIXME: This is just an adapted copy-paste
* of the normal blur but with blur alpha channel too
*/
surface blur_alpha_surface(const surface &surf, int depth = 1, bool optimize=true);
/** Cuts a rectangle from a surface. */
surface cut_surface(const surface &surf, SDL_Rect const &r);
/**
* Blends a surface with a color.
*
* Every pixel in the surface will be blended with the @p color given. The
* final color of a pixel is amount * @p color + (1 - amount) * original.
*
* @param surf The surface to blend.
* @param amount The amount of the new color is determined by
* @p color. Must be a number in the range
* [0, 1].
* @param color The color to blend width, note its alpha
* channel is ignored.
* @param optimize Should the return surface be RLE optimized.
*
* @return The blended surface.
*/
surface blend_surface(
const surface &surf
, const double amount
, const color_t color
, const bool optimize = true);
/**
* Rotates a surface by any degrees.
*
* @pre @p zoom >= @p offset Otherwise @return will have empty pixels.
* @pre @p offset > 0 Otherwise the procedure will not return.
*
* @param surf The surface to rotate.
* @param angle The angle of rotation.
* @param zoom Which zoom level to use for calculating the result.
* @param offset Pixel offset when scanning the zoomed source.
* @param optimize Should the return surface be RLE optimized.
*
* @return The rotated surface.
*/
surface rotate_any_surface(const surface& surf, float angle,
int zoom, int offset, bool optimize=true);
/**
* Rotates a surface 180 degrees.
*
* @param surf The surface to rotate.
* @param optimize Should the return surface be RLE optimized.
*
* @return The rotated surface.
*/
surface rotate_180_surface(const surface &surf, bool optimize=true);
/**
* Rotates a surface 90 degrees.
*
* @param surf The surface to rotate.
* @param clockwise Whether the rotation should be clockwise (true)
* or counter-clockwise (false).
* @param optimize Should the return surface be RLE optimized.
*
* @return The rotated surface.
*/
surface rotate_90_surface(const surface &surf, bool clockwise, bool optimize=true);
surface flip_surface(const surface &surf, bool optimize=true);
surface flop_surface(const surface &surf, bool optimize=true);
surface create_compatible_surface(const surface &surf, int width = -1, int height = -1);
/**
* Replacement for sdl_blit.
*
* sdl_blit has problems with blitting partly transparent surfaces so
* this is a replacement. It ignores the SDL_SRCALPHA and SDL_SRCCOLORKEY
* flags. src and dst will have the SDL_RLEACCEL flag removed.
* The return value of SDL_BlistSurface is normally ignored so no return value.
* The rectangles are const and will not be modified.
*
* @pre @p src contains a valid canvas.
* @pre @p dst contains a valid neutral canvas.
* @pre The caller must make sure the @p src fits on the @p dst.
*
* @param src The surface to blit.
* @param srcrect The region of the surface to blit
* @param dst The surface to blit on.
* @param dstrect The offset to blit the surface on, only x and y are used.
*/
void blit_surface(const surface& src,
const SDL_Rect* srcrect, surface& dst, const SDL_Rect* dstrect);
SDL_Rect get_non_transparent_portion(const surface &surf);
color_t inverse(const color_t& color);
/**
* Helper class for pinning SDL surfaces into memory.
* @note This class should be used only with neutral surfaces, so that
* the pointer returned by #pixels is meaningful.
*/
struct surface_lock
{
surface_lock(surface &surf);
~surface_lock();
Uint32* pixels() { return reinterpret_cast<Uint32*>(surface_->pixels); }
private:
surface& surface_;
bool locked_;
};
struct const_surface_lock
{
const_surface_lock(const surface &surf);
~const_surface_lock();
const Uint32* pixels() const { return reinterpret_cast<const Uint32*>(surface_->pixels); }
private:
const surface& surface_;
bool locked_;
};
/**
* Helper methods for setting/getting a single pixel in an image.
* Lifted from http://sdl.beuc.net/sdl.wiki/Pixel_Access
*
* @param surf The image to get or receive the pixel from.
* @param surf_lock The locked surface to make sure the pointers are valid.
* @param x The position in the row of the pixel.
* @param y The row of the pixel.
*/
void put_pixel(const surface& surf, surface_lock& surf_lock, int x, int y, Uint32 pixel);
Uint32 get_pixel(const surface& surf, const const_surface_lock& surf_lock, int x, int y);
struct surface_restorer
{
surface_restorer();
surface_restorer(class CVideo* target, const SDL_Rect& rect);
~surface_restorer();
void restore() const;
void restore(SDL_Rect const &dst) const;
void update();
void cancel();
const SDL_Rect& area() const { return rect_; }
private:
class CVideo* target_;
SDL_Rect rect_;
surface surface_;
};
struct clip_rect_setter
{
// if r is nullptr, clip to the full size of the surface.
clip_rect_setter(const surface &surf, const SDL_Rect* r, bool operate = true) : surface_(surf), rect_(), operate_(operate)
{
if(operate_){
SDL_GetClipRect(surface_, &rect_);
SDL_SetClipRect(surface_, r);
}
}
~clip_rect_setter() {
if (operate_)
SDL_SetClipRect(surface_, &rect_);
}
private:
surface surface_;
SDL_Rect rect_;
const bool operate_;
};
// blit the image on the center of the rectangle
// and a add a colored background
void draw_centered_on_background(surface surf, const SDL_Rect& rect,
const color_t& color, surface target);
#endif