gosu 1.4.6 → 2.0.0.pre6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/COPYING +2 -1
- data/dependencies/SDL/include/SDL_atomic.h +2 -3
- data/dependencies/SDL/include/SDL_audio.h +7 -7
- data/dependencies/SDL/include/SDL_blendmode.h +1 -1
- data/dependencies/SDL/include/SDL_endian.h +3 -3
- data/dependencies/SDL/include/SDL_gamecontroller.h +4 -4
- data/dependencies/SDL/include/SDL_hints.h +72 -28
- data/dependencies/SDL/include/SDL_joystick.h +8 -5
- data/dependencies/SDL/include/SDL_keycode.h +1 -1
- data/dependencies/SDL/include/SDL_main.h +7 -0
- data/dependencies/SDL/include/SDL_mouse.h +6 -7
- data/dependencies/SDL/include/SDL_mutex.h +79 -5
- data/dependencies/SDL/include/SDL_opengl_glext.h +5 -1
- data/dependencies/SDL/include/SDL_power.h +7 -8
- data/dependencies/SDL/include/SDL_render.h +5 -0
- data/dependencies/SDL/include/SDL_revision.h +2 -2
- data/dependencies/SDL/include/SDL_sensor.h +1 -1
- data/dependencies/SDL/include/SDL_stdinc.h +19 -11
- data/dependencies/SDL/include/SDL_thread.h +2 -2
- data/dependencies/SDL/include/SDL_version.h +2 -2
- data/dependencies/SDL/include/SDL_video.h +30 -2
- data/dependencies/SDL/include/begin_code.h +7 -7
- data/dependencies/SDL/include/close_code.h +2 -2
- data/dependencies/SDL/lib/x64/libSDL2.dll.a +0 -0
- data/dependencies/SDL/lib/x86/libSDL2.dll.a +0 -0
- data/dependencies/SDL_sound/SDL_sound.h +1 -1
- data/dependencies/SDL_sound/dr_flac.h +48 -23
- data/dependencies/SDL_sound/dr_mp3.h +34 -14
- data/dependencies/SDL_sound/stb_vorbis.h +3 -2
- data/dependencies/mojoAL/mojoal.c +1 -1
- data/ext/{gosu → gosu-ffi}/extconf.rb +34 -33
- data/ext/gosu-ffi/gosu-ffi.def +464 -0
- data/ffi/Gosu.cpp +307 -0
- data/ffi/Gosu.h +84 -0
- data/ffi/Gosu_Channel.cpp +62 -0
- data/ffi/Gosu_Channel.h +17 -0
- data/ffi/Gosu_Color.cpp +132 -0
- data/ffi/Gosu_Color.h +31 -0
- data/ffi/Gosu_Constants.cpp +334 -0
- data/ffi/Gosu_FFI.h +34 -0
- data/ffi/Gosu_FFI_internal.h +161 -0
- data/ffi/Gosu_Font.cpp +92 -0
- data/ffi/Gosu_Font.h +32 -0
- data/ffi/Gosu_Image.cpp +206 -0
- data/ffi/Gosu_Image.h +60 -0
- data/ffi/Gosu_Sample.cpp +29 -0
- data/ffi/Gosu_Sample.h +14 -0
- data/ffi/Gosu_Song.cpp +69 -0
- data/ffi/Gosu_Song.h +18 -0
- data/ffi/Gosu_TextInput.cpp +94 -0
- data/ffi/Gosu_TextInput.h +25 -0
- data/ffi/Gosu_Window.cpp +314 -0
- data/ffi/Gosu_Window.h +78 -0
- data/include/Gosu/Audio.hpp +6 -11
- data/include/Gosu/Bitmap.hpp +38 -53
- data/include/Gosu/Buffer.hpp +54 -0
- data/include/Gosu/Color.hpp +27 -35
- data/include/Gosu/Directories.hpp +25 -28
- data/include/Gosu/Drawable.hpp +58 -0
- data/include/Gosu/Font.hpp +6 -5
- data/include/Gosu/Fwd.hpp +4 -6
- data/include/Gosu/Gosu.hpp +5 -5
- data/include/Gosu/Graphics.hpp +51 -61
- data/include/Gosu/GraphicsBase.hpp +1 -11
- data/include/Gosu/Image.hpp +11 -14
- data/include/Gosu/Math.hpp +50 -72
- data/include/Gosu/Transform.hpp +32 -0
- data/include/Gosu/Utility.hpp +51 -1
- data/include/Gosu/Version.hpp +3 -3
- data/include/Gosu/Window.hpp +15 -9
- data/lib/SDL2.dll +0 -0
- data/lib/gosu/channel.rb +49 -0
- data/lib/gosu/color.rb +150 -0
- data/lib/gosu/compat.rb +29 -8
- data/lib/gosu/constants.rb +386 -0
- data/lib/gosu/ffi.rb +258 -0
- data/lib/gosu/font.rb +56 -0
- data/lib/gosu/gl_tex_info.rb +33 -0
- data/lib/gosu/gosu.rb +210 -0
- data/lib/gosu/image.rb +141 -0
- data/lib/gosu/numeric.rb +17 -0
- data/lib/gosu/preview.rb +6 -6
- data/lib/gosu/sample.rb +24 -0
- data/lib/gosu/song.rb +56 -0
- data/lib/gosu/text_input.rb +69 -0
- data/lib/gosu/window.rb +228 -0
- data/lib/gosu.rb +29 -8
- data/lib64/SDL2.dll +0 -0
- data/rdoc/gosu.rb +0 -2
- data/src/Audio.cpp +12 -12
- data/src/AudioFile.hpp +5 -4
- data/src/AudioFileAudioToolbox.cpp +8 -8
- data/src/AudioFileSDLSound.cpp +7 -10
- data/src/BinPacker.cpp +187 -0
- data/src/BinPacker.hpp +55 -0
- data/src/Bitmap.cpp +166 -144
- data/src/BitmapIO.cpp +60 -86
- data/src/Buffer.cpp +159 -0
- data/src/Color.cpp +75 -80
- data/src/Directories.cpp +47 -0
- data/src/DirectoriesUIKit.cpp +50 -0
- data/src/DrawOp.hpp +9 -4
- data/src/DrawOpQueue.hpp +2 -2
- data/src/Drawable.cpp +95 -0
- data/src/EmptyDrawable.hpp +38 -0
- data/src/FPS.cpp +31 -0
- data/src/Font.cpp +104 -74
- data/src/GosuGLView.cpp +14 -6
- data/src/GosuViewController.cpp +2 -10
- data/src/Graphics.cpp +60 -126
- data/src/GraphicsImpl.hpp +17 -47
- data/src/Image.cpp +41 -35
- data/src/Input.cpp +7 -8
- data/src/Macro.cpp +6 -6
- data/src/Macro.hpp +4 -4
- data/src/MarkupParser.cpp +5 -5
- data/src/Math.cpp +35 -22
- data/src/OffScreenTarget.cpp +53 -49
- data/src/OffScreenTarget.hpp +13 -11
- data/src/OpenGLContext.cpp +117 -0
- data/src/OpenGLContext.hpp +41 -0
- data/src/RenderState.hpp +21 -19
- data/src/Resolution.cpp +23 -21
- data/src/TexChunk.cpp +35 -80
- data/src/TexChunk.hpp +44 -35
- data/src/Text.cpp +1 -1
- data/src/TextBuilder.cpp +35 -21
- data/src/TextBuilder.hpp +6 -9
- data/src/Texture.cpp +62 -80
- data/src/Texture.hpp +25 -23
- data/src/TiledDrawable.cpp +150 -0
- data/src/TiledDrawable.hpp +47 -0
- data/src/TimingApple.cpp +1 -1
- data/src/Transform.cpp +45 -50
- data/src/TransformStack.hpp +16 -16
- data/src/TrueTypeFont.cpp +59 -51
- data/src/TrueTypeFont.hpp +6 -7
- data/src/TrueTypeFontApple.cpp +28 -19
- data/src/TrueTypeFontUnix.cpp +27 -23
- data/src/TrueTypeFontWin.cpp +30 -30
- data/src/Utility.cpp +84 -21
- data/src/UtilityWin.cpp +45 -0
- data/src/Window.cpp +92 -142
- data/src/WindowUIKit.cpp +14 -14
- metadata +72 -31
- data/include/Gosu/IO.hpp +0 -254
- data/include/Gosu/ImageData.hpp +0 -53
- data/include/Gosu/Inspection.hpp +0 -7
- data/lib/gosu/patches.rb +0 -66
- data/lib/gosu/run.rb +0 -20
- data/lib/gosu/swig_patches.rb +0 -110
- data/src/BlockAllocator.cpp +0 -131
- data/src/BlockAllocator.hpp +0 -32
- data/src/DirectoriesApple.cpp +0 -69
- data/src/DirectoriesUnix.cpp +0 -46
- data/src/DirectoriesWin.cpp +0 -65
- data/src/EmptyImageData.hpp +0 -52
- data/src/FileUnix.cpp +0 -99
- data/src/FileWin.cpp +0 -88
- data/src/IO.cpp +0 -60
- data/src/Iconv.hpp +0 -51
- data/src/Inspection.cpp +0 -27
- data/src/LargeImageData.cpp +0 -215
- data/src/LargeImageData.hpp +0 -39
- data/src/Log.hpp +0 -19
- data/src/RubyGosu.cxx +0 -13100
- data/src/RubyGosu.h +0 -49
- data/src/WinUtility.cpp +0 -61
- data/src/WinUtility.hpp +0 -27
data/src/TransformStack.hpp
CHANGED
@@ -14,7 +14,7 @@ namespace Gosu
|
|
14
14
|
Transforms absolute;
|
15
15
|
// Points to one absolute transform.
|
16
16
|
Transforms::const_iterator current_iterator;
|
17
|
-
|
17
|
+
|
18
18
|
void make_current(const Transform& transform)
|
19
19
|
{
|
20
20
|
current_iterator = std::find(absolute.begin(), absolute.end(), transform);
|
@@ -22,12 +22,12 @@ namespace Gosu
|
|
22
22
|
current_iterator = absolute.insert(absolute.end(), transform);
|
23
23
|
}
|
24
24
|
}
|
25
|
-
|
25
|
+
|
26
26
|
public:
|
27
27
|
TransformStack()
|
28
28
|
{
|
29
29
|
reset();
|
30
|
-
individual.front() = absolute.front() = scale(1);
|
30
|
+
individual.front() = absolute.front() = Transform::scale(1);
|
31
31
|
}
|
32
32
|
|
33
33
|
void reset()
|
@@ -39,18 +39,18 @@ namespace Gosu
|
|
39
39
|
absolute.resize(1);
|
40
40
|
current_iterator = absolute.begin();
|
41
41
|
}
|
42
|
-
|
42
|
+
|
43
43
|
TransformStack(const TransformStack& other)
|
44
44
|
{
|
45
45
|
*this = other;
|
46
46
|
}
|
47
|
-
|
47
|
+
|
48
48
|
// Custom assignment to ensure valid current_iterator
|
49
49
|
TransformStack& operator=(const TransformStack& other)
|
50
50
|
{
|
51
51
|
individual = other.individual;
|
52
52
|
absolute = other.absolute;
|
53
|
-
|
53
|
+
|
54
54
|
// Reset our current_iterator to point to the respective element
|
55
55
|
// in our own 'absolute' transforms by iterating both lists up to
|
56
56
|
// the other lists' current iterator
|
@@ -60,39 +60,39 @@ namespace Gosu
|
|
60
60
|
++current_iterator;
|
61
61
|
++other_iterator;
|
62
62
|
}
|
63
|
-
|
63
|
+
|
64
64
|
return *this;
|
65
65
|
}
|
66
|
-
|
66
|
+
|
67
67
|
void set_base_transform(const Transform& base_transform)
|
68
68
|
{
|
69
69
|
assert (individual.size() == 1);
|
70
70
|
assert (absolute.size() == 1);
|
71
|
-
|
71
|
+
|
72
72
|
individual.front() = absolute.front() = base_transform;
|
73
73
|
}
|
74
|
-
|
74
|
+
|
75
75
|
const Transform& current()
|
76
76
|
{
|
77
77
|
return *current_iterator;
|
78
78
|
}
|
79
|
-
|
79
|
+
|
80
80
|
void push(const Transform& transform)
|
81
81
|
{
|
82
82
|
individual.push_back(transform);
|
83
|
-
Transform result =
|
83
|
+
Transform result = transform * current();
|
84
84
|
make_current(result);
|
85
85
|
}
|
86
|
-
|
86
|
+
|
87
87
|
void pop()
|
88
88
|
{
|
89
89
|
assert (individual.size() > 1);
|
90
|
-
|
90
|
+
|
91
91
|
individual.pop_back();
|
92
|
-
Transform result = scale(1);
|
92
|
+
Transform result = Transform::scale(1);
|
93
93
|
for (Transforms::reverse_iterator it = individual.rbegin(),
|
94
94
|
end = individual.rend(); it != end; ++it)
|
95
|
-
result =
|
95
|
+
result = result * *it;
|
96
96
|
make_current(result);
|
97
97
|
}
|
98
98
|
};
|
data/src/TrueTypeFont.cpp
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
#include "TrueTypeFont.hpp"
|
2
|
-
#include <Gosu/
|
2
|
+
#include <Gosu/Buffer.hpp>
|
3
3
|
#include <Gosu/Text.hpp>
|
4
4
|
#include <Gosu/Utility.hpp>
|
5
5
|
#include <algorithm>
|
6
6
|
#include <map>
|
7
|
+
#include <mutex>
|
7
8
|
#include <stdexcept>
|
8
9
|
|
9
10
|
#define STB_TRUETYPE_IMPLEMENTATION
|
@@ -11,23 +12,25 @@
|
|
11
12
|
|
12
13
|
struct Gosu::TrueTypeFont::Impl : private Gosu::Noncopyable
|
13
14
|
{
|
14
|
-
stbtt_fontinfo info{};
|
15
|
+
stbtt_fontinfo info {};
|
15
16
|
std::shared_ptr<TrueTypeFont> fallback;
|
16
17
|
|
17
18
|
// The height of the ascent in internal font metrics (an arbitrary integer scale). The ascent is
|
18
19
|
// the part of the font above the baseline (which TrueType considers to be at y = 0).
|
19
|
-
int ascent
|
20
|
+
int ascent = 0;
|
20
21
|
|
21
22
|
// Scaling factor from internal font metrics (an arbitrary integer scale) to a font with
|
22
23
|
// height = 1px.
|
23
24
|
double base_scale;
|
24
25
|
|
25
|
-
Impl(const
|
26
|
-
|
26
|
+
Impl(const std::uint8_t* ttf_data, std::shared_ptr<TrueTypeFont> fallback)
|
27
|
+
: fallback(std::move(fallback))
|
27
28
|
{
|
28
29
|
auto offset = stbtt_GetFontOffsetForIndex(ttf_data, 0);
|
29
30
|
int success = stbtt_InitFont(&info, ttf_data, offset);
|
30
|
-
if (!success)
|
31
|
+
if (!success) {
|
32
|
+
throw std::runtime_error("Invalid TrueType font data");
|
33
|
+
}
|
31
34
|
|
32
35
|
// Calculate metrics.
|
33
36
|
int descent, line_gap;
|
@@ -40,7 +43,9 @@ struct Gosu::TrueTypeFont::Impl : private Gosu::Noncopyable
|
|
40
43
|
double draw_text(const std::u32string& text, bool is_end, double height, Bitmap* bitmap,
|
41
44
|
double x, double y, Color c)
|
42
45
|
{
|
43
|
-
if (text.empty())
|
46
|
+
if (text.empty()) {
|
47
|
+
return 0;
|
48
|
+
}
|
44
49
|
|
45
50
|
// The 'x' parameter is used as the running cursor variable in this method.
|
46
51
|
|
@@ -51,7 +56,9 @@ struct Gosu::TrueTypeFont::Impl : private Gosu::Noncopyable
|
|
51
56
|
for (std::size_t index = 0; index < text.size(); ++index) {
|
52
57
|
auto codepoint = text[index];
|
53
58
|
// Silently skip control characters, including the \r in Windows-style line breaks.
|
54
|
-
if (codepoint < ' ')
|
59
|
+
if (codepoint < ' ') {
|
60
|
+
continue;
|
61
|
+
}
|
55
62
|
|
56
63
|
int glyph = stbtt_FindGlyphIndex(&info, static_cast<int>(codepoint));
|
57
64
|
// Handle missing characters in this font...
|
@@ -98,10 +105,11 @@ struct Gosu::TrueTypeFont::Impl : private Gosu::Noncopyable
|
|
98
105
|
float fscale = static_cast<float>(scale);
|
99
106
|
int last_xoff, last_width;
|
100
107
|
// TODO: Don't allocate a buffer just to get metrics!
|
101
|
-
std::shared_ptr<
|
102
|
-
|
103
|
-
|
104
|
-
|
108
|
+
std::shared_ptr<std::uint8_t> unused_data {
|
109
|
+
stbtt_GetGlyphBitmapSubpixel(&info, fscale, fscale, shift_x, 0, last_glyph,
|
110
|
+
&last_width, nullptr, &last_xoff, nullptr),
|
111
|
+
std::free
|
112
|
+
};
|
105
113
|
// Move the cursor to the right if pixels have been touched by draw_glyph that are
|
106
114
|
// to the right of the current cursor.
|
107
115
|
// If the last character extends to the right of the cursor, then this prevents the
|
@@ -144,16 +152,16 @@ struct Gosu::TrueTypeFont::Impl : private Gosu::Noncopyable
|
|
144
152
|
int w, h, xoff, yoff;
|
145
153
|
// As an optimization, this method/class could try to re-use a buffer for rasterization
|
146
154
|
// instead of having stb_truetype allocate a fresh one for each draw_glyph call.
|
147
|
-
std::shared_ptr<
|
148
|
-
|
149
|
-
|
150
|
-
|
155
|
+
std::shared_ptr<std::uint8_t> pixels(stbtt_GetGlyphBitmapSubpixel(&info, fscale, fscale, //
|
156
|
+
shift_x, shift_y, glyph,
|
157
|
+
&w, &h, &xoff, &yoff),
|
158
|
+
std::free);
|
151
159
|
|
152
160
|
int target_y = static_cast<int>(y + ascent * scale + yoff);
|
153
161
|
blend_into_bitmap(bitmap, pixels.get(), x + xoff, target_y, w, h, c);
|
154
162
|
}
|
155
163
|
|
156
|
-
static void blend_into_bitmap(Bitmap& bitmap, const
|
164
|
+
static void blend_into_bitmap(Bitmap& bitmap, const std::uint8_t* pixels, //
|
157
165
|
int x, int y, int w, int h, Color c)
|
158
166
|
{
|
159
167
|
int stride = w;
|
@@ -188,9 +196,9 @@ struct Gosu::TrueTypeFont::Impl : private Gosu::Noncopyable
|
|
188
196
|
}
|
189
197
|
};
|
190
198
|
|
191
|
-
Gosu::TrueTypeFont::TrueTypeFont(const
|
199
|
+
Gosu::TrueTypeFont::TrueTypeFont(const std::uint8_t* ttf_data,
|
192
200
|
std::shared_ptr<TrueTypeFont> fallback)
|
193
|
-
: m_impl
|
201
|
+
: m_impl(new Impl(ttf_data, std::move(fallback)))
|
194
202
|
{
|
195
203
|
}
|
196
204
|
|
@@ -200,31 +208,33 @@ double Gosu::TrueTypeFont::draw_text(const std::u32string& text, double height,
|
|
200
208
|
return m_impl->draw_text(text, true, height, bitmap, x, y, c);
|
201
209
|
}
|
202
210
|
|
203
|
-
bool Gosu::TrueTypeFont::matches(const
|
211
|
+
bool Gosu::TrueTypeFont::matches(const std::uint8_t* ttf_data, const std::string& font_name,
|
204
212
|
unsigned font_flags)
|
205
213
|
{
|
206
214
|
// Gosu::FontFlags uses the same values as the STBTT_ macros, except for this one.
|
207
215
|
int flags = (font_flags == 0 ? STBTT_MACSTYLE_NONE : static_cast<int>(font_flags));
|
208
216
|
|
209
|
-
return stbtt_FindMatchingFont(ttf_data, font_name.c_str(), flags) >= 0
|
210
|
-
|
217
|
+
return stbtt_FindMatchingFont(ttf_data, font_name.c_str(), flags) >= 0
|
218
|
+
|| stbtt_FindMatchingFont(ttf_data, font_name.c_str(), STBTT_MACSTYLE_DONTCARE) >= 0;
|
211
219
|
}
|
212
220
|
|
213
|
-
static Gosu::TrueTypeFont& font_with_stack(std::vector<const
|
221
|
+
static Gosu::TrueTypeFont& font_with_stack(std::vector<const std::uint8_t*> ttf_stack)
|
214
222
|
{
|
215
|
-
|
216
|
-
static std::
|
223
|
+
static std::map<const std::uint8_t*, std::shared_ptr<Gosu::TrueTypeFont>> cache_by_data;
|
224
|
+
static std::recursive_mutex mutex;
|
225
|
+
std::scoped_lock lock(mutex);
|
217
226
|
|
218
|
-
// Filter out any fonts that could not be found, as well as duplicates.
|
219
|
-
|
220
|
-
|
221
|
-
ttf_stack.erase(end, ttf_stack.end());
|
227
|
+
// Filter out any fonts that could not be found, as well as (adjacent) duplicates.
|
228
|
+
ttf_stack.erase(std::remove(ttf_stack.begin(), ttf_stack.end(), nullptr), ttf_stack.end());
|
229
|
+
ttf_stack.erase(std::unique(ttf_stack.begin(), ttf_stack.end()), ttf_stack.end());
|
222
230
|
|
223
231
|
// This cannot happen because ttf_stack contains ttf_fallback_data(), which never returns null.
|
224
|
-
if (ttf_stack.empty())
|
232
|
+
if (ttf_stack.empty()) {
|
233
|
+
throw std::logic_error("Empty font stack");
|
234
|
+
}
|
225
235
|
|
226
236
|
std::shared_ptr<Gosu::TrueTypeFont> head_of_stack = nullptr;
|
227
|
-
for (const
|
237
|
+
for (const std::uint8_t* ttf_data : ttf_stack) {
|
228
238
|
auto& font_ptr = cache_by_data[ttf_data];
|
229
239
|
if (!font_ptr) {
|
230
240
|
font_ptr = std::make_shared<Gosu::TrueTypeFont>(ttf_data, head_of_stack);
|
@@ -236,17 +246,20 @@ static Gosu::TrueTypeFont& font_with_stack(std::vector<const unsigned char*> ttf
|
|
236
246
|
|
237
247
|
Gosu::TrueTypeFont& Gosu::font_by_name(const std::string& font_name, unsigned font_flags)
|
238
248
|
{
|
239
|
-
// TODO: Make this cache thread-safe.
|
240
249
|
static std::map<std::pair<std::string, unsigned>, TrueTypeFont*> cache_by_name_and_flags;
|
250
|
+
static std::recursive_mutex mutex;
|
251
|
+
std::scoped_lock lock(mutex);
|
241
252
|
|
242
253
|
auto& font_ptr = cache_by_name_and_flags[make_pair(font_name, font_flags)];
|
243
254
|
if (!font_ptr) {
|
244
255
|
// Build a stack of TTF data in order of preference, where the fallback font is at the
|
245
256
|
// front, and the desired font with all the right font flags (most preferable) at the back.
|
246
|
-
std::vector<const
|
257
|
+
std::vector<const std::uint8_t*> ttf_stack;
|
247
258
|
ttf_stack.push_back(ttf_fallback_data());
|
248
259
|
ttf_stack.push_back(ttf_data_by_name(default_font_name(), 0));
|
249
|
-
if (font_flags != 0)
|
260
|
+
if (font_flags != 0) {
|
261
|
+
ttf_stack.push_back(ttf_data_by_name(default_font_name(), font_flags));
|
262
|
+
}
|
250
263
|
|
251
264
|
if (font_name.find_first_of("./\\") != std::string::npos) {
|
252
265
|
// A filename? Load it and add it to the stack.
|
@@ -255,30 +268,25 @@ Gosu::TrueTypeFont& Gosu::font_by_name(const std::string& font_name, unsigned fo
|
|
255
268
|
else if (font_name != default_font_name()) {
|
256
269
|
// A font name? Add it to the stack, both with font_flags and without.
|
257
270
|
ttf_stack.push_back(ttf_data_by_name(font_name, 0));
|
258
|
-
if (font_flags != 0)
|
271
|
+
if (font_flags != 0) {
|
272
|
+
ttf_stack.push_back(ttf_data_by_name(font_name, font_flags));
|
273
|
+
}
|
259
274
|
}
|
260
275
|
|
261
|
-
font_ptr = &font_with_stack(move(ttf_stack));
|
276
|
+
font_ptr = &font_with_stack(std::move(ttf_stack));
|
262
277
|
}
|
263
278
|
|
264
279
|
return *font_ptr;
|
265
280
|
}
|
266
281
|
|
267
|
-
const
|
282
|
+
const std::uint8_t* Gosu::ttf_data_from_file(const std::string& filename)
|
268
283
|
{
|
269
|
-
|
270
|
-
static std::
|
271
|
-
|
272
|
-
|
273
|
-
if (!
|
274
|
-
|
275
|
-
try {
|
276
|
-
load_file(*buffer_ptr, filename);
|
277
|
-
} catch (...) {
|
278
|
-
// Prevent partially loaded files from getting stuck in the cache.
|
279
|
-
buffer_ptr = nullptr;
|
280
|
-
throw;
|
281
|
-
}
|
284
|
+
static std::map<std::string, Buffer> ttf_file_cache;
|
285
|
+
static std::recursive_mutex mutex;
|
286
|
+
std::scoped_lock lock(mutex);
|
287
|
+
|
288
|
+
if (!ttf_file_cache.contains(filename)) {
|
289
|
+
ttf_file_cache.emplace(filename, load_file(filename));
|
282
290
|
}
|
283
|
-
return
|
291
|
+
return ttf_file_cache.at(filename).data();
|
284
292
|
}
|
data/src/TrueTypeFont.hpp
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
#pragma once
|
2
2
|
|
3
3
|
#include <Gosu/Bitmap.hpp>
|
4
|
-
#include <
|
4
|
+
#include <cstdint>
|
5
5
|
#include <functional>
|
6
6
|
#include <memory>
|
7
7
|
#include <string>
|
8
|
-
#include <vector>
|
9
8
|
|
10
9
|
namespace Gosu
|
11
10
|
{
|
@@ -16,7 +15,7 @@ namespace Gosu
|
|
16
15
|
|
17
16
|
public:
|
18
17
|
/// The caller must ensure that the ttf_data pointer will outlive this object.
|
19
|
-
TrueTypeFont(const
|
18
|
+
TrueTypeFont(const std::uint8_t* ttf_data, std::shared_ptr<TrueTypeFont> fallback);
|
20
19
|
|
21
20
|
/// Returns the right edge of a string when rendered onto a bitmap at the given position,
|
22
21
|
/// and with the given height.
|
@@ -25,7 +24,7 @@ namespace Gosu
|
|
25
24
|
Bitmap* bitmap, double x, double y, Color c);
|
26
25
|
|
27
26
|
/// Returns true if the supplied buffer seems to be a font of the given name.
|
28
|
-
static bool matches(const
|
27
|
+
static bool matches(const std::uint8_t* ttf_data, //
|
29
28
|
const std::string& font_name, unsigned font_flags);
|
30
29
|
};
|
31
30
|
|
@@ -49,15 +48,15 @@ namespace Gosu
|
|
49
48
|
/// 3. As a last resort, Gosu could implement faux bold and faux italics. I think faux
|
50
49
|
/// underlines are a must anyway, since no font provides a dedicated TTF file for that.
|
51
50
|
/// These options are not mutually exclusive.
|
52
|
-
const
|
51
|
+
const std::uint8_t* ttf_data_from_file(const std::string& filename);
|
53
52
|
|
54
53
|
/// This method loads a system font with the given flags.
|
55
54
|
/// This method has a different implementation on each platform.
|
56
55
|
/// In case of failure, this method returns nullptr.
|
57
|
-
const
|
56
|
+
const std::uint8_t* ttf_data_by_name(const std::string& font_name, unsigned font_flags);
|
58
57
|
|
59
58
|
/// Returns the TTF data of a font that supports as many glyphs as possible.
|
60
59
|
/// This method has a different implementation on each platform.
|
61
60
|
/// In case of failure, this method must not return nullptr, but raise an exception.
|
62
|
-
const
|
61
|
+
const std::uint8_t* ttf_fallback_data();
|
63
62
|
}
|
data/src/TrueTypeFontApple.cpp
CHANGED
@@ -2,50 +2,55 @@
|
|
2
2
|
#if defined(GOSU_IS_MAC)
|
3
3
|
|
4
4
|
#include <Gosu/Text.hpp>
|
5
|
-
#include "Log.hpp"
|
6
5
|
#include "TrueTypeFont.hpp"
|
7
6
|
#include <CoreText/CoreText.h>
|
8
7
|
#include <Foundation/Foundation.h>
|
9
8
|
#include <map>
|
10
9
|
|
11
|
-
const
|
10
|
+
const std::uint8_t* Gosu::ttf_data_by_name(const std::string& font_name, unsigned font_flags)
|
12
11
|
{
|
13
|
-
|
14
|
-
static std::
|
12
|
+
static std::map<std::pair<std::string, unsigned>, const std::uint8_t*> ttf_file_cache;
|
13
|
+
static std::recursive_mutex mutex;
|
14
|
+
std::scoped_lock lock(mutex);
|
15
15
|
|
16
16
|
auto& ttf_ptr = ttf_file_cache[make_pair(font_name, font_flags)];
|
17
|
-
if (ttf_ptr)
|
18
|
-
|
19
|
-
|
17
|
+
if (ttf_ptr) {
|
18
|
+
return ttf_ptr;
|
19
|
+
}
|
20
20
|
|
21
21
|
unsigned symbolic_traits = 0;
|
22
|
-
if (font_flags & Gosu::FF_BOLD)
|
23
|
-
|
22
|
+
if (font_flags & Gosu::FF_BOLD) {
|
23
|
+
symbolic_traits |= kCTFontTraitBold;
|
24
|
+
}
|
25
|
+
if (font_flags & Gosu::FF_ITALIC) {
|
26
|
+
symbolic_traits |= kCTFontTraitItalic;
|
27
|
+
}
|
24
28
|
|
25
29
|
NSDictionary* attributes = @{
|
26
|
-
((__bridge id)
|
27
|
-
((__bridge id)
|
28
|
-
|
30
|
+
((__bridge id)kCTFontNameAttribute) : [NSString stringWithUTF8String:font_name.c_str()],
|
31
|
+
((__bridge id)kCTFontTraitsAttribute) :
|
32
|
+
@ { ((__bridge id)kCTFontSymbolicTrait) : @(symbolic_traits) }
|
29
33
|
};
|
30
34
|
CTFontDescriptorRef descriptor =
|
31
|
-
|
32
|
-
|
35
|
+
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
|
36
|
+
CTFontDescriptorCreateWithAttributes((__bridge CFDictionaryRef)attributes);
|
33
37
|
|
34
38
|
if (descriptor) {
|
35
39
|
CTFontRef font = CTFontCreateWithFontDescriptorAndOptions(descriptor, 20, nullptr, 0);
|
36
40
|
if (font) {
|
41
|
+
// GCOV_EXCL_START: This does not seem to happen anymore on recent macOS versions.
|
37
42
|
if ((CTFontGetSymbolicTraits(font) & symbolic_traits) != symbolic_traits) {
|
38
43
|
// For some reason the initial call to CTFontCreateWithFontDescriptorAndOptions does
|
39
44
|
// not respect the requested font traits. Explicitly requesting the traits again
|
40
45
|
// seems to help. Tested on macOS 11.2.2.
|
41
46
|
CTFontRef correct_font = CTFontCreateCopyWithSymbolicTraits(
|
42
|
-
|
47
|
+
font, 0.0, nullptr, symbolic_traits, symbolic_traits);
|
43
48
|
CFRelease(font);
|
44
49
|
font = correct_font;
|
45
50
|
}
|
51
|
+
// GCOV_EXCL_END
|
46
52
|
NSURL* url = CFBridgingRelease(CTFontCopyAttribute(font, kCTFontURLAttribute));
|
47
53
|
if (url && url.fileSystemRepresentation) {
|
48
|
-
log("Loading file '%s'", url.fileSystemRepresentation);
|
49
54
|
ttf_ptr = ttf_data_from_file(url.fileSystemRepresentation);
|
50
55
|
}
|
51
56
|
CFRelease(font);
|
@@ -56,13 +61,17 @@ const unsigned char* Gosu::ttf_data_by_name(const std::string& font_name, unsign
|
|
56
61
|
return ttf_ptr;
|
57
62
|
}
|
58
63
|
|
59
|
-
const
|
64
|
+
const std::uint8_t* Gosu::ttf_fallback_data()
|
60
65
|
{
|
61
66
|
// Prefer Arial Unicode MS as a fallback because it covers a lot of Unicode.
|
62
|
-
static const
|
63
|
-
if (arial_unicode)
|
67
|
+
static const std::uint8_t* arial_unicode = ttf_data_by_name("Arial Unicode MS", 0);
|
68
|
+
if (arial_unicode) {
|
69
|
+
return arial_unicode;
|
70
|
+
}
|
64
71
|
|
72
|
+
// GCOV_EXCL_START: We do not want to delete system fonts in order to test this line.
|
65
73
|
return ttf_data_from_file("/Library/Fonts/Arial.ttf");
|
74
|
+
// GCOV_EXCL_END
|
66
75
|
}
|
67
76
|
|
68
77
|
std::string Gosu::default_font_name()
|
data/src/TrueTypeFontUnix.cpp
CHANGED
@@ -1,23 +1,23 @@
|
|
1
1
|
#include <Gosu/Platform.hpp>
|
2
2
|
#if defined(GOSU_IS_X)
|
3
3
|
|
4
|
-
#include <Gosu/IO.hpp>
|
5
4
|
#include <Gosu/Text.hpp>
|
6
5
|
#include <Gosu/Utility.hpp>
|
7
|
-
#include "Log.hpp"
|
8
6
|
#include "TrueTypeFont.hpp"
|
9
7
|
#include <fontconfig/fontconfig.h>
|
10
8
|
#include <map>
|
9
|
+
#include <mutex>
|
11
10
|
|
12
|
-
const
|
11
|
+
const std::uint8_t* Gosu::ttf_data_by_name(const std::string& font_name, unsigned font_flags)
|
13
12
|
{
|
14
|
-
|
15
|
-
static std::
|
13
|
+
static std::map<std::pair<std::string, unsigned>, const std::uint8_t*> ttf_file_cache;
|
14
|
+
static std::recursive_mutex mutex;
|
15
|
+
std::scoped_lock lock(mutex);
|
16
16
|
|
17
17
|
auto& ttf_ptr = ttf_file_cache[make_pair(font_name, font_flags)];
|
18
|
-
if (ttf_ptr)
|
19
|
-
|
20
|
-
|
18
|
+
if (ttf_ptr) {
|
19
|
+
return ttf_ptr;
|
20
|
+
}
|
21
21
|
|
22
22
|
static FcConfig* config = FcInitLoadConfigAndFonts();
|
23
23
|
if (config) {
|
@@ -31,8 +31,6 @@ const unsigned char* Gosu::ttf_data_by_name(const std::string& font_name, unsign
|
|
31
31
|
FcObjectSet* props = FcObjectSetBuild(FC_FILE, FC_WEIGHT, FC_SLANT, nullptr);
|
32
32
|
|
33
33
|
if (FcFontSet* fonts = FcFontList(config, pattern, props)) {
|
34
|
-
log("Looking for the best candidate among %d matching fonts", (int) fonts->nfont);
|
35
|
-
|
36
34
|
// Among all matching fonts, find the variant that is the best fit for our font_flags.
|
37
35
|
std::string best_filename;
|
38
36
|
int best_diff;
|
@@ -72,7 +70,6 @@ const unsigned char* Gosu::ttf_data_by_name(const std::string& font_name, unsign
|
|
72
70
|
}
|
73
71
|
}
|
74
72
|
if (!best_filename.empty()) {
|
75
|
-
log("Loading best candidate '%s'", best_filename.c_str());
|
76
73
|
ttf_ptr = ttf_data_from_file(best_filename.c_str());
|
77
74
|
}
|
78
75
|
|
@@ -86,9 +83,9 @@ const unsigned char* Gosu::ttf_data_by_name(const std::string& font_name, unsign
|
|
86
83
|
return ttf_ptr;
|
87
84
|
}
|
88
85
|
|
89
|
-
static const
|
86
|
+
static const std::uint8_t* ttf_data_of_default_sans_serif_font()
|
90
87
|
{
|
91
|
-
const
|
88
|
+
const std::uint8_t* ttf_ptr = nullptr;
|
92
89
|
|
93
90
|
// At this point, we already have an open FcConfig, and can pass nullptr to these functions.
|
94
91
|
FcPattern* pattern = FcNameParse(reinterpret_cast<const FcChar8*>("sans-serif"));
|
@@ -99,7 +96,6 @@ static const unsigned char* ttf_data_of_default_sans_serif_font()
|
|
99
96
|
if (match_result == FcResultMatch) {
|
100
97
|
FcChar8* filename;
|
101
98
|
if (FcPatternGetString(pattern, FC_FILE, 0, &filename) == FcResultMatch) {
|
102
|
-
Gosu::log("Found the default sans-serif font: '%s'", filename);
|
103
99
|
ttf_ptr = Gosu::ttf_data_from_file(reinterpret_cast<char*>(filename));
|
104
100
|
}
|
105
101
|
}
|
@@ -108,24 +104,32 @@ static const unsigned char* ttf_data_of_default_sans_serif_font()
|
|
108
104
|
return ttf_ptr;
|
109
105
|
}
|
110
106
|
|
111
|
-
const
|
107
|
+
const std::uint8_t* Gosu::ttf_fallback_data()
|
112
108
|
{
|
113
109
|
// Prefer Arial Unicode MS as a fallback because it covers a lot of Unicode in a single file.
|
114
110
|
// This is also the fallback font on Windows and macOS.
|
115
|
-
static const
|
116
|
-
if (arial_unicode)
|
111
|
+
static const std::uint8_t* arial_unicode = ttf_data_by_name("Arial Unicode MS", 0);
|
112
|
+
if (arial_unicode) {
|
113
|
+
return arial_unicode;
|
114
|
+
}
|
117
115
|
|
118
116
|
// DejaVu has at least some Unicode coverage (though no CJK).
|
119
|
-
static const
|
120
|
-
if (deja_vu)
|
117
|
+
static const std::uint8_t* deja_vu = ttf_data_by_name("DejaVu", 0);
|
118
|
+
if (deja_vu) {
|
119
|
+
return deja_vu;
|
120
|
+
}
|
121
121
|
|
122
122
|
// Unifont has pretty good Unicode coverage, but looks extremely ugly.
|
123
|
-
static const
|
124
|
-
if (unifont)
|
123
|
+
static const std::uint8_t* unifont = ttf_data_by_name("Unifont", 0);
|
124
|
+
if (unifont) {
|
125
|
+
return unifont;
|
126
|
+
}
|
125
127
|
|
126
128
|
// If none of the fonts above work, try to use the default sans-serif font.
|
127
|
-
static const
|
128
|
-
if (default_font)
|
129
|
+
static const std::uint8_t* default_font = ttf_data_of_default_sans_serif_font();
|
130
|
+
if (default_font) {
|
131
|
+
return default_font;
|
132
|
+
}
|
129
133
|
|
130
134
|
// If nothing else works, try to load a file from this hardcoded path.
|
131
135
|
return ttf_data_from_file("/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf");
|