gosu 0.12.1 → 0.13.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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/Gosu/Audio.hpp +23 -25
  3. data/Gosu/Graphics.hpp +16 -12
  4. data/Gosu/Image.hpp +3 -0
  5. data/Gosu/Version.hpp +2 -2
  6. data/lib/gosu.rb +2 -2
  7. data/lib/gosu/compat.rb +1 -1
  8. data/lib/gosu/patches.rb +5 -0
  9. data/lib/gosu/swig_patches.rb +1 -1
  10. data/rdoc/gosu.rb +10 -10
  11. data/src/Audio.cpp +93 -228
  12. data/src/AudioImpl.cpp +94 -0
  13. data/src/AudioImpl.hpp +33 -0
  14. data/src/AudioToolboxFile.hpp +14 -18
  15. data/src/Bitmap.cpp +36 -30
  16. data/src/BitmapIO.cpp +14 -23
  17. data/src/BlockAllocator.cpp +7 -10
  18. data/src/BlockAllocator.hpp +2 -4
  19. data/src/Channel.cpp +89 -0
  20. data/src/Color.cpp +4 -9
  21. data/src/DirectoriesApple.cpp +13 -13
  22. data/src/DirectoriesUnix.cpp +8 -7
  23. data/src/DirectoriesWin.cpp +12 -11
  24. data/src/EmptyImageData.hpp +54 -0
  25. data/src/FileUnix.cpp +12 -9
  26. data/src/FileWin.cpp +8 -7
  27. data/src/Font.cpp +12 -13
  28. data/src/FormattedString.cpp +237 -0
  29. data/src/FormattedString.hpp +14 -265
  30. data/src/GosuViewController.cpp +2 -5
  31. data/src/Graphics.cpp +38 -39
  32. data/src/IO.cpp +11 -10
  33. data/src/Image.cpp +16 -9
  34. data/src/Input.cpp +16 -15
  35. data/src/InputUIKit.cpp +8 -7
  36. data/src/Macro.cpp +11 -11
  37. data/src/Math.cpp +9 -8
  38. data/src/RubyGosu.cxx +129 -99
  39. data/src/TextApple.cpp +19 -13
  40. data/src/TextInput.cpp +23 -22
  41. data/src/TextWin.cpp +17 -19
  42. data/src/Texture.cpp +15 -10
  43. data/src/Transform.cpp +13 -17
  44. data/src/Utility.cpp +3 -2
  45. data/src/UtilityApple.cpp +10 -11
  46. data/src/UtilityWin.cpp +2 -1
  47. data/src/Version.cpp +5 -4
  48. data/src/WinMain.cpp +3 -3
  49. data/src/WinUtility.cpp +7 -6
  50. data/src/Window.cpp +11 -10
  51. data/src/WindowUIKit.cpp +9 -8
  52. data/src/stb_image.h +782 -480
  53. data/src/stb_image_write.h +425 -15
  54. data/src/stb_vorbis.c +82 -32
  55. metadata +8 -4
  56. data/src/ALChannelManagement.hpp +0 -119
@@ -0,0 +1,94 @@
1
+ #include "AudioImpl.hpp"
2
+ #include <stdexcept>
3
+ #include <string>
4
+ using namespace std;
5
+
6
+ // Per-platform limit for playing OpenAL sources: https://stackoverflow.com/a/3203888
7
+ #ifdef GOSU_IS_IPHONE
8
+ static const unsigned CHANNELS = 32;
9
+ #else
10
+ static const unsigned CHANNELS = 255;
11
+ #endif
12
+
13
+ static ALCdevice* _device;
14
+ static ALCcontext* _context;
15
+ static ALuint _sources[CHANNELS];
16
+ static int _tokens[CHANNELS];
17
+
18
+ void Gosu::al_initialize()
19
+ {
20
+ if (_device) return;
21
+
22
+ _device = alcOpenDevice(nullptr);
23
+ _context = alcCreateContext(_device, nullptr);
24
+ alcMakeContextCurrent(_context);
25
+ alGenSources(CHANNELS, _sources);
26
+ }
27
+
28
+ bool Gosu::al_initialized()
29
+ {
30
+ return _device != nullptr;
31
+ }
32
+
33
+ void Gosu::al_shutdown()
34
+ {
35
+ if (_device == nullptr) return;
36
+
37
+ alDeleteSources(CHANNELS, _sources);
38
+ alcMakeContextCurrent(nullptr);
39
+ alcDestroyContext(_context);
40
+ _context = nullptr;
41
+ alcCloseDevice(_device);
42
+ _device = nullptr;
43
+ }
44
+
45
+ ALCdevice* Gosu::al_device()
46
+ {
47
+ al_initialize();
48
+
49
+ return _device;
50
+ }
51
+
52
+ ALCcontext* Gosu::al_context()
53
+ {
54
+ al_initialize();
55
+
56
+ return _context;
57
+ }
58
+
59
+ Gosu::Channel Gosu::allocate_channel()
60
+ {
61
+ al_initialize();
62
+
63
+ // Start looking at index 1 to keep one free channel for songs.
64
+ for (int i = 1; i < CHANNELS; ++i) {
65
+ // Do not interrupt any playing or paused samples.
66
+ ALint state;
67
+ alGetSourcei(_sources[i], AL_SOURCE_STATE, &state);
68
+ if (state == AL_PLAYING || state == AL_PAUSED) continue;
69
+
70
+ // Increase the token to invalidate the last playing Channel with this index.
71
+ return Channel(i, ++_tokens[i]);
72
+ }
73
+
74
+ // No free channel, return an object that is immediately expired.
75
+ return Channel(NO_CHANNEL, 0);
76
+ }
77
+
78
+ bool Gosu::channel_expired(int channel, int token)
79
+ {
80
+ return channel < 0 || channel >= CHANNELS || _tokens[channel] != token;
81
+ }
82
+
83
+ ALuint Gosu::al_source_for_channel(int channel)
84
+ {
85
+ if (channel <= 0 || channel >= CHANNELS) {
86
+ throw invalid_argument("No such channel: " + to_string(channel));
87
+ }
88
+ return _sources[channel];
89
+ }
90
+
91
+ ALuint Gosu::al_source_for_songs()
92
+ {
93
+ return _sources[0];
94
+ }
@@ -0,0 +1,33 @@
1
+ #pragma once
2
+
3
+ #include <Gosu/Audio.hpp>
4
+ #include <Gosu/Platform.hpp>
5
+ #ifdef GOSU_IS_MAC
6
+ #include <OpenAL/al.h>
7
+ #include <OpenAL/alc.h>
8
+ #else
9
+ #include <AL/al.h>
10
+ #include <AL/alc.h>
11
+ #endif
12
+
13
+ namespace Gosu
14
+ {
15
+ void al_initialize();
16
+ bool al_initialized();
17
+ void al_shutdown();
18
+
19
+ // Will initialize OpenAL if necessary.
20
+ ALCdevice* al_device();
21
+ // Will initialize OpenAL if necessary.
22
+ ALCcontext* al_context();
23
+
24
+ const int NO_CHANNEL = -1;
25
+
26
+ // Returns an expired Channel if no channel is free.
27
+ // Will initialize OpenAL if necessary.
28
+ Channel allocate_channel();
29
+
30
+ bool channel_expired(int channel, int token);
31
+ ALuint al_source_for_channel(int channel);
32
+ ALuint al_source_for_songs();
33
+ }
@@ -33,7 +33,7 @@ namespace Gosu
33
33
  {
34
34
  class AudioToolboxFile : public AudioFile
35
35
  {
36
- Gosu::Buffer buffer_;
36
+ Buffer buffer_;
37
37
  AudioFileID file_id_;
38
38
  ExtAudioFileRef file_;
39
39
  SInt64 position_;
@@ -45,10 +45,11 @@ namespace Gosu
45
45
  bool big_endian_;
46
46
 
47
47
  static OSStatus AudioFile_ReadProc(void* in_client_data, SInt64 in_position,
48
- UInt32 request_count, void* buffer, UInt32* actual_count)
48
+ UInt32 request_count, void* buffer, UInt32* actual_count)
49
49
  {
50
50
  const Resource& res = *static_cast<Resource*>(in_client_data);
51
- *actual_count = std::min<UInt32>(request_count, res.size() - in_position);
51
+ *actual_count = std::min<UInt32>(request_count,
52
+ static_cast<UInt32>(res.size() - in_position));
52
53
  res.read(in_position, *actual_count, buffer);
53
54
  return noErr;
54
55
  }
@@ -81,7 +82,9 @@ namespace Gosu
81
82
  AudioStreamBasicDescription client_data = { 0 };
82
83
  sample_rate_ = client_data.mSampleRate = 22050;
83
84
  client_data.mFormatID = kAudioFormatLinearPCM;
84
- client_data.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
85
+ client_data.mFormatFlags = kAudioFormatFlagIsSignedInteger |
86
+ kAudioFormatFlagsNativeEndian |
87
+ kAudioFormatFlagIsPacked;
85
88
  client_data.mBitsPerChannel = 16;
86
89
  client_data.mChannelsPerFrame = base.mChannelsPerFrame;
87
90
  client_data.mFramesPerPacket = 1;
@@ -119,22 +122,15 @@ namespace Gosu
119
122
 
120
123
  // Easy formats
121
124
  format_ = 0;
122
- if (desc.mChannelsPerFrame == 1) {
123
- /*if (desc.mBitsPerChannel == 8)
124
- format_ = AL_FORMAT_MONO8;
125
- else*/ if (desc.mBitsPerChannel == 16)
126
- format_ = AL_FORMAT_MONO16;
125
+ if (desc.mChannelsPerFrame == 1 && desc.mBitsPerChannel == 16) {
126
+ format_ = AL_FORMAT_MONO16;
127
127
  }
128
- else if (desc.mChannelsPerFrame == 2) {
129
- /*if (desc.mBitsPerChannel == 8)
130
- format_ = AL_FORMAT_STEREO8;
131
- else */if (desc.mBitsPerChannel == 16)
132
- format_ = AL_FORMAT_STEREO16;
128
+ else if (desc.mChannelsPerFrame == 2 && desc.mBitsPerChannel == 16) {
129
+ format_ = AL_FORMAT_STEREO16;
133
130
  }
134
131
 
135
132
  if (format_ == 0 ||
136
- // If format not native for OpenAL, set client data format
137
- // to enable conversion
133
+ // If format not native for OpenAL, set client data format to enable conversion
138
134
  desc.mFormatFlags & kAudioFormatFlagIsBigEndian ||
139
135
  desc.mFormatFlags & kAudioFormatFlagIsFloat ||
140
136
  !(desc.mFormatFlags & kAudioFormatFlagIsSignedInteger)) {
@@ -159,7 +155,7 @@ namespace Gosu
159
155
  init();
160
156
  }
161
157
 
162
- AudioToolboxFile(Gosu::Reader reader)
158
+ AudioToolboxFile(Reader reader)
163
159
  {
164
160
  buffer_.resize(reader.resource().size() - reader.position());
165
161
  reader.read(buffer_.data(), buffer_.size());
@@ -204,7 +200,7 @@ namespace Gosu
204
200
  AudioBufferList abl;
205
201
  abl.mNumberBuffers = 1;
206
202
  abl.mBuffers[0].mNumberChannels = 1;
207
- abl.mBuffers[0].mDataByteSize = length;
203
+ abl.mBuffers[0].mDataByteSize = static_cast<UInt32>(length);
208
204
  abl.mBuffers[0].mData = dest;
209
205
  UInt32 numFrames = 0xffffffff; // give us as many frames as possible given our buffer
210
206
  CHECK_OS(ExtAudioFileRead(file_, &numFrames, &abl));
@@ -1,7 +1,8 @@
1
1
  #include <Gosu/Bitmap.hpp>
2
2
  #include <cassert>
3
3
  #include <algorithm>
4
- #include <vector>
4
+ #include <vector>
5
+ using namespace std;
5
6
 
6
7
  void Gosu::Bitmap::swap(Bitmap& other)
7
8
  {
@@ -26,15 +27,14 @@ void Gosu::Bitmap::insert(const Bitmap& source, int x, int y)
26
27
  }
27
28
 
28
29
  void Gosu::Bitmap::insert(const Bitmap& source, int x, int y, unsigned src_x, unsigned src_y,
29
- unsigned src_width, unsigned src_height)
30
+ unsigned src_width, unsigned src_height)
30
31
  {
31
32
  // TODO: This should use memcpy if possible (x == 0 && src_width == this->width())
32
33
 
33
34
  if (x < 0) {
34
35
  unsigned clip_left = -x;
35
36
 
36
- if (clip_left >= src_width)
37
- return;
37
+ if (clip_left >= src_width) return;
38
38
 
39
39
  src_x += clip_left;
40
40
  src_width -= clip_left;
@@ -44,8 +44,7 @@ void Gosu::Bitmap::insert(const Bitmap& source, int x, int y, unsigned src_x, un
44
44
  if (y < 0) {
45
45
  unsigned clip_top = -y;
46
46
 
47
- if (clip_top >= src_height)
48
- return;
47
+ if (clip_top >= src_height) return;
49
48
 
50
49
  src_y += clip_top;
51
50
  src_height -= clip_top;
@@ -53,27 +52,27 @@ void Gosu::Bitmap::insert(const Bitmap& source, int x, int y, unsigned src_x, un
53
52
  }
54
53
 
55
54
  if (x + src_width > w) {
56
- if (static_cast<unsigned>(x) >= w)
57
- return;
55
+ if (static_cast<unsigned>(x) >= w) return;
58
56
 
59
57
  src_width = w - x;
60
58
  }
61
59
 
62
60
  if (y + src_height > h) {
63
- if (static_cast<unsigned>(y) >= h)
64
- return;
61
+ if (static_cast<unsigned>(y) >= h) return;
65
62
 
66
63
  src_height = h - y;
67
64
  }
68
65
 
69
- for (unsigned rel_y = 0; rel_y < src_height; ++rel_y)
70
- for (unsigned rel_x = 0; rel_x < src_width; ++rel_x)
71
- set_pixel(x + rel_x, y + rel_y, source.get_pixel(src_x + rel_x, src_y + rel_y));
66
+ for (unsigned rel_y = 0; rel_y < src_height; ++rel_y) {
67
+ for (unsigned rel_x = 0; rel_x < src_width; ++rel_x) {
68
+ set_pixel(x + rel_x, y + rel_y, source.get_pixel(src_x + rel_x, src_y + rel_y));
69
+ }
70
+ }
72
71
  }
73
72
 
74
73
  void Gosu::apply_color_key(Bitmap& bitmap, Color key)
75
74
  {
76
- std::vector<Color> surrounding_colors;
75
+ vector<Color> surrounding_colors;
77
76
  surrounding_colors.reserve(4);
78
77
 
79
78
  for (unsigned y = 0; y < bitmap.height(); ++y)
@@ -96,31 +95,35 @@ void Gosu::apply_color_key(Bitmap& bitmap, Color key)
96
95
 
97
96
  unsigned red = 0, green = 0, blue = 0;
98
97
  for (auto& color : surrounding_colors) {
99
- red += color.red();
98
+ red += color.red();
100
99
  green += color.green();
101
- blue += color.blue();
100
+ blue += color.blue();
102
101
  }
103
- bitmap.set_pixel(x, y, Color(0, red / surrounding_colors.size(),
104
- green / surrounding_colors.size(), blue / surrounding_colors.size()));
102
+ bitmap.set_pixel(x, y, Color(0,
103
+ red / surrounding_colors.size(),
104
+ green / surrounding_colors.size(),
105
+ blue / surrounding_colors.size()));
105
106
  }
106
107
  }
107
108
 
108
109
  void Gosu::unapply_color_key(Bitmap& bitmap, Color color)
109
110
  {
110
111
  Color* p = bitmap.data();
111
- for (int i = bitmap.width() * bitmap.height(); i > 0; --i, ++p)
112
- if (p->alpha() == 0)
113
- *p = color;
114
- else
115
- p->set_alpha(255);
112
+ for (int i = bitmap.width() * bitmap.height(); i > 0; --i, ++p) {
113
+ if (p->alpha() == 0) {
114
+ *p = color;
115
+ }
116
+ else {
117
+ p->set_alpha(255);
118
+ }
119
+ }
116
120
  }
117
121
 
118
122
  void Gosu::apply_border_flags(Bitmap& dest, const Bitmap& source, unsigned src_x, unsigned src_y,
119
- unsigned src_width, unsigned src_height, unsigned image_flags)
123
+ unsigned src_width, unsigned src_height, unsigned image_flags)
120
124
  {
121
125
  // Backward compatibility: This used to be 'bool tileable'.
122
- if (image_flags == 1)
123
- image_flags = IF_TILEABLE;
126
+ if (image_flags == 1) image_flags = IF_TILEABLE;
124
127
 
125
128
  dest.resize(src_width + 2, src_height + 2);
126
129
 
@@ -142,17 +145,20 @@ void Gosu::apply_border_flags(Bitmap& dest, const Bitmap& source, unsigned src_x
142
145
 
143
146
  // Top left.
144
147
  if ((image_flags & IF_TILEABLE_TOP) && (image_flags & IF_TILEABLE_LEFT))
145
- dest.set_pixel(0, 0, source.get_pixel(src_x, src_y));
148
+ dest.set_pixel(0, 0,
149
+ source.get_pixel(src_x, src_y));
146
150
  // Top right.
147
151
  if ((image_flags & IF_TILEABLE_TOP) && (image_flags & IF_TILEABLE_RIGHT))
148
- dest.set_pixel(dest.width() - 1, 0, source.get_pixel(src_x + src_width - 1, src_y));
152
+ dest.set_pixel(dest.width() - 1, 0,
153
+ source.get_pixel(src_x + src_width - 1, src_y));
149
154
  // Bottom left.
150
155
  if ((image_flags & IF_TILEABLE_BOTTOM) && (image_flags & IF_TILEABLE_LEFT))
151
- dest.set_pixel(0, dest.height() - 1, source.get_pixel(src_x, src_y + src_height - 1));
156
+ dest.set_pixel(0, dest.height() - 1,
157
+ source.get_pixel(src_x, src_y + src_height - 1));
152
158
  // Bottom right.
153
159
  if ((image_flags & IF_TILEABLE_BOTTOM) && (image_flags & IF_TILEABLE_RIGHT))
154
160
  dest.set_pixel(dest.width() - 1, dest.height() - 1,
155
- source.get_pixel(src_x + src_width - 1, src_y + src_height - 1));
161
+ source.get_pixel(src_x + src_width - 1, src_y + src_height - 1));
156
162
 
157
163
  // Now put the final image into the prepared borders.
158
164
  dest.insert(source, 1, 1, src_x, src_y, src_width, src_height);
@@ -9,21 +9,17 @@
9
9
  #define STBI_NO_STDIO
10
10
  #define STBI_NO_LINEAR
11
11
 
12
- // Work around this bug:
13
- // https://bugs.launchpad.net/ubuntu/+source/gcc-5/+bug/1568899
14
- #ifdef GOSU_IS_X
15
- #define STBI_NO_SIMD
16
- #endif
17
-
18
12
  #include "stb_image.h"
19
13
 
14
+ using namespace std;
15
+
20
16
  namespace
21
17
  {
22
18
  int read_callback(void* user, char* data, int size)
23
19
  {
24
20
  Gosu::Reader* reader = static_cast<Gosu::Reader*>(user);
25
- std::size_t remaining = reader->resource().size() - reader->position();
26
- std::size_t actual_size = (size < remaining ? size : remaining);
21
+ size_t remaining = reader->resource().size() - reader->position();
22
+ size_t actual_size = (size < remaining ? size : remaining);
27
23
  reader->read(data, actual_size);
28
24
  return static_cast<int>(actual_size);
29
25
  }
@@ -42,18 +38,15 @@ namespace
42
38
 
43
39
  bool is_bmp(Gosu::Reader reader)
44
40
  {
45
- std::size_t remaining = reader.resource().size() - reader.position();
46
- if (remaining < 2) {
47
- return false;
48
- }
41
+ size_t remaining = reader.resource().size() - reader.position();
42
+ if (remaining < 2) return false;
49
43
  char magic_bytes[2];
50
44
  reader.read(magic_bytes, sizeof magic_bytes);
51
- reader.seek(sizeof magic_bytes);
52
45
  return magic_bytes[0] == 'B' && magic_bytes[1] == 'M';
53
46
  }
54
47
  }
55
48
 
56
- void Gosu::load_image_file(Gosu::Bitmap& bitmap, const std::string& filename)
49
+ void Gosu::load_image_file(Gosu::Bitmap& bitmap, const string& filename)
57
50
  {
58
51
  Buffer buffer;
59
52
  load_file(buffer, filename);
@@ -74,11 +67,11 @@ void Gosu::load_image_file(Gosu::Bitmap& bitmap, Reader input)
74
67
  if (bytes == nullptr) {
75
68
  // TODO - stbi_failure_reason is not thread safe. Everything here should be wrapped in a
76
69
  // mutex.
77
- throw std::runtime_error("Cannot load image: " + std::string(stbi_failure_reason()));
70
+ throw runtime_error("Cannot load image: " + string(stbi_failure_reason()));
78
71
  }
79
72
 
80
73
  bitmap.resize(x, y);
81
- std::memcpy(bitmap.data(), bytes, x * y * sizeof(Gosu::Color));
74
+ memcpy(bitmap.data(), bytes, x * y * sizeof(Gosu::Color));
82
75
 
83
76
  stbi_image_free(bytes);
84
77
 
@@ -90,7 +83,7 @@ void Gosu::load_image_file(Gosu::Bitmap& bitmap, Reader input)
90
83
  #define STB_IMAGE_WRITE_IMPLEMENTATION
91
84
  #include "stb_image_write.h"
92
85
 
93
- void Gosu::save_image_file(const Gosu::Bitmap& bitmap, const std::string& filename)
86
+ void Gosu::save_image_file(const Gosu::Bitmap& bitmap, const string& filename)
94
87
  {
95
88
  int ok;
96
89
 
@@ -104,9 +97,7 @@ void Gosu::save_image_file(const Gosu::Bitmap& bitmap, const std::string& filena
104
97
  ok = stbi_write_png(filename.c_str(), bitmap.width(), bitmap.height(), 4, bitmap.data(), 0);
105
98
  }
106
99
 
107
- if (ok == 0) {
108
- throw std::runtime_error("Could not save image data to file: " + filename);
109
- }
100
+ if (ok == 0) throw runtime_error("Could not save image data to file: " + filename);
110
101
  }
111
102
 
112
103
  static void stbi_write_to_writer(void* context, void* data, int size)
@@ -116,7 +107,7 @@ static void stbi_write_to_writer(void* context, void* data, int size)
116
107
  }
117
108
 
118
109
  void Gosu::save_image_file(const Gosu::Bitmap& bitmap, Gosu::Writer writer,
119
- const std::string& format_hint)
110
+ const string& format_hint)
120
111
  {
121
112
  int ok;
122
113
 
@@ -135,7 +126,7 @@ void Gosu::save_image_file(const Gosu::Bitmap& bitmap, Gosu::Writer writer,
135
126
  }
136
127
 
137
128
  if (ok == 0) {
138
- throw std::runtime_error("Could not save image data to memory (format hint = '" +
139
- format_hint + "'");
129
+ throw runtime_error("Could not save image data to memory (format hint = '" +
130
+ format_hint + "'");
140
131
  }
141
132
  }