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.
- checksums.yaml +4 -4
- data/COPYING +2 -1
- data/dependencies/SDL/include/SDL_atomic.h +2 -3
- data/dependencies/SDL/include/SDL_audio.h +7 -7
- data/dependencies/SDL/include/SDL_blendmode.h +1 -1
- data/dependencies/SDL/include/SDL_endian.h +3 -3
- data/dependencies/SDL/include/SDL_gamecontroller.h +4 -4
- data/dependencies/SDL/include/SDL_hints.h +72 -28
- data/dependencies/SDL/include/SDL_joystick.h +8 -5
- data/dependencies/SDL/include/SDL_keycode.h +1 -1
- data/dependencies/SDL/include/SDL_main.h +7 -0
- data/dependencies/SDL/include/SDL_mouse.h +6 -7
- data/dependencies/SDL/include/SDL_mutex.h +79 -5
- data/dependencies/SDL/include/SDL_opengl_glext.h +5 -1
- data/dependencies/SDL/include/SDL_power.h +7 -8
- data/dependencies/SDL/include/SDL_render.h +5 -0
- data/dependencies/SDL/include/SDL_revision.h +2 -2
- data/dependencies/SDL/include/SDL_sensor.h +1 -1
- data/dependencies/SDL/include/SDL_stdinc.h +19 -11
- data/dependencies/SDL/include/SDL_thread.h +2 -2
- data/dependencies/SDL/include/SDL_version.h +2 -2
- data/dependencies/SDL/include/SDL_video.h +30 -2
- data/dependencies/SDL/include/begin_code.h +7 -7
- data/dependencies/SDL/include/close_code.h +2 -2
- data/dependencies/SDL/lib/x64/libSDL2.dll.a +0 -0
- data/dependencies/SDL/lib/x86/libSDL2.dll.a +0 -0
- data/dependencies/SDL_sound/SDL_sound.h +1 -1
- data/dependencies/SDL_sound/dr_flac.h +48 -23
- data/dependencies/SDL_sound/dr_mp3.h +34 -14
- data/dependencies/SDL_sound/stb_vorbis.h +3 -2
- data/dependencies/mojoAL/mojoal.c +1 -1
- data/ext/{gosu → gosu-ffi}/extconf.rb +34 -33
- data/ext/gosu-ffi/gosu-ffi.def +464 -0
- data/ffi/Gosu.cpp +307 -0
- data/ffi/Gosu.h +84 -0
- data/ffi/Gosu_Channel.cpp +62 -0
- data/ffi/Gosu_Channel.h +17 -0
- data/ffi/Gosu_Color.cpp +132 -0
- data/ffi/Gosu_Color.h +31 -0
- data/ffi/Gosu_Constants.cpp +334 -0
- data/ffi/Gosu_FFI.h +34 -0
- data/ffi/Gosu_FFI_internal.h +161 -0
- data/ffi/Gosu_Font.cpp +92 -0
- data/ffi/Gosu_Font.h +32 -0
- data/ffi/Gosu_Image.cpp +206 -0
- data/ffi/Gosu_Image.h +60 -0
- data/ffi/Gosu_Sample.cpp +29 -0
- data/ffi/Gosu_Sample.h +14 -0
- data/ffi/Gosu_Song.cpp +69 -0
- data/ffi/Gosu_Song.h +18 -0
- data/ffi/Gosu_TextInput.cpp +94 -0
- data/ffi/Gosu_TextInput.h +25 -0
- data/ffi/Gosu_Window.cpp +314 -0
- data/ffi/Gosu_Window.h +78 -0
- data/include/Gosu/Audio.hpp +6 -11
- data/include/Gosu/Bitmap.hpp +38 -53
- data/include/Gosu/Buffer.hpp +54 -0
- data/include/Gosu/Color.hpp +27 -35
- data/include/Gosu/Directories.hpp +25 -28
- data/include/Gosu/Drawable.hpp +58 -0
- data/include/Gosu/Font.hpp +6 -5
- data/include/Gosu/Fwd.hpp +4 -6
- data/include/Gosu/Gosu.hpp +5 -5
- data/include/Gosu/Graphics.hpp +51 -61
- data/include/Gosu/GraphicsBase.hpp +1 -11
- data/include/Gosu/Image.hpp +11 -14
- data/include/Gosu/Math.hpp +50 -72
- data/include/Gosu/Transform.hpp +32 -0
- data/include/Gosu/Utility.hpp +51 -1
- data/include/Gosu/Version.hpp +3 -3
- data/include/Gosu/Window.hpp +15 -9
- data/lib/SDL2.dll +0 -0
- data/lib/gosu/channel.rb +49 -0
- data/lib/gosu/color.rb +150 -0
- data/lib/gosu/compat.rb +29 -8
- data/lib/gosu/constants.rb +386 -0
- data/lib/gosu/ffi.rb +258 -0
- data/lib/gosu/font.rb +56 -0
- data/lib/gosu/gl_tex_info.rb +33 -0
- data/lib/gosu/gosu.rb +210 -0
- data/lib/gosu/image.rb +141 -0
- data/lib/gosu/numeric.rb +17 -0
- data/lib/gosu/preview.rb +6 -6
- data/lib/gosu/sample.rb +24 -0
- data/lib/gosu/song.rb +56 -0
- data/lib/gosu/text_input.rb +69 -0
- data/lib/gosu/window.rb +228 -0
- data/lib/gosu.rb +29 -8
- data/lib64/SDL2.dll +0 -0
- data/rdoc/gosu.rb +0 -2
- data/src/Audio.cpp +12 -12
- data/src/AudioFile.hpp +5 -4
- data/src/AudioFileAudioToolbox.cpp +8 -8
- data/src/AudioFileSDLSound.cpp +7 -10
- data/src/BinPacker.cpp +187 -0
- data/src/BinPacker.hpp +55 -0
- data/src/Bitmap.cpp +166 -144
- data/src/BitmapIO.cpp +60 -86
- data/src/Buffer.cpp +159 -0
- data/src/Color.cpp +75 -80
- data/src/Directories.cpp +47 -0
- data/src/DirectoriesUIKit.cpp +50 -0
- data/src/DrawOp.hpp +9 -4
- data/src/DrawOpQueue.hpp +2 -2
- data/src/Drawable.cpp +95 -0
- data/src/EmptyDrawable.hpp +38 -0
- data/src/FPS.cpp +31 -0
- data/src/Font.cpp +104 -74
- data/src/GosuGLView.cpp +14 -6
- data/src/GosuViewController.cpp +2 -10
- data/src/Graphics.cpp +60 -126
- data/src/GraphicsImpl.hpp +17 -47
- data/src/Image.cpp +41 -35
- data/src/Input.cpp +7 -8
- data/src/Macro.cpp +6 -6
- data/src/Macro.hpp +4 -4
- data/src/MarkupParser.cpp +5 -5
- data/src/Math.cpp +35 -22
- data/src/OffScreenTarget.cpp +53 -49
- data/src/OffScreenTarget.hpp +13 -11
- data/src/OpenGLContext.cpp +117 -0
- data/src/OpenGLContext.hpp +41 -0
- data/src/RenderState.hpp +21 -19
- data/src/Resolution.cpp +23 -21
- data/src/TexChunk.cpp +35 -80
- data/src/TexChunk.hpp +44 -35
- data/src/Text.cpp +1 -1
- data/src/TextBuilder.cpp +35 -21
- data/src/TextBuilder.hpp +6 -9
- data/src/Texture.cpp +62 -80
- data/src/Texture.hpp +25 -23
- data/src/TiledDrawable.cpp +150 -0
- data/src/TiledDrawable.hpp +47 -0
- data/src/TimingApple.cpp +1 -1
- data/src/Transform.cpp +45 -50
- data/src/TransformStack.hpp +16 -16
- data/src/TrueTypeFont.cpp +59 -51
- data/src/TrueTypeFont.hpp +6 -7
- data/src/TrueTypeFontApple.cpp +28 -19
- data/src/TrueTypeFontUnix.cpp +27 -23
- data/src/TrueTypeFontWin.cpp +30 -30
- data/src/Utility.cpp +84 -21
- data/src/UtilityWin.cpp +45 -0
- data/src/Window.cpp +92 -142
- data/src/WindowUIKit.cpp +14 -14
- metadata +72 -31
- data/include/Gosu/IO.hpp +0 -254
- data/include/Gosu/ImageData.hpp +0 -53
- data/include/Gosu/Inspection.hpp +0 -7
- data/lib/gosu/patches.rb +0 -66
- data/lib/gosu/run.rb +0 -20
- data/lib/gosu/swig_patches.rb +0 -110
- data/src/BlockAllocator.cpp +0 -131
- data/src/BlockAllocator.hpp +0 -32
- data/src/DirectoriesApple.cpp +0 -69
- data/src/DirectoriesUnix.cpp +0 -46
- data/src/DirectoriesWin.cpp +0 -65
- data/src/EmptyImageData.hpp +0 -52
- data/src/FileUnix.cpp +0 -99
- data/src/FileWin.cpp +0 -88
- data/src/IO.cpp +0 -60
- data/src/Iconv.hpp +0 -51
- data/src/Inspection.cpp +0 -27
- data/src/LargeImageData.cpp +0 -215
- data/src/LargeImageData.hpp +0 -39
- data/src/Log.hpp +0 -19
- data/src/RubyGosu.cxx +0 -13100
- data/src/RubyGosu.h +0 -49
- data/src/WinUtility.cpp +0 -61
- data/src/WinUtility.hpp +0 -27
data/lib/gosu/window.rb
ADDED
@@ -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
|
1
|
+
require "ffi"
|
2
2
|
|
3
3
|
if RUBY_PLATFORM =~ /mswin$|mingw|win32\-|\-win32/
|
4
|
-
binary_path = File.
|
5
|
-
# 64-bit builds of Windows use "x64-
|
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
|
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
|
-
|
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
|
-
|
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
data/src/Audio.cpp
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#include <Gosu/Audio.hpp>
|
2
|
-
#include <Gosu/
|
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
|
45
|
+
: m_impl(new Impl(AudioFile(filename)))
|
46
46
|
{
|
47
47
|
}
|
48
48
|
|
49
|
-
Gosu::Sample::Sample(
|
50
|
-
: m_impl
|
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
|
-
|
105
|
-
|
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(
|
112
|
-
|
113
|
-
|
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
|
232
|
+
: m_impl(new Impl(filename))
|
233
233
|
{
|
234
234
|
}
|
235
235
|
|
236
|
-
Gosu::Song::Song(
|
237
|
-
: m_impl
|
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/
|
3
|
+
#include <Gosu/Fwd.hpp>
|
4
4
|
|
5
5
|
#ifdef GOSU_IS_IPHONE
|
6
|
-
// Ignore OpenAL deprecation warnings. If
|
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(
|
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
|
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.
|
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
|
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(
|
167
|
+
Gosu::AudioFile::AudioFile(Buffer buffer)
|
166
168
|
: pimpl(new Impl)
|
167
169
|
{
|
168
|
-
pimpl->buffer
|
169
|
-
reader.read(pimpl->buffer.data(), pimpl->buffer.size());
|
170
|
+
pimpl->buffer = std::move(buffer);
|
170
171
|
|
171
|
-
|
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
|
|
data/src/AudioFileSDLSound.cpp
CHANGED
@@ -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(
|
58
|
+
Gosu::AudioFile::AudioFile(Gosu::Buffer buffer)
|
61
59
|
: pimpl(new Impl)
|
62
60
|
{
|
63
|
-
pimpl->buffer
|
64
|
-
|
65
|
-
|
66
|
-
|
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
|
+
}
|