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.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/Gosu/Audio.hpp +15 -11
  3. data/Gosu/Font.hpp +24 -20
  4. data/Gosu/Fwd.hpp +1 -1
  5. data/Gosu/Graphics.hpp +8 -9
  6. data/Gosu/ImageData.hpp +1 -1
  7. data/Gosu/Input.hpp +1 -1
  8. data/Gosu/Math.hpp +0 -18
  9. data/Gosu/Text.hpp +22 -30
  10. data/Gosu/TextInput.hpp +13 -0
  11. data/Gosu/Utility.hpp +2 -0
  12. data/Gosu/Window.hpp +3 -3
  13. data/README.md +3 -4
  14. data/ext/gosu/extconf.rb +7 -9
  15. data/lib/gosu/swig_patches.rb +1 -4
  16. data/rdoc/gosu.rb +34 -9
  17. data/src/Audio.cpp +6 -6
  18. data/src/AudioImpl.cpp +2 -2
  19. data/src/Bitmap.cpp +1 -2
  20. data/src/BitmapIO.cpp +21 -2
  21. data/src/BlockAllocator.cpp +1 -1
  22. data/src/Channel.cpp +7 -1
  23. data/src/ClipRectStack.hpp +4 -1
  24. data/src/Color.cpp +2 -1
  25. data/src/DirectoriesWin.cpp +1 -1
  26. data/src/DrawOp.hpp +8 -4
  27. data/src/DrawOpQueue.hpp +13 -24
  28. data/src/FileUnix.cpp +3 -1
  29. data/src/Font.cpp +92 -96
  30. data/src/GosuGLView.cpp +59 -31
  31. data/src/GosuGLView.hpp +14 -0
  32. data/src/GosuViewController.cpp +21 -21
  33. data/src/{GosuViewController.h → GosuViewController.hpp} +2 -4
  34. data/src/Graphics.cpp +71 -38
  35. data/src/GraphicsImpl.hpp +12 -29
  36. data/src/Image.cpp +5 -7
  37. data/src/Input.cpp +7 -5
  38. data/src/InputUIKit.cpp +19 -37
  39. data/src/Macro.cpp +10 -2
  40. data/src/MarkupParser.cpp +241 -0
  41. data/src/MarkupParser.hpp +61 -0
  42. data/src/Math.cpp +1 -1
  43. data/src/OffScreenTarget.cpp +99 -0
  44. data/src/OffScreenTarget.hpp +23 -0
  45. data/src/OggFile.hpp +10 -0
  46. data/src/RenderState.hpp +0 -2
  47. data/src/Resolution.cpp +2 -2
  48. data/src/RubyGosu.cxx +457 -244
  49. data/src/TexChunk.cpp +8 -6
  50. data/src/Text.cpp +58 -345
  51. data/src/TextBuilder.cpp +138 -0
  52. data/src/TextBuilder.hpp +55 -0
  53. data/src/TextInput.cpp +27 -10
  54. data/src/Texture.cpp +22 -17
  55. data/src/Texture.hpp +19 -20
  56. data/src/TimingApple.cpp +5 -7
  57. data/src/TimingUnix.cpp +1 -4
  58. data/src/TimingWin.cpp +4 -1
  59. data/src/TrueTypeFont.cpp +282 -0
  60. data/src/TrueTypeFont.hpp +66 -0
  61. data/src/TrueTypeFontApple.cpp +65 -0
  62. data/src/TrueTypeFontUnix.cpp +91 -0
  63. data/src/TrueTypeFontWin.cpp +82 -0
  64. data/src/Utility.cpp +40 -0
  65. data/src/Window.cpp +7 -6
  66. data/src/WindowUIKit.cpp +9 -4
  67. data/src/stb_truetype.h +4589 -0
  68. data/src/utf8proc.c +755 -0
  69. data/src/utf8proc.h +699 -0
  70. data/src/utf8proc_data.h +14386 -0
  71. metadata +23 -16
  72. data/src/FormattedString.cpp +0 -237
  73. data/src/FormattedString.hpp +0 -47
  74. data/src/GosuAppDelegate.cpp +0 -30
  75. data/src/GosuAppDelegate.h +0 -8
  76. data/src/GosuGLView.h +0 -8
  77. data/src/TextApple.cpp +0 -212
  78. data/src/TextTTFWin.cpp +0 -197
  79. data/src/TextUnix.cpp +0 -280
  80. data/src/TextWin.cpp +0 -191
@@ -0,0 +1,138 @@
1
+ #include "TextBuilder.hpp"
2
+ #include <Gosu/Text.hpp>
3
+ #include <cassert>
4
+ #include <cmath>
5
+ #include "utf8proc.h"
6
+ using namespace std;
7
+
8
+ Gosu::WordInfo::WordInfo(const string& font_name, double font_height, vector<FormattedString> parts)
9
+ {
10
+ assert (! parts.empty());
11
+
12
+ auto* properties = utf8proc_get_property(parts.front().text.front());
13
+
14
+ // Also check the BiDi class to filter out non-breaking spaces.
15
+ is_whitespace = properties->category == UTF8PROC_CATEGORY_ZS &&
16
+ properties->bidi_class == UTF8PROC_BIDI_CLASS_WS;
17
+
18
+ is_end_of_line = parts.back().text.back() == '\n';
19
+ // Remove the trailing backspace character to avoid errors from Gosu::text_width().
20
+ if (is_end_of_line) parts.back().text.pop_back();
21
+
22
+ width = 0;
23
+ for (const auto& part : parts) {
24
+ assert (! part.text.empty());
25
+
26
+ width += text_width(part.text, font_name, font_height, part.flags);
27
+ }
28
+
29
+ this->parts = move(parts);
30
+ }
31
+
32
+ void Gosu::TextBuilder::flush_current_line(EndOfLineReason reason)
33
+ {
34
+ if (current_line.empty()) {
35
+ if (reason == END_OF_PARAGRAPH) allocate_next_line();
36
+ return;
37
+ }
38
+
39
+ allocate_next_line();
40
+
41
+ // Remove trailing whitespace so that justifying the text across the line works.
42
+ if (current_line.back().is_whitespace) current_line.pop_back();
43
+
44
+ // Shouldn't happen because the first word on a line should never be whitespace.
45
+ assert (! current_line.empty());
46
+
47
+ double words_width = 0, whitespace_width = 0;
48
+ for (const auto& word : current_line) {
49
+ (word.is_whitespace ? whitespace_width : words_width) += word.width;
50
+ }
51
+
52
+ double x = 0;
53
+ if (align == AL_RIGHT) {
54
+ x = result.width() - words_width - whitespace_width;
55
+ }
56
+ else if (align == AL_CENTER) {
57
+ x = (result.width() - words_width - whitespace_width) / 2.0;
58
+ }
59
+
60
+ double whitespace_factor = 1.0;
61
+ if (align == AL_JUSTIFY && reason == LINE_TOO_LONG) {
62
+ whitespace_factor = (result.width() - words_width) / whitespace_width;
63
+ }
64
+
65
+ double y = (used_lines - 1) * (font_height + line_spacing);
66
+
67
+ for (const auto& word : current_line) {
68
+ if (word.is_whitespace) {
69
+ x += word.width * whitespace_factor;
70
+ }
71
+ else {
72
+ for (const auto& part : word.parts) {
73
+ draw_text(result, x, y, part.color, part.text, font_name, font_height, part.flags);
74
+ }
75
+ x += word.width;
76
+ }
77
+ }
78
+
79
+ current_line.clear();
80
+ current_line_width = 0;
81
+ }
82
+
83
+ void Gosu::TextBuilder::allocate_next_line()
84
+ {
85
+ if (used_lines == allocated_lines) {
86
+ allocated_lines += 10;
87
+ resize_to_allocated_lines();
88
+ }
89
+
90
+ ++used_lines;
91
+ }
92
+
93
+ void Gosu::TextBuilder::resize_to_allocated_lines()
94
+ {
95
+ double new_height = font_height * allocated_lines + line_spacing * max(0, allocated_lines - 1);
96
+ result.resize(result.width(), ceil(new_height));
97
+ }
98
+
99
+ Gosu::TextBuilder::TextBuilder(const string& font_name, int font_height, int line_spacing,
100
+ int width, Alignment align)
101
+ : font_name(font_name), font_height(font_height), line_spacing(line_spacing), align(align)
102
+ {
103
+ // This class uses result.width() to remember its destination width, so store it in there.
104
+ result.resize(width, 0);
105
+ }
106
+
107
+ Gosu::Bitmap Gosu::TextBuilder::move_into_bitmap()
108
+ {
109
+ flush_current_line(END_OF_TEXT);
110
+
111
+ // Shrink to fit the currently used height.
112
+ allocated_lines = used_lines;
113
+ resize_to_allocated_lines();
114
+ return move(result);
115
+ }
116
+
117
+ void Gosu::TextBuilder::feed_word(vector<FormattedString>&& word)
118
+ {
119
+ WordInfo new_word(font_name, font_height, word);
120
+
121
+ if (current_line_width + new_word.width > result.width()) {
122
+ // Can't fit it on the same line as before, so flush the last line before adding the word to
123
+ // the next line.
124
+ flush_current_line(LINE_TOO_LONG);
125
+
126
+ if (new_word.is_whitespace) {
127
+ // Do not wrap trailing whitespace onto the start of the next line - discard this word.
128
+ return;
129
+ }
130
+ }
131
+
132
+ current_line.emplace_back(new_word);
133
+ current_line_width += new_word.width;
134
+
135
+ if (current_line_width > result.width() || new_word.is_end_of_line) {
136
+ flush_current_line(new_word.is_end_of_line ? END_OF_PARAGRAPH : LINE_TOO_LONG);
137
+ }
138
+ }
@@ -0,0 +1,55 @@
1
+ #pragma once
2
+
3
+ #include "GraphicsImpl.hpp"
4
+ #include "MarkupParser.hpp"
5
+ #include <vector>
6
+
7
+ namespace Gosu
8
+ {
9
+ struct WordInfo
10
+ {
11
+ std::vector<FormattedString> parts;
12
+ bool is_whitespace;
13
+ bool is_end_of_line;
14
+ double width;
15
+
16
+ WordInfo(const std::string& font_name, double font_height,
17
+ std::vector<FormattedString> parts);
18
+ };
19
+
20
+ class TextBuilder
21
+ {
22
+ // Parameters.
23
+ std::string font_name;
24
+ double font_height;
25
+ double line_spacing;
26
+ Alignment align;
27
+
28
+ enum EndOfLineReason {
29
+ LINE_TOO_LONG,
30
+ END_OF_PARAGRAPH,
31
+ END_OF_TEXT
32
+ };
33
+
34
+ // Input.
35
+ std::vector<WordInfo> current_line;
36
+ int current_line_width = 0;
37
+ void flush_current_line(EndOfLineReason reason);
38
+
39
+ // Output.
40
+ Bitmap result;
41
+ int used_lines = 0;
42
+ int allocated_lines = 0;
43
+ void allocate_next_line();
44
+ void resize_to_allocated_lines();
45
+
46
+ public:
47
+ TextBuilder(const std::string& font_name, int font_height, int line_spacing,
48
+ int width, Alignment align);
49
+
50
+ void feed_word(std::vector<FormattedString>&& word);
51
+
52
+ Bitmap move_into_bitmap();
53
+ };
54
+ }
55
+
@@ -1,18 +1,19 @@
1
- #include <Gosu/Platform.hpp>
2
- #if !defined(GOSU_IS_IPHONE)
3
-
4
1
  #include <Gosu/TextInput.hpp>
5
2
  #include <Gosu/Input.hpp>
6
3
  #include <Gosu/Platform.hpp>
4
+
5
+ #ifndef GOSU_IS_IPHONE
7
6
  #include <SDL.h>
8
7
  #include <cctype>
8
+ #endif
9
+
9
10
  using namespace std;
10
11
 
11
12
  struct Gosu::TextInput::Impl
12
13
  {
13
14
  string text;
14
15
 
15
- // This is the current IME composition.
16
+ // This is the current IME composition (not used on iOS).
16
17
  // http://wiki.libsdl.org/Tutorials/TextInput#CandidateList
17
18
  string composition;
18
19
 
@@ -152,6 +153,7 @@ Gosu::TextInput::TextInput()
152
153
 
153
154
  Gosu::TextInput::~TextInput()
154
155
  {
156
+ // TODO: Unset Input::text_input to avoid stale pointers?
155
157
  }
156
158
 
157
159
  string Gosu::TextInput::text() const
@@ -172,12 +174,12 @@ void Gosu::TextInput::set_text(const string& text)
172
174
 
173
175
  unsigned Gosu::TextInput::caret_pos() const
174
176
  {
175
- return static_cast<unsigned>(pimpl->caret_pos);
177
+ return pimpl->caret_pos;
176
178
  }
177
179
 
178
- void Gosu::TextInput::set_caret_pos(unsigned pos)
180
+ void Gosu::TextInput::set_caret_pos(unsigned caret_pos)
179
181
  {
180
- pimpl->caret_pos = pos;
182
+ pimpl->caret_pos = caret_pos;
181
183
  }
182
184
 
183
185
  unsigned Gosu::TextInput::selection_start() const
@@ -185,11 +187,12 @@ unsigned Gosu::TextInput::selection_start() const
185
187
  return pimpl->selection_start;
186
188
  }
187
189
 
188
- void Gosu::TextInput::set_selection_start(unsigned pos)
190
+ void Gosu::TextInput::set_selection_start(unsigned selection_start)
189
191
  {
190
- pimpl->selection_start = pos;
192
+ pimpl->selection_start = selection_start;
191
193
  }
192
194
 
195
+ #ifndef GOSU_IS_IPHONE
193
196
  bool Gosu::TextInput::feed_sdl_event(void* event)
194
197
  {
195
198
  const SDL_Event* e = static_cast<SDL_Event*>(event);
@@ -275,5 +278,19 @@ bool Gosu::TextInput::feed_sdl_event(void* event)
275
278
 
276
279
  return false;
277
280
  }
278
-
279
281
  #endif
282
+
283
+ void Gosu::TextInput::insert_text(string text)
284
+ {
285
+ pimpl->insert_text(text);
286
+ }
287
+
288
+ void Gosu::TextInput::delete_forward()
289
+ {
290
+ pimpl->delete_forward();
291
+ }
292
+
293
+ void Gosu::TextInput::delete_backward()
294
+ {
295
+ pimpl->delete_backward();
296
+ }
@@ -11,16 +11,14 @@ namespace Gosu
11
11
  bool undocumented_retrofication = false;
12
12
  }
13
13
 
14
- Gosu::Texture::Texture(unsigned size, bool retro)
15
- : allocator_(size, size), retro_(retro)
14
+ Gosu::Texture::Texture(unsigned width, unsigned height, bool retro)
15
+ : allocator_(width, height), retro_(retro)
16
16
  {
17
17
  ensure_current_context();
18
18
 
19
19
  // Create texture name.
20
20
  glGenTextures(1, &tex_name_);
21
- if (tex_name_ == static_cast<GLuint>(-1)) {
22
- throw runtime_error("Couldn't create OpenGL texture");
23
- }
21
+ if (tex_name_ == static_cast<GLuint>(-1)) throw runtime_error("Couldn't create OpenGL texture");
24
22
 
25
23
  // Create empty texture.
26
24
  glBindTexture(GL_TEXTURE_2D, tex_name_);
@@ -57,9 +55,14 @@ Gosu::Texture::~Texture()
57
55
  glDeleteTextures(1, &tex_name_);
58
56
  }
59
57
 
60
- unsigned Gosu::Texture::size() const
58
+ unsigned Gosu::Texture::width() const
59
+ {
60
+ return allocator_.width();
61
+ }
62
+
63
+ unsigned Gosu::Texture::height() const
61
64
  {
62
- return allocator_.width(); // == height
65
+ return allocator_.height();
63
66
  }
64
67
 
65
68
  GLuint Gosu::Texture::tex_name() const
@@ -72,19 +75,18 @@ bool Gosu::Texture::retro() const
72
75
  return retro_;
73
76
  }
74
77
 
75
- unique_ptr<Gosu::TexChunk> Gosu::Texture::try_alloc(shared_ptr<Texture> ptr, const Bitmap& bmp,
76
- unsigned padding)
78
+ unique_ptr<Gosu::TexChunk> Gosu::Texture::try_alloc(const Bitmap& bmp, unsigned padding)
77
79
  {
78
80
  BlockAllocator::Block block;
79
81
 
80
82
  if (!allocator_.alloc(bmp.width(), bmp.height(), block)) return nullptr;
81
83
 
82
- unique_ptr<Gosu::TexChunk> result(new TexChunk(ptr,
83
- block.left + padding,
84
- block.top + padding,
85
- block.width - 2 * padding,
86
- block.height - 2 * padding,
87
- padding));
84
+ unique_ptr<TexChunk> result(new TexChunk(shared_from_this(),
85
+ block.left + padding,
86
+ block.top + padding,
87
+ block.width - 2 * padding,
88
+ block.height - 2 * padding,
89
+ padding));
88
90
 
89
91
  ensure_current_context();
90
92
 
@@ -108,14 +110,17 @@ void Gosu::Texture::free(unsigned x, unsigned y, unsigned width, unsigned height
108
110
  Gosu::Bitmap Gosu::Texture::to_bitmap(unsigned x, unsigned y, unsigned width, unsigned height) const
109
111
  {
110
112
  #ifdef GOSU_IS_OPENGLES
113
+ // See here for one possible implementation: https://github.com/apitrace/apitrace/issues/70
114
+ // (Could reuse a lot of code from OffScreenTarget)
111
115
  throw logic_error("Texture::to_bitmap not supported on iOS");
112
116
  #else
113
117
  ensure_current_context();
114
118
 
115
- Gosu::Bitmap full_texture(size(), size());
119
+ Bitmap full_texture(this->width(), this->height());
116
120
  glBindTexture(GL_TEXTURE_2D, tex_name());
121
+ // TODO: There are ways to retrieve only part of a texture, which we should use sooner or later.
117
122
  glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, full_texture.data());
118
- Gosu::Bitmap bitmap(width, height);
123
+ Bitmap bitmap(width, height);
119
124
  bitmap.insert(full_texture, -int(x), -int(y));
120
125
 
121
126
  return bitmap;
@@ -5,26 +5,25 @@
5
5
  #include "TexChunk.hpp"
6
6
  #include <Gosu/Fwd.hpp>
7
7
  #include <Gosu/Bitmap.hpp>
8
+ #include <memory>
8
9
  #include <vector>
9
10
 
10
- namespace Gosu
11
+ class Gosu::Texture : public std::enable_shared_from_this<Texture>
11
12
  {
12
- class Texture
13
- {
14
- BlockAllocator allocator_;
15
- GLuint tex_name_;
16
- bool retro_;
17
-
18
- public:
19
- Texture(unsigned size, bool retro);
20
- ~Texture();
21
- unsigned size() const;
22
- GLuint tex_name() const;
23
- bool retro() const;
24
- std::unique_ptr<TexChunk>
25
- try_alloc(std::shared_ptr<Texture> ptr, const Bitmap& bmp, unsigned padding);
26
- void block(unsigned x, unsigned y, unsigned width, unsigned height);
27
- void free(unsigned x, unsigned y, unsigned width, unsigned height);
28
- Gosu::Bitmap to_bitmap(unsigned x, unsigned y, unsigned width, unsigned height) const;
29
- };
30
- }
13
+ // BlockAllocator can't be copied or moved, so neither can Texture.
14
+ BlockAllocator allocator_;
15
+ GLuint tex_name_;
16
+ bool retro_;
17
+
18
+ public:
19
+ Texture(unsigned width, unsigned height, bool retro);
20
+ ~Texture();
21
+ unsigned width() const;
22
+ unsigned height() const;
23
+ GLuint tex_name() const;
24
+ bool retro() const;
25
+ std::unique_ptr<TexChunk> try_alloc(const Bitmap& bmp, unsigned padding);
26
+ void block(unsigned x, unsigned y, unsigned width, unsigned height);
27
+ void free(unsigned x, unsigned y, unsigned width, unsigned height);
28
+ Bitmap to_bitmap(unsigned x, unsigned y, unsigned width, unsigned height) const;
29
+ };
@@ -16,16 +16,14 @@ void Gosu::sleep(unsigned milliseconds)
16
16
 
17
17
  unsigned long Gosu::milliseconds()
18
18
  {
19
- static uint64_t first_tick = 0;
20
19
  static mach_timebase_info_data_t info;
21
-
22
- if (first_tick == 0) {
20
+ static uint64_t first_tick = [] {
23
21
  mach_timebase_info(&info);
24
- first_tick = mach_absolute_time();
25
- }
26
-
22
+ return mach_absolute_time();
23
+ }();
24
+
27
25
  uint64_t runtime = mach_absolute_time() - first_tick;
28
- return runtime * info.numer / info.denom / 1000000.0;
26
+ return runtime * info.numer / info.denom / 1000000;
29
27
  }
30
28
 
31
29
  #endif
@@ -21,10 +21,7 @@ unsigned long Gosu::milliseconds()
21
21
  start = tp.tv_usec / 1000UL + tp.tv_sec * 1000UL;
22
22
  }
23
23
 
24
- // Truncate to 2^30, C++ users shouldn't mind and Ruby users will
25
- // have a happy GC on 32-bit systems.
26
- // No, don't ask why this is an unsigned long then :)
27
- return (tp.tv_usec / 1000UL + tp.tv_sec * 1000UL - start) & 0x1fffffff;
24
+ return tp.tv_usec / 1000UL + tp.tv_sec * 1000UL - start;
28
25
  }
29
26
 
30
27
  #endif
@@ -12,7 +12,10 @@ void Gosu::sleep(unsigned milliseconds)
12
12
 
13
13
  unsigned long Gosu::milliseconds()
14
14
  {
15
- static unsigned long start = (timeBeginPeriod(1), timeGetTime());
15
+ static unsigned long start = [] {
16
+ timeBeginPeriod(1);
17
+ return timeGetTime();
18
+ }();
16
19
  return timeGetTime() - start;
17
20
  }
18
21