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.
data/src/DrawOpQueue.hpp CHANGED
@@ -13,9 +13,10 @@
13
13
 
14
14
  class Gosu::DrawOpQueue
15
15
  {
16
+ const QueueMode queue_mode;
17
+
16
18
  TransformStack transform_stack;
17
19
  ClipRectStack clip_rect_stack;
18
- QueueMode queue_mode = QM_RENDER_TO_SCREEN;
19
20
 
20
21
  std::vector<DrawOp> ops;
21
22
  std::vector<std::function<void ()>> gl_blocks;
data/src/FileWin.cpp CHANGED
@@ -1,88 +1,88 @@
1
- #include <Gosu/Platform.hpp>
2
- #if defined(GOSU_IS_WIN)
3
-
4
- #include "WinUtility.hpp"
5
- #include <Gosu/IO.hpp>
6
- #include <Gosu/Utility.hpp>
1
+ #include <Gosu/Platform.hpp>
2
+ #if defined(GOSU_IS_WIN)
3
+
4
+ #include "WinUtility.hpp"
5
+ #include <Gosu/IO.hpp>
6
+ #include <Gosu/Utility.hpp>
7
7
  #include <windows.h>
8
- using namespace std;
9
-
10
- // TODO: Error checking
11
-
12
- struct Gosu::File::Impl
13
- {
14
- HANDLE handle = INVALID_HANDLE_VALUE;
15
-
16
- ~Impl()
17
- {
18
- if (handle != INVALID_HANDLE_VALUE) {
19
- CloseHandle(handle);
20
- }
21
- }
22
- };
23
-
24
- Gosu::File::File(const string& filename, FileMode mode)
25
- : pimpl(new Impl)
26
- {
27
- DWORD access;
28
- switch (mode) {
29
- case FM_READ:
30
- access = GENERIC_READ;
31
- break;
32
- case FM_REPLACE:
33
- access = GENERIC_WRITE;
34
- break;
35
- case FM_ALTER:
36
- access = GENERIC_READ | GENERIC_WRITE;
37
- break;
38
- }
39
- DWORD share_mode = FILE_SHARE_READ;
40
- DWORD creation_disp = (mode == FM_READ) ? OPEN_EXISTING : OPEN_ALWAYS;
41
-
42
- wstring wfilename = utf8_to_wstring(filename);
43
- pimpl->handle = CreateFileW(wfilename.c_str(), access, share_mode, 0, creation_disp,
44
- FILE_ATTRIBUTE_NORMAL, 0);
45
- if (pimpl->handle == INVALID_HANDLE_VALUE) {
46
- throw_last_winapi_error("opening " + filename);
47
- }
48
- if (mode == FM_REPLACE) {
49
- resize(0);
50
- }
51
- }
52
-
53
- Gosu::File::~File()
54
- {
55
- }
56
-
57
- size_t Gosu::File::size() const
58
- {
59
- return GetFileSize(pimpl->handle, 0);
60
- }
61
-
62
- void Gosu::File::resize(size_t new_size)
63
- {
64
- if (SetFilePointer(pimpl->handle, new_size, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
65
- throw_last_winapi_error("setting the file pointer");
66
- }
67
- winapi_check(SetEndOfFile(pimpl->handle), "resizing a file");
68
- }
69
-
70
- void Gosu::File::read(size_t offset, size_t length, void* dest_buffer) const
71
- {
72
- if (SetFilePointer(pimpl->handle, offset, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
73
- throw_last_winapi_error("setting the file pointer");
74
- }
75
- DWORD dummy;
76
- winapi_check(ReadFile(pimpl->handle, dest_buffer, length, &dummy, 0));
77
- }
78
-
79
- void Gosu::File::write(size_t offset, size_t length, const void* source_buffer)
80
- {
81
- if (SetFilePointer(pimpl->handle, offset, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
82
- throw_last_winapi_error("setting the file pointer");
83
- }
84
- DWORD dummy;
85
- winapi_check(WriteFile(pimpl->handle, source_buffer, length, &dummy, 0));
86
- }
87
-
88
- #endif
8
+ using namespace std;
9
+
10
+ // TODO: Error checking
11
+
12
+ struct Gosu::File::Impl
13
+ {
14
+ HANDLE handle = INVALID_HANDLE_VALUE;
15
+
16
+ ~Impl()
17
+ {
18
+ if (handle != INVALID_HANDLE_VALUE) {
19
+ CloseHandle(handle);
20
+ }
21
+ }
22
+ };
23
+
24
+ Gosu::File::File(const string& filename, FileMode mode)
25
+ : pimpl(new Impl)
26
+ {
27
+ DWORD access;
28
+ switch (mode) {
29
+ case FM_READ:
30
+ access = GENERIC_READ;
31
+ break;
32
+ case FM_REPLACE:
33
+ access = GENERIC_WRITE;
34
+ break;
35
+ case FM_ALTER:
36
+ access = GENERIC_READ | GENERIC_WRITE;
37
+ break;
38
+ }
39
+ DWORD share_mode = FILE_SHARE_READ;
40
+ DWORD creation_disp = (mode == FM_READ) ? OPEN_EXISTING : OPEN_ALWAYS;
41
+
42
+ wstring wfilename = utf8_to_utf16(filename);
43
+ pimpl->handle = CreateFileW(wfilename.c_str(), access, share_mode, 0, creation_disp,
44
+ FILE_ATTRIBUTE_NORMAL, 0);
45
+ if (pimpl->handle == INVALID_HANDLE_VALUE) {
46
+ throw_last_winapi_error("opening " + filename);
47
+ }
48
+ if (mode == FM_REPLACE) {
49
+ resize(0);
50
+ }
51
+ }
52
+
53
+ Gosu::File::~File()
54
+ {
55
+ }
56
+
57
+ size_t Gosu::File::size() const
58
+ {
59
+ return GetFileSize(pimpl->handle, 0);
60
+ }
61
+
62
+ void Gosu::File::resize(size_t new_size)
63
+ {
64
+ if (SetFilePointer(pimpl->handle, new_size, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
65
+ throw_last_winapi_error("setting the file pointer");
66
+ }
67
+ winapi_check(SetEndOfFile(pimpl->handle), "resizing a file");
68
+ }
69
+
70
+ void Gosu::File::read(size_t offset, size_t length, void* dest_buffer) const
71
+ {
72
+ if (SetFilePointer(pimpl->handle, offset, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
73
+ throw_last_winapi_error("setting the file pointer");
74
+ }
75
+ DWORD dummy;
76
+ winapi_check(ReadFile(pimpl->handle, dest_buffer, length, &dummy, 0));
77
+ }
78
+
79
+ void Gosu::File::write(size_t offset, size_t length, const void* source_buffer)
80
+ {
81
+ if (SetFilePointer(pimpl->handle, offset, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
82
+ throw_last_winapi_error("setting the file pointer");
83
+ }
84
+ DWORD dummy;
85
+ winapi_check(WriteFile(pimpl->handle, source_buffer, length, &dummy, 0));
86
+ }
87
+
88
+ #endif
data/src/Font.cpp CHANGED
@@ -27,10 +27,10 @@ struct Gosu::Font::Impl
27
27
  // Everything else is looked up through a map...
28
28
  array<map<utf8proc_int32_t, Image>, FF_COMBINATIONS> other_glyphs;
29
29
 
30
- const Image& image(char32_t codepoint, unsigned font_flags)
30
+ Image& image(char32_t codepoint, unsigned font_flags)
31
31
  {
32
32
  Image* image;
33
- if (codepoint < fast_glyphs.size()) {
33
+ if (codepoint < fast_glyphs[font_flags].size()) {
34
34
  image = &fast_glyphs[font_flags][codepoint];
35
35
  }
36
36
  else {
@@ -43,13 +43,13 @@ struct Gosu::Font::Impl
43
43
 
44
44
  u32string string(1, codepoint);
45
45
  Bitmap bitmap(scaled_height, scaled_height);
46
- auto required_width = ceil(draw_text(bitmap, 0, 0, Color::WHITE, string,
47
- name, scaled_height, font_flags));
46
+ auto required_width = ceil(Gosu::draw_text(bitmap, 0, 0, Color::WHITE, string,
47
+ name, scaled_height, font_flags));
48
48
  if (required_width > bitmap.width()) {
49
49
  // If the character was wider than high, we need to render it again.
50
50
  Bitmap(required_width, scaled_height).swap(bitmap);
51
- draw_text(bitmap, 0, 0, Color::WHITE, string,
52
- name, scaled_height, font_flags);
51
+ Gosu::draw_text(bitmap, 0, 0, Color::WHITE, string,
52
+ name, scaled_height, font_flags);
53
53
  }
54
54
 
55
55
  *image = Image(bitmap, 0, 0, required_width, scaled_height);
@@ -82,60 +82,79 @@ unsigned Gosu::Font::flags() const
82
82
  return pimpl->base_flags;
83
83
  }
84
84
 
85
- double Gosu::Font::text_width(const string& text, double scale_x) const
85
+ double Gosu::Font::text_width(const string& text) const
86
86
  {
87
- int width = 0;
87
+ return markup_width(escape_markup(text));
88
+ }
89
+
90
+ double Gosu::Font::markup_width(const string& markup) const
91
+ {
92
+ double width = 0;
88
93
 
89
94
  // Split the text into lines (split_words = false) because Font doesn't implement word-wrapping.
90
- MarkupParser(text.c_str(), pimpl->base_flags, false, [&](vector<FormattedString>&& line) {
91
- int line_width = 0;
95
+ MarkupParser parser(pimpl->base_flags, false, [&](vector<FormattedString>&& line) {
96
+ double line_width = 0;
92
97
  for (auto& part : line) {
93
98
  for (auto codepoint : part.text) {
94
- line_width += pimpl->image(codepoint, part.flags).width();
99
+ auto& image = pimpl->image(codepoint, part.flags);
100
+ double image_scale = 1.0 * height() / image.height();
101
+ line_width += image_scale * image.width();
95
102
  }
96
103
  }
97
104
  width = max(width, line_width);
98
- }).parse();
105
+ });
106
+ parser.parse(markup);
99
107
 
100
- return scale_x * width / FONT_RENDER_SCALE;
108
+ return width;
109
+ }
110
+
111
+ void Gosu::Font::draw_text(const string& text, double x, double y, ZPos z,
112
+ double scale_x, double scale_y, Color c, AlphaMode mode) const
113
+ {
114
+ draw_markup(escape_markup(text), x, y, z, scale_x, scale_y, c, mode);
101
115
  }
102
116
 
103
- void Gosu::Font::draw(const string& text, double x, double y, ZPos z,
104
- double scale_x, double scale_y, Color c, AlphaMode mode) const
117
+ void Gosu::Font::draw_markup(const string& markup, double x, double y, ZPos z,
118
+ double scale_x, double scale_y, Color c, AlphaMode mode) const
105
119
  {
106
120
  double current_y = y;
107
121
 
108
122
  // Split the text into lines (split_words = false) because Font doesn't implement word-wrapping.
109
- MarkupParser(text.c_str(), pimpl->base_flags, false, [&](vector<FormattedString>&& line) {
123
+ MarkupParser parser(pimpl->base_flags, false, [&](vector<FormattedString>&& line) {
110
124
  double current_x = x;
111
125
  for (auto& part : line) {
112
126
  for (auto codepoint : part.text) {
113
127
  auto& image = pimpl->image(codepoint, part.flags);
128
+ double image_scale = 1.0 * height() / image.height();
114
129
  image.draw(current_x, current_y, z,
115
- scale_x / FONT_RENDER_SCALE, scale_y / FONT_RENDER_SCALE,
116
- c, mode);
117
- current_x += scale_x * image.width() / FONT_RENDER_SCALE;
130
+ image_scale * scale_x, image_scale * scale_y,
131
+ multiply(c, part.color), mode);
132
+ current_x += image_scale * scale_x * image.width();
118
133
  }
119
134
  }
120
135
  current_y += scale_y * height();
121
- }).parse();
136
+ });
137
+ parser.parse(markup);
122
138
  }
123
139
 
124
- void Gosu::Font::draw_rel(const string& text, double x, double y, ZPos z,
125
- double rel_x, double rel_y, double scale_x, double scale_y, Color c, AlphaMode mode) const
140
+ void Gosu::Font::draw_text_rel(const string& text, double x, double y, ZPos z,
141
+ double rel_x, double rel_y, double scale_x, double scale_y,
142
+ Color c, AlphaMode mode) const
126
143
  {
127
- x -= text_width(text) * scale_x * rel_x;
128
- y -= height() * scale_y * rel_y;
144
+ if (rel_x) x -= text_width(text) * scale_x * rel_x;
145
+ if (rel_y) y -= height() * scale_y * rel_y;
129
146
 
130
- draw(text, x, y, z, scale_x, scale_y, c, mode);
147
+ draw_text(text, x, y, z, scale_x, scale_y, c, mode);
131
148
  }
132
149
 
133
- void Gosu::Font::draw_rot(const string& text, double x, double y, ZPos z, double angle,
134
- double scale_x, double scale_y, Color c, AlphaMode mode) const
150
+ void Gosu::Font::draw_markup_rel(const string& markup, double x, double y, ZPos z,
151
+ double rel_x, double rel_y, double scale_x, double scale_y,
152
+ Color c, AlphaMode mode) const
135
153
  {
136
- Graphics::transform(rotate(angle, x, y), [&] {
137
- draw(text, x, y, z, scale_x, scale_y, c, mode);
138
- });
154
+ if (rel_x) x -= markup_width(markup) * scale_x * rel_x;
155
+ if (rel_y) y -= height() * scale_y * rel_y;
156
+
157
+ draw_markup(markup, x, y, z, scale_x, scale_y, c, mode);
139
158
  }
140
159
 
141
160
  void Gosu::Font::set_image(std::string codepoint, unsigned font_flags, const Gosu::Image& image)
@@ -147,7 +166,8 @@ void Gosu::Font::set_image(std::string codepoint, unsigned font_flags, const Gos
147
166
 
148
167
  if (utc4[0] < pimpl->fast_glyphs[font_flags].size()) {
149
168
  pimpl->fast_glyphs[font_flags][utc4[0]] = image;
150
- } else {
169
+ }
170
+ else {
151
171
  pimpl->other_glyphs[font_flags][utc4[0]] = image;
152
172
  }
153
173
  }
data/src/Graphics.cpp CHANGED
@@ -288,7 +288,7 @@ Gosu::Image Gosu::Graphics::render(int width, int height, const function<void ()
288
288
  Image result = OffScreenTarget(width, height).render([&] {
289
289
  glClearColor(0, 0, 0, 0);
290
290
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
291
- queues.emplace_back(QM_RENDER_TO_SCREEN);
291
+ queues.emplace_back(QM_RENDER_TO_TEXTURE);
292
292
  f();
293
293
  queues.back().perform_draw_ops_and_code();
294
294
  queues.pop_back();
data/src/GraphicsImpl.hpp CHANGED
@@ -8,6 +8,7 @@
8
8
  #include <OpenGLES/ES1/gl.h>
9
9
  #include <OpenGLES/ES1/glext.h>
10
10
  #else
11
+ #include <SDL.h>
11
12
  #include <SDL_opengl.h>
12
13
  #endif
13
14
 
@@ -102,5 +103,23 @@ namespace Gosu
102
103
  inline int clip_rect_base_factor() { return 1; }
103
104
  #endif
104
105
 
106
+ #ifndef GOSU_IS_IPHONE
107
+ SDL_Window* shared_window();
108
+ #endif
109
+
105
110
  void ensure_current_context();
111
+
112
+ inline std::string escape_markup(const std::string& text) {
113
+ // Escape all markup and delegate to layout_markup.
114
+ auto markup = text;
115
+ for (std::string::size_type pos = 0; pos < markup.length(); ++pos) {
116
+ if (markup[pos] == '&') {
117
+ markup.replace(pos, 1, "&amp;");
118
+ }
119
+ else if (markup[pos] == '<') {
120
+ markup.replace(pos, 1, "&lt;");
121
+ }
122
+ }
123
+ return markup;
124
+ }
106
125
  }
data/src/Input.cpp CHANGED
@@ -4,13 +4,22 @@
4
4
  #include <Gosu/Input.hpp>
5
5
  #include <Gosu/TextInput.hpp>
6
6
  #include <Gosu/Utility.hpp>
7
+
7
8
  #include <SDL.h>
9
+ #include "utf8proc.h"
10
+
8
11
  #include <cwctype>
9
12
  #include <cstdlib>
10
13
  #include <algorithm>
11
14
  #include <array>
12
15
  using namespace std;
13
16
 
17
+ // Workaround for broken SDL_GetGlobalMouseState, see below.
18
+ #ifdef GOSU_IS_MAC
19
+ #import <CoreGraphics/CoreGraphics.h>
20
+ #import <AppKit/AppKit.h>
21
+ #endif
22
+
14
23
  static void require_sdl_video()
15
24
  {
16
25
  static bool initialized = false;
@@ -71,11 +80,17 @@ struct Gosu::Input::Impl
71
80
 
72
81
  void update_mouse_position()
73
82
  {
74
- // Do not use GetGlobalMouseState on Linux for now to prevent this bug:
75
- // https://github.com/gosu/gosu/issues/326
76
- // Once SDL 2.0.5 has been released, we can use this function as a workaround:
77
- // https://wiki.libsdl.org/SDL_GetWindowBordersSize
78
- #if SDL_VERSION_ATLEAST(2, 0, 4) && !defined(GOSU_IS_X)
83
+ #if defined(GOSU_IS_MAC)
84
+ // Avoid SDL_GetGlobalMouseState on macOS until this bug is fixed:
85
+ // https://bugzilla.libsdl.org/show_bug.cgi?id=4255
86
+ int window_x, window_y;
87
+ SDL_GetWindowPosition(window, &window_x, &window_y);
88
+ auto mouse_position = NSEvent.mouseLocation;
89
+ mouse_x = mouse_position.x - window_x;
90
+ mouse_y = (CGDisplayPixelsHigh(kCGDirectMainDisplay) - mouse_position.y) - window_y;
91
+ #elif SDL_VERSION_ATLEAST(2, 0, 5)
92
+ // SDL_GetGlobalMouseState was added in SDL 2.0.4, but it only started using the same
93
+ // coordinate system as SDL_GetWindowPosition on X11 in 2.0.5.
79
94
  int x, y, window_x, window_y;
80
95
  SDL_GetWindowPosition(window, &window_x, &window_y);
81
96
  SDL_GetGlobalMouseState(&x, &y);
@@ -325,14 +340,17 @@ string Gosu::Input::id_to_char(Button btn)
325
340
  const char* name = SDL_GetKeyName(keycode);
326
341
  if (name == nullptr) return "";
327
342
 
328
- wstring wname = utf8_to_wstring(name);
329
- if (wname.length() != 1) return "";
343
+ u32string codepoints = utf8_to_composed_utc4(name);
344
+
345
+ // Filter out names that are more than one logical character.
346
+ if (codepoints.length() != 1) return "";
330
347
 
331
- // Convert to lower case to be consistent with previous versions of Gosu.
332
- // German umlauts are already reported in lower-case by SDL, anyway.
333
- // (This should handle Turkish i/I just fine because it uses the current locale.)
334
- wname[0] = (wchar_t) towlower((wint_t) wname[0]);
335
- return wstring_to_utf8(wname);
348
+ // Always return lower case to be consistent with previous versions of Gosu.
349
+ codepoints[0] = utf8proc_tolower(codepoints[0]);
350
+ // Convert back to UTF-8.
351
+ utf8proc_uint8_t utf8_buffer[4];
352
+ auto len = utf8proc_encode_char(codepoints[0], utf8_buffer);
353
+ return string(reinterpret_cast<char*>(utf8_buffer), len);
336
354
  }
337
355
 
338
356
  Gosu::Button Gosu::Input::char_to_id(string ch)
data/src/MarkupParser.cpp CHANGED
@@ -97,9 +97,9 @@ bool Gosu::MarkupParser::parse_markup()
97
97
 
98
98
  if (hex_chars == 3) {
99
99
  // Expand 0xrgb to 0xFFrrggbb:
100
- auto r = argb >> 8 & 0x7;
101
- auto g = argb >> 4 & 0x7;
102
- auto b = argb >> 0 & 0x7;
100
+ auto r = argb >> 8 & 0xf;
101
+ auto g = argb >> 4 & 0xf;
102
+ auto b = argb >> 0 & 0xf;
103
103
  argb = 0xff000000 | r << 20 | r << 16 | g << 12 | g << 8 | b << 4 | b << 0;
104
104
  }
105
105
  else if (hex_chars == 6) {
@@ -139,7 +139,7 @@ bool Gosu::MarkupParser::parse_escape_entity()
139
139
 
140
140
  void Gosu::MarkupParser::add_current_substring()
141
141
  {
142
- if (!substring.empty()) {
142
+ if (! substring.empty()) {
143
143
  add_composed_substring(utf8_to_composed_utc4(substring));
144
144
  substring.clear();
145
145
  }
@@ -168,9 +168,9 @@ void Gosu::MarkupParser::flush_to_consumer()
168
168
  }
169
169
  }
170
170
 
171
- Gosu::MarkupParser::MarkupParser(const char* markup, unsigned base_flags, bool split_words,
171
+ Gosu::MarkupParser::MarkupParser(unsigned base_flags, bool split_words,
172
172
  function<void (vector<FormattedString>)> consumer)
173
- : markup(markup), consumer(move(consumer))
173
+ : consumer(move(consumer))
174
174
  {
175
175
  word_state = (split_words ? ADDING_WORD : IGNORE_WORDS);
176
176
 
@@ -179,9 +179,10 @@ Gosu::MarkupParser::MarkupParser(const char* markup, unsigned base_flags, bool s
179
179
  u = (base_flags & FF_UNDERLINE) ? 1 : 0;
180
180
  }
181
181
 
182
- void Gosu::MarkupParser::parse()
182
+ void Gosu::MarkupParser::parse(const std::string& markup_string)
183
183
  {
184
- auto end_of_markup = markup + strlen(markup);
184
+ markup = markup_string.data();
185
+ const char* end_of_markup = markup_string.data() + markup_string.length();
185
186
 
186
187
  while (markup < end_of_markup) {
187
188
  if (*markup == '<' && parse_markup()) {
@@ -196,7 +197,9 @@ void Gosu::MarkupParser::parse()
196
197
  if (*markup == '\n') {
197
198
  // Explicitly add the trailing \n to the current substring so that the consumer can
198
199
  // distinguish between line breaks and word breaks in split_words mode.
200
+ substring.append(1, '\n');
199
201
  ++markup;
202
+
200
203
  add_current_substring();
201
204
  flush_to_consumer();
202
205
  // Avoid incrementing ++markup again.