gosu 0.14.0.pre2 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|