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.
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.