1 | // SuperTux |
2 | // Copyright (C) 2016 Ingo Ruhnke <grumbel@gmail.com> |
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 3 of the License, or |
7 | // (at your option) any later version. |
8 | // |
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. |
13 | // |
14 | // You should have received a copy of the GNU General Public License |
15 | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | |
17 | #include "video/ttf_surface.hpp" |
18 | |
19 | #include <SDL_ttf.h> |
20 | |
21 | #include <sstream> |
22 | |
23 | #include "util/log.hpp" |
24 | #include "video/sdl_surface.hpp" |
25 | #include "video/surface.hpp" |
26 | #include "video/ttf_font.hpp" |
27 | #include "video/ttf_surface_manager.hpp" |
28 | #include "video/video_system.hpp" |
29 | |
30 | TTFSurfacePtr |
31 | TTFSurface::create(const TTFFont& font, const std::string& text) |
32 | { |
33 | SDLSurfacePtr text_surface(TTF_RenderUTF8_Blended(font.get_ttf_font(), |
34 | text.c_str(), |
35 | SDL_Color{255, 255, 255, 255})); |
36 | if (!text_surface) |
37 | { |
38 | log_warning << "Couldn't render text '" << text << "' :" << SDL_GetError(); |
39 | return std::make_shared<TTFSurface>(SurfacePtr(), Vector()); |
40 | } |
41 | |
42 | // FIXME: handle shadow offset |
43 | int grow = std::max(font.get_border() * 2, font.get_shadow_size() * 2); |
44 | |
45 | SDLSurfacePtr target = SDLSurface::create_rgba(text_surface->w + grow, text_surface->h + grow); |
46 | |
47 | #if !SDL_VERSION_ATLEAST(2,0,5) |
48 | // Perform blitting in ARGB8888, instead of RGBA8888, to avoid bug in older SDL2. |
49 | // https://bugzilla.libsdl.org/show_bug.cgi?id=3159 |
50 | target.reset(SDL_ConvertSurfaceFormat(target.get(), SDL_PIXELFORMAT_ARGB8888, 0)); |
51 | #endif |
52 | |
53 | { // shadow |
54 | SDL_SetSurfaceAlphaMod(text_surface.get(), 192); |
55 | SDL_SetSurfaceColorMod(text_surface.get(), 0, 0, 0); |
56 | SDL_SetSurfaceBlendMode(text_surface.get(), SDL_BLENDMODE_BLEND); |
57 | |
58 | using P = std::tuple<int, int>; |
59 | const std::initializer_list<std::tuple<int, int> > positions[] = { |
60 | {}, |
61 | {P{0, 0}}, |
62 | {P{-1, 0}, P{1, 0}, P{0, -1}, P{0, 1}}, |
63 | {P{-2, 0}, P{2, 0}, P{0, -2}, P{0, 2}, |
64 | P{-1, -1}, P{1, -1}, P{-1, 1}, P{1, 1}} |
65 | }; |
66 | |
67 | int shadow_size = std::min(2, font.get_shadow_size()); |
68 | for (const auto& p : positions[shadow_size]) |
69 | { |
70 | SDL_Rect dstrect{std::get<0>(p) + 2, std::get<1>(p) + 2, text_surface->w, text_surface->h}; |
71 | SDL_BlitSurface(text_surface.get(), nullptr, |
72 | target.get(), &dstrect); |
73 | } |
74 | } |
75 | |
76 | { // outline |
77 | SDL_SetSurfaceAlphaMod(text_surface.get(), 255); |
78 | SDL_SetSurfaceColorMod(text_surface.get(), 0, 0, 0); |
79 | SDL_SetSurfaceBlendMode(text_surface.get(), SDL_BLENDMODE_BLEND); |
80 | |
81 | using P = std::tuple<int, int>; |
82 | const std::initializer_list<std::tuple<int, int> > positions[] = { |
83 | {}, |
84 | {P{-1, 0}, P{1, 0}, P{0, -1}, P{0, 1}}, |
85 | {P{-2, 0}, P{2, 0}, P{0, -2}, P{0, 2}, |
86 | P{-1, -1}, P{1, -1}, P{-1, 1}, P{1, 1}} |
87 | }; |
88 | |
89 | int border = std::min(2, font.get_border()); |
90 | for (const auto& p : positions[border]) |
91 | { |
92 | SDL_Rect dstrect{std::get<0>(p), std::get<1>(p), text_surface->w, text_surface->h}; |
93 | SDL_BlitSurface(text_surface.get(), nullptr, |
94 | target.get(), &dstrect); |
95 | } |
96 | } |
97 | |
98 | { // white core |
99 | SDL_SetSurfaceAlphaMod(text_surface.get(), 255); |
100 | SDL_SetSurfaceColorMod(text_surface.get(), 255, 255, 255); |
101 | SDL_SetSurfaceBlendMode(text_surface.get(), SDL_BLENDMODE_BLEND); |
102 | |
103 | SDL_Rect dstrect{0, 0, text_surface->w, text_surface->h}; |
104 | |
105 | SDL_BlitSurface(text_surface.get(), nullptr, target.get(), &dstrect); |
106 | } |
107 | |
108 | #if !SDL_VERSION_ATLEAST(2,0,5) |
109 | target.reset(SDL_ConvertSurfaceFormat(target.get(), SDL_PIXELFORMAT_RGBA8888, 0)); |
110 | #endif |
111 | |
112 | SurfacePtr result = Surface::from_texture(VideoSystem::current()->new_texture(*target)); |
113 | return std::make_shared<TTFSurface>(result, Vector(0, 0)); |
114 | } |
115 | |
116 | TTFSurface::TTFSurface(const SurfacePtr& surface, const Vector& offset) : |
117 | m_surface(surface), |
118 | m_offset(offset) |
119 | { |
120 | } |
121 | |
122 | int |
123 | TTFSurface::get_width() const |
124 | { |
125 | if (m_surface) { |
126 | return m_surface->get_width(); |
127 | } else { |
128 | return 0; |
129 | } |
130 | } |
131 | |
132 | int |
133 | TTFSurface::get_height() const |
134 | { |
135 | if (m_surface) { |
136 | return m_surface->get_height(); |
137 | } else { |
138 | return 0; |
139 | } |
140 | } |
141 | |
142 | /* EOF */ |
143 | |