gosu 0.14.0.pre2 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gosu/Bitmap.hpp +4 -0
- data/Gosu/Font.hpp +29 -34
- data/Gosu/Text.hpp +19 -8
- data/Gosu/Utility.hpp +0 -5
- data/Gosu/Version.hpp +2 -2
- data/Gosu/Window.hpp +23 -16
- data/lib/gosu/compat.rb +17 -4
- data/lib/gosu/patches.rb +16 -0
- data/rdoc/gosu.rb +33 -9
- data/src/Bitmap.cpp +20 -0
- data/src/DirectoriesWin.cpp +3 -3
- data/src/DrawOpQueue.hpp +2 -1
- data/src/FileWin.cpp +87 -87
- data/src/Font.cpp +51 -31
- data/src/Graphics.cpp +1 -1
- data/src/GraphicsImpl.hpp +19 -0
- data/src/Input.cpp +30 -12
- data/src/MarkupParser.cpp +11 -8
- data/src/MarkupParser.hpp +2 -2
- data/src/Resolution.cpp +81 -50
- data/src/RubyGosu.cxx +285 -480
- data/src/Text.cpp +77 -50
- data/src/TextBuilder.cpp +1 -1
- data/src/TimingUnix.cpp +1 -1
- data/src/TrueTypeFont.cpp +26 -27
- data/src/TrueTypeFont.hpp +2 -1
- data/src/TrueTypeFontUnix.cpp +1 -1
- data/src/TrueTypeFontWin.cpp +4 -4
- data/src/Utility.cpp +0 -54
- data/src/UtilityApple.cpp +0 -35
- data/src/WinUtility.cpp +60 -41
- data/src/WinUtility.hpp +5 -0
- data/src/Window.cpp +19 -7
- data/src/WindowUIKit.cpp +26 -30
- metadata +4 -5
- data/src/ResolutionApple.cpp +0 -25
data/src/Text.cpp
CHANGED
@@ -12,6 +12,9 @@ using namespace std;
|
|
12
12
|
double Gosu::text_width(const u32string& text,
|
13
13
|
const string& font_name, double font_height, unsigned font_flags)
|
14
14
|
{
|
15
|
+
if (font_height <= 0) throw invalid_argument("font_height must be > 0");
|
16
|
+
if (font_flags >= FF_COMBINATIONS) throw invalid_argument("Invalid font_flags");
|
17
|
+
|
15
18
|
auto& font = font_by_name(font_name, font_flags);
|
16
19
|
return font.draw_text(text, font_height, nullptr, 0, 0, Gosu::Color::NONE);
|
17
20
|
}
|
@@ -19,66 +22,90 @@ double Gosu::text_width(const u32string& text,
|
|
19
22
|
double Gosu::draw_text(Bitmap& bitmap, double x, double y, Color c, const u32string& text,
|
20
23
|
const string& font_name, double font_height, unsigned font_flags)
|
21
24
|
{
|
25
|
+
if (font_height <= 0) throw invalid_argument("font_height must be > 0");
|
26
|
+
if (font_flags >= FF_COMBINATIONS) throw invalid_argument("Invalid font_flags");
|
27
|
+
|
22
28
|
auto& font = font_by_name(font_name, font_flags);
|
23
29
|
return font.draw_text(text, font_height, &bitmap, x, y, c);
|
24
30
|
}
|
25
31
|
|
26
|
-
Gosu::Bitmap Gosu::
|
27
|
-
double
|
32
|
+
Gosu::Bitmap Gosu::layout_text(const string& text, const string& font_name,
|
33
|
+
double font_height, double line_spacing,
|
34
|
+
int width, Alignment align, unsigned font_flags)
|
28
35
|
{
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
TextBuilder text_builder(font_name, font_height, line_spacing, width, align);
|
34
|
-
|
35
|
-
// Feed all formatted substrings to the TextBuilder, which will construct the resulting bitmap.
|
36
|
-
// Split the input string into words here, because this method implements word-wrapping.
|
37
|
-
MarkupParser(text.c_str(), font_flags, true, [&text_builder](vector<FormattedString> word) {
|
38
|
-
text_builder.feed_word(move(word));
|
39
|
-
}).parse();
|
40
|
-
|
41
|
-
return text_builder.move_into_bitmap();
|
36
|
+
return layout_markup(escape_markup(text), font_name,
|
37
|
+
font_height, line_spacing,
|
38
|
+
width, align, font_flags);
|
42
39
|
}
|
43
40
|
|
44
|
-
Gosu::Bitmap Gosu::
|
45
|
-
|
41
|
+
Gosu::Bitmap Gosu::layout_markup(const string& markup, const string& font_name,
|
42
|
+
double font_height, double line_spacing,
|
43
|
+
int width, Alignment align, unsigned font_flags)
|
46
44
|
{
|
47
|
-
if (font_height <= 0)
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
// Split the text into lines (split_words = false) since this method does not break lines.
|
52
|
-
MarkupParser(text.c_str(), font_flags, false, [&lines](vector<FormattedString>&& line) {
|
53
|
-
// Remove trailing \n characters from each line to avoid errors from Gosu::text_width().
|
54
|
-
if (line.back().text.back() == '\n') {
|
55
|
-
line.back().text.pop_back();
|
56
|
-
}
|
57
|
-
|
58
|
-
lines.emplace_back(line);
|
59
|
-
}).parse();
|
45
|
+
if (font_height <= 0) throw invalid_argument("font_height must be > 0");
|
46
|
+
if (line_spacing < -font_height) throw invalid_argument("line_spacing must be ≥ -font_height");
|
47
|
+
if (font_flags >= FF_COMBINATIONS) throw invalid_argument("Invalid font_flags");
|
60
48
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
49
|
+
if (width >= 0) {
|
50
|
+
TextBuilder text_builder(font_name, font_height, line_spacing, width, align);
|
51
|
+
|
52
|
+
// Feed all formatted substrings to the TextBuilder, which will construct the result.
|
53
|
+
// Split the input string into words, because this method implements word-wrapping.
|
54
|
+
MarkupParser parser(font_flags, true, [&text_builder](vector<FormattedString> word) {
|
55
|
+
text_builder.feed_word(move(word));
|
56
|
+
});
|
57
|
+
parser.parse(markup);
|
58
|
+
|
59
|
+
return text_builder.move_into_bitmap();
|
69
60
|
}
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
61
|
+
else {
|
62
|
+
vector<vector<FormattedString>> lines;
|
63
|
+
|
64
|
+
// Split the text into lines (split_words = false) since this method does not wrap lines.
|
65
|
+
MarkupParser parser(font_flags, false, [&lines](vector<FormattedString>&& line) {
|
66
|
+
// Remove trailing \n characters from each line to avoid errors from Gosu::text_width().
|
67
|
+
if (line.back().text.back() == '\n') {
|
68
|
+
line.back().text.pop_back();
|
69
|
+
}
|
70
|
+
|
71
|
+
lines.emplace_back(line);
|
72
|
+
});
|
73
|
+
parser.parse(markup);
|
74
|
+
|
75
|
+
if (lines.empty()) return Bitmap();
|
76
|
+
|
77
|
+
// Measure every part of every line.
|
78
|
+
vector<double> line_widths;
|
79
|
+
double max_width = 0;
|
80
|
+
for (auto& line : lines) {
|
81
|
+
line_widths.push_back(0);
|
82
|
+
for (auto& part : line) {
|
83
|
+
line_widths.back() += text_width(part.text, font_name, font_height, part.flags);
|
84
|
+
}
|
85
|
+
max_width = max(max_width, line_widths.back());
|
79
86
|
}
|
80
|
-
|
87
|
+
|
88
|
+
double height = lines.size() * font_height + (lines.size() - 1) * line_spacing;
|
89
|
+
Bitmap result(ceil(max_width), ceil(height));
|
90
|
+
|
91
|
+
// Render every part of every line.
|
92
|
+
double y = 0;
|
93
|
+
for (int i = 0; i < lines.size(); ++i) {
|
94
|
+
double x = 0;
|
95
|
+
if (align == AL_CENTER) {
|
96
|
+
x = (result.width() - line_widths[i]) / 2;
|
97
|
+
}
|
98
|
+
else if (align == AL_RIGHT) {
|
99
|
+
x = result.width() - line_widths[i];
|
100
|
+
}
|
101
|
+
|
102
|
+
for (auto& part : lines[i]) {
|
103
|
+
x = draw_text(result, x, y, part.color, part.text,
|
104
|
+
font_name, font_height, part.flags);
|
105
|
+
}
|
106
|
+
y += (font_height + line_spacing);
|
107
|
+
}
|
108
|
+
|
109
|
+
return result;
|
81
110
|
}
|
82
|
-
|
83
|
-
return result;
|
84
111
|
}
|
data/src/TextBuilder.cpp
CHANGED
@@ -21,7 +21,7 @@ Gosu::WordInfo::WordInfo(const string& font_name, double font_height, vector<For
|
|
21
21
|
|
22
22
|
width = 0;
|
23
23
|
for (const auto& part : parts) {
|
24
|
-
assert (! part.text.empty());
|
24
|
+
assert (is_end_of_line || ! part.text.empty());
|
25
25
|
|
26
26
|
width += text_width(part.text, font_name, font_height, part.flags);
|
27
27
|
}
|
data/src/TimingUnix.cpp
CHANGED
data/src/TrueTypeFont.cpp
CHANGED
@@ -70,16 +70,8 @@ struct Gosu::TrueTypeFont::Impl
|
|
70
70
|
// Missing characters often come in clusters, so build a substring of
|
71
71
|
// codepoints that this font doesn't contain and then defer to the fallback
|
72
72
|
// font.
|
73
|
-
u32string fallback_string;
|
74
|
-
|
75
|
-
auto codepoint = text[index];
|
76
|
-
// Skip control characters.
|
77
|
-
if (codepoint < ' ') continue;
|
78
|
-
// Stop as soon as a glyph is available in the current font.
|
79
|
-
if (stbtt_FindGlyphIndex(&info, codepoint) != 0) break;
|
80
|
-
|
81
|
-
fallback_string.push_back(codepoint);
|
82
|
-
}
|
73
|
+
u32string fallback_string = string_of_missing_glyphs(text, index);
|
74
|
+
index += fallback_string.length();
|
83
75
|
x = fallback->pimpl->draw_text(fallback_string, index == text.size(), height,
|
84
76
|
bitmap, x, y, c);
|
85
77
|
last_glyph = 0;
|
@@ -130,6 +122,21 @@ struct Gosu::TrueTypeFont::Impl
|
|
130
122
|
return max<double>(0, x);
|
131
123
|
}
|
132
124
|
|
125
|
+
u32string string_of_missing_glyphs(const u32string& text, u32string::size_type from_index)
|
126
|
+
{
|
127
|
+
u32string result;
|
128
|
+
|
129
|
+
for (u32string::size_type index = from_index; index < text.size(); ++index) {
|
130
|
+
auto codepoint = text[index];
|
131
|
+
// Stop as soon as a glyph (except control characters) is available in the current font.
|
132
|
+
if (codepoint >= ' ' && stbtt_FindGlyphIndex(&info, codepoint) != 0) break;
|
133
|
+
|
134
|
+
result.push_back(codepoint);
|
135
|
+
}
|
136
|
+
|
137
|
+
return result;
|
138
|
+
}
|
139
|
+
|
133
140
|
void draw_glyph(Bitmap& bitmap, double fx, double fy, Color c, int glyph, double scale)
|
134
141
|
{
|
135
142
|
int x = static_cast<int>(fx);
|
@@ -146,15 +153,13 @@ struct Gosu::TrueTypeFont::Impl
|
|
146
153
|
free(pixels);
|
147
154
|
}
|
148
155
|
|
149
|
-
// This implements the "over" alpha compositing operator, see:
|
150
|
-
// https://en.wikipedia.org/wiki/Alpha_compositing
|
151
156
|
void blend_into_bitmap(Bitmap& bitmap, const unsigned char* pixels, int x, int y, int w, int h,
|
152
157
|
Color c)
|
153
158
|
{
|
154
159
|
int stride = w;
|
155
160
|
|
156
161
|
// Instead of transferring all pixels in the range [0; w) x [0; h) into the bitmap, clip
|
157
|
-
// these values because Bitmap::
|
162
|
+
// these values because Bitmap::blend_pixel does not perform bounds checking.
|
158
163
|
|
159
164
|
int src_x = 0;
|
160
165
|
if (x < 0) {
|
@@ -175,18 +180,9 @@ struct Gosu::TrueTypeFont::Impl
|
|
175
180
|
|
176
181
|
for (int rel_y = 0; rel_y < h; ++rel_y) {
|
177
182
|
for (int rel_x = 0; rel_x < w; ++rel_x) {
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
if (src_alpha == 0) continue;
|
182
|
-
|
183
|
-
Color dest = bitmap.get_pixel(x + rel_x, y + rel_y);
|
184
|
-
dest.set_alpha(src_alpha + (dest.alpha() * inv_src_alpha) / 255);
|
185
|
-
dest.set_red ((c.red() * src_alpha + dest.red() * inv_src_alpha) / src_alpha);
|
186
|
-
dest.set_green((c.green() * src_alpha + dest.green() * inv_src_alpha) / src_alpha);
|
187
|
-
dest.set_blue ((c.blue() * src_alpha + dest.blue() * inv_src_alpha) / src_alpha);
|
188
|
-
|
189
|
-
bitmap.set_pixel(x + rel_x, y + rel_y, dest);
|
183
|
+
int pixel = pixels[(src_y + rel_y) * stride + src_x + rel_x];
|
184
|
+
Color c_with_alpha(pixel * c.alpha() / 255, c.red(), c.green(), c.blue());
|
185
|
+
bitmap.blend_pixel(x + rel_x, y + rel_y, c_with_alpha);
|
190
186
|
}
|
191
187
|
}
|
192
188
|
}
|
@@ -203,9 +199,12 @@ double Gosu::TrueTypeFont::draw_text(const u32string &text, double height,
|
|
203
199
|
return pimpl->draw_text(text, true, height, bitmap, x, y, c);
|
204
200
|
}
|
205
201
|
|
206
|
-
bool Gosu::TrueTypeFont::verify_font_name(const unsigned char* ttf_data, const string& font_name)
|
202
|
+
bool Gosu::TrueTypeFont::verify_font_name(const unsigned char* ttf_data, const string& font_name, unsigned font_flags)
|
207
203
|
{
|
208
|
-
|
204
|
+
// Gosu's FontFlags enum mostly uses the same values as the STBTT_ macros.
|
205
|
+
int flags = (font_flags == 0 ? STBTT_MACSTYLE_NONE : font_flags);
|
206
|
+
|
207
|
+
return stbtt_FindMatchingFont(ttf_data, font_name.c_str(), font_flags) >= 0 ||
|
209
208
|
stbtt_FindMatchingFont(ttf_data, font_name.c_str(), STBTT_MACSTYLE_DONTCARE) >= 0;
|
210
209
|
}
|
211
210
|
|
data/src/TrueTypeFont.hpp
CHANGED
@@ -25,7 +25,8 @@ namespace Gosu
|
|
25
25
|
Bitmap* bitmap, double x, double y, Color c);
|
26
26
|
|
27
27
|
//! Returns true if the supplied buffer seems to be a font of the given name.
|
28
|
-
static bool verify_font_name(const unsigned char* ttf_data,
|
28
|
+
static bool verify_font_name(const unsigned char* ttf_data,
|
29
|
+
const std::string& font_name, unsigned font_flags);
|
29
30
|
};
|
30
31
|
|
31
32
|
TrueTypeFont& font_by_name(const std::string& font_name, unsigned font_flags);
|
data/src/TrueTypeFontUnix.cpp
CHANGED
@@ -80,7 +80,7 @@ const unsigned char* Gosu::ttf_fallback_data()
|
|
80
80
|
static const unsigned char* unifont = ttf_data_by_name("Unifont", 0);
|
81
81
|
if (unifont) return unifont;
|
82
82
|
|
83
|
-
return ttf_data_from_file("/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf"
|
83
|
+
return ttf_data_from_file("/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf");
|
84
84
|
}
|
85
85
|
|
86
86
|
string Gosu::default_font_name()
|
data/src/TrueTypeFontWin.cpp
CHANGED
@@ -27,16 +27,16 @@ const unsigned char* Gosu::ttf_data_by_name(const string& font_name, unsigned fo
|
|
27
27
|
if (buffer_ptr) return static_cast<const unsigned char*>(buffer_ptr->data());
|
28
28
|
|
29
29
|
LOGFONT logfont = {
|
30
|
-
|
30
|
+
0, 0, 0, 0,
|
31
31
|
(font_flags & Gosu::FF_BOLD) ? FW_BOLD : FW_NORMAL,
|
32
32
|
(font_flags & Gosu::FF_ITALIC) ? TRUE : FALSE,
|
33
33
|
(font_flags & Gosu::FF_UNDERLINE) ? TRUE : FALSE,
|
34
34
|
FALSE /* no strikethrough */,
|
35
|
-
|
35
|
+
ANSI_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
|
36
36
|
DEFAULT_PITCH | FF_DONTCARE
|
37
37
|
};
|
38
38
|
|
39
|
-
wstring wfont_name =
|
39
|
+
wstring wfont_name = utf8_to_utf16(font_name);
|
40
40
|
wcsncpy(logfont.lfFaceName, wfont_name.c_str(), LF_FACESIZE);
|
41
41
|
logfont.lfFaceName[LF_FACESIZE - 1] = 0;
|
42
42
|
|
@@ -49,7 +49,7 @@ const unsigned char* Gosu::ttf_data_by_name(const string& font_name, unsigned fo
|
|
49
49
|
buffer->resize(ttf_buffer_size);
|
50
50
|
if (GetFontData(hdc, 0, 0, buffer->data(), buffer->size()) != GDI_ERROR) {
|
51
51
|
auto data = static_cast<const unsigned char*>(buffer->data());
|
52
|
-
if (TrueTypeFont::verify_font_name(data, font_name)) {
|
52
|
+
if (TrueTypeFont::verify_font_name(data, font_name, font_flags)) {
|
53
53
|
buffer_ptr = buffer;
|
54
54
|
}
|
55
55
|
}
|
data/src/Utility.cpp
CHANGED
@@ -3,64 +3,10 @@
|
|
3
3
|
|
4
4
|
#include "utf8proc.h"
|
5
5
|
|
6
|
-
#include <cstddef>
|
7
|
-
#include <cstdlib>
|
8
6
|
#include <cstring>
|
9
|
-
#include <cwchar>
|
10
|
-
#include <cwctype>
|
11
|
-
#include <algorithm>
|
12
7
|
#include <stdexcept>
|
13
|
-
#include <vector>
|
14
8
|
using namespace std;
|
15
9
|
|
16
|
-
#ifndef GOSU_IS_IPHONE
|
17
|
-
|
18
|
-
#ifndef GOSU_IS_WIN
|
19
|
-
#include "Iconv.hpp"
|
20
|
-
#endif
|
21
|
-
using namespace std;
|
22
|
-
|
23
|
-
#ifndef GOSU_IS_WIN
|
24
|
-
namespace
|
25
|
-
{
|
26
|
-
extern const char UTF_8[] = "UTF-8";
|
27
|
-
#ifdef __BIG_ENDIAN__
|
28
|
-
extern const char UCS_4_INTERNAL[] = "UCS-4BE";
|
29
|
-
#else
|
30
|
-
extern const char UCS_4_INTERNAL[] = "UCS-4LE";
|
31
|
-
#endif
|
32
|
-
}
|
33
|
-
|
34
|
-
wstring Gosu::utf8_to_wstring(const string& s)
|
35
|
-
{
|
36
|
-
return iconvert<wstring, UCS_4_INTERNAL, UTF_8>(s);
|
37
|
-
}
|
38
|
-
string Gosu::wstring_to_utf8(const wstring& ws)
|
39
|
-
{
|
40
|
-
return iconvert<string, UTF_8, UCS_4_INTERNAL>(ws);
|
41
|
-
}
|
42
|
-
|
43
|
-
#else
|
44
|
-
#ifndef NOMINMAX
|
45
|
-
#define NOMINMAX
|
46
|
-
#endif
|
47
|
-
#include <windows.h>
|
48
|
-
wstring Gosu::utf8_to_wstring(const string& utf8)
|
49
|
-
{
|
50
|
-
vector<wchar_t> buffer(utf8.size() + 1);
|
51
|
-
MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), utf8.size() + 1, &buffer[0], buffer.size());
|
52
|
-
return &buffer[0];
|
53
|
-
}
|
54
|
-
string Gosu::wstring_to_utf8(const wstring& ws)
|
55
|
-
{
|
56
|
-
unsigned size = WideCharToMultiByte(CP_UTF8, 0, ws.c_str(), ws.size(), 0, 0, 0, 0);
|
57
|
-
vector<char> buffer(size + 1);
|
58
|
-
WideCharToMultiByte(CP_UTF8, 0, ws.c_str(), ws.size(), &buffer[0], buffer.size(), 0, 0);
|
59
|
-
return &buffer[0];
|
60
|
-
}
|
61
|
-
#endif
|
62
|
-
#endif
|
63
|
-
|
64
10
|
u32string Gosu::utf8_to_composed_utc4(const string& utf8)
|
65
11
|
{
|
66
12
|
u32string utc4;
|
data/src/UtilityApple.cpp
CHANGED
@@ -3,43 +3,8 @@
|
|
3
3
|
|
4
4
|
#import <Gosu/Utility.hpp>
|
5
5
|
#import <Foundation/Foundation.h>
|
6
|
-
#import <stdexcept>
|
7
|
-
#import <vector>
|
8
6
|
using namespace std;
|
9
7
|
|
10
|
-
#ifdef GOSU_IS_IPHONE
|
11
|
-
wstring Gosu::utf8_to_wstring(const string& s)
|
12
|
-
{
|
13
|
-
if (s.empty()) return wstring();
|
14
|
-
|
15
|
-
NSString* string = [NSString stringWithUTF8String:s.c_str()];
|
16
|
-
vector<wchar_t> buffer(s.size());
|
17
|
-
NSUInteger buffer_size;
|
18
|
-
if (![string getBytes:&buffer[0]
|
19
|
-
maxLength:buffer.size() * sizeof(wchar_t)
|
20
|
-
usedLength:&buffer_size
|
21
|
-
encoding:NSUTF32LittleEndianStringEncoding
|
22
|
-
options:0
|
23
|
-
range:NSMakeRange(0, string.length)
|
24
|
-
remainingRange:nullptr]) {
|
25
|
-
throw runtime_error("String " + s + " could not be converted to UTF-32");
|
26
|
-
}
|
27
|
-
return wstring(&buffer[0], &buffer[0] + buffer_size / sizeof(wchar_t));
|
28
|
-
}
|
29
|
-
|
30
|
-
string Gosu::wstring_to_utf8(const wstring& ws)
|
31
|
-
{
|
32
|
-
if (ws.empty()) return string();
|
33
|
-
|
34
|
-
@autoreleasepool {
|
35
|
-
NSString* string = [[NSString alloc] initWithBytes:ws.data()
|
36
|
-
length:ws.size() * sizeof(wchar_t)
|
37
|
-
encoding:NSUTF32LittleEndianStringEncoding];
|
38
|
-
return string.UTF8String ?: "";
|
39
|
-
}
|
40
|
-
}
|
41
|
-
#endif
|
42
|
-
|
43
8
|
string Gosu::language()
|
44
9
|
{
|
45
10
|
@autoreleasepool {
|
data/src/WinUtility.cpp
CHANGED
@@ -1,42 +1,61 @@
|
|
1
|
-
#include <Gosu/Platform.hpp>
|
2
|
-
#if defined(GOSU_IS_WIN)
|
3
|
-
|
4
|
-
#include "WinUtility.hpp"
|
5
|
-
#include <Gosu/Utility.hpp>
|
6
|
-
#include <stdexcept>
|
1
|
+
#include <Gosu/Platform.hpp>
|
2
|
+
#if defined(GOSU_IS_WIN)
|
3
|
+
|
4
|
+
#include "WinUtility.hpp"
|
5
|
+
#include <Gosu/Utility.hpp>
|
6
|
+
#include <stdexcept>
|
7
7
|
#include <windows.h>
|
8
|
-
using namespace std;
|
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
|
-
|
8
|
+
using namespace std;
|
9
|
+
|
10
|
+
wstring Gosu::utf8_to_utf16(const string& utf8)
|
11
|
+
{
|
12
|
+
wstring utf16(utf8.size(), '\0');
|
13
|
+
auto len = MultiByteToWideChar(CP_UTF8, 0, utf8.data(), utf8.size(),
|
14
|
+
const_cast<wchar_t*>(utf16.data()), utf16.size());
|
15
|
+
utf16.resize(len);
|
16
|
+
return utf16;
|
17
|
+
}
|
18
|
+
|
19
|
+
string Gosu::utf16_to_utf8(const wstring& utf16)
|
20
|
+
{
|
21
|
+
auto len = WideCharToMultiByte(CP_UTF8, 0, utf16.c_str(), utf16.size(),
|
22
|
+
nullptr, 0, nullptr, nullptr);
|
23
|
+
string utf8(len, '\0');
|
24
|
+
WideCharToMultiByte(CP_UTF8, 0, utf16.c_str(), utf16.size(),
|
25
|
+
const_cast<char*>(utf8.data()), utf8.size(), nullptr, nullptr);
|
26
|
+
return utf8;
|
27
|
+
}
|
28
|
+
|
29
|
+
void Gosu::throw_last_winapi_error(const string& action)
|
30
|
+
{
|
31
|
+
// Obtain error message from Windows.
|
32
|
+
wchar_t* buffer;
|
33
|
+
|
34
|
+
if (!FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
35
|
+
FORMAT_MESSAGE_FROM_SYSTEM |
|
36
|
+
FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, GetLastError(),
|
37
|
+
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR) &buffer, 0, nullptr)
|
38
|
+
|| buffer == nullptr) {
|
39
|
+
throw runtime_error("Unknown error");
|
40
|
+
}
|
41
|
+
|
42
|
+
// Safely move the message into a string.
|
43
|
+
string message;
|
44
|
+
try {
|
45
|
+
message = utf16_to_utf8(buffer);
|
46
|
+
}
|
47
|
+
catch (...) {
|
48
|
+
LocalFree(buffer);
|
49
|
+
throw;
|
50
|
+
}
|
51
|
+
LocalFree(buffer);
|
52
|
+
|
53
|
+
// Optionally prepend the action.
|
54
|
+
if (!action.empty()) {
|
55
|
+
message = "While " + action + ", the following error occured: " + message;
|
56
|
+
}
|
57
|
+
|
58
|
+
throw runtime_error(message);
|
59
|
+
}
|
60
|
+
|
61
|
+
#endif
|