gosu 0.13.3 → 0.14.0.pre2
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/Audio.hpp +15 -11
- data/Gosu/Font.hpp +24 -20
- data/Gosu/Fwd.hpp +1 -1
- data/Gosu/Graphics.hpp +8 -9
- data/Gosu/ImageData.hpp +1 -1
- data/Gosu/Input.hpp +1 -1
- data/Gosu/Math.hpp +0 -18
- data/Gosu/Text.hpp +22 -30
- data/Gosu/TextInput.hpp +13 -0
- data/Gosu/Utility.hpp +2 -0
- data/Gosu/Window.hpp +3 -3
- data/README.md +3 -4
- data/ext/gosu/extconf.rb +7 -9
- data/lib/gosu/swig_patches.rb +1 -4
- data/rdoc/gosu.rb +34 -9
- data/src/Audio.cpp +6 -6
- data/src/AudioImpl.cpp +2 -2
- data/src/Bitmap.cpp +1 -2
- data/src/BitmapIO.cpp +21 -2
- data/src/BlockAllocator.cpp +1 -1
- data/src/Channel.cpp +7 -1
- data/src/ClipRectStack.hpp +4 -1
- data/src/Color.cpp +2 -1
- data/src/DirectoriesWin.cpp +1 -1
- data/src/DrawOp.hpp +8 -4
- data/src/DrawOpQueue.hpp +13 -24
- data/src/FileUnix.cpp +3 -1
- data/src/Font.cpp +92 -96
- data/src/GosuGLView.cpp +59 -31
- data/src/GosuGLView.hpp +14 -0
- data/src/GosuViewController.cpp +21 -21
- data/src/{GosuViewController.h → GosuViewController.hpp} +2 -4
- data/src/Graphics.cpp +71 -38
- data/src/GraphicsImpl.hpp +12 -29
- data/src/Image.cpp +5 -7
- data/src/Input.cpp +7 -5
- data/src/InputUIKit.cpp +19 -37
- data/src/Macro.cpp +10 -2
- data/src/MarkupParser.cpp +241 -0
- data/src/MarkupParser.hpp +61 -0
- data/src/Math.cpp +1 -1
- data/src/OffScreenTarget.cpp +99 -0
- data/src/OffScreenTarget.hpp +23 -0
- data/src/OggFile.hpp +10 -0
- data/src/RenderState.hpp +0 -2
- data/src/Resolution.cpp +2 -2
- data/src/RubyGosu.cxx +457 -244
- data/src/TexChunk.cpp +8 -6
- data/src/Text.cpp +58 -345
- data/src/TextBuilder.cpp +138 -0
- data/src/TextBuilder.hpp +55 -0
- data/src/TextInput.cpp +27 -10
- data/src/Texture.cpp +22 -17
- data/src/Texture.hpp +19 -20
- data/src/TimingApple.cpp +5 -7
- data/src/TimingUnix.cpp +1 -4
- data/src/TimingWin.cpp +4 -1
- data/src/TrueTypeFont.cpp +282 -0
- data/src/TrueTypeFont.hpp +66 -0
- data/src/TrueTypeFontApple.cpp +65 -0
- data/src/TrueTypeFontUnix.cpp +91 -0
- data/src/TrueTypeFontWin.cpp +82 -0
- data/src/Utility.cpp +40 -0
- data/src/Window.cpp +7 -6
- data/src/WindowUIKit.cpp +9 -4
- data/src/stb_truetype.h +4589 -0
- data/src/utf8proc.c +755 -0
- data/src/utf8proc.h +699 -0
- data/src/utf8proc_data.h +14386 -0
- metadata +23 -16
- data/src/FormattedString.cpp +0 -237
- data/src/FormattedString.hpp +0 -47
- data/src/GosuAppDelegate.cpp +0 -30
- data/src/GosuAppDelegate.h +0 -8
- data/src/GosuGLView.h +0 -8
- data/src/TextApple.cpp +0 -212
- data/src/TextTTFWin.cpp +0 -197
- data/src/TextUnix.cpp +0 -280
- data/src/TextWin.cpp +0 -191
data/src/TexChunk.cpp
CHANGED
@@ -3,21 +3,23 @@
|
|
3
3
|
#include "Texture.hpp"
|
4
4
|
#include <Gosu/Bitmap.hpp>
|
5
5
|
#include <Gosu/Graphics.hpp>
|
6
|
+
#include <stdexcept>
|
7
|
+
|
6
8
|
using namespace std;
|
7
9
|
|
8
10
|
void Gosu::TexChunk::set_tex_info()
|
9
11
|
{
|
10
|
-
double
|
12
|
+
double width = texture->width(), height = texture->height();
|
11
13
|
|
12
14
|
info.tex_name = texture->tex_name();
|
13
|
-
info.left = x /
|
14
|
-
info.top = y /
|
15
|
-
info.right = (x + w) /
|
16
|
-
info.bottom = (y + h) /
|
15
|
+
info.left = x / width;
|
16
|
+
info.top = y / height;
|
17
|
+
info.right = (x + w) / width;
|
18
|
+
info.bottom = (y + h) / height;
|
17
19
|
}
|
18
20
|
|
19
21
|
Gosu::TexChunk::TexChunk(shared_ptr<Texture> texture, int x, int y, int w, int h, int padding)
|
20
|
-
: texture(texture), x(x), y(y), w(w), h(h), padding(padding)
|
22
|
+
: texture(move(texture)), x(x), y(y), w(w), h(h), padding(padding)
|
21
23
|
{
|
22
24
|
set_tex_info();
|
23
25
|
}
|
data/src/Text.cpp
CHANGED
@@ -1,371 +1,84 @@
|
|
1
|
-
#include "
|
1
|
+
#include "MarkupParser.hpp"
|
2
|
+
#include "TextBuilder.hpp"
|
2
3
|
#include "GraphicsImpl.hpp"
|
3
|
-
#include
|
4
|
-
#include <Gosu/Graphics.hpp>
|
5
|
-
#include <Gosu/Image.hpp>
|
6
|
-
#include <Gosu/Math.hpp>
|
4
|
+
#include "TrueTypeFont.hpp"
|
7
5
|
#include <Gosu/Text.hpp>
|
8
|
-
#include <Gosu/Utility.hpp>
|
9
6
|
#include <cassert>
|
10
7
|
#include <cmath>
|
11
8
|
#include <algorithm>
|
12
|
-
#include <map>
|
13
9
|
#include <vector>
|
14
10
|
using namespace std;
|
15
11
|
|
16
|
-
|
12
|
+
double Gosu::text_width(const u32string& text,
|
13
|
+
const string& font_name, double font_height, unsigned font_flags)
|
17
14
|
{
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
// of the cases.
|
22
|
-
bool is_breaking_asian_glyph(wchar_t ch)
|
23
|
-
{
|
24
|
-
return (ch >= 0x3040 && ch <= 0x3096) || // Hiragana
|
25
|
-
(ch >= 0x30a0 && ch <= 0x30fa) || // Katakana
|
26
|
-
(ch >= 0x4e00 && ch <= 0x9fff) || // CJK Unfied Ideographs
|
27
|
-
(ch >= 0x3400 && ch <= 0x4db5); // CJK Unified Ideographs Extension A
|
28
|
-
}
|
29
|
-
|
30
|
-
struct WordInfo
|
31
|
-
{
|
32
|
-
FormattedString text;
|
33
|
-
unsigned width;
|
34
|
-
unsigned space_width;
|
35
|
-
};
|
36
|
-
typedef vector<WordInfo> Words;
|
37
|
-
|
38
|
-
// Local helper class which manages building the bitmap from the
|
39
|
-
// collected words.
|
40
|
-
class TextBlockBuilder
|
41
|
-
{
|
42
|
-
Bitmap bmp;
|
43
|
-
unsigned used_lines, allocated_lines;
|
44
|
-
|
45
|
-
string font_name;
|
46
|
-
unsigned font_height;
|
47
|
-
int line_spacing;
|
48
|
-
Alignment align;
|
49
|
-
|
50
|
-
unsigned space_width_;
|
51
|
-
|
52
|
-
void alloc_next_line()
|
53
|
-
{
|
54
|
-
++used_lines;
|
55
|
-
if (used_lines == allocated_lines) {
|
56
|
-
allocated_lines += 10;
|
57
|
-
bmp.resize(bmp.width(),
|
58
|
-
font_height * allocated_lines + line_spacing * (allocated_lines - 1),
|
59
|
-
0x00ffffff);
|
60
|
-
}
|
61
|
-
}
|
62
|
-
|
63
|
-
public:
|
64
|
-
TextBlockBuilder(const string& font_name, unsigned font_height, int line_spacing,
|
65
|
-
unsigned width, Alignment align)
|
66
|
-
{
|
67
|
-
used_lines = 0;
|
68
|
-
allocated_lines = 10;
|
69
|
-
|
70
|
-
bmp.resize(width, (line_spacing + font_height) * allocated_lines, 0x00ffffff);
|
71
|
-
|
72
|
-
this->font_name = font_name;
|
73
|
-
this->font_height = font_height;
|
74
|
-
this->line_spacing = line_spacing;
|
75
|
-
this->align = align;
|
76
|
-
|
77
|
-
space_width_ = text_width(FormattedString(L" ", 0));
|
78
|
-
}
|
79
|
-
|
80
|
-
unsigned width() const
|
81
|
-
{
|
82
|
-
return bmp.width();
|
83
|
-
}
|
84
|
-
|
85
|
-
unsigned text_width(const FormattedString& text) const
|
86
|
-
{
|
87
|
-
if (text.length() == 0) {
|
88
|
-
return 0;
|
89
|
-
}
|
90
|
-
|
91
|
-
if (text.entity_at(0)) {
|
92
|
-
return entity_bitmap(text.entity_at(0)).width();
|
93
|
-
}
|
94
|
-
|
95
|
-
vector<FormattedString> parts = text.split_parts();
|
96
|
-
unsigned result = 0;
|
97
|
-
for (auto& part : parts) {
|
98
|
-
string text = wstring_to_utf8(part.unformat());
|
99
|
-
result += Gosu::text_width(text, font_name, font_height, part.flags_at(0));
|
100
|
-
}
|
101
|
-
return result;
|
102
|
-
}
|
103
|
-
|
104
|
-
void add_line(Words::const_iterator begin, Words::const_iterator end,
|
105
|
-
unsigned words_width, bool override_align)
|
106
|
-
{
|
107
|
-
alloc_next_line();
|
108
|
-
|
109
|
-
auto words = end - begin;
|
110
|
-
|
111
|
-
unsigned total_spacing = 0;
|
112
|
-
if (begin < end) {
|
113
|
-
for (auto i = begin; i != end - 1; ++i) {
|
114
|
-
total_spacing += i->space_width;
|
115
|
-
}
|
116
|
-
}
|
117
|
-
|
118
|
-
// Where does the line start? (y)
|
119
|
-
int top = (used_lines - 1) * (font_height + line_spacing);
|
120
|
-
|
121
|
-
// Where does the line start? (x)
|
122
|
-
int pos;
|
123
|
-
switch (align) {
|
124
|
-
// Start so that the text touches the right border.
|
125
|
-
case AL_RIGHT:
|
126
|
-
pos = bmp.width() - words_width - total_spacing;
|
127
|
-
break;
|
128
|
-
|
129
|
-
// Start so that the text is centered.
|
130
|
-
case AL_CENTER:
|
131
|
-
pos = bmp.width() - words_width - total_spacing;
|
132
|
-
pos /= 2;
|
133
|
-
break;
|
134
|
-
|
135
|
-
// Just start at the left border.
|
136
|
-
default:
|
137
|
-
pos = 0;
|
138
|
-
}
|
139
|
-
|
140
|
-
for (auto cur = begin; cur != end; ++cur) {
|
141
|
-
vector<FormattedString> parts = cur->text.split_parts();
|
142
|
-
int x = 0;
|
143
|
-
for (auto& part : parts) {
|
144
|
-
if (part.entity_at(0)) {
|
145
|
-
Gosu::Bitmap entity = entity_bitmap(part.entity_at(0));
|
146
|
-
multiply_bitmap_alpha(entity, part.color_at(0).alpha());
|
147
|
-
bmp.insert(entity, pos + x, top);
|
148
|
-
x += entity.width();
|
149
|
-
continue;
|
150
|
-
}
|
151
|
-
|
152
|
-
string unformatted_part = wstring_to_utf8(part.unformat());
|
153
|
-
draw_text(bmp, unformatted_part, pos + x, top,
|
154
|
-
part.color_at(0), font_name, font_height, part.flags_at(0));
|
155
|
-
|
156
|
-
x += Gosu::text_width(unformatted_part, font_name, font_height,
|
157
|
-
part.flags_at(0));
|
158
|
-
}
|
159
|
-
|
160
|
-
if (align == AL_JUSTIFY && !override_align) {
|
161
|
-
pos += cur->width + 1.0 * (width() - words_width) / (words - 1);
|
162
|
-
}
|
163
|
-
else {
|
164
|
-
pos += cur->width + cur->space_width;
|
165
|
-
}
|
166
|
-
}
|
167
|
-
}
|
168
|
-
|
169
|
-
void add_empty_line()
|
170
|
-
{
|
171
|
-
alloc_next_line();
|
172
|
-
}
|
173
|
-
|
174
|
-
Bitmap result() const
|
175
|
-
{
|
176
|
-
Bitmap result = bmp;
|
177
|
-
result.resize(result.width(),
|
178
|
-
font_height * used_lines + line_spacing * (used_lines - 1),
|
179
|
-
0x00ffffff);
|
180
|
-
return result;
|
181
|
-
}
|
182
|
-
|
183
|
-
unsigned space_width() const
|
184
|
-
{
|
185
|
-
return space_width_;
|
186
|
-
}
|
187
|
-
};
|
188
|
-
|
189
|
-
void process_words(TextBlockBuilder& builder, const Words& words)
|
190
|
-
{
|
191
|
-
if (words.empty()) return builder.add_empty_line();
|
192
|
-
|
193
|
-
// Index into words to the first word in the current line.
|
194
|
-
auto line_begin = words.begin();
|
195
|
-
|
196
|
-
// Used width, in pixels, of the words [line_begin..w[.
|
197
|
-
unsigned words_width = 0;
|
198
|
-
|
199
|
-
// Used width of the spaces between (w-line_begin) words.
|
200
|
-
unsigned spaces_width = 0;
|
201
|
-
|
202
|
-
for (auto w = words.begin(); w != words.end(); ++w) {
|
203
|
-
unsigned new_words_width = words_width + w->width;
|
204
|
-
|
205
|
-
if (new_words_width + spaces_width <= builder.width()) {
|
206
|
-
// There's enough space for the words [line_begin..w] plus
|
207
|
-
// the spaces between them: Proceed with the next word.
|
208
|
-
words_width = new_words_width;
|
209
|
-
spaces_width += w->space_width;
|
210
|
-
}
|
211
|
-
else {
|
212
|
-
// No, this word wouldn't fit into the current line: Draw
|
213
|
-
// the current line, then start a new line with the current
|
214
|
-
// word.
|
215
|
-
builder.add_line(line_begin, w, words_width, false);
|
216
|
-
|
217
|
-
line_begin = w;
|
218
|
-
words_width = w->width;
|
219
|
-
spaces_width = w->space_width;
|
220
|
-
}
|
221
|
-
}
|
222
|
-
|
223
|
-
// Draw the last line as well.
|
224
|
-
if (words.empty() || line_begin != words.end()) {
|
225
|
-
builder.add_line(line_begin, words.end(), words_width, true);
|
226
|
-
}
|
227
|
-
}
|
228
|
-
|
229
|
-
void process_paragraph(TextBlockBuilder& builder, const FormattedString& paragraph)
|
230
|
-
{
|
231
|
-
Words collected_words;
|
232
|
-
|
233
|
-
unsigned begin_of_word = 0;
|
234
|
-
|
235
|
-
for (unsigned cur = 0; cur < paragraph.length(); ++cur) {
|
236
|
-
WordInfo new_word;
|
237
|
-
|
238
|
-
if (paragraph.char_at(cur) == L' ') {
|
239
|
-
// Whitespace:
|
240
|
-
// Add last word to list if existent
|
241
|
-
if (begin_of_word != cur) {
|
242
|
-
new_word.text = paragraph.range(begin_of_word, cur);
|
243
|
-
new_word.width = builder.text_width(new_word.text);
|
244
|
-
new_word.space_width = builder.space_width();
|
245
|
-
collected_words.push_back(new_word);
|
246
|
-
}
|
247
|
-
begin_of_word = cur + 1;
|
248
|
-
}
|
249
|
-
else if (is_breaking_asian_glyph(paragraph.char_at(cur))) {
|
250
|
-
// Asian glyph (treat as single word):
|
251
|
-
// Add last word to list if existent
|
252
|
-
if (begin_of_word != cur) {
|
253
|
-
new_word.text = paragraph.range(begin_of_word, cur);
|
254
|
-
new_word.width = builder.text_width(new_word.text);
|
255
|
-
new_word.space_width = 0;
|
256
|
-
collected_words.push_back(new_word);
|
257
|
-
}
|
258
|
-
// Add glyph as a single "word"
|
259
|
-
new_word.text = paragraph.range(cur, cur + 1);
|
260
|
-
new_word.width = builder.text_width(new_word.text);
|
261
|
-
new_word.space_width = 0;
|
262
|
-
collected_words.push_back(new_word);
|
263
|
-
begin_of_word = cur + 1;
|
264
|
-
}
|
265
|
-
}
|
266
|
-
if (begin_of_word < paragraph.length()) {
|
267
|
-
WordInfo last_word;
|
268
|
-
last_word.text = paragraph.range(begin_of_word, paragraph.length());
|
269
|
-
last_word.width = builder.text_width(last_word.text);
|
270
|
-
last_word.space_width = 0;
|
271
|
-
collected_words.push_back(last_word);
|
272
|
-
}
|
273
|
-
|
274
|
-
process_words(builder, collected_words);
|
275
|
-
}
|
15
|
+
auto& font = font_by_name(font_name, font_flags);
|
16
|
+
return font.draw_text(text, font_height, nullptr, 0, 0, Gosu::Color::NONE);
|
17
|
+
}
|
276
18
|
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
}
|
283
|
-
}
|
284
|
-
}
|
19
|
+
double Gosu::draw_text(Bitmap& bitmap, double x, double y, Color c, const u32string& text,
|
20
|
+
const string& font_name, double font_height, unsigned font_flags)
|
21
|
+
{
|
22
|
+
auto& font = font_by_name(font_name, font_flags);
|
23
|
+
return font.draw_text(text, font_height, &bitmap, x, y, c);
|
285
24
|
}
|
286
25
|
|
287
|
-
Gosu::Bitmap Gosu::create_text(const string& text, const string& font_name,
|
288
|
-
|
26
|
+
Gosu::Bitmap Gosu::create_text(const string& text, const string& font_name, double font_height,
|
27
|
+
double line_spacing, int width, Alignment align, unsigned font_flags)
|
289
28
|
{
|
290
|
-
if (
|
291
|
-
|
292
|
-
|
29
|
+
if (font_height <= 0) throw invalid_argument("font_height must be > 0");
|
30
|
+
if (width <= 0) throw invalid_argument("width must be > 0");
|
31
|
+
if (line_spacing < -font_height) throw invalid_argument("line_spacing must be ≥ -font_height");
|
293
32
|
|
294
|
-
|
295
|
-
FormattedString fs(wtext.c_str(), font_flags);
|
296
|
-
if (fs.length() == 0) {
|
297
|
-
return Bitmap(width, font_height);
|
298
|
-
}
|
33
|
+
TextBuilder text_builder(font_name, font_height, line_spacing, width, align);
|
299
34
|
|
300
|
-
//
|
301
|
-
//
|
302
|
-
|
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();
|
303
40
|
|
304
|
-
|
305
|
-
process_text(builder, fs);
|
306
|
-
|
307
|
-
// Done!
|
308
|
-
return builder.result();
|
41
|
+
return text_builder.move_into_bitmap();
|
309
42
|
}
|
310
43
|
|
311
|
-
|
312
|
-
|
313
|
-
unsigned font_flags)
|
44
|
+
Gosu::Bitmap Gosu::create_text(const string& text, const string& font_name, double font_height,
|
45
|
+
unsigned font_flags)
|
314
46
|
{
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
47
|
+
if (font_height <= 0) throw invalid_argument("font_height must be > 0");
|
48
|
+
|
49
|
+
vector<vector<FormattedString>> lines;
|
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();
|
320
60
|
|
321
|
-
|
61
|
+
// Measure every part of every line.
|
62
|
+
int width = 0;
|
63
|
+
for (auto& line : lines) {
|
64
|
+
int line_width = 0;
|
65
|
+
for (auto& part : line) {
|
66
|
+
line_width += text_width(part.text, font_name, font_height, part.flags);
|
67
|
+
}
|
68
|
+
width = max(width, line_width);
|
69
|
+
}
|
322
70
|
|
323
|
-
Bitmap
|
71
|
+
Bitmap result(width, static_cast<int>(ceil(lines.size() * font_height)));
|
324
72
|
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
if (part.length() == 1 && part.entity_at(0)) {
|
332
|
-
Gosu::Bitmap entity = entity_bitmap(part.entity_at(0));
|
333
|
-
multiply_bitmap_alpha(entity, part.color_at(0).alpha());
|
334
|
-
bmp.resize(max(bmp.width(), x + entity.width()), bmp.height(), 0x00ffffff);
|
335
|
-
bmp.insert(entity, x, i * font_height);
|
336
|
-
x += entity.width();
|
337
|
-
continue;
|
338
|
-
}
|
339
|
-
|
340
|
-
assert (part.length() > 0);
|
341
|
-
string unformatted_text = wstring_to_utf8(part.unformat());
|
342
|
-
unsigned part_width = text_width(unformatted_text, font_name, font_height,
|
343
|
-
part.flags_at(0));
|
344
|
-
bmp.resize(max(bmp.width(), x + part_width), bmp.height(), 0x00ffffff);
|
345
|
-
draw_text(bmp, unformatted_text, x, i * font_height, part.color_at(0), font_name,
|
346
|
-
font_height, part.flags_at(0));
|
347
|
-
x += part_width;
|
73
|
+
// Render every part of every line.
|
74
|
+
int y = 0;
|
75
|
+
for (auto& line : lines) {
|
76
|
+
int x = 0;
|
77
|
+
for (auto& part : line) {
|
78
|
+
x += draw_text(result, x, y, part.color, part.text, font_name, font_height);
|
348
79
|
}
|
80
|
+
y += font_height;
|
349
81
|
}
|
350
82
|
|
351
|
-
return
|
352
|
-
}
|
353
|
-
|
354
|
-
static map<string, shared_ptr<Gosu::Bitmap>> entities;
|
355
|
-
|
356
|
-
void Gosu::register_entity(const string& name, const Gosu::Bitmap& replacement)
|
357
|
-
{
|
358
|
-
entities[name].reset(new Bitmap(replacement));
|
359
|
-
}
|
360
|
-
|
361
|
-
bool Gosu::is_entity(const string& name)
|
362
|
-
{
|
363
|
-
return entities[name].get();
|
364
|
-
}
|
365
|
-
|
366
|
-
const Gosu::Bitmap& Gosu::entity_bitmap(const string& name)
|
367
|
-
{
|
368
|
-
shared_ptr<Gosu::Bitmap>& ptr = entities[name];
|
369
|
-
if (!ptr) throw runtime_error("Unknown entity: " + name);
|
370
|
-
return *ptr;
|
83
|
+
return result;
|
371
84
|
}
|