Class: SFML::Shape

Inherits:
Object
  • Object
show all
Includes:
Graphics::ShapeInspectable, Graphics::Transformable
Defined in:
lib/sfml/graphics/shape.rb

Overview

Abstract callback-driven shape — for when neither CircleShape, RectangleShape, nor ConvexShape fits. Subclass and override #point_count (returns Integer) and #point(i) (returns a Vector2 or [x, y]). CSFML asks Ruby every frame for the point list, so you can drive geometry from live data.

class Pentagon < SFML::Shape
def point_count = 5
def point(i)
  angle = i * 2 * Math::PI / 5 - Math::PI / 2
  [Math.cos(angle) * 50, Math.sin(angle) * 50]
end
end

pent = Pentagon.new(fill_color: SFML::Color.red, position: [400, 300])
window.draw(pent)

When your underlying geometry changes (e.g. the data feeding #point updates), call #update to invalidate the cached outline / bounds — otherwise the next draw will still use the previously sampled points.

CAVEATS

  • Callbacks run on whichever thread invokes the draw. With single-threaded rendering (the SFML default) this is fine; if you're driving the renderer from a different thread, make sure #point_count / #point are thread-safe.
  • Keep a Ruby reference to the Shape — if it's GC'd while CSFML still holds the function pointers, the next draw crashes.

Constant Summary collapse

CSFML_PREFIX =
:sfShape

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Graphics::ShapeInspectable

#dup, #geometric_center, #global_bounds, #inverse_transform, #local_bounds, #set_texture, #texture, #texture=, #texture_rect, #texture_rect=, #transform

Methods included from Graphics::Transformable

#move, #origin, #origin=, #position, #position=, #rotate, #rotation, #rotation=, #scale, #scale=, #scale_by

Constructor Details

#initialize(**opts) ⇒ Shape

Returns a new instance of Shape.

Raises:



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/sfml/graphics/shape.rb', line 36

def initialize(**opts)
  # Hold strong refs so the GC doesn't disappear our FFI callbacks.
  @get_point_count_cb = FFI::Function.new(:size_t, [:pointer]) do |_user|
    Integer(point_count)
  end
  @get_point_cb = FFI::Function.new(C::System::Vector2f.by_value, [:size_t, :pointer]) do |i, _user|
    p = point(i)
    pt = p.is_a?(Vector2) ? p : Vector2.new(*p)
    v  = C::System::Vector2f.new
    v[:x] = pt.x.to_f; v[:y] = pt.y.to_f
    v
  end

  ptr = C::Graphics.sfShape_create(@get_point_count_cb, @get_point_cb, nil)
  raise GraphicsError, "sfShape_create returned NULL" if ptr.null?
  @handle = FFI::AutoPointer.new(ptr, C::Graphics.method(:sfShape_destroy))

  self.fill_color         = opts[:fill_color]         if opts.key?(:fill_color)
  self.outline_color      = opts[:outline_color]      if opts.key?(:outline_color)
  self.outline_thickness  = opts[:outline_thickness]  if opts.key?(:outline_thickness)
  self.texture            = opts[:texture]            if opts.key?(:texture)
  self.texture_rect       = opts[:texture_rect]       if opts.key?(:texture_rect)
  self.position           = opts[:position]           if opts.key?(:position)
  self.origin             = opts[:origin]             if opts.key?(:origin)
  self.rotation           = opts[:rotation]           if opts.key?(:rotation)
  self.scale              = opts[:scale]              if opts.key?(:scale)
end

Instance Attribute Details

#handle ⇒ Object (readonly)

:nodoc:



119
120
121
# File 'lib/sfml/graphics/shape.rb', line 119

def handle
  @handle
end

Instance Method Details

#draw_on(target, states_ptr = nil) ⇒ Object

Returns the draw on.



110
111
112
# File 'lib/sfml/graphics/shape.rb', line 110

def draw_on(target, states_ptr = nil) # :nodoc:
  target._draw_native(:Shape, @handle, states_ptr)
end

#fill_color ⇒ Object

---- Public API ----



77
# File 'lib/sfml/graphics/shape.rb', line 77

def fill_color = Color.from_native(C::Graphics.sfShape_getFillColor(@handle))

#fill_color=(c) ⇒ Object

Set the fill color.



80
81
82
# File 'lib/sfml/graphics/shape.rb', line 80

def fill_color=(c)
  C::Graphics.sfShape_setFillColor(@handle, c.to_native)
end

#outline_color ⇒ Object

Returns the outline color.



85
# File 'lib/sfml/graphics/shape.rb', line 85

def outline_color = Color.from_native(C::Graphics.sfShape_getOutlineColor(@handle))

#outline_color=(c) ⇒ Object

Set the outline color.



88
89
90
# File 'lib/sfml/graphics/shape.rb', line 88

def outline_color=(c)
  C::Graphics.sfShape_setOutlineColor(@handle, c.to_native)
end

#outline_thickness ⇒ Object

Returns the outline thickness.



93
# File 'lib/sfml/graphics/shape.rb', line 93

def outline_thickness = C::Graphics.sfShape_getOutlineThickness(@handle)

#outline_thickness=(t) ⇒ Object

Set the outline thickness.



96
97
98
# File 'lib/sfml/graphics/shape.rb', line 96

def outline_thickness=(t)
  C::Graphics.sfShape_setOutlineThickness(@handle, t.to_f)
end

#point(_index) ⇒ Object

Returns the point.

Raises:

  • (NoMethodError)


71
72
73
# File 'lib/sfml/graphics/shape.rb', line 71

def point(_index)
  raise NoMethodError, "#{self.class} must override #point(index)"
end

#point_count ⇒ Object

---- Subclass hooks ----

Raises:

  • (NoMethodError)


66
67
68
# File 'lib/sfml/graphics/shape.rb', line 66

def point_count
  raise NoMethodError, "#{self.class} must override #point_count"
end

#update ⇒ Object

Recompute the outline + bounds from the current #point_count / #point(i). Call after the data driving your callbacks changes. No-op on construction (CSFML samples the points once at the first draw).



104
105
106
107
# File 'lib/sfml/graphics/shape.rb', line 104

def update
  C::Graphics.sfShape_update(@handle)
  self
end