ruby-sfml 3.0.0.0 → 3.0.0.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +130 -0
- data/README.md +34 -45
- data/lib/sfml/audio/internal.rb +41 -0
- data/lib/sfml/audio/listener.rb +31 -0
- data/lib/sfml/audio/music.rb +64 -0
- data/lib/sfml/audio/sound.rb +82 -0
- data/lib/sfml/audio/sound_cone.rb +56 -0
- data/lib/sfml/audio/sound_stream.rb +206 -0
- data/lib/sfml/c/audio.rb +78 -0
- data/lib/sfml/c/graphics.rb +51 -0
- data/lib/sfml/c/network.rb +104 -0
- data/lib/sfml/c/system.rb +10 -0
- data/lib/sfml/c/window.rb +42 -0
- data/lib/sfml/graphics/image.rb +23 -0
- data/lib/sfml/graphics/render_states.rb +5 -3
- data/lib/sfml/graphics/render_target.rb +23 -2
- data/lib/sfml/graphics/render_window.rb +55 -0
- data/lib/sfml/graphics/shader.rb +71 -11
- data/lib/sfml/graphics/stencil_mode.rb +93 -0
- data/lib/sfml/graphics/vertex_buffer.rb +127 -0
- data/lib/sfml/network/ftp.rb +184 -0
- data/lib/sfml/network/http.rb +117 -0
- data/lib/sfml/network/socket_selector.rb +93 -0
- data/lib/sfml/version.rb +1 -1
- data/lib/sfml/window/event.rb +14 -0
- data/lib/sfml/window/sensor.rb +50 -0
- data/lib/sfml/window/touch.rb +39 -0
- data/lib/sfml/window/window.rb +57 -0
- data/lib/sfml.rb +27 -2
- metadata +11 -1
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
module SFML
|
|
2
|
+
module Network
|
|
3
|
+
# CSFML's tiny HTTP/1.x client. Useful when an SFML 3 game wants
|
|
4
|
+
# to talk to a leaderboard / asset server without pulling in
|
|
5
|
+
# `Net::HTTP`. For anything more involved (TLS, redirects,
|
|
6
|
+
# streaming, retries, JSON), Ruby's stdlib `Net::HTTP` is the
|
|
7
|
+
# better tool — this wrapper exists for parity with CSFML, not
|
|
8
|
+
# because we recommend it.
|
|
9
|
+
#
|
|
10
|
+
# http = SFML::Network::Http.new("http://localhost", port: 8080)
|
|
11
|
+
# resp = http.send_request(method: :get, uri: "/")
|
|
12
|
+
# resp.status #=> 200
|
|
13
|
+
# resp.body #=> "Hello world\n"
|
|
14
|
+
#
|
|
15
|
+
# `send_request` accepts:
|
|
16
|
+
# method: :get / :post / :head / :put / :delete (default :get)
|
|
17
|
+
# uri: path string (default "/")
|
|
18
|
+
# fields: Hash of header name → value
|
|
19
|
+
# body: String body (POST/PUT)
|
|
20
|
+
# http_version: [major, minor] (default [1, 0])
|
|
21
|
+
# timeout: SFML::Time or seconds (default 0 = no timeout)
|
|
22
|
+
class Http
|
|
23
|
+
DEFAULT_TIMEOUT = SFML::Time.zero
|
|
24
|
+
DEFAULT_VERSION = [1, 0].freeze
|
|
25
|
+
|
|
26
|
+
def initialize(host, port: 0)
|
|
27
|
+
ptr = C::Network.sfHttp_create
|
|
28
|
+
raise Error, "sfHttp_create returned NULL" if ptr.null?
|
|
29
|
+
|
|
30
|
+
@handle = FFI::AutoPointer.new(ptr, C::Network.method(:sfHttp_destroy))
|
|
31
|
+
C::Network.sfHttp_setHost(@handle, host.to_s, Integer(port))
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def send_request(method: :get, uri: "/", fields: nil, body: nil,
|
|
35
|
+
http_version: DEFAULT_VERSION, timeout: DEFAULT_TIMEOUT)
|
|
36
|
+
request_ptr = C::Network.sfHttpRequest_create
|
|
37
|
+
raise Error, "sfHttpRequest_create returned NULL" if request_ptr.null?
|
|
38
|
+
|
|
39
|
+
begin
|
|
40
|
+
method_idx = C::Network::HTTP_METHODS.index(method) ||
|
|
41
|
+
raise(ArgumentError, "Unknown HTTP method: #{method.inspect} " \
|
|
42
|
+
"(expected one of #{C::Network::HTTP_METHODS.inspect})")
|
|
43
|
+
C::Network.sfHttpRequest_setMethod(request_ptr, method_idx)
|
|
44
|
+
C::Network.sfHttpRequest_setUri(request_ptr, uri.to_s)
|
|
45
|
+
C::Network.sfHttpRequest_setHttpVersion(request_ptr, Integer(http_version[0]), Integer(http_version[1]))
|
|
46
|
+
C::Network.sfHttpRequest_setBody(request_ptr, body.to_s) if body
|
|
47
|
+
fields&.each_pair do |name, value|
|
|
48
|
+
C::Network.sfHttpRequest_setField(request_ptr, name.to_s, value.to_s)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
t = timeout.is_a?(Time) ? timeout : Time.seconds(timeout.to_f)
|
|
52
|
+
response_ptr = C::Network.sfHttp_sendRequest(@handle, request_ptr, t.to_native)
|
|
53
|
+
raise Error, "sfHttp_sendRequest returned NULL" if response_ptr.null?
|
|
54
|
+
|
|
55
|
+
Response.send(:_take_ownership, response_ptr)
|
|
56
|
+
ensure
|
|
57
|
+
C::Network.sfHttpRequest_destroy(request_ptr)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
attr_reader :handle # :nodoc:
|
|
62
|
+
|
|
63
|
+
# Read-only view onto a CSFML sfHttpResponse. Wraps the C pointer
|
|
64
|
+
# in a Ruby object that destroys the response when GC'd.
|
|
65
|
+
class Response
|
|
66
|
+
# Status mappings — most map onto standard HTTP codes; the four
|
|
67
|
+
# at the bottom are SFML-side transport errors above the
|
|
68
|
+
# standard range (≥ 1000).
|
|
69
|
+
STATUS_NAMES = {
|
|
70
|
+
200 => :ok, 201 => :created, 202 => :accepted, 204 => :no_content,
|
|
71
|
+
205 => :reset_content, 206 => :partial_content,
|
|
72
|
+
301 => :multiple_choices, 302 => :moved_permanently, 303 => :moved_temporarily,
|
|
73
|
+
304 => :not_modified,
|
|
74
|
+
400 => :bad_request, 401 => :unauthorized, 403 => :forbidden, 404 => :not_found,
|
|
75
|
+
405 => :range_not_satisfiable,
|
|
76
|
+
500 => :internal_server_error, 501 => :not_implemented, 502 => :bad_gateway,
|
|
77
|
+
503 => :service_not_available, 504 => :gateway_timeout, 505 => :version_not_supported,
|
|
78
|
+
1000 => :invalid_response, 1001 => :connection_failed,
|
|
79
|
+
}.freeze
|
|
80
|
+
|
|
81
|
+
def initialize
|
|
82
|
+
raise NoMethodError, "use SFML::Network::Http#send_request to create a Response"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def status
|
|
86
|
+
C::Network.sfHttpResponse_getStatus(@handle)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# The status as a symbol when CSFML maps it, otherwise the
|
|
90
|
+
# raw integer. Useful for `case resp.status_symbol in :ok`.
|
|
91
|
+
def status_symbol
|
|
92
|
+
STATUS_NAMES[status] || status
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def body = C::Network.sfHttpResponse_getBody(@handle).to_s
|
|
96
|
+
def field(name) = C::Network.sfHttpResponse_getField(@handle, name.to_s)
|
|
97
|
+
|
|
98
|
+
def http_version
|
|
99
|
+
[
|
|
100
|
+
C::Network.sfHttpResponse_getMajorVersion(@handle),
|
|
101
|
+
C::Network.sfHttpResponse_getMinorVersion(@handle),
|
|
102
|
+
]
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
attr_reader :handle # :nodoc:
|
|
106
|
+
|
|
107
|
+
# @!visibility private
|
|
108
|
+
def self._take_ownership(ptr)
|
|
109
|
+
obj = allocate
|
|
110
|
+
obj.instance_variable_set(:@handle,
|
|
111
|
+
FFI::AutoPointer.new(ptr, C::Network.method(:sfHttpResponse_destroy)))
|
|
112
|
+
obj
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
module SFML
|
|
2
|
+
module Network
|
|
3
|
+
# Multiplex many sockets onto a single blocking #wait. Useful for
|
|
4
|
+
# one-thread network servers — register every socket / listener
|
|
5
|
+
# you care about, call #wait, then ask each one whether it's
|
|
6
|
+
# `ready?`. Ready means there's data to read or, for a listener,
|
|
7
|
+
# an incoming connection waiting.
|
|
8
|
+
#
|
|
9
|
+
# selector = SFML::Network::SocketSelector.new
|
|
10
|
+
# selector.add(listener)
|
|
11
|
+
# clients.each { |c| selector.add(c) }
|
|
12
|
+
#
|
|
13
|
+
# if selector.wait(timeout: 1.0)
|
|
14
|
+
# if selector.ready?(listener)
|
|
15
|
+
# # accept() will not block
|
|
16
|
+
# end
|
|
17
|
+
# clients.each do |c|
|
|
18
|
+
# next unless selector.ready?(c)
|
|
19
|
+
# # receive() will return data
|
|
20
|
+
# end
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
# Ruby's `IO.select` covers a similar use case for plain Ruby IO
|
|
24
|
+
# objects; this binding exists for game code that's already using
|
|
25
|
+
# `SFML::Network::Tcp{Socket,Listener}` / `UdpSocket`.
|
|
26
|
+
class SocketSelector
|
|
27
|
+
def initialize
|
|
28
|
+
ptr = C::Network.sfSocketSelector_create
|
|
29
|
+
raise Error, "sfSocketSelector_create returned NULL" if ptr.null?
|
|
30
|
+
|
|
31
|
+
@handle = FFI::AutoPointer.new(ptr, C::Network.method(:sfSocketSelector_destroy))
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def add(socket)
|
|
35
|
+
case socket
|
|
36
|
+
when TcpListener then C::Network.sfSocketSelector_addTcpListener(@handle, socket.handle)
|
|
37
|
+
when TcpSocket then C::Network.sfSocketSelector_addTcpSocket(@handle, socket.handle)
|
|
38
|
+
when UdpSocket then C::Network.sfSocketSelector_addUdpSocket(@handle, socket.handle)
|
|
39
|
+
else
|
|
40
|
+
raise ArgumentError,
|
|
41
|
+
"SocketSelector#add expects TcpListener, TcpSocket, or UdpSocket (got #{socket.class})"
|
|
42
|
+
end
|
|
43
|
+
self
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def remove(socket)
|
|
47
|
+
case socket
|
|
48
|
+
when TcpListener then C::Network.sfSocketSelector_removeTcpListener(@handle, socket.handle)
|
|
49
|
+
when TcpSocket then C::Network.sfSocketSelector_removeTcpSocket(@handle, socket.handle)
|
|
50
|
+
when UdpSocket then C::Network.sfSocketSelector_removeUdpSocket(@handle, socket.handle)
|
|
51
|
+
else
|
|
52
|
+
raise ArgumentError,
|
|
53
|
+
"SocketSelector#remove expects TcpListener, TcpSocket, or UdpSocket (got #{socket.class})"
|
|
54
|
+
end
|
|
55
|
+
self
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def clear
|
|
59
|
+
C::Network.sfSocketSelector_clear(@handle)
|
|
60
|
+
self
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Block until at least one registered socket has activity, or
|
|
64
|
+
# `timeout` elapses. `timeout` may be a SFML::Time, a Numeric
|
|
65
|
+
# (seconds), or nil / SFML::Time.zero (no timeout — block
|
|
66
|
+
# forever). Returns true if a socket is ready, false on timeout.
|
|
67
|
+
def wait(timeout: nil)
|
|
68
|
+
t =
|
|
69
|
+
case timeout
|
|
70
|
+
when nil then SFML::Time.zero
|
|
71
|
+
when Time then timeout
|
|
72
|
+
when Numeric then SFML::Time.seconds(timeout.to_f)
|
|
73
|
+
else
|
|
74
|
+
raise ArgumentError, "timeout must be SFML::Time, Numeric, or nil"
|
|
75
|
+
end
|
|
76
|
+
C::Network.sfSocketSelector_wait(@handle, t.to_native)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def ready?(socket)
|
|
80
|
+
case socket
|
|
81
|
+
when TcpListener then C::Network.sfSocketSelector_isTcpListenerReady(@handle, socket.handle)
|
|
82
|
+
when TcpSocket then C::Network.sfSocketSelector_isTcpSocketReady(@handle, socket.handle)
|
|
83
|
+
when UdpSocket then C::Network.sfSocketSelector_isUdpSocketReady(@handle, socket.handle)
|
|
84
|
+
else
|
|
85
|
+
raise ArgumentError,
|
|
86
|
+
"SocketSelector#ready? expects TcpListener, TcpSocket, or UdpSocket (got #{socket.class})"
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
attr_reader :handle # :nodoc:
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
data/lib/sfml/version.rb
CHANGED
data/lib/sfml/window/event.rb
CHANGED
|
@@ -122,6 +122,20 @@ module SFML
|
|
|
122
122
|
c = C::Window::JoystickConnectEvent.new(ptr)
|
|
123
123
|
{ joystick_id: c[:joystick_id] }
|
|
124
124
|
|
|
125
|
+
when :touch_began, :touch_moved, :touch_ended
|
|
126
|
+
t = C::Window::TouchEvent.new(ptr)
|
|
127
|
+
{
|
|
128
|
+
finger: t[:finger],
|
|
129
|
+
position: Vector2.new(t[:position][:x], t[:position][:y]),
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
when :sensor_changed
|
|
133
|
+
s = C::Window::SensorEvent.new(ptr)
|
|
134
|
+
{
|
|
135
|
+
sensor: Sensor::TYPES[s[:sensor]] || :unknown,
|
|
136
|
+
value: Vector3.new(s[:value][:x], s[:value][:y], s[:value][:z]),
|
|
137
|
+
}
|
|
138
|
+
|
|
125
139
|
else
|
|
126
140
|
EMPTY
|
|
127
141
|
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module SFML
|
|
2
|
+
# Mobile-platform inertial / environment sensors. SFML treats every
|
|
3
|
+
# device the same way: identify the sensor by symbol, ask if it's
|
|
4
|
+
# available, enable it before reading, then poll a Vector3 value
|
|
5
|
+
# whose components depend on the sensor type (e.g. acceleration in
|
|
6
|
+
# m/s² for `:accelerometer`, angular velocity in deg/s for
|
|
7
|
+
# `:gyroscope`, magnetic field in µT for `:magnetometer`).
|
|
8
|
+
#
|
|
9
|
+
# if SFML::Sensor.available?(:accelerometer)
|
|
10
|
+
# SFML::Sensor.enable(:accelerometer)
|
|
11
|
+
# gravity = SFML::Sensor.value(:accelerometer)
|
|
12
|
+
# end
|
|
13
|
+
#
|
|
14
|
+
# On desktop platforms without sensor hardware, `available?` returns
|
|
15
|
+
# `false` and `value` returns the zero vector — calls don't raise.
|
|
16
|
+
#
|
|
17
|
+
# Sensor data also surfaces through the event loop as
|
|
18
|
+
# `{type: :sensor_changed, sensor: :accelerometer, value: Vector3}`.
|
|
19
|
+
module Sensor
|
|
20
|
+
TYPES = C::Window::SENSOR_TYPES
|
|
21
|
+
TYPE_INDEX = TYPES.each_with_index.to_h.freeze
|
|
22
|
+
|
|
23
|
+
module_function
|
|
24
|
+
|
|
25
|
+
def available?(type)
|
|
26
|
+
C::Window.sfSensor_isAvailable(_index(type))
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def enable(type)
|
|
30
|
+
C::Window.sfSensor_setEnabled(_index(type), true)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def disable(type)
|
|
34
|
+
C::Window.sfSensor_setEnabled(_index(type), false)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def value(type)
|
|
38
|
+
v = C::Window.sfSensor_getValue(_index(type))
|
|
39
|
+
Vector3.new(v[:x], v[:y], v[:z])
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# @!visibility private
|
|
43
|
+
def _index(type)
|
|
44
|
+
TYPE_INDEX.fetch(type) do
|
|
45
|
+
raise ArgumentError, "Unknown sensor type: #{type.inspect} " \
|
|
46
|
+
"(expected one of #{TYPES.inspect})"
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module SFML
|
|
2
|
+
# Polling API for touchscreen input. Each finger is identified by an
|
|
3
|
+
# integer (0 = first contact, 1 = second, etc.). The same fingers
|
|
4
|
+
# also surface through the event loop as `:touch_began`,
|
|
5
|
+
# `:touch_moved`, `:touch_ended` events with `finger:` and
|
|
6
|
+
# `position:` fields.
|
|
7
|
+
#
|
|
8
|
+
# if SFML::Touch.down?(0)
|
|
9
|
+
# pos = SFML::Touch.position(0, relative_to: window)
|
|
10
|
+
# ...
|
|
11
|
+
# end
|
|
12
|
+
#
|
|
13
|
+
# On desktop platforms without touchscreen hardware these always
|
|
14
|
+
# return `false` / `[0, 0]`.
|
|
15
|
+
module Touch
|
|
16
|
+
module_function
|
|
17
|
+
|
|
18
|
+
# True while finger `n` is currently in contact with the screen.
|
|
19
|
+
def down?(finger = 0)
|
|
20
|
+
C::Window.sfTouch_isDown(Integer(finger))
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Position of finger `n`. Without `relative_to:`, returns
|
|
24
|
+
# desktop-relative coordinates; pass a Window or RenderWindow to
|
|
25
|
+
# get window-local coordinates.
|
|
26
|
+
def position(finger = 0, relative_to: nil)
|
|
27
|
+
f = Integer(finger)
|
|
28
|
+
vec =
|
|
29
|
+
case relative_to
|
|
30
|
+
when nil then C::Window.sfTouch_getPosition(f, nil)
|
|
31
|
+
when RenderWindow then C::Graphics.sfTouch_getPositionRenderWindow(f, relative_to.handle)
|
|
32
|
+
when Window then C::Window.sfTouch_getPosition(f, relative_to.handle)
|
|
33
|
+
else
|
|
34
|
+
raise ArgumentError, "relative_to: must be SFML::Window, SFML::RenderWindow, or nil"
|
|
35
|
+
end
|
|
36
|
+
Vector2.new(vec[:x], vec[:y])
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
data/lib/sfml/window/window.rb
CHANGED
|
@@ -129,10 +129,67 @@ module SFML
|
|
|
129
129
|
C::Window.sfWindow_setActive(@handle, value ? true : false)
|
|
130
130
|
end
|
|
131
131
|
|
|
132
|
+
# Replace the window's title-bar / taskbar icon with the pixels from
|
|
133
|
+
# the given SFML::Image. The OS scales it as needed; 32×32 RGBA
|
|
134
|
+
# is the typical sweet spot.
|
|
135
|
+
def icon=(image)
|
|
136
|
+
raise ArgumentError, "Window#icon= requires a SFML::Image" unless image.is_a?(SFML::Image)
|
|
137
|
+
|
|
138
|
+
size = C::System::Vector2u.new
|
|
139
|
+
size[:x] = image.width
|
|
140
|
+
size[:y] = image.height
|
|
141
|
+
C::Window.sfWindow_setIcon(@handle, size, C::Graphics.sfImage_getPixelsPtr(image.handle))
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Constrain user-driven resizes. Accepts a [w, h] Array, a Vector2,
|
|
145
|
+
# or nil to clear the limit. When set, the OS won't let the user
|
|
146
|
+
# drag the window smaller (or larger) than this — programmatic
|
|
147
|
+
# `size=` is not affected.
|
|
148
|
+
def minimum_size=(value)
|
|
149
|
+
C::Window.sfWindow_setMinimumSize(@handle, _vec2u_or_nil(value))
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def maximum_size=(value)
|
|
153
|
+
C::Window.sfWindow_setMaximumSize(@handle, _vec2u_or_nil(value))
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# OS-specific native handle for the underlying window — `HWND` on
|
|
157
|
+
# Windows, `NSView*` on macOS, X11 `Window` xid on Linux.
|
|
158
|
+
# Returns an FFI::Pointer; cast or read as the platform expects.
|
|
159
|
+
def native_handle
|
|
160
|
+
C::Window.sfWindow_getNativeHandle(@handle)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Wrap an existing OS-level window. `handle` is a platform native
|
|
164
|
+
# handle (Integer address or FFI::Pointer). Useful when SFML is
|
|
165
|
+
# being embedded inside another framework (Qt, Gtk, raw Win32,
|
|
166
|
+
# Cocoa NSView). The framework owns the window's lifecycle; SFML
|
|
167
|
+
# only renders into it.
|
|
168
|
+
def self.from_handle(handle)
|
|
169
|
+
ptr = handle.is_a?(FFI::Pointer) ? handle : FFI::Pointer.new(:void, Integer(handle))
|
|
170
|
+
raw = C::Window.sfWindow_createFromHandle(ptr, nil)
|
|
171
|
+
raise Error, "sfWindow_createFromHandle returned NULL" if raw.null?
|
|
172
|
+
|
|
173
|
+
win = allocate
|
|
174
|
+
win.instance_variable_set(:@handle,
|
|
175
|
+
FFI::AutoPointer.new(raw, C::Window.method(:sfWindow_destroy)))
|
|
176
|
+
win.instance_variable_set(:@event_buffer, C::Window::Event.new)
|
|
177
|
+
win
|
|
178
|
+
end
|
|
179
|
+
|
|
132
180
|
attr_reader :handle # :nodoc:
|
|
133
181
|
|
|
134
182
|
private
|
|
135
183
|
|
|
184
|
+
def _vec2u_or_nil(value)
|
|
185
|
+
return nil if value.nil?
|
|
186
|
+
|
|
187
|
+
vec = value.is_a?(Vector2) ? value : Vector2.new(*value)
|
|
188
|
+
v = C::System::Vector2u.new
|
|
189
|
+
v[:x] = Integer(vec.x); v[:y] = Integer(vec.y)
|
|
190
|
+
v
|
|
191
|
+
end
|
|
192
|
+
|
|
136
193
|
def parse_args(args)
|
|
137
194
|
case args.length
|
|
138
195
|
when 2
|
data/lib/sfml.rb
CHANGED
|
@@ -32,13 +32,28 @@ at_exit do
|
|
|
32
32
|
else 1
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
# 2.
|
|
35
|
+
# 2. If we're exiting because of an unhandled exception, print it
|
|
36
|
+
# ourselves — `exit!` below skips Ruby's terminal exception
|
|
37
|
+
# reporter, so without this the user sees a silent exit instead
|
|
38
|
+
# of the stack trace they'd normally get.
|
|
39
|
+
if $! && !$!.is_a?(SystemExit)
|
|
40
|
+
err = $!
|
|
41
|
+
warn "#{err.backtrace.first}: #{err.message} (#{err.class})"
|
|
42
|
+
err.backtrace.drop(1).each { |line| warn "\tfrom #{line}" }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# 3. Quiet the audio thread before anything else — OpenAL holds onto
|
|
36
46
|
# sample buffers and crashes if Ruby starts freeing them while
|
|
37
47
|
# a Sound/Music is mid-loop.
|
|
38
48
|
ObjectSpace.each_object(SFML::Sound) { |s| s.stop rescue nil } if defined?(SFML::Sound)
|
|
39
49
|
ObjectSpace.each_object(SFML::Music) { |m| m.stop rescue nil } if defined?(SFML::Music)
|
|
50
|
+
# SoundStream isn't stopped from this hook on purpose — by the time
|
|
51
|
+
# at_exit runs, finalizer ordering can have already destroyed
|
|
52
|
+
# the underlying CSFML stream, and CSFML asserts on a stale handle.
|
|
53
|
+
# Either explicitly #stop your SoundStream before exit, or rely on
|
|
54
|
+
# exit!() below to skip the audio thread's natural teardown.
|
|
40
55
|
|
|
41
|
-
#
|
|
56
|
+
# 4. Bypass Ruby's natural finalizer pass entirely. Process memory is
|
|
42
57
|
# about to be reclaimed by the kernel anyway, and Ruby's
|
|
43
58
|
# non-deterministic destruction order races with CSFML's GL/audio
|
|
44
59
|
# internals — segfaulting inside libopenal/libGL is the typical
|
|
@@ -59,6 +74,8 @@ require "sfml/system/rect"
|
|
|
59
74
|
require "sfml/window/keyboard"
|
|
60
75
|
require "sfml/window/mouse"
|
|
61
76
|
require "sfml/window/joystick"
|
|
77
|
+
require "sfml/window/touch"
|
|
78
|
+
require "sfml/window/sensor"
|
|
62
79
|
require "sfml/window/cursor"
|
|
63
80
|
require "sfml/window/clipboard"
|
|
64
81
|
require "sfml/window/video_mode"
|
|
@@ -74,25 +91,33 @@ require "sfml/graphics/rectangle_shape"
|
|
|
74
91
|
require "sfml/graphics/convex_shape"
|
|
75
92
|
require "sfml/graphics/vertex"
|
|
76
93
|
require "sfml/graphics/vertex_array"
|
|
94
|
+
require "sfml/graphics/vertex_buffer"
|
|
77
95
|
require "sfml/graphics/font"
|
|
78
96
|
require "sfml/graphics/text"
|
|
79
97
|
require "sfml/graphics/view"
|
|
80
98
|
require "sfml/graphics/blend_mode"
|
|
99
|
+
require "sfml/graphics/stencil_mode"
|
|
81
100
|
require "sfml/graphics/shader"
|
|
82
101
|
require "sfml/graphics/transform"
|
|
83
102
|
require "sfml/graphics/render_states"
|
|
84
103
|
require "sfml/graphics/render_target"
|
|
85
104
|
require "sfml/graphics/render_window"
|
|
86
105
|
require "sfml/graphics/render_texture"
|
|
106
|
+
require "sfml/audio/internal"
|
|
87
107
|
require "sfml/audio/sound_buffer"
|
|
108
|
+
require "sfml/audio/sound_cone"
|
|
88
109
|
require "sfml/audio/sound"
|
|
89
110
|
require "sfml/audio/music"
|
|
90
111
|
require "sfml/audio/listener"
|
|
91
112
|
require "sfml/audio/sound_recorder"
|
|
92
113
|
require "sfml/audio/sound_buffer_recorder"
|
|
114
|
+
require "sfml/audio/sound_stream"
|
|
93
115
|
require "sfml/network/ip_address"
|
|
94
116
|
require "sfml/network/tcp_socket"
|
|
95
117
|
require "sfml/network/tcp_listener"
|
|
96
118
|
require "sfml/network/udp_socket"
|
|
119
|
+
require "sfml/network/socket_selector"
|
|
120
|
+
require "sfml/network/http"
|
|
121
|
+
require "sfml/network/ftp"
|
|
97
122
|
require "sfml/assets"
|
|
98
123
|
require "sfml/game"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruby-sfml
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.0.0.
|
|
4
|
+
version: 3.0.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mykhailo Melnyk
|
|
@@ -82,12 +82,15 @@ files:
|
|
|
82
82
|
- lib/sfml/assets.rb
|
|
83
83
|
- lib/sfml/assets/fonts/DejaVuSans.LICENSE.txt
|
|
84
84
|
- lib/sfml/assets/fonts/DejaVuSans.ttf
|
|
85
|
+
- lib/sfml/audio/internal.rb
|
|
85
86
|
- lib/sfml/audio/listener.rb
|
|
86
87
|
- lib/sfml/audio/music.rb
|
|
87
88
|
- lib/sfml/audio/sound.rb
|
|
88
89
|
- lib/sfml/audio/sound_buffer.rb
|
|
89
90
|
- lib/sfml/audio/sound_buffer_recorder.rb
|
|
91
|
+
- lib/sfml/audio/sound_cone.rb
|
|
90
92
|
- lib/sfml/audio/sound_recorder.rb
|
|
93
|
+
- lib/sfml/audio/sound_stream.rb
|
|
91
94
|
- lib/sfml/c.rb
|
|
92
95
|
- lib/sfml/c/audio.rb
|
|
93
96
|
- lib/sfml/c/graphics.rb
|
|
@@ -108,14 +111,19 @@ files:
|
|
|
108
111
|
- lib/sfml/graphics/render_window.rb
|
|
109
112
|
- lib/sfml/graphics/shader.rb
|
|
110
113
|
- lib/sfml/graphics/sprite.rb
|
|
114
|
+
- lib/sfml/graphics/stencil_mode.rb
|
|
111
115
|
- lib/sfml/graphics/text.rb
|
|
112
116
|
- lib/sfml/graphics/texture.rb
|
|
113
117
|
- lib/sfml/graphics/transform.rb
|
|
114
118
|
- lib/sfml/graphics/transformable.rb
|
|
115
119
|
- lib/sfml/graphics/vertex.rb
|
|
116
120
|
- lib/sfml/graphics/vertex_array.rb
|
|
121
|
+
- lib/sfml/graphics/vertex_buffer.rb
|
|
117
122
|
- lib/sfml/graphics/view.rb
|
|
123
|
+
- lib/sfml/network/ftp.rb
|
|
124
|
+
- lib/sfml/network/http.rb
|
|
118
125
|
- lib/sfml/network/ip_address.rb
|
|
126
|
+
- lib/sfml/network/socket_selector.rb
|
|
119
127
|
- lib/sfml/network/tcp_listener.rb
|
|
120
128
|
- lib/sfml/network/tcp_socket.rb
|
|
121
129
|
- lib/sfml/network/udp_socket.rb
|
|
@@ -131,6 +139,8 @@ files:
|
|
|
131
139
|
- lib/sfml/window/joystick.rb
|
|
132
140
|
- lib/sfml/window/keyboard.rb
|
|
133
141
|
- lib/sfml/window/mouse.rb
|
|
142
|
+
- lib/sfml/window/sensor.rb
|
|
143
|
+
- lib/sfml/window/touch.rb
|
|
134
144
|
- lib/sfml/window/video_mode.rb
|
|
135
145
|
- lib/sfml/window/window.rb
|
|
136
146
|
- ruby-sfml.gemspec
|