The Battle for Wesnoth  1.15.2+dev
surface.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2018 the Battle for Wesnoth Project https://www.wesnoth.org/
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY.
10 
11  See the COPYING file for more details.
12 */
13 
14 #include "sdl/surface.hpp"
15 
16 #include "sdl/rect.hpp"
17 #include "video.hpp"
18 
19 const SDL_PixelFormat surface::neutral_pixel_format = []() {
20 #if SDL_VERSION_ATLEAST(2, 0, 6)
21  return *SDL_CreateRGBSurfaceWithFormat(0, 1, 1, 32, SDL_PIXELFORMAT_ARGB8888)->format;
22 #else
23  return *SDL_CreateRGBSurface(0, 1, 1, 32, SDL_RED_MASK, SDL_GREEN_MASK, SDL_BLUE_MASK, SDL_ALPHA_MASK)->format;
24 #endif
25 }();
26 
27 surface::surface(SDL_Surface* surf)
28  : surface_(surf)
29 {
30  make_neutral(); // EXTREMELY IMPORTANT!
31 }
32 
33 surface::surface(int w, int h)
34  : surface_(nullptr)
35 {
36  if (w < 0 || h < 0) {
37  throw std::invalid_argument("Creating surface with negative dimensions");
38  }
39 
40 #if SDL_VERSION_ATLEAST(2, 0, 6)
41  surface_ = SDL_CreateRGBSurfaceWithFormat(0, w, h, neutral_pixel_format.BitsPerPixel, neutral_pixel_format.format);
42 #else
43  surface_ = SDL_CreateRGBSurface(0, w, h,
44  neutral_pixel_format.BitsPerPixel,
48  neutral_pixel_format.Amask);
49 #endif
50 }
51 
52 bool surface::is_neutral() const
53 {
54  return surface_
55  && SDL_ISPIXELFORMAT_INDEXED(surface_->format->format) == SDL_FALSE
56  && surface_->format->BytesPerPixel == 4
57  && surface_->format->Rmask == SDL_RED_MASK
58  && (surface_->format->Amask | SDL_ALPHA_MASK) == SDL_ALPHA_MASK;
59 }
60 
62 {
63  if(surface_ && !is_neutral()) {
64  SDL_Surface* res = SDL_ConvertSurface(surface_, &neutral_pixel_format, 0);
65 
66  // Ensure we don't leak memory with the old surface.
67  free_surface();
68 
69  surface_ = res;
70  }
71 
72  return *this;
73 }
74 
76 {
77  // Use SDL_ConvertSurface to make a copy
78  return surface(SDL_ConvertSurface(surface_, &neutral_pixel_format, 0));
79 }
80 
81 void surface::assign_surface_internal(SDL_Surface* surf)
82 {
83  add_surface_ref(surf); // Needs to be done before assignment to avoid corruption on "a = a;"
84  free_surface();
85  surface_ = surf;
86  make_neutral(); // EXTREMELY IMPORTANT!
87 }
88 
90 {
91  if(surface_) {
92  /* Workaround for an SDL bug.
93  * SDL 2.0.6 frees the blit map unconditionally in SDL_FreeSurface() without checking
94  * if the reference count has fallen to zero. However, many SDL functions such as
95  * SDL_ConvertSurface() assume that the blit map is present.
96  * Thus, we only call SDL_FreeSurface() if this is the last reference to the surface.
97  * Otherwise we just decrement the reference count ourselves.
98  *
99  * - Jyrki, 2017-09-23
100  */
101  if(surface_->refcount > 1 && sdl_get_version() == version_info(2, 0, 6)) {
102  --surface_->refcount;
103  } else {
104  SDL_FreeSurface(surface_);
105  }
106  }
107 }
108 
110  : target_(nullptr)
111  , rect_(sdl::empty_rect)
112  , surface_(nullptr)
113 {
114 }
115 
116 surface_restorer::surface_restorer(CVideo* target, const SDL_Rect& rect)
117  : target_(target)
118  , rect_(rect)
119  , surface_(nullptr)
120 {
121  update();
122 }
123 
125 {
126  restore();
127 }
128 
129 void surface_restorer::restore(const SDL_Rect& dst) const
130 {
131  if(!surface_) {
132  return;
133  }
134 
135  SDL_Rect dst2 = sdl::intersect_rects(dst, rect_);
136  if(dst2.w == 0 || dst2.h == 0) {
137  return;
138  }
139 
140  SDL_Rect src = dst2;
141  src.x -= rect_.x;
142  src.y -= rect_.y;
143  sdl_blit(surface_, &src, target_->getSurface(), &dst2);
144 }
145 
147 {
148  if(!surface_) {
149  return;
150  }
151 
152  SDL_Rect dst = rect_;
153  sdl_blit(surface_, nullptr, target_->getSurface(), &dst);
154 }
155 
157 {
158  if(rect_.w <= 0 || rect_.h <= 0) {
159  surface_ = nullptr;
160  } else {
162  }
163 }
164 
166 {
167  surface_ = nullptr;
168 }
169 
170 bool operator<(const surface& a, const surface& b)
171 {
172  return a.get() < b.get();
173 }
SDL_Surface * get() const
Definition: surface.hpp:99
void free_surface()
Definition: surface.cpp:89
const uint32_t SDL_BLUE_MASK
Definition: color.hpp:31
const uint32_t SDL_ALPHA_MASK
Definition: color.hpp:28
#define a
Definition: video.hpp:31
bool operator<(const surface &a, const surface &b)
Definition: surface.cpp:170
static void add_surface_ref(SDL_Surface *surf)
Definition: surface.hpp:104
SDL_Rect intersect_rects(const SDL_Rect &rect1, const SDL_Rect &rect2)
Calculates the intersection of two rectangles.
Definition: rect.cpp:39
#define h
surface get_surface_portion(const surface &src, SDL_Rect &area)
Get a portion of the screen.
Definition: utils.cpp:2157
void assign_surface_internal(SDL_Surface *surf)
Definition: surface.cpp:81
-file util.hpp
surface clone() const
Makes a copy of this surface.
Definition: surface.cpp:75
surface & getSurface()
Returns a reference to the framebuffer.
Definition: video.cpp:459
surface surface_
Definition: surface.hpp:138
#define b
surface()
Definition: surface.hpp:26
const uint32_t SDL_RED_MASK
Definition: color.hpp:29
surface & make_neutral()
Converts this surface to a neutral format if it is not already.
Definition: surface.cpp:61
SDL_Rect rect_
Definition: surface.hpp:137
class CVideo * target_
Definition: surface.hpp:136
SDL_Surface * surface_
Definition: surface.hpp:115
int w
void restore() const
Definition: surface.cpp:146
version_info sdl_get_version()
Definition: utils.cpp:33
bool is_neutral() const
Check that the surface is neutral bpp 32.
Definition: surface.cpp:52
Represents version numbers.
Contains the SDL_Rect helper code.
constexpr const SDL_Rect empty_rect
Definition: rect.hpp:31
static const SDL_PixelFormat neutral_pixel_format
Definition: surface.hpp:117
const uint32_t SDL_GREEN_MASK
Definition: color.hpp:30
void sdl_blit(const surface &src, SDL_Rect *src_rect, surface &dst, SDL_Rect *dst_rect)
Definition: utils.hpp:33