sfml3-rb 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 +7 -0
- data/LICENSE.md +14 -0
- data/README.md +110 -0
- data/ext/circle.c +198 -0
- data/ext/clock.c +65 -0
- data/ext/color.c +43 -0
- data/ext/drawable.c +39 -0
- data/ext/event.c +148 -0
- data/ext/event_name.c +45 -0
- data/ext/exceptions.c +44 -0
- data/ext/ext/exceptions.h +16 -0
- data/ext/ext/klass/clock.h +12 -0
- data/ext/ext/klass/color.h +26 -0
- data/ext/ext/klass/drawable/circle.h +12 -0
- data/ext/ext/klass/drawable/image.h +4 -0
- data/ext/ext/klass/drawable/polygon.h +4 -0
- data/ext/ext/klass/drawable/rectangle.h +4 -0
- data/ext/ext/klass/drawable/sprite.h +4 -0
- data/ext/ext/klass/drawable/texture.h +4 -0
- data/ext/ext/klass/event/event_name.h +8 -0
- data/ext/ext/klass/event.h +12 -0
- data/ext/ext/klass/keyboard.h +8 -0
- data/ext/ext/klass/render_state.h +16 -0
- data/ext/ext/klass/target.h +18 -0
- data/ext/ext/klass/transform.h +17 -0
- data/ext/ext/klass/transformable.h +13 -0
- data/ext/ext/klass/video_mode.h +12 -0
- data/ext/ext/klass/view.h +14 -0
- data/ext/ext/klass/window.h +12 -0
- data/ext/ext/module/drawable/drawable.h +10 -0
- data/ext/ext/module/transform.h +18 -0
- data/ext/ext/module.h +10 -0
- data/ext/ext/rect.h +16 -0
- data/ext/ext/sfml.h +16 -0
- data/ext/ext/style_name.h +11 -0
- data/ext/ext/vec2.h +38 -0
- data/ext/ext.c +47 -0
- data/ext/extconf.rb +84 -0
- data/ext/image.c +5 -0
- data/ext/keyboard.c +135 -0
- data/ext/polygon.c +5 -0
- data/ext/ports.rb +368 -0
- data/ext/rect.c +26 -0
- data/ext/rectangle.c +5 -0
- data/ext/render_state.c +109 -0
- data/ext/sprite.c +5 -0
- data/ext/style_name.c +15 -0
- data/ext/target.c +106 -0
- data/ext/texture.c +5 -0
- data/ext/transform.c +107 -0
- data/ext/transformable.c +145 -0
- data/ext/vec2.c +42 -0
- data/ext/video_mode.c +78 -0
- data/ext/view.c +170 -0
- data/ext/window.c +274 -0
- data/lib/sfml/version.rb +3 -0
- data/lib/sfml.rb +9 -0
- metadata +104 -0
data/ext/keyboard.c
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
#include "ext/klass/keyboard.h"
|
|
2
|
+
|
|
3
|
+
#include <stddef.h>
|
|
4
|
+
#include <string.h>
|
|
5
|
+
|
|
6
|
+
#include "ext/sfml.h"
|
|
7
|
+
|
|
8
|
+
/* Indexed by sfKeyCode rather than by position: if upstream reorders or
|
|
9
|
+
removes a key, this fails to compile instead of silently renaming every
|
|
10
|
+
key after the change. sfKeyUnknown is -1 and so has no entry. */
|
|
11
|
+
static const char *keys[] = {
|
|
12
|
+
[sfKeyA] = "a",
|
|
13
|
+
[sfKeyB] = "b",
|
|
14
|
+
[sfKeyC] = "c",
|
|
15
|
+
[sfKeyD] = "d",
|
|
16
|
+
[sfKeyE] = "e",
|
|
17
|
+
[sfKeyF] = "f",
|
|
18
|
+
[sfKeyG] = "g",
|
|
19
|
+
[sfKeyH] = "h",
|
|
20
|
+
[sfKeyI] = "i",
|
|
21
|
+
[sfKeyJ] = "j",
|
|
22
|
+
[sfKeyK] = "k",
|
|
23
|
+
[sfKeyL] = "l",
|
|
24
|
+
[sfKeyM] = "m",
|
|
25
|
+
[sfKeyN] = "n",
|
|
26
|
+
[sfKeyO] = "o",
|
|
27
|
+
[sfKeyP] = "p",
|
|
28
|
+
[sfKeyQ] = "q",
|
|
29
|
+
[sfKeyR] = "r",
|
|
30
|
+
[sfKeyS] = "s",
|
|
31
|
+
[sfKeyT] = "t",
|
|
32
|
+
[sfKeyU] = "u",
|
|
33
|
+
[sfKeyV] = "v",
|
|
34
|
+
[sfKeyW] = "w",
|
|
35
|
+
[sfKeyX] = "x",
|
|
36
|
+
[sfKeyY] = "y",
|
|
37
|
+
[sfKeyZ] = "z",
|
|
38
|
+
[sfKeyNum0] = "num0",
|
|
39
|
+
[sfKeyNum1] = "num1",
|
|
40
|
+
[sfKeyNum2] = "num2",
|
|
41
|
+
[sfKeyNum3] = "num3",
|
|
42
|
+
[sfKeyNum4] = "num4",
|
|
43
|
+
[sfKeyNum5] = "num5",
|
|
44
|
+
[sfKeyNum6] = "num6",
|
|
45
|
+
[sfKeyNum7] = "num7",
|
|
46
|
+
[sfKeyNum8] = "num8",
|
|
47
|
+
[sfKeyNum9] = "num9",
|
|
48
|
+
[sfKeyEscape] = "escape",
|
|
49
|
+
[sfKeyLControl] = "LControl",
|
|
50
|
+
[sfKeyLShift] = "LShift",
|
|
51
|
+
[sfKeyLAlt] = "LAlt",
|
|
52
|
+
[sfKeyLSystem] = "LSystem",
|
|
53
|
+
[sfKeyRControl] = "RControl",
|
|
54
|
+
[sfKeyRShift] = "RShift",
|
|
55
|
+
[sfKeyRAlt] = "RAlt",
|
|
56
|
+
[sfKeyRSystem] = "RSystem",
|
|
57
|
+
[sfKeyMenu] = "Menu",
|
|
58
|
+
[sfKeyLBracket] = "LBracket",
|
|
59
|
+
[sfKeyRBracket] = "RBracket",
|
|
60
|
+
[sfKeySemicolon] = "Semicolon",
|
|
61
|
+
[sfKeyComma] = "Comma",
|
|
62
|
+
[sfKeyPeriod] = "Period",
|
|
63
|
+
[sfKeyApostrophe] = "Quote",
|
|
64
|
+
[sfKeySlash] = "Slash",
|
|
65
|
+
[sfKeyBackslash] = "Backslash",
|
|
66
|
+
[sfKeyGrave] = "Tilde",
|
|
67
|
+
[sfKeyEqual] = "Equal",
|
|
68
|
+
[sfKeyHyphen] = "Hyphen",
|
|
69
|
+
[sfKeySpace] = "Space",
|
|
70
|
+
[sfKeyEnter] = "Enter",
|
|
71
|
+
[sfKeyBackspace] = "Backspace",
|
|
72
|
+
[sfKeyTab] = "Tab",
|
|
73
|
+
[sfKeyPageUp] = "PageUp",
|
|
74
|
+
[sfKeyPageDown] = "PageDown",
|
|
75
|
+
[sfKeyEnd] = "End",
|
|
76
|
+
[sfKeyHome] = "Home",
|
|
77
|
+
[sfKeyInsert] = "Insert",
|
|
78
|
+
[sfKeyDelete] = "Delete",
|
|
79
|
+
[sfKeyAdd] = "Add",
|
|
80
|
+
[sfKeySubtract] = "Subtract",
|
|
81
|
+
[sfKeyMultiply] = "Multiply",
|
|
82
|
+
[sfKeyDivide] = "Divide",
|
|
83
|
+
[sfKeyLeft] = "Left",
|
|
84
|
+
[sfKeyRight] = "Right",
|
|
85
|
+
[sfKeyUp] = "Up",
|
|
86
|
+
[sfKeyDown] = "Down",
|
|
87
|
+
[sfKeyNumpad0] = "Numpad0",
|
|
88
|
+
[sfKeyNumpad1] = "Numpad1",
|
|
89
|
+
[sfKeyNumpad2] = "Numpad2",
|
|
90
|
+
[sfKeyNumpad3] = "Numpad3",
|
|
91
|
+
[sfKeyNumpad4] = "Numpad4",
|
|
92
|
+
[sfKeyNumpad5] = "Numpad5",
|
|
93
|
+
[sfKeyNumpad6] = "Numpad6",
|
|
94
|
+
[sfKeyNumpad7] = "Numpad7",
|
|
95
|
+
[sfKeyNumpad8] = "Numpad8",
|
|
96
|
+
[sfKeyNumpad9] = "Numpad9",
|
|
97
|
+
[sfKeyF1] = "f1",
|
|
98
|
+
[sfKeyF2] = "f2",
|
|
99
|
+
[sfKeyF3] = "f3",
|
|
100
|
+
[sfKeyF4] = "f4",
|
|
101
|
+
[sfKeyF5] = "f5",
|
|
102
|
+
[sfKeyF6] = "f6",
|
|
103
|
+
[sfKeyF7] = "f7",
|
|
104
|
+
[sfKeyF8] = "f8",
|
|
105
|
+
[sfKeyF9] = "f9",
|
|
106
|
+
[sfKeyF10] = "f10",
|
|
107
|
+
[sfKeyF11] = "f11",
|
|
108
|
+
[sfKeyF12] = "f12",
|
|
109
|
+
[sfKeyF13] = "f13",
|
|
110
|
+
[sfKeyF14] = "f14",
|
|
111
|
+
[sfKeyF15] = "f15",
|
|
112
|
+
[sfKeyPause] = "pause",
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
#define LENGTH_KEYS (sizeof(keys) / sizeof(keys[0]))
|
|
116
|
+
|
|
117
|
+
int find_key(const char *name) {
|
|
118
|
+
size_t i;
|
|
119
|
+
|
|
120
|
+
for (i = 0; i < LENGTH_KEYS; i++) {
|
|
121
|
+
if (keys[i] != NULL && strcmp(keys[i], name) == 0) {
|
|
122
|
+
return (int) i;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return -1;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const char *get_key_event(unsigned int key) {
|
|
130
|
+
if (key < LENGTH_KEYS && keys[key] != NULL) {
|
|
131
|
+
return keys[key];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return "";
|
|
135
|
+
}
|
data/ext/polygon.c
ADDED
data/ext/ports.rb
ADDED
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
require 'digest'
|
|
2
|
+
require 'etc'
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
require 'open-uri'
|
|
5
|
+
require 'rbconfig'
|
|
6
|
+
|
|
7
|
+
# Downloads, verifies and builds FreeType, SFML 3 and CSFML 3 from source into
|
|
8
|
+
# ports/<target>, static and position-independent, so the extension links them
|
|
9
|
+
# directly and the resulting .so has no libsfml/libcsfml runtime dependency.
|
|
10
|
+
#
|
|
11
|
+
# This lives under ext/ rather than rakelib/ because the gemspec ships
|
|
12
|
+
# ext/**/*.rb: it has to be inside the gem for `gem install` to build its own
|
|
13
|
+
# dependencies. For the same reason it uses no Rake helpers -- Rake is not
|
|
14
|
+
# guaranteed to be loaded during an extension build.
|
|
15
|
+
#
|
|
16
|
+
# Three entry points call it: `rake ports` (development), ext/extconf.rb
|
|
17
|
+
# (source-gem install time), and `rake gem:native` (cross-compilation inside
|
|
18
|
+
# rake-compiler-dock, which exports SFML_TARGET).
|
|
19
|
+
module Ports
|
|
20
|
+
ROOT = File.expand_path('../ports', __dir__)
|
|
21
|
+
ARCHIVES = File.join(ROOT, 'archives')
|
|
22
|
+
|
|
23
|
+
# Cross targets, keyed by the RubyGems platform name that rake-compiler and
|
|
24
|
+
# rake-compiler-dock use for them. `triple` is the GNU host triple whose
|
|
25
|
+
# toolchain the matching rake-compiler-dock image installs as <triple>-gcc.
|
|
26
|
+
TARGETS = {
|
|
27
|
+
'x86_64-linux-gnu' => { triple: 'x86_64-linux-gnu', os: :linux, cpu: 'x86_64' },
|
|
28
|
+
'aarch64-linux-gnu' => { triple: 'aarch64-linux-gnu', os: :linux, cpu: 'aarch64' },
|
|
29
|
+
'x86_64-linux-musl' => { triple: 'x86_64-unknown-linux-musl', os: :linux, cpu: 'x86_64' },
|
|
30
|
+
'x64-mingw-ucrt' => { triple: 'x86_64-w64-mingw32', os: :windows, cpu: 'x86_64' },
|
|
31
|
+
'x86_64-darwin' => { triple: 'x86_64-apple-darwin', os: :darwin, cpu: 'x86_64' },
|
|
32
|
+
'arm64-darwin' => { triple: 'aarch64-apple-darwin', os: :darwin, cpu: 'arm64' }
|
|
33
|
+
}.freeze
|
|
34
|
+
|
|
35
|
+
CMAKE_SYSTEM = { linux: 'Linux', windows: 'Windows', darwin: 'Darwin' }.freeze
|
|
36
|
+
|
|
37
|
+
# osxcross ships clang wrappers rather than gcc ones.
|
|
38
|
+
COMPILERS = {
|
|
39
|
+
darwin: %w[clang clang++],
|
|
40
|
+
linux: %w[gcc g++],
|
|
41
|
+
windows: %w[gcc g++]
|
|
42
|
+
}.freeze
|
|
43
|
+
|
|
44
|
+
# What the extension links on top of the static SFML/CSFML/FreeType archives.
|
|
45
|
+
# SFML resolves GL entry points through its own loader, so on Linux libGL is
|
|
46
|
+
# only needed for the handful of symbols SFML references directly.
|
|
47
|
+
SYSTEM_LIBS = {
|
|
48
|
+
linux: %w[GL X11 Xrandr Xcursor Xi udev pthread dl rt m],
|
|
49
|
+
windows: %w[opengl32 winmm gdi32 user32 advapi32 ole32],
|
|
50
|
+
darwin: %w[]
|
|
51
|
+
}.freeze
|
|
52
|
+
|
|
53
|
+
# Clang wants -framework, not -l, and SFML's macOS backend is Objective-C++.
|
|
54
|
+
FRAMEWORKS = { darwin: %w[Cocoa OpenGL IOKit Carbon], linux: [], windows: [] }.freeze
|
|
55
|
+
|
|
56
|
+
# Order matters. CSFML does find_package(SFML 3 ... REQUIRED) and does not
|
|
57
|
+
# fetch SFML itself, and SFML does find_package(Freetype REQUIRED) once
|
|
58
|
+
# SFML_USE_SYSTEM_DEPS is on -- so each has to be installed into PREFIX
|
|
59
|
+
# before the next configures.
|
|
60
|
+
#
|
|
61
|
+
# FreeType is built here rather than left to SFML because SFML's own
|
|
62
|
+
# FetchContent path clones it from git (no checksum, needs git at configure
|
|
63
|
+
# time) and then does not install the resulting archive -- which leaves
|
|
64
|
+
# libsfml-graphics-s.a with an undefined FT_Init_FreeType that only stays
|
|
65
|
+
# latent while nothing binds sf::Font. Pinning it as a port fixes both.
|
|
66
|
+
#
|
|
67
|
+
# Audio and network are off because the binding wraps neither, which also
|
|
68
|
+
# drops the FLAC/Ogg/Vorbis and mbedtls dependency families.
|
|
69
|
+
RECIPES = [
|
|
70
|
+
{
|
|
71
|
+
name: 'freetype',
|
|
72
|
+
version: '2.13.2',
|
|
73
|
+
sha256: '1ac27e16c134a7f2ccea177faba19801131116fd682efc1f5737037c5db224b5',
|
|
74
|
+
url: 'https://download.savannah.gnu.org/releases/freetype/freetype-%<version>s.tar.gz',
|
|
75
|
+
# FreeType 2.13.2 still declares cmake_minimum_required(VERSION 3.0),
|
|
76
|
+
# which CMake 4 refuses outright. Older CMake ignores the variable.
|
|
77
|
+
flags: %w[
|
|
78
|
+
-DCMAKE_POLICY_VERSION_MINIMUM=3.5
|
|
79
|
+
-DFT_DISABLE_ZLIB=ON
|
|
80
|
+
-DFT_DISABLE_BZIP2=ON
|
|
81
|
+
-DFT_DISABLE_PNG=ON
|
|
82
|
+
-DFT_DISABLE_HARFBUZZ=ON
|
|
83
|
+
-DFT_DISABLE_BROTLI=ON
|
|
84
|
+
]
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: 'SFML',
|
|
88
|
+
version: '3.0.2',
|
|
89
|
+
sha256: '0034e05f95509e5d3fb81b1625713e06da7b068f210288ce3fd67106f8f46995',
|
|
90
|
+
flags: %w[
|
|
91
|
+
-DSFML_USE_SYSTEM_DEPS=ON
|
|
92
|
+
-DSFML_BUILD_AUDIO=OFF
|
|
93
|
+
-DSFML_BUILD_NETWORK=OFF
|
|
94
|
+
-DSFML_BUILD_EXAMPLES=OFF
|
|
95
|
+
-DSFML_BUILD_DOC=OFF
|
|
96
|
+
-DSFML_BUILD_TEST_SUITE=OFF
|
|
97
|
+
]
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: 'CSFML',
|
|
101
|
+
version: '3.0.0',
|
|
102
|
+
sha256: '903cd4a782fb0b233f732dc5b37861b552998e93ae8f268c40bd4ce50b2e88ca',
|
|
103
|
+
flags: %w[
|
|
104
|
+
-DCSFML_BUILD_AUDIO=OFF
|
|
105
|
+
-DCSFML_BUILD_NETWORK=OFF
|
|
106
|
+
-DCSFML_BUILD_EXAMPLES=OFF
|
|
107
|
+
-DCSFML_LINK_SFML_STATICALLY=ON
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
].freeze
|
|
111
|
+
|
|
112
|
+
TOOLCHAIN_HINT = <<~HINT.freeze
|
|
113
|
+
Building SFML from source needs CMake >= 3.22, a C++17 compiler, and the
|
|
114
|
+
X11/udev/OpenGL development headers. SFML links those from the system and
|
|
115
|
+
they cannot be bundled.
|
|
116
|
+
|
|
117
|
+
Fedora/RHEL sudo dnf install cmake gcc-c++ libX11-devel \\
|
|
118
|
+
libXrandr-devel libXcursor-devel libXi-devel systemd-devel libglvnd-devel
|
|
119
|
+
|
|
120
|
+
Debian/Ubuntu sudo apt-get install cmake build-essential libx11-dev \\
|
|
121
|
+
libxrandr-dev libxcursor-dev libxi-dev libudev-dev libgl1-mesa-dev
|
|
122
|
+
|
|
123
|
+
If you already have CSFML 3 installed system-wide, skip this build with:
|
|
124
|
+
|
|
125
|
+
gem install sfml3-rb -- --enable-system-libraries
|
|
126
|
+
|
|
127
|
+
A precompiled binary gem may also be available for your platform; upgrading
|
|
128
|
+
RubyGems (gem update --system) lets it be selected automatically.
|
|
129
|
+
HINT
|
|
130
|
+
|
|
131
|
+
module_function
|
|
132
|
+
|
|
133
|
+
# The RubyGems platform being built for. rake-compiler-dock invocations set
|
|
134
|
+
# this explicitly; a native build falls back to the host triple, which is not
|
|
135
|
+
# a TARGETS key and so uses the native toolchain and native system headers.
|
|
136
|
+
def target
|
|
137
|
+
ENV.fetch('SFML_TARGET', nil) || RbConfig::CONFIG['host']
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def cross?
|
|
141
|
+
TARGETS.key?(target)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def spec
|
|
145
|
+
TARGETS.fetch(target)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Each target gets its own prefix so a cross build never reuses the host's
|
|
149
|
+
# archives -- they are the same file names with an incompatible ABI.
|
|
150
|
+
def prefix
|
|
151
|
+
File.join(ROOT, target)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def build_root
|
|
155
|
+
File.join(ROOT, 'build', target)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def os
|
|
159
|
+
return spec[:os] if cross?
|
|
160
|
+
|
|
161
|
+
case RbConfig::CONFIG['host_os']
|
|
162
|
+
when /darwin/ then :darwin
|
|
163
|
+
when /mingw|mswin|cygwin/ then :windows
|
|
164
|
+
else :linux
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def libs
|
|
169
|
+
SYSTEM_LIBS.fetch(os)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def frameworks
|
|
173
|
+
FRAMEWORKS.fetch(os)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# On Windows the CSFML and SFML headers declare every entry point
|
|
177
|
+
# __declspec(dllimport) unless told the build is static, which leaves the
|
|
178
|
+
# link hunting for __imp_-prefixed symbols that a static archive never has.
|
|
179
|
+
# Applies to any Windows build against the vendored ports, cross or native.
|
|
180
|
+
def defines
|
|
181
|
+
return [] unless os == :windows
|
|
182
|
+
|
|
183
|
+
%w[-DCSFML_STATIC -DSFML_STATIC]
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# SFML is C++, but mkmf links the extension with `gcc -shared` because every
|
|
187
|
+
# source here is C -- so libstdc++ has to be named explicitly, and
|
|
188
|
+
# -static-libstdc++ does nothing, since it only redirects the -lstdc++ the
|
|
189
|
+
# driver would have added itself.
|
|
190
|
+
#
|
|
191
|
+
# For a binary gem that matters: a Windows user has no libstdc++-6.dll, and
|
|
192
|
+
# a musl one may have no libstdc++ at all. -Bstatic/-Bdynamic pins just this
|
|
193
|
+
# one library to its archive and is understood by both GNU ld and mingw's.
|
|
194
|
+
# macOS resolves C++ through the system libc++ and needs none of it.
|
|
195
|
+
def cxx_runtime
|
|
196
|
+
return [] if os == :darwin
|
|
197
|
+
return ['-lstdc++'] unless cross?
|
|
198
|
+
|
|
199
|
+
['-Wl,-Bstatic', '-lstdc++', '-Wl,-Bdynamic']
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def built?
|
|
203
|
+
Dir.exist?(File.join(prefix, 'include', 'CSFML'))
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def build!
|
|
207
|
+
RECIPES.each do |recipe|
|
|
208
|
+
fetch(recipe)
|
|
209
|
+
compile(recipe)
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def tarball(recipe)
|
|
214
|
+
File.join(ARCHIVES, "#{recipe[:name]}-#{recipe[:version]}.tar.gz")
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def source_dir(recipe)
|
|
218
|
+
File.join(build_root, "#{recipe[:name]}-#{recipe[:version]}")
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def fetch(recipe)
|
|
222
|
+
path = tarball(recipe)
|
|
223
|
+
download(recipe, path) unless File.exist?(path)
|
|
224
|
+
|
|
225
|
+
actual = Digest::SHA256.file(path).hexdigest
|
|
226
|
+
return if actual == recipe[:sha256]
|
|
227
|
+
|
|
228
|
+
# Never build unverified source: remove it so a retry re-downloads.
|
|
229
|
+
File.delete(path)
|
|
230
|
+
raise "#{File.basename(path)} failed checksum verification\n" \
|
|
231
|
+
"expected #{recipe[:sha256]}\nactual #{actual}"
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def url_for(recipe)
|
|
235
|
+
template = recipe[:url] ||
|
|
236
|
+
"https://github.com/SFML/#{recipe[:name]}/archive/refs/tags/%<version>s.tar.gz"
|
|
237
|
+
format(template, version: recipe[:version])
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def download(recipe, path)
|
|
241
|
+
url = url_for(recipe)
|
|
242
|
+
puts "Downloading #{url}"
|
|
243
|
+
|
|
244
|
+
FileUtils.mkdir_p(ARCHIVES)
|
|
245
|
+
partial = "#{path}.part"
|
|
246
|
+
|
|
247
|
+
begin
|
|
248
|
+
# URI.parse(...).open rather than URI.open: the latter routes through
|
|
249
|
+
# Kernel#open semantics, where a "|command" string would be executed.
|
|
250
|
+
URI.parse(url).open { |remote| IO.copy_stream(remote, partial) }
|
|
251
|
+
rescue StandardError => e
|
|
252
|
+
FileUtils.rm_f(partial)
|
|
253
|
+
raise "Could not download #{url}: #{e.message}\n\n" \
|
|
254
|
+
"`gem install` needs network access to build SFML from source.\n" \
|
|
255
|
+
"#{TOOLCHAIN_HINT}"
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# Only becomes the real tarball once complete, so an interrupted download
|
|
259
|
+
# cannot be mistaken for a cached one on the next run.
|
|
260
|
+
FileUtils.mv(partial, path)
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
# CMAKE_INSTALL_LIBDIR is pinned because GNUInstallDirs otherwise picks lib64
|
|
264
|
+
# on Fedora/RHEL and lib on Debian, which would split the ports across two
|
|
265
|
+
# directories that extconf would then both have to know about.
|
|
266
|
+
def common_flags
|
|
267
|
+
flags = %W[
|
|
268
|
+
-DCMAKE_INSTALL_PREFIX=#{prefix}
|
|
269
|
+
-DCMAKE_PREFIX_PATH=#{prefix}
|
|
270
|
+
-DCMAKE_BUILD_TYPE=Release
|
|
271
|
+
-DBUILD_SHARED_LIBS=OFF
|
|
272
|
+
-DCMAKE_POSITION_INDEPENDENT_CODE=ON
|
|
273
|
+
-DCMAKE_INSTALL_LIBDIR=lib
|
|
274
|
+
]
|
|
275
|
+
flags << "-DCMAKE_TOOLCHAIN_FILE=#{toolchain_file}" if cross?
|
|
276
|
+
flags
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
# The musl toolchain rake-compiler-dock builds with musl-cross-make installs
|
|
280
|
+
# its sysroot here, and build/provision.sh unpacks Alpine's X11 development
|
|
281
|
+
# files into it.
|
|
282
|
+
def musl_sysroot
|
|
283
|
+
"/usr/#{spec[:triple]}"
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
# osxcross keeps the macOS SDK under its target directory; the exact version
|
|
287
|
+
# tracks the rake-compiler-dock image, so find it rather than pin it.
|
|
288
|
+
def osx_sysroot
|
|
289
|
+
ENV.fetch('SFML_OSX_SYSROOT', nil) ||
|
|
290
|
+
Dir.glob('/opt/osxcross/target/SDK/MacOSX*.sdk').max ||
|
|
291
|
+
raise("No macOS SDK found under /opt/osxcross/target/SDK.\n#{TOOLCHAIN_HINT}")
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
# Written rather than shipped because the prefix and triple are only known at
|
|
295
|
+
# build time, and CMake needs a real file path for CMAKE_TOOLCHAIN_FILE.
|
|
296
|
+
def toolchain_file
|
|
297
|
+
path = File.join(build_root, 'toolchain.cmake')
|
|
298
|
+
return path if File.exist?(path)
|
|
299
|
+
|
|
300
|
+
FileUtils.mkdir_p(build_root)
|
|
301
|
+
File.write(path, toolchain_source)
|
|
302
|
+
path
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
def toolchain_source
|
|
306
|
+
cc, cxx = COMPILERS.fetch(spec[:os])
|
|
307
|
+
roots = [prefix]
|
|
308
|
+
lines = [
|
|
309
|
+
"set(CMAKE_SYSTEM_NAME #{CMAKE_SYSTEM.fetch(spec[:os])})",
|
|
310
|
+
"set(CMAKE_SYSTEM_PROCESSOR #{spec[:cpu]})",
|
|
311
|
+
"set(CMAKE_C_COMPILER #{spec[:triple]}-#{cc})",
|
|
312
|
+
"set(CMAKE_CXX_COMPILER #{spec[:triple]}-#{cxx})"
|
|
313
|
+
]
|
|
314
|
+
|
|
315
|
+
case spec[:os]
|
|
316
|
+
when :windows
|
|
317
|
+
lines << "set(CMAKE_RC_COMPILER #{spec[:triple]}-windres)"
|
|
318
|
+
when :darwin
|
|
319
|
+
# SFML's macOS backend is Objective-C++, so the SDK has to be visible to
|
|
320
|
+
# the frameworks lookup as well as to the compiler.
|
|
321
|
+
lines << "set(CMAKE_OSX_SYSROOT #{osx_sysroot})"
|
|
322
|
+
lines << "set(CMAKE_OSX_ARCHITECTURES #{spec[:cpu]})"
|
|
323
|
+
roots << osx_sysroot
|
|
324
|
+
when :linux
|
|
325
|
+
if spec[:triple].include?('musl')
|
|
326
|
+
lines << "set(CMAKE_SYSROOT #{musl_sysroot})"
|
|
327
|
+
roots << musl_sysroot << "#{musl_sysroot}/usr"
|
|
328
|
+
else
|
|
329
|
+
# Debian multiarch: without this CMake searches /usr/lib, finds the
|
|
330
|
+
# container's own amd64 libraries and hands them to an aarch64 linker.
|
|
331
|
+
lines << "set(CMAKE_LIBRARY_ARCHITECTURE #{spec[:triple]})"
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
<<~CMAKE
|
|
336
|
+
#{lines.join("\n")}
|
|
337
|
+
|
|
338
|
+
# Look for headers and libraries in the target's sysroot and in our own
|
|
339
|
+
# prefix, but run build tools from the host.
|
|
340
|
+
set(CMAKE_FIND_ROOT_PATH #{roots.join(';')})
|
|
341
|
+
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
|
342
|
+
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH)
|
|
343
|
+
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH)
|
|
344
|
+
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH)
|
|
345
|
+
CMAKE
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
def compile(recipe)
|
|
349
|
+
source = source_dir(recipe)
|
|
350
|
+
build = "#{source}-build"
|
|
351
|
+
|
|
352
|
+
unless Dir.exist?(source)
|
|
353
|
+
FileUtils.mkdir_p(build_root)
|
|
354
|
+
run('tar', 'xzf', tarball(recipe), '-C', build_root)
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
puts "Building #{recipe[:name]} #{recipe[:version]} for #{target}"
|
|
358
|
+
run('cmake', '-S', source, '-B', build, *common_flags, *recipe[:flags])
|
|
359
|
+
run('cmake', '--build', build, '--parallel', Etc.nprocessors.to_s)
|
|
360
|
+
run('cmake', '--install', build)
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
def run(*command)
|
|
364
|
+
return if system(*command)
|
|
365
|
+
|
|
366
|
+
raise "Command failed: #{command.join(' ')}\n\n#{TOOLCHAIN_HINT}"
|
|
367
|
+
end
|
|
368
|
+
end
|
data/ext/rect.c
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#include "ext/rect.h"
|
|
2
|
+
|
|
3
|
+
#include <stdio.h>
|
|
4
|
+
#include <stdlib.h>
|
|
5
|
+
|
|
6
|
+
#include <ext/sfml.h>
|
|
7
|
+
#include <ext/module.h>
|
|
8
|
+
|
|
9
|
+
VALUE Rect_new(float x, float y, float width, float height) {
|
|
10
|
+
VALUE arr;
|
|
11
|
+
|
|
12
|
+
arr = rb_ary_new();
|
|
13
|
+
|
|
14
|
+
rb_ary_store(arr, 0, DBL2NUM(x));
|
|
15
|
+
rb_ary_store(arr, 1, DBL2NUM(y));
|
|
16
|
+
rb_ary_store(arr, 2, DBL2NUM(width));
|
|
17
|
+
rb_ary_store(arr, 3, DBL2NUM(height));
|
|
18
|
+
|
|
19
|
+
return arr;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
void Rect_check(VALUE rb_arr) {
|
|
23
|
+
if (rb_array_len(rb_arr) != 4) {
|
|
24
|
+
rb_raise(rb_eArgError, "invalid length of array");
|
|
25
|
+
}
|
|
26
|
+
}
|
data/ext/rectangle.c
ADDED
data/ext/render_state.c
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#include "ext/klass/render_state.h"
|
|
2
|
+
|
|
3
|
+
#include <ruby.h>
|
|
4
|
+
#include <stdio.h>
|
|
5
|
+
|
|
6
|
+
#include "ext/module/transform.h"
|
|
7
|
+
#include "ext/klass/transformable.h"
|
|
8
|
+
#include "ext/vec2.h"
|
|
9
|
+
#include "ext/rect.h"
|
|
10
|
+
#include "ext/module.h"
|
|
11
|
+
#include "ext/sfml.h"
|
|
12
|
+
|
|
13
|
+
static VALUE rb_cRenderState;
|
|
14
|
+
|
|
15
|
+
static sfRenderStates *RenderStates_create(sfTransform transform) {
|
|
16
|
+
sfRenderStates *states = malloc(sizeof(sfRenderStates));
|
|
17
|
+
|
|
18
|
+
states->transform = transform;
|
|
19
|
+
states->blendMode = sfBlendAlpha;
|
|
20
|
+
states->texture = NULL;
|
|
21
|
+
states->shader = NULL;
|
|
22
|
+
|
|
23
|
+
return states;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
static void RenderStates_free(void *ptr) {
|
|
27
|
+
free(ptr);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
static VALUE RenderStates_new(int argc, VALUE *argv, VALUE klass) {
|
|
31
|
+
float c_matrix[MATRIX_LENGTH] = DefaultMatrix3x3();
|
|
32
|
+
sfRenderStates *states;
|
|
33
|
+
sfTransform transform;
|
|
34
|
+
VALUE self;
|
|
35
|
+
|
|
36
|
+
if (argc > 1) {
|
|
37
|
+
rb_raise(rb_eArgError, "invalid number of arguments");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (argc == 1) {
|
|
41
|
+
VALUE rb_arr = argv[0];
|
|
42
|
+
|
|
43
|
+
if (TYPE(rb_arr) == T_ARRAY) {
|
|
44
|
+
if (rb_array_len(rb_arr) != 9) {
|
|
45
|
+
rb_raise(rb_eArgError, "invalid length array");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
Transform_ArrayToMatrix(rb_arr, c_matrix);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
Transform_SwapMatrix(c_matrix, transform.matrix);
|
|
53
|
+
|
|
54
|
+
states = RenderStates_create(transform);
|
|
55
|
+
self = Data_Wrap_Struct(klass, 0, RenderStates_free, states);
|
|
56
|
+
|
|
57
|
+
rb_obj_call_init(self, argc, argv);
|
|
58
|
+
|
|
59
|
+
return self;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
static VALUE RenderStates_init(int argc, VALUE *argv, VALUE self) {
|
|
63
|
+
return self;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
static VALUE RenderStates_set_matrix(VALUE self, VALUE rb_matrix) {
|
|
67
|
+
float c_matrix[MATRIX_LENGTH];
|
|
68
|
+
sfRenderStates *states;
|
|
69
|
+
|
|
70
|
+
states = Get_RenderState_Struct(self);
|
|
71
|
+
|
|
72
|
+
Transform_ArrayToMatrix(rb_matrix, c_matrix);
|
|
73
|
+
Transform_SwapMatrix(c_matrix, states->transform.matrix);
|
|
74
|
+
|
|
75
|
+
return self;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static VALUE RenderStates_get_matrix(VALUE self) {
|
|
79
|
+
return Transform_MatrixToArray(((sfRenderStates *) Get_RenderState_Struct(self))->transform.matrix);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
void Init_RenderState(VALUE rb_module) {
|
|
83
|
+
rb_cRenderState = rb_define_class_under(rb_module, "RenderState", rb_cObject);
|
|
84
|
+
|
|
85
|
+
rb_define_singleton_method(rb_cRenderState, "new", RenderStates_new, -1);
|
|
86
|
+
|
|
87
|
+
// methods
|
|
88
|
+
rb_define_method(rb_cRenderState, "initialize", RenderStates_init, -1);
|
|
89
|
+
|
|
90
|
+
// setters
|
|
91
|
+
rb_define_method(rb_cRenderState, "matrix=", RenderStates_set_matrix, 1);
|
|
92
|
+
|
|
93
|
+
// getters
|
|
94
|
+
rb_define_method(rb_cRenderState, "matrix", RenderStates_get_matrix, 0);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
void *Get_RenderState_Struct(VALUE self) {
|
|
98
|
+
sfRenderStates *states;
|
|
99
|
+
Data_Get_Struct(self, sfRenderStates, states);
|
|
100
|
+
return states;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
VALUE Get_Klass_RenderState(void) {
|
|
104
|
+
return rb_cRenderState;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
VALUE Get_New_RenderState(void) {
|
|
108
|
+
return RenderStates_new(0, NULL, Get_Klass_RenderState());
|
|
109
|
+
}
|
data/ext/sprite.c
ADDED
data/ext/style_name.c
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#include "ext/style_name.h"
|
|
2
|
+
|
|
3
|
+
const char *styles[STYLES_LENGTH] = {"none", "titlebar", "resize", "close", "fullscreen", "default"};
|
|
4
|
+
|
|
5
|
+
int search_style_name(const char *style) {
|
|
6
|
+
int i;
|
|
7
|
+
|
|
8
|
+
for (i = 0; i < STYLES_LENGTH; i++) {
|
|
9
|
+
if (strcmp(styles[i], style) != 0) {
|
|
10
|
+
return i;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return -1;
|
|
15
|
+
}
|