gosu 0.13.3 → 0.14.0.pre2

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