gosu 1.4.6 → 2.0.0.pre6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (170) hide show
  1. checksums.yaml +4 -4
  2. data/COPYING +2 -1
  3. data/dependencies/SDL/include/SDL_atomic.h +2 -3
  4. data/dependencies/SDL/include/SDL_audio.h +7 -7
  5. data/dependencies/SDL/include/SDL_blendmode.h +1 -1
  6. data/dependencies/SDL/include/SDL_endian.h +3 -3
  7. data/dependencies/SDL/include/SDL_gamecontroller.h +4 -4
  8. data/dependencies/SDL/include/SDL_hints.h +72 -28
  9. data/dependencies/SDL/include/SDL_joystick.h +8 -5
  10. data/dependencies/SDL/include/SDL_keycode.h +1 -1
  11. data/dependencies/SDL/include/SDL_main.h +7 -0
  12. data/dependencies/SDL/include/SDL_mouse.h +6 -7
  13. data/dependencies/SDL/include/SDL_mutex.h +79 -5
  14. data/dependencies/SDL/include/SDL_opengl_glext.h +5 -1
  15. data/dependencies/SDL/include/SDL_power.h +7 -8
  16. data/dependencies/SDL/include/SDL_render.h +5 -0
  17. data/dependencies/SDL/include/SDL_revision.h +2 -2
  18. data/dependencies/SDL/include/SDL_sensor.h +1 -1
  19. data/dependencies/SDL/include/SDL_stdinc.h +19 -11
  20. data/dependencies/SDL/include/SDL_thread.h +2 -2
  21. data/dependencies/SDL/include/SDL_version.h +2 -2
  22. data/dependencies/SDL/include/SDL_video.h +30 -2
  23. data/dependencies/SDL/include/begin_code.h +7 -7
  24. data/dependencies/SDL/include/close_code.h +2 -2
  25. data/dependencies/SDL/lib/x64/libSDL2.dll.a +0 -0
  26. data/dependencies/SDL/lib/x86/libSDL2.dll.a +0 -0
  27. data/dependencies/SDL_sound/SDL_sound.h +1 -1
  28. data/dependencies/SDL_sound/dr_flac.h +48 -23
  29. data/dependencies/SDL_sound/dr_mp3.h +34 -14
  30. data/dependencies/SDL_sound/stb_vorbis.h +3 -2
  31. data/dependencies/mojoAL/mojoal.c +1 -1
  32. data/ext/{gosu → gosu-ffi}/extconf.rb +34 -33
  33. data/ext/gosu-ffi/gosu-ffi.def +464 -0
  34. data/ffi/Gosu.cpp +307 -0
  35. data/ffi/Gosu.h +84 -0
  36. data/ffi/Gosu_Channel.cpp +62 -0
  37. data/ffi/Gosu_Channel.h +17 -0
  38. data/ffi/Gosu_Color.cpp +132 -0
  39. data/ffi/Gosu_Color.h +31 -0
  40. data/ffi/Gosu_Constants.cpp +334 -0
  41. data/ffi/Gosu_FFI.h +34 -0
  42. data/ffi/Gosu_FFI_internal.h +161 -0
  43. data/ffi/Gosu_Font.cpp +92 -0
  44. data/ffi/Gosu_Font.h +32 -0
  45. data/ffi/Gosu_Image.cpp +206 -0
  46. data/ffi/Gosu_Image.h +60 -0
  47. data/ffi/Gosu_Sample.cpp +29 -0
  48. data/ffi/Gosu_Sample.h +14 -0
  49. data/ffi/Gosu_Song.cpp +69 -0
  50. data/ffi/Gosu_Song.h +18 -0
  51. data/ffi/Gosu_TextInput.cpp +94 -0
  52. data/ffi/Gosu_TextInput.h +25 -0
  53. data/ffi/Gosu_Window.cpp +314 -0
  54. data/ffi/Gosu_Window.h +78 -0
  55. data/include/Gosu/Audio.hpp +6 -11
  56. data/include/Gosu/Bitmap.hpp +38 -53
  57. data/include/Gosu/Buffer.hpp +54 -0
  58. data/include/Gosu/Color.hpp +27 -35
  59. data/include/Gosu/Directories.hpp +25 -28
  60. data/include/Gosu/Drawable.hpp +58 -0
  61. data/include/Gosu/Font.hpp +6 -5
  62. data/include/Gosu/Fwd.hpp +4 -6
  63. data/include/Gosu/Gosu.hpp +5 -5
  64. data/include/Gosu/Graphics.hpp +51 -61
  65. data/include/Gosu/GraphicsBase.hpp +1 -11
  66. data/include/Gosu/Image.hpp +11 -14
  67. data/include/Gosu/Math.hpp +50 -72
  68. data/include/Gosu/Transform.hpp +32 -0
  69. data/include/Gosu/Utility.hpp +51 -1
  70. data/include/Gosu/Version.hpp +3 -3
  71. data/include/Gosu/Window.hpp +15 -9
  72. data/lib/SDL2.dll +0 -0
  73. data/lib/gosu/channel.rb +49 -0
  74. data/lib/gosu/color.rb +150 -0
  75. data/lib/gosu/compat.rb +29 -8
  76. data/lib/gosu/constants.rb +386 -0
  77. data/lib/gosu/ffi.rb +258 -0
  78. data/lib/gosu/font.rb +56 -0
  79. data/lib/gosu/gl_tex_info.rb +33 -0
  80. data/lib/gosu/gosu.rb +210 -0
  81. data/lib/gosu/image.rb +141 -0
  82. data/lib/gosu/numeric.rb +17 -0
  83. data/lib/gosu/preview.rb +6 -6
  84. data/lib/gosu/sample.rb +24 -0
  85. data/lib/gosu/song.rb +56 -0
  86. data/lib/gosu/text_input.rb +69 -0
  87. data/lib/gosu/window.rb +228 -0
  88. data/lib/gosu.rb +29 -8
  89. data/lib64/SDL2.dll +0 -0
  90. data/rdoc/gosu.rb +0 -2
  91. data/src/Audio.cpp +12 -12
  92. data/src/AudioFile.hpp +5 -4
  93. data/src/AudioFileAudioToolbox.cpp +8 -8
  94. data/src/AudioFileSDLSound.cpp +7 -10
  95. data/src/BinPacker.cpp +187 -0
  96. data/src/BinPacker.hpp +55 -0
  97. data/src/Bitmap.cpp +166 -144
  98. data/src/BitmapIO.cpp +60 -86
  99. data/src/Buffer.cpp +159 -0
  100. data/src/Color.cpp +75 -80
  101. data/src/Directories.cpp +47 -0
  102. data/src/DirectoriesUIKit.cpp +50 -0
  103. data/src/DrawOp.hpp +9 -4
  104. data/src/DrawOpQueue.hpp +2 -2
  105. data/src/Drawable.cpp +95 -0
  106. data/src/EmptyDrawable.hpp +38 -0
  107. data/src/FPS.cpp +31 -0
  108. data/src/Font.cpp +104 -74
  109. data/src/GosuGLView.cpp +14 -6
  110. data/src/GosuViewController.cpp +2 -10
  111. data/src/Graphics.cpp +60 -126
  112. data/src/GraphicsImpl.hpp +17 -47
  113. data/src/Image.cpp +41 -35
  114. data/src/Input.cpp +7 -8
  115. data/src/Macro.cpp +6 -6
  116. data/src/Macro.hpp +4 -4
  117. data/src/MarkupParser.cpp +5 -5
  118. data/src/Math.cpp +35 -22
  119. data/src/OffScreenTarget.cpp +53 -49
  120. data/src/OffScreenTarget.hpp +13 -11
  121. data/src/OpenGLContext.cpp +117 -0
  122. data/src/OpenGLContext.hpp +41 -0
  123. data/src/RenderState.hpp +21 -19
  124. data/src/Resolution.cpp +23 -21
  125. data/src/TexChunk.cpp +35 -80
  126. data/src/TexChunk.hpp +44 -35
  127. data/src/Text.cpp +1 -1
  128. data/src/TextBuilder.cpp +35 -21
  129. data/src/TextBuilder.hpp +6 -9
  130. data/src/Texture.cpp +62 -80
  131. data/src/Texture.hpp +25 -23
  132. data/src/TiledDrawable.cpp +150 -0
  133. data/src/TiledDrawable.hpp +47 -0
  134. data/src/TimingApple.cpp +1 -1
  135. data/src/Transform.cpp +45 -50
  136. data/src/TransformStack.hpp +16 -16
  137. data/src/TrueTypeFont.cpp +59 -51
  138. data/src/TrueTypeFont.hpp +6 -7
  139. data/src/TrueTypeFontApple.cpp +28 -19
  140. data/src/TrueTypeFontUnix.cpp +27 -23
  141. data/src/TrueTypeFontWin.cpp +30 -30
  142. data/src/Utility.cpp +84 -21
  143. data/src/UtilityWin.cpp +45 -0
  144. data/src/Window.cpp +92 -142
  145. data/src/WindowUIKit.cpp +14 -14
  146. metadata +72 -31
  147. data/include/Gosu/IO.hpp +0 -254
  148. data/include/Gosu/ImageData.hpp +0 -53
  149. data/include/Gosu/Inspection.hpp +0 -7
  150. data/lib/gosu/patches.rb +0 -66
  151. data/lib/gosu/run.rb +0 -20
  152. data/lib/gosu/swig_patches.rb +0 -110
  153. data/src/BlockAllocator.cpp +0 -131
  154. data/src/BlockAllocator.hpp +0 -32
  155. data/src/DirectoriesApple.cpp +0 -69
  156. data/src/DirectoriesUnix.cpp +0 -46
  157. data/src/DirectoriesWin.cpp +0 -65
  158. data/src/EmptyImageData.hpp +0 -52
  159. data/src/FileUnix.cpp +0 -99
  160. data/src/FileWin.cpp +0 -88
  161. data/src/IO.cpp +0 -60
  162. data/src/Iconv.hpp +0 -51
  163. data/src/Inspection.cpp +0 -27
  164. data/src/LargeImageData.cpp +0 -215
  165. data/src/LargeImageData.hpp +0 -39
  166. data/src/Log.hpp +0 -19
  167. data/src/RubyGosu.cxx +0 -13100
  168. data/src/RubyGosu.h +0 -49
  169. data/src/WinUtility.cpp +0 -61
  170. data/src/WinUtility.hpp +0 -27
@@ -0,0 +1,228 @@
1
+ module Gosu
2
+ class Window
3
+ %w(update draw needs_redraw? needs_cursor? capture_cursor? hit_test gain_focus lose_focus
4
+ button_down button_up gamepad_connected gamepad_disconnected drop close).each do |callback|
5
+ define_method "protected_#{callback}" do |*args|
6
+ begin
7
+ # If there has been an exception, don't do anything as to not make matters worse.
8
+ # Conveniently turn the return value into a boolean result (for needs_cursor? etc).
9
+ defined?(@__exception) ? false : send(callback, *args)
10
+ rescue Exception => e
11
+ # Exit the message loop naturally, then re-throw during the next tick.
12
+ @__exception = e
13
+ close!
14
+ false
15
+ ensure
16
+ $gosu_gl_blocks = nil if callback == "draw"
17
+ end
18
+ end
19
+ end
20
+
21
+ def initialize(width, height, _fullscreen = nil, _update_interval = nil, _resizable = nil, _borderless = nil,
22
+ fullscreen: false, update_interval: 16.66666667, resizable: false, borderless: false)
23
+ fullscreen = _fullscreen if _fullscreen
24
+ update_interval = _update_interval if _update_interval
25
+ resizable = _resizable if _resizable
26
+ borderless = _borderless if _borderless
27
+
28
+ window_flags = GosuFFI.window_flags(fullscreen: fullscreen, resizable: resizable, borderless: borderless)
29
+
30
+ __window = GosuFFI.Gosu_Window_create(width, height, window_flags, update_interval)
31
+ GosuFFI.check_last_error
32
+ @memory_pointer = FFI::AutoPointer.new(__window, GosuFFI.method(:Gosu_Window_destroy))
33
+ @text_input = nil
34
+
35
+ {
36
+ update: [],
37
+ draw: [],
38
+ button_down: [:id],
39
+ button_up: [:id],
40
+ gamepad_connected: [:id],
41
+ gamepad_disconnected: [:id],
42
+ drop: [:filename],
43
+ needs_redraw?: [],
44
+ needs_cursor?: [],
45
+ close: [],
46
+ gain_focus: [],
47
+ lose_focus: [],
48
+ }.each do |callback, args|
49
+ callback_safename = callback.to_s.sub("?", "")
50
+
51
+ instance_eval("@__#{callback_safename}_proc = proc { |#{[:data, args].flatten.join(",")}| protected_#{callback}(#{args.join(",")}) }")
52
+ GosuFFI.send(:"Gosu_Window_set_#{callback_safename}", __pointer, instance_variable_get(:"@__#{callback_safename}_proc"), nil)
53
+ GosuFFI.check_last_error
54
+ end
55
+ end
56
+
57
+ # Returns FFI pointer of C side Gosu::Window
58
+ def __pointer
59
+ @memory_pointer
60
+ end
61
+
62
+ def update
63
+ end
64
+
65
+ def draw
66
+ end
67
+
68
+ def button_down(id)
69
+ GosuFFI.Gosu_Window_default_button_down(__pointer, id)
70
+ GosuFFI.check_last_error
71
+ end
72
+
73
+ def button_up(id)
74
+ end
75
+
76
+ def gamepad_connected(id)
77
+ end
78
+
79
+ def gamepad_disconnected(id)
80
+ end
81
+
82
+ def drop(filename)
83
+ end
84
+
85
+ def needs_redraw?
86
+ true
87
+ end
88
+
89
+ def needs_cursor?
90
+ false
91
+ end
92
+
93
+ def capture_cursor?
94
+ false
95
+ end
96
+
97
+ def close
98
+ close!
99
+ end
100
+
101
+ def gain_focus
102
+ end
103
+
104
+ def lose_focus
105
+ end
106
+
107
+ def caption
108
+ GosuFFI.check_last_error(GosuFFI.Gosu_Window_caption(__pointer))
109
+ end
110
+
111
+ def caption=(text)
112
+ GosuFFI.Gosu_Window_set_caption(__pointer, text)
113
+ GosuFFI.check_last_error
114
+ end
115
+
116
+ def fullscreen?
117
+ GosuFFI.check_last_error(GosuFFI.Gosu_Window_is_fullscreen(__pointer))
118
+ end
119
+
120
+ def fullscreen=(boolean)
121
+ GosuFFI.Gosu_Window_resize(__pointer, width, height, !!boolean)
122
+ GosuFFI.check_last_error
123
+ end
124
+
125
+ def resizable?
126
+ GosuFFI.check_last_error(GosuFFI.Gosu_Window_is_resizable(__pointer))
127
+ end
128
+
129
+ def resizable=(boolean)
130
+ GosuFFI.Gosu_Window_set_resizable(__pointer, !!boolean)
131
+ GosuFFI.check_last_error
132
+ end
133
+
134
+ def borderless?
135
+ GosuFFI.check_last_error(GosuFFI.Gosu_Window_is_borderless(__pointer))
136
+ end
137
+
138
+ def borderless=(boolean)
139
+ GosuFFI.Gosu_Window_set_borderless(__pointer, !!boolean)
140
+ GosuFFI.check_last_error
141
+ end
142
+
143
+ def text_input
144
+ @text_input || nil
145
+ end
146
+
147
+ def text_input=(text_input)
148
+ if not text_input.nil? and not text_input.is_a? Gosu::TextInput
149
+ raise ArgumentError, "text_input must be nil or a Gosu::TextInput"
150
+ end
151
+
152
+ @text_input = text_input
153
+
154
+ GosuFFI.Gosu_Window_set_text_input(__pointer, text_input&.__pointer)
155
+ GosuFFI.check_last_error
156
+ end
157
+
158
+ def update_interval
159
+ GosuFFI.check_last_error(GosuFFI.Gosu_Window_update_interval(__pointer))
160
+ end
161
+
162
+ def update_interval=(double)
163
+ GosuFFI.Gosu_Window_set_update_interval(__pointer, double)
164
+ GosuFFI.check_last_error
165
+ end
166
+
167
+ def width
168
+ GosuFFI.check_last_error(GosuFFI.Gosu_Window_width(__pointer))
169
+ end
170
+
171
+ def width=(int)
172
+ GosuFFI.Gosu_Window_resize(__pointer, int, height, fullscreen?)
173
+ GosuFFI.check_last_error
174
+ end
175
+
176
+ def height
177
+ GosuFFI.check_last_error(GosuFFI.Gosu_Window_height(__pointer))
178
+ end
179
+
180
+ def height=(int)
181
+ GosuFFI.Gosu_Window_resize(__pointer, width, int, fullscreen?)
182
+ GosuFFI.check_last_error
183
+ end
184
+
185
+ def mouse_x
186
+ GosuFFI.check_last_error(GosuFFI.Gosu_Window_mouse_x(__pointer))
187
+ end
188
+
189
+ def mouse_x=(double)
190
+ GosuFFI.Gosu_Window_set_mouse_x(__pointer, double)
191
+ GosuFFI.check_last_error
192
+ end
193
+
194
+ def mouse_y
195
+ GosuFFI.check_last_error(GosuFFI.Gosu_Window_mouse_y(__pointer))
196
+ end
197
+
198
+ def mouse_y=(double)
199
+ GosuFFI.Gosu_Window_set_mouse_y(__pointer, double)
200
+ GosuFFI.check_last_error
201
+ end
202
+
203
+ def show
204
+ GosuFFI.Gosu_Window_show(__pointer)
205
+
206
+ raise @__exception if defined?(@__exception)
207
+
208
+ GosuFFI.check_last_error
209
+ end
210
+
211
+ def tick
212
+ value = GosuFFI.check_last_error(GosuFFI.Gosu_Window_tick(__pointer))
213
+
214
+ raise @__exception if defined?(@__exception)
215
+
216
+ value
217
+ end
218
+
219
+ def close!
220
+ GosuFFI.Gosu_Window_close_immediately(__pointer)
221
+ GosuFFI.check_last_error
222
+ end
223
+
224
+ def sdl_window
225
+ GosuFFI.check_last_error(GosuFFI.Gosu_Window_sdl_window(__pointer))
226
+ end
227
+ end
228
+ end
data/lib/gosu.rb CHANGED
@@ -1,14 +1,14 @@
1
- require 'rbconfig'
1
+ require "ffi"
2
2
 
3
3
  if RUBY_PLATFORM =~ /mswin$|mingw|win32\-|\-win32/
4
- binary_path = File.dirname(__FILE__)
5
- # 64-bit builds of Windows use "x64-mingw32" as RUBY_PLATFORM
4
+ binary_path = File.expand_path("../lib", __dir__)
5
+ # 64-bit builds of Windows use "x64-mingw" as RUBY_PLATFORM
6
6
  binary_path += "64" if RUBY_PLATFORM =~ /^x64-/
7
7
 
8
8
  begin
9
9
  # Make DLLs available as shown here:
10
10
  # https://github.com/oneclick/rubyinstaller2/wiki/For-gem-developers
11
- require 'ruby_installer'
11
+ require "ruby_installer"
12
12
  RubyInstaller::Runtime.add_dll_directory(binary_path)
13
13
  rescue LoadError
14
14
  # Add this gem to the PATH on Windows so that bundled DLLs can be found.
@@ -17,10 +17,31 @@ if RUBY_PLATFORM =~ /mswin$|mingw|win32\-|\-win32/
17
17
  path_encoding = ENV["PATH"].encoding
18
18
  ENV["PATH"] = "#{binary_path.encode(path_encoding)};#{ENV["PATH"]}"
19
19
  end
20
+
21
+ # Add the correct lib directory for the current version of Ruby (major.minor).
22
+ $LOAD_PATH.prepend File.join(binary_path, RUBY_VERSION[/^\d+.\d+/])
23
+ end
24
+
25
+ module Gosu
20
26
  end
21
27
 
22
- require "gosu.#{RbConfig::CONFIG["DLEXT"]}"
28
+ require_relative "gosu/ffi"
29
+ require_relative "gosu/constants"
30
+
31
+ require_relative "gosu/numeric"
32
+
33
+ # Individual classes need to be loaded after defining GosuFFI.check_last_error.
34
+
35
+ require_relative "gosu/gosu"
36
+
37
+ require_relative "gosu/channel"
38
+ require_relative "gosu/color"
39
+ require_relative "gosu/font"
40
+ require_relative "gosu/gl_tex_info"
41
+ require_relative "gosu/image"
42
+ require_relative "gosu/sample"
43
+ require_relative "gosu/song"
44
+ require_relative "gosu/text_input"
45
+ require_relative "gosu/window"
23
46
 
24
- require "gosu/swig_patches"
25
- require "gosu/patches"
26
- require "gosu/compat"
47
+ require_relative "gosu/compat"
data/lib64/SDL2.dll CHANGED
Binary file
data/rdoc/gosu.rb CHANGED
@@ -1,5 +1,3 @@
1
- ## Encoding: UTF-8
2
-
3
1
  module Gosu
4
2
  ##
5
3
  # The first component of the version.
data/src/Audio.cpp CHANGED
@@ -1,5 +1,5 @@
1
1
  #include <Gosu/Audio.hpp>
2
- #include <Gosu/IO.hpp>
2
+ #include <Gosu/Buffer.hpp>
3
3
  #include <Gosu/Math.hpp>
4
4
  #include "AudioFile.hpp"
5
5
  #include "AudioImpl.hpp"
@@ -42,12 +42,12 @@ Gosu::Sample::Sample()
42
42
  }
43
43
 
44
44
  Gosu::Sample::Sample(const std::string& filename)
45
- : m_impl{new Impl(AudioFile(filename))}
45
+ : m_impl(new Impl(AudioFile(filename)))
46
46
  {
47
47
  }
48
48
 
49
- Gosu::Sample::Sample(Gosu::Reader reader)
50
- : m_impl{new Impl(AudioFile(reader))}
49
+ Gosu::Sample::Sample(Buffer buffer)
50
+ : m_impl(new Impl(AudioFile(std::move(buffer))))
51
51
  {
52
52
  }
53
53
 
@@ -101,16 +101,16 @@ private:
101
101
 
102
102
  public:
103
103
  explicit Impl(const std::string& filename)
104
- : m_buffers{},
105
- m_file{new AudioFile{filename}}
104
+ : m_buffers {},
105
+ m_file(new AudioFile(filename))
106
106
  {
107
107
  al_initialize();
108
108
  alGenBuffers(2, m_buffers);
109
109
  }
110
110
 
111
- explicit Impl(Reader reader)
112
- : m_buffers{},
113
- m_file{new AudioFile{reader}}
111
+ explicit Impl(Buffer buffer)
112
+ : m_buffers {},
113
+ m_file(new AudioFile(std::move(buffer)))
114
114
  {
115
115
  al_initialize();
116
116
  alGenBuffers(2, m_buffers);
@@ -229,12 +229,12 @@ public:
229
229
  };
230
230
 
231
231
  Gosu::Song::Song(const std::string& filename)
232
- : m_impl{new Impl(filename)}
232
+ : m_impl(new Impl(filename))
233
233
  {
234
234
  }
235
235
 
236
- Gosu::Song::Song(Reader reader)
237
- : m_impl{new Impl(reader)}
236
+ Gosu::Song::Song(Buffer buffer)
237
+ : m_impl(new Impl(std::move(buffer)))
238
238
  {
239
239
  }
240
240
 
data/src/AudioFile.hpp CHANGED
@@ -1,10 +1,10 @@
1
1
  #pragma once
2
2
 
3
- #include <Gosu/IO.hpp>
3
+ #include <Gosu/Fwd.hpp>
4
4
 
5
5
  #ifdef GOSU_IS_IPHONE
6
- // Ignore OpenAL deprecation warnings. If macOS stops shipping OpenAL, it's more likely that we bundle our own version
7
- // of it than that we switch to another audio API.
6
+ // Ignore OpenAL deprecation warnings. If iOS stops shipping OpenAL, it's more likely that we
7
+ // bundle our own version of it than that we switch to another audio API.
8
8
  #define OPENAL_DEPRECATED
9
9
  #include <OpenAL/al.h>
10
10
  #else
@@ -12,6 +12,7 @@
12
12
  #endif
13
13
 
14
14
  #include <cstddef>
15
+ #include <memory>
15
16
  #include <string>
16
17
  #include <vector>
17
18
 
@@ -24,7 +25,7 @@ namespace Gosu
24
25
 
25
26
  public:
26
27
  explicit AudioFile(const std::string& filename);
27
- explicit AudioFile(Reader reader);
28
+ explicit AudioFile(Buffer buffer);
28
29
  ~AudioFile();
29
30
 
30
31
  ALenum format() const;
@@ -8,6 +8,7 @@
8
8
 
9
9
  #include "AudioFile.hpp"
10
10
  #include "AudioImpl.hpp"
11
+ #include <Gosu/Buffer.hpp>
11
12
  #include <Gosu/Utility.hpp>
12
13
 
13
14
  #import <AudioToolbox/AudioToolbox.h>
@@ -18,6 +19,7 @@
18
19
 
19
20
  #include <algorithm>
20
21
  #include <arpa/inet.h>
22
+ #include <cstring>
21
23
  #include <stdexcept>
22
24
  #include <vector>
23
25
 
@@ -53,16 +55,16 @@ struct Gosu::AudioFile::Impl : private Gosu::Noncopyable
53
55
  static OSStatus AudioFile_ReadProc(void* in_client_data, SInt64 in_position,
54
56
  UInt32 request_count, void* buffer, UInt32* actual_count)
55
57
  {
56
- const Resource& res = *static_cast<Resource*>(in_client_data);
58
+ const Buffer& res = *static_cast<Buffer*>(in_client_data);
57
59
  *actual_count = std::min<UInt32>(request_count,
58
60
  static_cast<UInt32>(res.size() - in_position));
59
- res.read(in_position, *actual_count, buffer);
61
+ std::memcpy(buffer, res.data() + in_position, *actual_count);
60
62
  return noErr;
61
63
  }
62
64
 
63
65
  static SInt64 AudioFile_GetSizeProc(void* in_client_data)
64
66
  {
65
- const Resource& res = *static_cast<Resource*>(in_client_data);
67
+ const Buffer& res = *static_cast<Buffer*>(in_client_data);
66
68
  return res.size();
67
69
  }
68
70
 
@@ -162,14 +164,12 @@ Gosu::AudioFile::AudioFile(const std::string& filename)
162
164
  pimpl->init();
163
165
  }
164
166
 
165
- Gosu::AudioFile::AudioFile(Reader reader)
167
+ Gosu::AudioFile::AudioFile(Buffer buffer)
166
168
  : pimpl(new Impl)
167
169
  {
168
- pimpl->buffer.resize(reader.resource().size() - reader.position());
169
- reader.read(pimpl->buffer.data(), pimpl->buffer.size());
170
+ pimpl->buffer = std::move(buffer);
170
171
 
171
- void* client_data = &pimpl->buffer;
172
- CHECK_OS(AudioFileOpenWithCallbacks(client_data, Impl::AudioFile_ReadProc, nullptr,
172
+ CHECK_OS(AudioFileOpenWithCallbacks(&pimpl->buffer, Impl::AudioFile_ReadProc, nullptr,
173
173
  Impl::AudioFile_GetSizeProc, nullptr, 0, &pimpl->file_id));
174
174
  CHECK_OS(ExtAudioFileWrapAudioFileID(pimpl->file_id, false, &pimpl->file));
175
175
 
@@ -1,20 +1,18 @@
1
+ #include <Gosu/Buffer.hpp>
1
2
  #include <Gosu/Platform.hpp>
2
3
 
3
4
  #ifndef GOSU_IS_IPHONE
4
5
 
5
6
  #include "AudioFile.hpp"
6
7
  #include "AudioImpl.hpp"
7
-
8
8
  #include <SDL_sound.h>
9
-
9
+ #include <algorithm>
10
10
  #include <cstdlib>
11
11
  #include <cstring>
12
- #include <algorithm>
13
12
  #include <memory>
14
13
  #include <mutex>
15
14
  #include <stdexcept>
16
15
  #include <vector>
17
- #include <stdexcept>
18
16
 
19
17
  struct Gosu::AudioFile::Impl : private Gosu::Noncopyable
20
18
  {
@@ -57,14 +55,13 @@ Gosu::AudioFile::AudioFile(const std::string& filename)
57
55
  }
58
56
  }
59
57
 
60
- Gosu::AudioFile::AudioFile(Reader reader)
58
+ Gosu::AudioFile::AudioFile(Gosu::Buffer buffer)
61
59
  : pimpl(new Impl)
62
60
  {
63
- pimpl->buffer.resize(reader.resource().size() - reader.position());
64
- reader.read(pimpl->buffer.data(), pimpl->buffer.size());
65
- pimpl->sample.reset(Sound_NewSampleFromMem(reinterpret_cast<Uint8*>(pimpl->buffer.data()),
66
- static_cast<Uint32>(pimpl->buffer.size()),
67
- "", nullptr, 4096),
61
+ pimpl->buffer = std::move(buffer);
62
+ pimpl->sample.reset(Sound_NewSampleFromMem(pimpl->buffer.data(),
63
+ static_cast<Uint32>(pimpl->buffer.size()), "",
64
+ nullptr, 4096),
68
65
  Sound_FreeSample);
69
66
  if (!pimpl->sample) {
70
67
  std::string message = "Could not parse audio file";
data/src/BinPacker.cpp ADDED
@@ -0,0 +1,187 @@
1
+ #include <Gosu/Utility.hpp>
2
+ #include "BinPacker.hpp"
3
+ #include <algorithm>
4
+
5
+ #ifndef NDEBUG
6
+ #include <cassert>
7
+ #endif
8
+
9
+ Gosu::BinPacker::BinPacker(int width, int height)
10
+ : m_width(width),
11
+ m_height(height),
12
+ m_free_rects { Rect { 0, 0, width, height } }
13
+ {
14
+ }
15
+
16
+ std::shared_ptr<const Gosu::Rect> Gosu::BinPacker::alloc(int width, int height)
17
+ {
18
+ std::unique_lock lock(m_mutex);
19
+
20
+ const Rect* best_rect = best_free_rect(width, height);
21
+
22
+ // We didn't find a single free rectangle that can fit the required size? Exit.
23
+ if (best_rect == nullptr) {
24
+ return nullptr;
25
+ }
26
+
27
+ // We found a free area, place the result in the top left corner of it.
28
+ // (Also make sure that the pointer's deleter returns the rectangle. Note: Even though
29
+ // shared_ptr may call its deleter with a nullptr in general, it will not do so here.)
30
+ std::shared_ptr<const Rect> result(new Rect { best_rect->x, best_rect->y, width, height },
31
+ [this](const Rect* p) { add_free_rect(*p); });
32
+
33
+ // We need to split the remaining rectangle into two. We use the axis with the longer side.
34
+ // (Called "Longer Axis Split Rule", "-LAS" in the paper.)
35
+ Rect new_rect_right = *best_rect;
36
+ Rect new_rect_below = *best_rect;
37
+ if (best_rect->width < best_rect->height) {
38
+ // ┏━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓
39
+ // ┃ result ┃ new_rect_right ┃
40
+ // ┣━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┫
41
+ // ┃ new_rect_below ┃
42
+ // ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
43
+ new_rect_right.x += width;
44
+ new_rect_right.width -= width;
45
+ new_rect_right.height = height;
46
+
47
+ new_rect_below.y += height;
48
+ new_rect_below.height -= height;
49
+ }
50
+ else {
51
+ // ┏━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓
52
+ // ┃ result ┃ ┃
53
+ // ┣━━━━━━━━━━━━━━━━┫ new_rect_right ┃
54
+ // ┃ new_rect_below ┃ ┃
55
+ // ┗━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━┛
56
+ new_rect_right.x += width;
57
+ new_rect_right.width -= width;
58
+
59
+ new_rect_below.y += height;
60
+ new_rect_below.height -= height;
61
+ new_rect_below.width = width;
62
+ }
63
+
64
+ remove_free_rect(static_cast<int>(best_rect - m_free_rects.data()));
65
+
66
+ // Release the mutex lock before calling add_free_rect to avoid a deadlock.
67
+ lock.unlock();
68
+
69
+ if (!new_rect_below.empty()) {
70
+ add_free_rect(new_rect_below);
71
+ }
72
+ if (!new_rect_right.empty()) {
73
+ add_free_rect(new_rect_right);
74
+ }
75
+
76
+ return result;
77
+ }
78
+
79
+ void Gosu::BinPacker::add_free_rect(const Rect& rect)
80
+ {
81
+ const std::scoped_lock lock(m_mutex);
82
+
83
+ #ifndef NDEBUG
84
+ for (const Rect& other_free_rect : m_free_rects) {
85
+ assert(!rect.overlaps(other_free_rect));
86
+ }
87
+ #endif
88
+
89
+ m_free_rects.push_back(rect);
90
+ merge_neighbors(static_cast<int>(m_free_rects.size() - 1));
91
+ }
92
+
93
+ const Gosu::Rect* Gosu::BinPacker::best_free_rect(int width, int height) const
94
+ {
95
+ // The rect wouldn't even fit onto the texture!
96
+ if (width > m_width || height > m_height) {
97
+ return nullptr;
98
+ }
99
+
100
+ const Rect* best_rect = nullptr;
101
+ int best_weight = 0;
102
+
103
+ for (const Rect& free_rect : m_free_rects) {
104
+ // This implements the "Best Short Side Fit" (BSSF) metric for choosing a free area.
105
+ int weight = std::min(free_rect.width - width, free_rect.height - height);
106
+ if (weight < 0) {
107
+ continue;
108
+ }
109
+ if (best_rect == nullptr || weight < best_weight) {
110
+ best_rect = &free_rect;
111
+ best_weight = weight;
112
+ }
113
+ }
114
+
115
+ return best_rect;
116
+ }
117
+
118
+ void Gosu::BinPacker::remove_free_rect(int index, int* other_index)
119
+ {
120
+ std::swap(m_free_rects.at(index), m_free_rects.back());
121
+ if (other_index && *other_index == m_free_rects.size() - 1) {
122
+ *other_index = index;
123
+ }
124
+
125
+ m_free_rects.pop_back();
126
+ }
127
+
128
+ void Gosu::BinPacker::merge_neighbors(int index)
129
+ {
130
+ // This algorithm tries to merge adjacent free rectangles into larger ones where possible.
131
+ // However, it only finds pairwise combinations of rectangles that can be merged into a single,
132
+ // larger rectangle. You may find that textures/bins sometimes end up with free rectangles that
133
+ // are shaped like this:
134
+ // ┏━━━━┳━┓
135
+ // ┣━┳━━┫ ┃
136
+ // ┃ ┣━━┻━┫
137
+ // ┗━┻━━━━┛
138
+ // In this case, the texture gets stuck in this fragmented state. We assume that this is not an
139
+ // issue in practice, just like memory
140
+
141
+ // Merge any of the other rectangles in the list into the one with the given index if they share
142
+ // any of their four sides.
143
+ for (int j = 0; j < m_free_rects.size(); ++j) {
144
+ Rect& rect = m_free_rects[index];
145
+
146
+ const Rect& other_rect = m_free_rects[j];
147
+ bool merged = false;
148
+ if (rect.x == other_rect.x && rect.width == other_rect.width) {
149
+ // Both rectangles are horizontally aligned.
150
+
151
+ if (rect.y == other_rect.bottom()) {
152
+ // rect is directly below other_rect, expand it upward.
153
+ rect.y = other_rect.y;
154
+ rect.height += other_rect.height;
155
+ merged = true;
156
+ }
157
+ else if (other_rect.y == rect.bottom()) {
158
+ // rect is directly above other_rect, expand it downward.
159
+ rect.height += other_rect.height;
160
+ merged = true;
161
+ }
162
+ }
163
+ else if (rect.y == other_rect.y && rect.height == other_rect.height) {
164
+ // Both rectangles are vertically aligned.
165
+
166
+ if (rect.x == other_rect.right()) {
167
+ // rect is directly to the right of other_rect, expand it to the left.
168
+ rect.x = other_rect.x;
169
+ rect.width += other_rect.width;
170
+ merged = true;
171
+ }
172
+ else if (other_rect.x == rect.right()) {
173
+ // rect is directly to the left of other_rect, expand it to the right.
174
+ rect.width += other_rect.width;
175
+ merged = true;
176
+ }
177
+ }
178
+
179
+ // If we merged two rectangles, then we need to start over because the longer sides of the
180
+ // combined rectangle might allow new mergers with other adjacent rectangles, and so on.
181
+ if (merged) {
182
+ remove_free_rect(j, &index);
183
+ // Reset j to -1 so that the next loop iteration will resume at j == 0.
184
+ j = -1;
185
+ }
186
+ }
187
+ }