ruby-sfml 3.0.0.2 → 3.0.0.3
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 +77 -0
- data/lib/sfml/app.rb +5 -0
- data/lib/sfml/c/graphics.rb +61 -4
- data/lib/sfml/c/window.rb +7 -0
- data/lib/sfml/graphics/font.rb +80 -0
- data/lib/sfml/graphics/image.rb +47 -0
- data/lib/sfml/graphics/render_texture.rb +27 -0
- data/lib/sfml/graphics/render_window.rb +62 -0
- data/lib/sfml/graphics/shader.rb +13 -0
- data/lib/sfml/graphics/text.rb +47 -0
- data/lib/sfml/graphics/texture.rb +65 -0
- data/lib/sfml/version.rb +1 -1
- data/lib/sfml/window/window.rb +38 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3261668821d3742648968ea78730bf09a83c72a428e69fe9fc5f2492f13f8557
|
|
4
|
+
data.tar.gz: 860208fab91bf28c6825948892bca54478defebdc29c596cb30088e394a7f516
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2cae71d47e55c1d1fa1b39c8c18d7362fff927224ae410449ef33444fe07060ef2cf8c8c3c6b0b65beffd7d2f9c99e6cd89c6d2558a5573817150c636493375b
|
|
7
|
+
data.tar.gz: 5a4e5a8f78ae23ed08d72bc62df15587787e172000abd53b8fe1b9869952f98348d9c775f37c606555f25e5c5b26f2009685e136a26b788ae4ce9123817090be
|
data/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,83 @@ ruby-sfml's own patch level.
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## [3.0.0.3] — 2026-05-09
|
|
12
|
+
|
|
13
|
+
### Added — typography
|
|
14
|
+
- `Font#family` — human-readable family name from `sfFont_getInfo`.
|
|
15
|
+
- `Font#has_glyph?(codepoint)` — accepts an Integer codepoint or
|
|
16
|
+
a single-character String.
|
|
17
|
+
- `Font#kerning(a, b, character_size:, bold: false)` — wraps
|
|
18
|
+
`sfFont_getKerning` / `getBoldKerning` for accurate glyph
|
|
19
|
+
pairing. Used in advanced text layout.
|
|
20
|
+
- `Font#line_spacing(size)`, `Font#underline_position(size)`,
|
|
21
|
+
`Font#underline_thickness(size)` — typography metrics for the
|
|
22
|
+
given character size.
|
|
23
|
+
- `Font#texture(size)` — borrowed `SFML::Texture` of the glyph
|
|
24
|
+
atlas (handy for debug visualisations of what's been rasterised).
|
|
25
|
+
- `Font#dup` / `#clone` — independent deep copy.
|
|
26
|
+
- `Font.from_memory(bytes)` — load from a Ruby String (embedded
|
|
27
|
+
assets, network responses, `data:` URLs).
|
|
28
|
+
- `Text#find_character_pos(index)` — exact `Vector2` position of
|
|
29
|
+
the character at the given byte index. Critical for caret /
|
|
30
|
+
selection rendering in text inputs.
|
|
31
|
+
- `Text#letter_spacing` / `#line_spacing` getters (the setters
|
|
32
|
+
were already there).
|
|
33
|
+
- `Text#dup` / `#clone` — independent copy with the same string
|
|
34
|
+
and font reference.
|
|
35
|
+
- `Text#transform` / `#inverse_transform` — the `SFML::Transform`
|
|
36
|
+
the renderer applies when drawing this Text.
|
|
37
|
+
|
|
38
|
+
### Added — Image / Texture / RenderTexture
|
|
39
|
+
- `Image.from_memory(bytes)` — decode PNG / JPG / BMP / TGA /
|
|
40
|
+
GIF / HDR / PSD from a Ruby String. Mirror of
|
|
41
|
+
`Image#save_to_memory`.
|
|
42
|
+
- `Image#copy_from(source, at:, source_rect: nil, apply_alpha: false)`
|
|
43
|
+
— stamp a region of `source` into self. Useful for hand-built
|
|
44
|
+
texture atlases or composite images.
|
|
45
|
+
- `Texture.create(width, height)` — allocate a blank GPU
|
|
46
|
+
texture; pair with `Texture#update(image)` to stream pixels.
|
|
47
|
+
- `Texture.maximum_size` / `Texture.unbind` — class-level
|
|
48
|
+
helpers.
|
|
49
|
+
- `Texture#bind(coord:)` — manually bind for raw OpenGL interop.
|
|
50
|
+
- `Texture#srgb?`, `Texture#generate_mipmap`, `Texture#dup`.
|
|
51
|
+
- `RenderTexture.maximum_anti_aliasing_level`,
|
|
52
|
+
`RenderTexture#srgb?`, `RenderTexture#generate_mipmap`.
|
|
53
|
+
- `RenderTexture#active=`, `#push_gl_states`, `#pop_gl_states`,
|
|
54
|
+
`#reset_gl_states` — same GL-state machinery as RenderWindow.
|
|
55
|
+
|
|
56
|
+
### Added — Window / RenderWindow polish
|
|
57
|
+
- `RenderWindow#focused?` / `#request_focus` / `#position` /
|
|
58
|
+
`#position=` / `#srgb?`.
|
|
59
|
+
- `RenderWindow#visible=`, `#key_repeat_enabled=`,
|
|
60
|
+
`#joystick_threshold=`.
|
|
61
|
+
- `RenderWindow#active=`, `#push_gl_states`, `#pop_gl_states`,
|
|
62
|
+
`#reset_gl_states` — for mixing raw OpenGL calls with SFML
|
|
63
|
+
rendering. Surround custom GL with push/pop so SFML's
|
|
64
|
+
internal state survives.
|
|
65
|
+
- `RenderWindow#wait_event(timeout:)` — block until the next
|
|
66
|
+
event or `timeout` elapses (a `SFML::Time`). For low-power /
|
|
67
|
+
event-driven apps that don't need a 60Hz update loop.
|
|
68
|
+
- `Window#cursor=`, `#cursor_visible=`, `#cursor_grabbed=` —
|
|
69
|
+
parity with the same setters that already existed on
|
|
70
|
+
`RenderWindow`.
|
|
71
|
+
- `Window#joystick_threshold=`, `Window#context_settings`,
|
|
72
|
+
`Window#wait_event(timeout:)`.
|
|
73
|
+
|
|
74
|
+
### Added — Shader
|
|
75
|
+
- `Shader#bind`, `Shader.unbind`, `Shader#native_handle` — for
|
|
76
|
+
raw GL interop and debug introspection.
|
|
77
|
+
|
|
78
|
+
### Fixed
|
|
79
|
+
- `SFML::App._dispatch` now forwards `:resized` events to *both*
|
|
80
|
+
`on_resize(width, height)` *and* `on_event(event)`. The 3.0.0.2
|
|
81
|
+
refactor accidentally routed `:resized` only through the
|
|
82
|
+
structured hook, which broke any app that forwarded
|
|
83
|
+
`on_event` to a sub-system (e.g. `def on_event(e) =
|
|
84
|
+
@gui.on_event(e)`) — the GUI never got told to refresh its
|
|
85
|
+
view + reflow on resize. Both hooks now receive the event;
|
|
86
|
+
apps that already use `on_resize` are unaffected.
|
|
87
|
+
|
|
11
88
|
## [3.0.0.2] — 2026-05-09
|
|
12
89
|
|
|
13
90
|
### Added
|
data/lib/sfml/app.rb
CHANGED
|
@@ -224,7 +224,12 @@ module SFML
|
|
|
224
224
|
in {type: :closed}
|
|
225
225
|
quit
|
|
226
226
|
in {type: :resized, size: {x:, y:}}
|
|
227
|
+
# `:resized` fires BOTH the structured hook and the generic
|
|
228
|
+
# event sink — apps that forward `on_event` to a sub-system
|
|
229
|
+
# (`@gui.on_event(event)`, etc.) keep getting the event,
|
|
230
|
+
# while apps that just want clean (w, h) override the hook.
|
|
227
231
|
on_resize(x, y)
|
|
232
|
+
on_event(event)
|
|
228
233
|
in {type: :key_pressed, code:}
|
|
229
234
|
# Scene-level bindings win over app-level (CSS-style cascade:
|
|
230
235
|
# the more-specific layer overrides the more-general one).
|
data/lib/sfml/c/graphics.rb
CHANGED
|
@@ -108,6 +108,19 @@ module SFML
|
|
|
108
108
|
attach_function :sfRenderWindow_setMaximumSize, [:render_window_t, :pointer], :void
|
|
109
109
|
attach_function :sfRenderWindow_createFromHandle, [:pointer, :pointer], :render_window_t
|
|
110
110
|
attach_function :sfRenderWindow_getNativeHandle, [:render_window_t], :pointer
|
|
111
|
+
attach_function :sfRenderWindow_hasFocus, [:render_window_t], :bool
|
|
112
|
+
attach_function :sfRenderWindow_requestFocus, [:render_window_t], :void
|
|
113
|
+
attach_function :sfRenderWindow_getPosition, [:render_window_t], System::Vector2i.by_value
|
|
114
|
+
attach_function :sfRenderWindow_setPosition, [:render_window_t, System::Vector2i.by_value], :void
|
|
115
|
+
attach_function :sfRenderWindow_setVisible, [:render_window_t, :bool], :void
|
|
116
|
+
attach_function :sfRenderWindow_setKeyRepeatEnabled, [:render_window_t, :bool], :void
|
|
117
|
+
attach_function :sfRenderWindow_setJoystickThreshold, [:render_window_t, :float], :void
|
|
118
|
+
attach_function :sfRenderWindow_setActive, [:render_window_t, :bool], :bool
|
|
119
|
+
attach_function :sfRenderWindow_pushGLStates, [:render_window_t], :void
|
|
120
|
+
attach_function :sfRenderWindow_popGLStates, [:render_window_t], :void
|
|
121
|
+
attach_function :sfRenderWindow_resetGLStates, [:render_window_t], :void
|
|
122
|
+
attach_function :sfRenderWindow_isSrgb, [:render_window_t], :bool
|
|
123
|
+
attach_function :sfRenderWindow_waitEvent, [:render_window_t, System::Time.by_value, :pointer], :bool
|
|
111
124
|
|
|
112
125
|
typedef :pointer, :texture_t
|
|
113
126
|
typedef :pointer, :render_texture_t
|
|
@@ -205,8 +218,16 @@ module SFML
|
|
|
205
218
|
System::Vector2i.by_value
|
|
206
219
|
|
|
207
220
|
# ---- Texture ----
|
|
221
|
+
attach_function :sfTexture_create, [System::Vector2u.by_value], :texture_t
|
|
208
222
|
attach_function :sfTexture_createFromFile, [:string, :pointer], :texture_t
|
|
209
223
|
attach_function :sfTexture_createFromImage,[:image_t, :pointer], :texture_t
|
|
224
|
+
attach_function :sfTexture_copy, [:texture_t], :texture_t
|
|
225
|
+
attach_function :sfTexture_isSrgb, [:texture_t], :bool
|
|
226
|
+
attach_function :sfTexture_generateMipmap, [:texture_t], :bool
|
|
227
|
+
attach_function :sfTexture_getMaximumSize, [], :uint
|
|
228
|
+
# `sfTexture_bind` takes a CoordinateType enum (0 = normalised,
|
|
229
|
+
# 1 = pixels). Pass NULL to unbind.
|
|
230
|
+
attach_function :sfTexture_bind, [:texture_t, :int], :void
|
|
210
231
|
attach_function :sfTexture_destroy, [:texture_t], :void
|
|
211
232
|
attach_function :sfTexture_getSize, [:texture_t], System::Vector2u.by_value
|
|
212
233
|
attach_function :sfTexture_setSmooth, [:texture_t, :bool], :void
|
|
@@ -223,7 +244,9 @@ module SFML
|
|
|
223
244
|
attach_function :sfImage_createFromColor, [System::Vector2u.by_value, Color.by_value], :image_t
|
|
224
245
|
attach_function :sfImage_createFromPixels, [System::Vector2u.by_value, :pointer], :image_t
|
|
225
246
|
attach_function :sfImage_createFromFile, [:string], :image_t
|
|
247
|
+
attach_function :sfImage_createFromMemory, [:pointer, :size_t], :image_t
|
|
226
248
|
attach_function :sfImage_copy, [:image_t], :image_t
|
|
249
|
+
attach_function :sfImage_copyImage, [:image_t, :image_t, System::Vector2u.by_value, IntRect.by_value, :bool], :bool
|
|
227
250
|
attach_function :sfImage_destroy, [:image_t], :void
|
|
228
251
|
attach_function :sfImage_saveToFile, [:image_t, :string], :bool
|
|
229
252
|
attach_function :sfImage_saveToMemory, [:image_t, :pointer, :string], :bool
|
|
@@ -356,6 +379,12 @@ module SFML
|
|
|
356
379
|
attach_function :sfRenderTexture_isSmooth, [:render_texture_t], :bool
|
|
357
380
|
attach_function :sfRenderTexture_setRepeated, [:render_texture_t, :bool], :void
|
|
358
381
|
attach_function :sfRenderTexture_isRepeated, [:render_texture_t], :bool
|
|
382
|
+
attach_function :sfRenderTexture_isSrgb, [:render_texture_t], :bool
|
|
383
|
+
attach_function :sfRenderTexture_generateMipmap, [:render_texture_t], :bool
|
|
384
|
+
attach_function :sfRenderTexture_getMaximumAntiAliasingLevel, [], :uint
|
|
385
|
+
attach_function :sfRenderTexture_pushGLStates, [:render_texture_t], :void
|
|
386
|
+
attach_function :sfRenderTexture_popGLStates, [:render_texture_t], :void
|
|
387
|
+
attach_function :sfRenderTexture_resetGLStates, [:render_texture_t], :void
|
|
359
388
|
|
|
360
389
|
attach_function :sfRenderTexture_mapPixelToCoords,
|
|
361
390
|
[:render_texture_t, System::Vector2i.by_value, :view_t],
|
|
@@ -386,6 +415,8 @@ module SFML
|
|
|
386
415
|
attach_function :sfShader_createFromMemory, [:string, :string, :string], :shader_t
|
|
387
416
|
attach_function :sfShader_destroy, [:shader_t], :void
|
|
388
417
|
attach_function :sfShader_isAvailable, [], :bool
|
|
418
|
+
attach_function :sfShader_bind, [:shader_t], :void
|
|
419
|
+
attach_function :sfShader_getNativeHandle, [:shader_t], :uint
|
|
389
420
|
attach_function :sfShader_isGeometryAvailable, [], :bool
|
|
390
421
|
|
|
391
422
|
attach_function :sfShader_setFloatUniform, [:shader_t, :string, :float], :void
|
|
@@ -429,10 +460,28 @@ module SFML
|
|
|
429
460
|
attach_function :sfShader_setVec4UniformArray, [:shader_t, :string, :pointer, :size_t], :void
|
|
430
461
|
|
|
431
462
|
# ---- Font ----
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
463
|
+
# `sfFontInfo` carries one field — the human-readable font
|
|
464
|
+
# family. CSFML 3 expanded this struct's surface area only
|
|
465
|
+
# through the existing `getInfo` getter; new fields would
|
|
466
|
+
# arrive as additional struct members.
|
|
467
|
+
class FontInfo < FFI::Struct
|
|
468
|
+
layout :family, :pointer # C string; copy out before the font is destroyed
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
attach_function :sfFont_createFromFile, [:string], :font_t
|
|
472
|
+
attach_function :sfFont_createFromMemory, [:pointer, :size_t], :font_t
|
|
473
|
+
attach_function :sfFont_copy, [:font_t], :font_t
|
|
474
|
+
attach_function :sfFont_destroy, [:font_t], :void
|
|
475
|
+
attach_function :sfFont_setSmooth, [:font_t, :bool], :void
|
|
476
|
+
attach_function :sfFont_isSmooth, [:font_t], :bool
|
|
477
|
+
attach_function :sfFont_getInfo, [:font_t], FontInfo.by_value
|
|
478
|
+
attach_function :sfFont_hasGlyph, [:font_t, :uint32], :bool
|
|
479
|
+
attach_function :sfFont_getKerning, [:font_t, :uint32, :uint32, :uint], :float
|
|
480
|
+
attach_function :sfFont_getBoldKerning, [:font_t, :uint32, :uint32, :uint], :float
|
|
481
|
+
attach_function :sfFont_getLineSpacing, [:font_t, :uint], :float
|
|
482
|
+
attach_function :sfFont_getUnderlinePosition, [:font_t, :uint], :float
|
|
483
|
+
attach_function :sfFont_getUnderlineThickness, [:font_t, :uint], :float
|
|
484
|
+
attach_function :sfFont_getTexture, [:font_t, :uint], :texture_t
|
|
436
485
|
|
|
437
486
|
# ---- Text ----
|
|
438
487
|
attach_function :sfText_create, [:font_t], :text_t
|
|
@@ -455,7 +504,15 @@ module SFML
|
|
|
455
504
|
attach_function :sfText_setStyle, [:text_t, :uint32], :void
|
|
456
505
|
attach_function :sfText_getStyle, [:text_t], :uint32
|
|
457
506
|
attach_function :sfText_setLetterSpacing, [:text_t, :float], :void
|
|
507
|
+
attach_function :sfText_getLetterSpacing, [:text_t], :float
|
|
458
508
|
attach_function :sfText_setLineSpacing, [:text_t, :float], :void
|
|
509
|
+
attach_function :sfText_getLineSpacing, [:text_t], :float
|
|
510
|
+
attach_function :sfText_findCharacterPos, [:text_t, :size_t], System::Vector2f.by_value
|
|
511
|
+
attach_function :sfText_getFont, [:text_t], :font_t
|
|
512
|
+
attach_function :sfText_copy, [:text_t], :text_t
|
|
513
|
+
attach_function :sfText_getString, [:text_t], :string
|
|
514
|
+
attach_function :sfText_getTransform, [:text_t], Transform.by_value
|
|
515
|
+
attach_function :sfText_getInverseTransform,[:text_t], Transform.by_value
|
|
459
516
|
attach_function :sfText_setPosition, [:text_t, System::Vector2f.by_value], :void
|
|
460
517
|
attach_function :sfText_getPosition, [:text_t], System::Vector2f.by_value
|
|
461
518
|
attach_function :sfText_setRotation, [:text_t, :float], :void
|
data/lib/sfml/c/window.rb
CHANGED
|
@@ -241,8 +241,15 @@ module SFML
|
|
|
241
241
|
attach_function :sfWindow_setKeyRepeatEnabled, [:raw_window_t, :bool], :void
|
|
242
242
|
attach_function :sfWindow_requestFocus, [:raw_window_t], :void
|
|
243
243
|
attach_function :sfWindow_hasFocus, [:raw_window_t], :bool
|
|
244
|
+
attach_function :sfWindow_requestFocus, [:raw_window_t], :void
|
|
244
245
|
attach_function :sfWindow_setActive, [:raw_window_t, :bool], :bool
|
|
245
246
|
attach_function :sfWindow_setIcon, [:raw_window_t, System::Vector2u.by_value, :pointer], :void
|
|
247
|
+
attach_function :sfWindow_setMouseCursor, [:raw_window_t, :pointer], :void
|
|
248
|
+
attach_function :sfWindow_setMouseCursorVisible, [:raw_window_t, :bool], :void
|
|
249
|
+
attach_function :sfWindow_setMouseCursorGrabbed, [:raw_window_t, :bool], :void
|
|
250
|
+
attach_function :sfWindow_setJoystickThreshold, [:raw_window_t, :float], :void
|
|
251
|
+
attach_function :sfWindow_getSettings, [:raw_window_t], ContextSettings.by_value
|
|
252
|
+
attach_function :sfWindow_waitEvent, [:raw_window_t, System::Time.by_value, :pointer], :bool
|
|
246
253
|
# NULL pointer clears the limit. Pass a Vector2u* to set it.
|
|
247
254
|
attach_function :sfWindow_setMinimumSize, [:raw_window_t, :pointer], :void
|
|
248
255
|
attach_function :sfWindow_setMaximumSize, [:raw_window_t, :pointer], :void
|
data/lib/sfml/graphics/font.rb
CHANGED
|
@@ -27,6 +27,23 @@ module SFML
|
|
|
27
27
|
font
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
# Load a font from a Ruby String of bytes — useful when the
|
|
31
|
+
# font lives inside a `data:` URL, an embedded asset, or a
|
|
32
|
+
# network response. The bytes are copied by SFML before this
|
|
33
|
+
# call returns; the caller's String can be GC'd safely.
|
|
34
|
+
def self.from_memory(bytes)
|
|
35
|
+
raise ArgumentError, "expected a String, got #{bytes.class}" unless bytes.is_a?(String)
|
|
36
|
+
|
|
37
|
+
buf = FFI::MemoryPointer.new(:uint8, bytes.bytesize)
|
|
38
|
+
buf.write_bytes(bytes)
|
|
39
|
+
ptr = C::Graphics.sfFont_createFromMemory(buf, bytes.bytesize)
|
|
40
|
+
raise Error, "sfFont_createFromMemory returned NULL" if ptr.null?
|
|
41
|
+
|
|
42
|
+
font = allocate
|
|
43
|
+
font.send(:_take_ownership, ptr)
|
|
44
|
+
font
|
|
45
|
+
end
|
|
46
|
+
|
|
30
47
|
# The default font bundled with ruby-sfml. Use this when you don't
|
|
31
48
|
# care which typeface as long as you can render text — examples,
|
|
32
49
|
# debug HUDs, prototypes. Memoized so subsequent calls return the
|
|
@@ -56,6 +73,69 @@ module SFML
|
|
|
56
73
|
C::Graphics.sfFont_setSmooth(@handle, !!value)
|
|
57
74
|
end
|
|
58
75
|
|
|
76
|
+
# Human-readable family name (e.g. "DejaVu Sans"). Read once
|
|
77
|
+
# via `sfFont_getInfo` — CSFML returns a static C string from
|
|
78
|
+
# FreeType so we copy out into a Ruby String.
|
|
79
|
+
def family
|
|
80
|
+
info = C::Graphics.sfFont_getInfo(@handle)
|
|
81
|
+
info[:family].null? ? nil : info[:family].read_string
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# `true` if the font has a glyph for the given Unicode codepoint
|
|
85
|
+
# (Integer) or single-character String.
|
|
86
|
+
def has_glyph?(codepoint)
|
|
87
|
+
cp = codepoint.is_a?(String) ? codepoint.codepoints.first : Integer(codepoint)
|
|
88
|
+
C::Graphics.sfFont_hasGlyph(@handle, cp || 0)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Horizontal kerning offset between two adjacent glyphs at the
|
|
92
|
+
# given character size. Float, in pixels (often negative — the
|
|
93
|
+
# kern pulls the second glyph leftward).
|
|
94
|
+
def kerning(first, second, character_size:, bold: false)
|
|
95
|
+
a = first.is_a?(String) ? first.codepoints.first : Integer(first)
|
|
96
|
+
b = second.is_a?(String) ? second.codepoints.first : Integer(second)
|
|
97
|
+
fn = bold ? :sfFont_getBoldKerning : :sfFont_getKerning
|
|
98
|
+
C::Graphics.send(fn, @handle, a || 0, b || 0, Integer(character_size))
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Distance between two consecutive baselines for the given
|
|
102
|
+
# character size. Float, in pixels.
|
|
103
|
+
def line_spacing(character_size)
|
|
104
|
+
C::Graphics.sfFont_getLineSpacing(@handle, Integer(character_size))
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Vertical offset of the underline from the baseline (positive
|
|
108
|
+
# values point downward). Float, in pixels.
|
|
109
|
+
def underline_position(character_size)
|
|
110
|
+
C::Graphics.sfFont_getUnderlinePosition(@handle, Integer(character_size))
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Thickness of the underline stroke. Float, in pixels.
|
|
114
|
+
def underline_thickness(character_size)
|
|
115
|
+
C::Graphics.sfFont_getUnderlineThickness(@handle, Integer(character_size))
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# The internal glyph atlas as a `SFML::Texture` (read-only — we
|
|
119
|
+
# don't own the pointer; CSFML keeps it alive as long as the
|
|
120
|
+
# font does).
|
|
121
|
+
def texture(character_size)
|
|
122
|
+
ptr = C::Graphics.sfFont_getTexture(@handle, Integer(character_size))
|
|
123
|
+
return nil if ptr.null?
|
|
124
|
+
Texture.send(:_borrow, ptr)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Deep copy. The returned font has its own atlas state; mutate
|
|
128
|
+
# one without affecting the other.
|
|
129
|
+
def dup
|
|
130
|
+
ptr = C::Graphics.sfFont_copy(@handle)
|
|
131
|
+
raise Error, "sfFont_copy returned NULL" if ptr.null?
|
|
132
|
+
|
|
133
|
+
font = self.class.allocate
|
|
134
|
+
font.send(:_take_ownership, ptr)
|
|
135
|
+
font
|
|
136
|
+
end
|
|
137
|
+
alias clone dup
|
|
138
|
+
|
|
59
139
|
attr_reader :handle # :nodoc:
|
|
60
140
|
|
|
61
141
|
private
|
data/lib/sfml/graphics/image.rb
CHANGED
|
@@ -41,6 +41,23 @@ module SFML
|
|
|
41
41
|
img
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
+
# Decode an image from a Ruby String of bytes (PNG, JPG, BMP,
|
|
45
|
+
# TGA, GIF, HDR, PSD — whatever stb_image / SFML's loader
|
|
46
|
+
# supports). Mirror of `Image#save_to_memory` for round-trips
|
|
47
|
+
# without touching the disk.
|
|
48
|
+
def self.from_memory(bytes)
|
|
49
|
+
raise ArgumentError, "expected a String, got #{bytes.class}" unless bytes.is_a?(String)
|
|
50
|
+
|
|
51
|
+
buf = FFI::MemoryPointer.new(:uint8, bytes.bytesize)
|
|
52
|
+
buf.write_bytes(bytes)
|
|
53
|
+
ptr = C::Graphics.sfImage_createFromMemory(buf, bytes.bytesize)
|
|
54
|
+
raise Error, "sfImage_createFromMemory returned NULL — unsupported format?" if ptr.null?
|
|
55
|
+
|
|
56
|
+
img = allocate
|
|
57
|
+
img.send(:_take_ownership, ptr)
|
|
58
|
+
img
|
|
59
|
+
end
|
|
60
|
+
|
|
44
61
|
# Build an image from a raw RGBA byte string. `pixels` must be
|
|
45
62
|
# exactly width*height*4 bytes, row-major from the top-left.
|
|
46
63
|
def self.from_pixels(width, height, pixels)
|
|
@@ -90,6 +107,36 @@ module SFML
|
|
|
90
107
|
ptr.read_bytes(width * height * 4)
|
|
91
108
|
end
|
|
92
109
|
|
|
110
|
+
# Copy a rectangular region of `source` into this image. The
|
|
111
|
+
# source region is `source_rect` (a `SFML::Rect` or `[x, y, w,
|
|
112
|
+
# h]` Array; defaults to the entire source); the destination
|
|
113
|
+
# top-left in this image is `at` (`[x, y]`). When `apply_alpha`
|
|
114
|
+
# is true, the source's alpha channel blends with this image's
|
|
115
|
+
# existing pixels; otherwise the copy is opaque.
|
|
116
|
+
#
|
|
117
|
+
# Useful for stamping sprites onto an atlas, blitting one
|
|
118
|
+
# image into a sub-rect of another, or hand-building a
|
|
119
|
+
# composite before uploading to GPU.
|
|
120
|
+
def copy_from(source, at:, source_rect: nil, apply_alpha: false)
|
|
121
|
+
raise ArgumentError, "Image#copy_from needs a SFML::Image" unless source.is_a?(Image)
|
|
122
|
+
|
|
123
|
+
dest = C::System::Vector2u.new
|
|
124
|
+
dest[:x] = Integer(at[0]); dest[:y] = Integer(at[1])
|
|
125
|
+
|
|
126
|
+
sr_struct = C::Graphics::IntRect.new
|
|
127
|
+
x, y, w, h =
|
|
128
|
+
case source_rect
|
|
129
|
+
when nil then [0, 0, 0, 0] # zeroes = "entire source" in CSFML
|
|
130
|
+
when Rect then [source_rect.x, source_rect.y, source_rect.width, source_rect.height]
|
|
131
|
+
when Array then source_rect
|
|
132
|
+
else raise ArgumentError, "source_rect must be a SFML::Rect or [x, y, w, h]"
|
|
133
|
+
end
|
|
134
|
+
sr_struct[:position][:x] = Integer(x); sr_struct[:position][:y] = Integer(y)
|
|
135
|
+
sr_struct[:size][:x] = Integer(w); sr_struct[:size][:y] = Integer(h)
|
|
136
|
+
C::Graphics.sfImage_copyImage(@handle, source.handle, dest, sr_struct, !!apply_alpha)
|
|
137
|
+
self
|
|
138
|
+
end
|
|
139
|
+
|
|
93
140
|
def save(path)
|
|
94
141
|
ok = C::Graphics.sfImage_saveToFile(@handle, path.to_s)
|
|
95
142
|
raise Error, "Could not save image to #{path.inspect}" unless ok
|
|
@@ -51,6 +51,33 @@ module SFML
|
|
|
51
51
|
C::Graphics.sfRenderTexture_setRepeated(@handle, !!value)
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
+
# `true` if the framebuffer is sRGB-capable.
|
|
55
|
+
def srgb? = C::Graphics.sfRenderTexture_isSrgb(@handle)
|
|
56
|
+
|
|
57
|
+
# Generate mipmaps for the underlying texture. Useful when the
|
|
58
|
+
# texture will be sampled at a downscaled size — without
|
|
59
|
+
# mipmaps you get aliasing on minification. Returns `true` if
|
|
60
|
+
# the GPU honoured the request (NPOT or unsupported drivers
|
|
61
|
+
# return `false`).
|
|
62
|
+
def generate_mipmap
|
|
63
|
+
C::Graphics.sfRenderTexture_generateMipmap(@handle)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Maximum MSAA level the driver can apply to a RenderTexture
|
|
67
|
+
# at this moment. Class-level — independent of the instance.
|
|
68
|
+
def self.maximum_anti_aliasing_level
|
|
69
|
+
C::Graphics.sfRenderTexture_getMaximumAntiAliasingLevel
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# ---- GL interop (mirror of RenderWindow's) ----
|
|
73
|
+
|
|
74
|
+
def active=(value)
|
|
75
|
+
C::Graphics.sfRenderTexture_setActive(@handle, value ? true : false)
|
|
76
|
+
end
|
|
77
|
+
def push_gl_states = C::Graphics.sfRenderTexture_pushGLStates(@handle)
|
|
78
|
+
def pop_gl_states = C::Graphics.sfRenderTexture_popGLStates(@handle)
|
|
79
|
+
def reset_gl_states = C::Graphics.sfRenderTexture_resetGLStates(@handle)
|
|
80
|
+
|
|
54
81
|
# The Texture this RenderTexture is rendering into. Borrowed — its
|
|
55
82
|
# lifetime is bounded by `self`. Memoised so repeated calls return
|
|
56
83
|
# the same Ruby wrapper.
|
|
@@ -162,6 +162,68 @@ module SFML
|
|
|
162
162
|
C::Graphics.sfRenderWindow_getNativeHandle(@handle)
|
|
163
163
|
end
|
|
164
164
|
|
|
165
|
+
# ---- Focus ----
|
|
166
|
+
def focused? = C::Graphics.sfRenderWindow_hasFocus(@handle)
|
|
167
|
+
def request_focus = C::Graphics.sfRenderWindow_requestFocus(@handle)
|
|
168
|
+
|
|
169
|
+
# ---- OS-window state ----
|
|
170
|
+
def visible=(value)
|
|
171
|
+
C::Graphics.sfRenderWindow_setVisible(@handle, value ? true : false)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def key_repeat_enabled=(value)
|
|
175
|
+
C::Graphics.sfRenderWindow_setKeyRepeatEnabled(@handle, value ? true : false)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def joystick_threshold=(value)
|
|
179
|
+
C::Graphics.sfRenderWindow_setJoystickThreshold(@handle, Float(value))
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Top-left corner in desktop coordinates.
|
|
183
|
+
def position
|
|
184
|
+
Vector2.from_native(C::Graphics.sfRenderWindow_getPosition(@handle))
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def position=(value)
|
|
188
|
+
vec = value.is_a?(Vector2) ? value : Vector2.new(*value)
|
|
189
|
+
v = C::System::Vector2i.new
|
|
190
|
+
v[:x] = Integer(vec.x); v[:y] = Integer(vec.y)
|
|
191
|
+
C::Graphics.sfRenderWindow_setPosition(@handle, v)
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# `true` if the framebuffer is sRGB-capable (i.e. the GL
|
|
195
|
+
# context was created with the sRGB attribute and the driver
|
|
196
|
+
# honoured it).
|
|
197
|
+
def srgb? = C::Graphics.sfRenderWindow_isSrgb(@handle)
|
|
198
|
+
|
|
199
|
+
# ---- GL interop ----
|
|
200
|
+
#
|
|
201
|
+
# When mixing raw OpenGL calls with SFML rendering, surround
|
|
202
|
+
# the OpenGL block with `push_gl_states` / `pop_gl_states` so
|
|
203
|
+
# SFML's internal state survives. `reset_gl_states` is a
|
|
204
|
+
# heavier "throw away whatever's been changed" reset.
|
|
205
|
+
# `active=` toggles the GL context's activation on the
|
|
206
|
+
# current thread — the only way to use SFML rendering from a
|
|
207
|
+
# non-main thread.
|
|
208
|
+
|
|
209
|
+
def active=(value)
|
|
210
|
+
C::Graphics.sfRenderWindow_setActive(@handle, value ? true : false)
|
|
211
|
+
end
|
|
212
|
+
def push_gl_states = C::Graphics.sfRenderWindow_pushGLStates(@handle)
|
|
213
|
+
def pop_gl_states = C::Graphics.sfRenderWindow_popGLStates(@handle)
|
|
214
|
+
def reset_gl_states = C::Graphics.sfRenderWindow_resetGLStates(@handle)
|
|
215
|
+
|
|
216
|
+
# Block until an event arrives or `timeout` (a SFML::Time)
|
|
217
|
+
# elapses. Returns the next pending Event or nil on timeout.
|
|
218
|
+
# Useful for low-power apps that don't need to redraw at
|
|
219
|
+
# 60fps — wake on input.
|
|
220
|
+
def wait_event(timeout: nil)
|
|
221
|
+
t = timeout || Time.zero
|
|
222
|
+
ok = C::Graphics.sfRenderWindow_waitEvent(@handle, t.to_native, @event_buffer)
|
|
223
|
+
return nil unless ok
|
|
224
|
+
Event.from_native(@event_buffer)
|
|
225
|
+
end
|
|
226
|
+
|
|
165
227
|
# Wrap an existing OS-level window. `handle` is a platform native
|
|
166
228
|
# handle (Integer address or FFI::Pointer). Useful for embedding
|
|
167
229
|
# the renderer inside another framework's window (Qt, Gtk, raw
|
data/lib/sfml/graphics/shader.rb
CHANGED
|
@@ -139,6 +139,19 @@ module SFML
|
|
|
139
139
|
C::Graphics.sfShader_setFloatUniformArray(@handle, name.to_s, buf, values.length)
|
|
140
140
|
end
|
|
141
141
|
|
|
142
|
+
# Bind this shader as the active GL program. Useful when you
|
|
143
|
+
# want to issue raw GL draw calls under SFML's context. Pair
|
|
144
|
+
# with `Shader.unbind` to restore SFML's default. Most users
|
|
145
|
+
# don't need this — just pass the shader to `target.draw(...,
|
|
146
|
+
# render_states: SFML::RenderStates.new(shader: self))`.
|
|
147
|
+
def bind = C::Graphics.sfShader_bind(@handle)
|
|
148
|
+
|
|
149
|
+
def self.unbind = C::Graphics.sfShader_bind(nil)
|
|
150
|
+
|
|
151
|
+
# The OpenGL program ID. Useful for debug printf / interop
|
|
152
|
+
# with raw GL libraries.
|
|
153
|
+
def native_handle = C::Graphics.sfShader_getNativeHandle(@handle)
|
|
154
|
+
|
|
142
155
|
attr_reader :handle # :nodoc:
|
|
143
156
|
|
|
144
157
|
private
|
data/lib/sfml/graphics/text.rb
CHANGED
|
@@ -123,6 +123,53 @@ module SFML
|
|
|
123
123
|
C::Graphics.sfText_setStyle(@handle, bits)
|
|
124
124
|
end
|
|
125
125
|
|
|
126
|
+
# The character spacing modifier — a multiplier on the font's
|
|
127
|
+
# natural advance. Read with no args, set with a Float (1.0 =
|
|
128
|
+
# default).
|
|
129
|
+
def letter_spacing = C::Graphics.sfText_getLetterSpacing(@handle)
|
|
130
|
+
|
|
131
|
+
def letter_spacing=(value)
|
|
132
|
+
C::Graphics.sfText_setLetterSpacing(@handle, Float(value))
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# The line-spacing multiplier (1.0 = default).
|
|
136
|
+
def line_spacing = C::Graphics.sfText_getLineSpacing(@handle)
|
|
137
|
+
|
|
138
|
+
def line_spacing=(value)
|
|
139
|
+
C::Graphics.sfText_setLineSpacing(@handle, Float(value))
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# The screen-space position of the character at byte index
|
|
143
|
+
# `index` in the Text's current string. Returns a `Vector2`.
|
|
144
|
+
# Useful for positioning a caret in a text field, drawing
|
|
145
|
+
# selection highlights, or anchoring tooltips.
|
|
146
|
+
def find_character_pos(index)
|
|
147
|
+
Vector2.from_native(C::Graphics.sfText_findCharacterPos(@handle, Integer(index)))
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Combined translation/scale/rotation as a SFML::Transform.
|
|
151
|
+
# Same matrix the renderer uses to draw the Text.
|
|
152
|
+
def transform
|
|
153
|
+
C::Graphics.sfText_getTransform(@handle)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def inverse_transform
|
|
157
|
+
C::Graphics.sfText_getInverseTransform(@handle)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Deep copy. The returned Text holds the same Font reference
|
|
161
|
+
# (Fonts are shareable; each owns its own glyph atlas).
|
|
162
|
+
def dup
|
|
163
|
+
ptr = C::Graphics.sfText_copy(@handle)
|
|
164
|
+
raise Error, "sfText_copy returned NULL" if ptr.null?
|
|
165
|
+
|
|
166
|
+
copy = self.class.allocate
|
|
167
|
+
copy.instance_variable_set(:@handle, FFI::AutoPointer.new(ptr, C::Graphics.method(:sfText_destroy)))
|
|
168
|
+
copy.instance_variable_set(:@font, @font)
|
|
169
|
+
copy
|
|
170
|
+
end
|
|
171
|
+
alias clone dup
|
|
172
|
+
|
|
126
173
|
# Bounding box of the text in its own (untransformed) coordinate system.
|
|
127
174
|
# Use this to centre or align glyphs precisely:
|
|
128
175
|
# text.origin = [text.local_bounds.width / 2, 0]
|
|
@@ -16,6 +16,21 @@ module SFML
|
|
|
16
16
|
tex
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
+
# Allocate a blank texture on the GPU at the given size — use
|
|
20
|
+
# `update(image)` afterwards to upload pixels. Useful when
|
|
21
|
+
# you'll be filling the texture from a procedurally-generated
|
|
22
|
+
# Image or repeatedly streaming pixel data into it.
|
|
23
|
+
def self.create(width, height)
|
|
24
|
+
size = C::System::Vector2u.new
|
|
25
|
+
size[:x] = Integer(width); size[:y] = Integer(height)
|
|
26
|
+
ptr = C::Graphics.sfTexture_create(size)
|
|
27
|
+
raise Error, "sfTexture_create returned NULL — out of GPU memory?" if ptr.null?
|
|
28
|
+
|
|
29
|
+
tex = allocate
|
|
30
|
+
tex.send(:_take_ownership, ptr)
|
|
31
|
+
tex
|
|
32
|
+
end
|
|
33
|
+
|
|
19
34
|
# Upload a CPU-side SFML::Image to the GPU as a new Texture. Keeps
|
|
20
35
|
# the RGBA byte order and dimensions of the source image.
|
|
21
36
|
def self.from_image(image, smooth: false, repeated: false)
|
|
@@ -68,8 +83,58 @@ module SFML
|
|
|
68
83
|
C::Graphics.sfTexture_setRepeated(@handle, !!value)
|
|
69
84
|
end
|
|
70
85
|
|
|
86
|
+
def srgb? = C::Graphics.sfTexture_isSrgb(@handle)
|
|
87
|
+
|
|
88
|
+
# Generate mipmaps for this texture. Returns `true` if the
|
|
89
|
+
# GPU honoured it. Required for the `_MIPMAP_*` minification
|
|
90
|
+
# filters; otherwise downscaled samples alias.
|
|
91
|
+
def generate_mipmap = C::Graphics.sfTexture_generateMipmap(@handle)
|
|
92
|
+
|
|
93
|
+
# Bind this texture to the active OpenGL texture unit. `coord`
|
|
94
|
+
# is one of `:normalized` (default — UVs in [0..1]) or
|
|
95
|
+
# `:pixels` (UVs in [0..size]). Useful when mixing raw
|
|
96
|
+
# OpenGL with SFML rendering. Pass `nil` to unbind:
|
|
97
|
+
# `SFML::Texture.unbind`.
|
|
98
|
+
COORDINATE_TYPES = {normalized: 0, pixels: 1}.freeze
|
|
99
|
+
|
|
100
|
+
def bind(coord: :normalized)
|
|
101
|
+
raise ArgumentError, "coord must be :normalized or :pixels" unless COORDINATE_TYPES.key?(coord)
|
|
102
|
+
C::Graphics.sfTexture_bind(@handle, COORDINATE_TYPES[coord])
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def self.unbind
|
|
106
|
+
C::Graphics.sfTexture_bind(nil, 0)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Maximum texture dimension the driver will allocate. Tied to
|
|
110
|
+
# the GL state, so it's a class-level call (no instance).
|
|
111
|
+
def self.maximum_size
|
|
112
|
+
C::Graphics.sfTexture_getMaximumSize
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Deep copy. The returned texture has its own GPU memory.
|
|
116
|
+
def dup
|
|
117
|
+
ptr = C::Graphics.sfTexture_copy(@handle)
|
|
118
|
+
raise Error, "sfTexture_copy returned NULL" if ptr.null?
|
|
119
|
+
|
|
120
|
+
tex = self.class.allocate
|
|
121
|
+
tex.send(:_take_ownership, ptr)
|
|
122
|
+
tex
|
|
123
|
+
end
|
|
124
|
+
alias clone dup
|
|
125
|
+
|
|
71
126
|
attr_reader :handle # :nodoc:
|
|
72
127
|
|
|
128
|
+
# Internal — borrow a CSFML-owned `sfTexture*` (e.g. one
|
|
129
|
+
# returned by `sfFont_getTexture`) without registering an
|
|
130
|
+
# auto-destroy hook. The owning object is responsible for
|
|
131
|
+
# outliving any draw call that uses this borrowed handle.
|
|
132
|
+
def self._borrow(ptr)
|
|
133
|
+
tex = allocate
|
|
134
|
+
tex.instance_variable_set(:@handle, ptr)
|
|
135
|
+
tex
|
|
136
|
+
end
|
|
137
|
+
|
|
73
138
|
private
|
|
74
139
|
|
|
75
140
|
def _take_ownership(ptr)
|
data/lib/sfml/version.rb
CHANGED
data/lib/sfml/window/window.rb
CHANGED
|
@@ -129,6 +129,44 @@ module SFML
|
|
|
129
129
|
C::Window.sfWindow_setActive(@handle, value ? true : false)
|
|
130
130
|
end
|
|
131
131
|
|
|
132
|
+
# ---- Mouse cursor ----
|
|
133
|
+
|
|
134
|
+
def cursor=(cursor)
|
|
135
|
+
raise ArgumentError, "Window#cursor= requires a SFML::Cursor" unless cursor.is_a?(Cursor)
|
|
136
|
+
C::Window.sfWindow_setMouseCursor(@handle, cursor.handle)
|
|
137
|
+
@cursor = cursor # keep alive
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def cursor_visible=(visible)
|
|
141
|
+
C::Window.sfWindow_setMouseCursorVisible(@handle, visible ? true : false)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def cursor_grabbed=(grabbed)
|
|
145
|
+
C::Window.sfWindow_setMouseCursorGrabbed(@handle, grabbed ? true : false)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# ---- Misc state ----
|
|
149
|
+
|
|
150
|
+
def joystick_threshold=(value)
|
|
151
|
+
C::Window.sfWindow_setJoystickThreshold(@handle, Float(value))
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# The actual GL context settings the driver gave us — may differ
|
|
155
|
+
# from what was requested via `ContextSettings`.
|
|
156
|
+
def context_settings
|
|
157
|
+
ContextSettings.from_native(C::Window.sfWindow_getSettings(@handle))
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Block until the next event arrives or `timeout` (a SFML::Time)
|
|
161
|
+
# elapses. `nil` timeout = wait forever (matches CSFML's
|
|
162
|
+
# `sfTime_Zero` / no-timeout convention).
|
|
163
|
+
def wait_event(timeout: nil)
|
|
164
|
+
t = timeout || Time.zero
|
|
165
|
+
ok = C::Window.sfWindow_waitEvent(@handle, t.to_native, @event_buffer)
|
|
166
|
+
return nil unless ok
|
|
167
|
+
Event.from_native(@event_buffer)
|
|
168
|
+
end
|
|
169
|
+
|
|
132
170
|
# Replace the window's title-bar / taskbar icon with the pixels from
|
|
133
171
|
# the given SFML::Image. The OS scales it as needed; 32×32 RGBA
|
|
134
172
|
# is the typical sweet spot.
|