class Castaway::Element::Base

Attributes

attributes[R]

reevaluated at each render, represents the value of the attributes at the current point in time.

position[R]
production[R]
scene[R]
size[R]

Public Class Methods

new(production, scene) click to toggle source
# File lib/castaway/element/base.rb, line 36
def initialize(production, scene)
  @production = production
  @scene = scene

  @enter = 0
  @exit = scene.duration
  @position = Castaway::Point.new(0, 0)
  @size = production.resolution

  @animations = Hash.new { |h, k| h[k] = [] }
  @attribute_defs = {}

  attribute(:alpha, 1.0) { |memo, value| memo * value }
  attribute(:position, -> { position }) { |memo, value| memo + value }
  attribute(:size, -> { @size }) { |memo, value| memo * value }
end

Public Instance Methods

_absolute(t) click to toggle source
# File lib/castaway/element/base.rb, line 270
def _absolute(t)
  scene.start + t
end
_composite(canvas, alpha) click to toggle source
# File lib/castaway/element/base.rb, line 238
def _composite(canvas, alpha)
  if alpha < 0.99995 # the point where %.2f rounds alpha*100 to 100
    canvas.compose 'blend'
    canvas.define format('compose:args=%.2f', alpha * 100)
  else
    canvas.compose 'src-over'
  end

  canvas.composite
end
_convert(t) click to toggle source
# File lib/castaway/element/base.rb, line 274
def _convert(t)
  t && t.to_f
end
_evaluate_animation_list(type, t, list) click to toggle source
# File lib/castaway/element/base.rb, line 256
def _evaluate_animation_list(type, t, list)
  list.reduce(@attribute_defs[type].initial) do |memo, animation|
    # animations are always specified relative to the "enter" time of
    # element they are attached to.
    relative_t = t - t1
    if relative_t < animation.from
      memo
    else
      result = animation[relative_t]
      @attribute_defs[type][memo, result]
    end
  end
end
_evaluate_attributes!(t) click to toggle source
# File lib/castaway/element/base.rb, line 249
def _evaluate_attributes!(t)
  @attributes = @attribute_defs.keys.each.with_object({}) do |type, map|
    list = @animations[type]
    map[type] = _evaluate_animation_list(type, t, list)
  end
end
_transform(canvas) click to toggle source
# File lib/castaway/element/base.rb, line 229
def _transform(canvas)
  return unless @scale || @angle

  canvas.virtual_pixel 'transparent'

  distort = "#{@scale || '1'} #{@angle || '0'}"
  canvas.distort.+('ScaleRotateTranslate', distort.strip)
end
alive_at?(t) click to toggle source

`t` is relative to the beginning of the production

# File lib/castaway/element/base.rb, line 54
def alive_at?(t)
  t.between?(t1, t2)
end
animate(attribute, options = {}) click to toggle source
# File lib/castaway/element/base.rb, line 181
def animate(attribute, options = {})
  options = options.dup
  %i( from to ).each { |a| options[a] = _convert(options[a]) }
  @animations[attribute] << Animation.from_options(options)
  self
end
at(*args) click to toggle source
# File lib/castaway/element/base.rb, line 100
def at(*args)
  if args.length == 1
    @position = args.first
  elsif args.length == 2
    @position = Castaway::Point.new(args[0], args[1])
  else
    raise ArgumentError, 'expected 1 or 2 arguments to #at'
  end

  self
end
attribute(name, initial, fn = nil, &block) click to toggle source
# File lib/castaway/element/base.rb, line 58
def attribute(name, initial, fn = nil, &block)
  @attribute_defs[name] = Attribute.new(initial, fn || block)
end
duration() click to toggle source
# File lib/castaway/element/base.rb, line 96
def duration
  @exit - @enter
end
effect(type, options = {}) click to toggle source
# File lib/castaway/element/base.rb, line 176
def effect(type, options = {})
  Castaway::Effect.invoke(type, self, options)
  self
end
enter(t = nil) click to toggle source

Specify or return the start time for this element, relative to the beginning of the scene.

# File lib/castaway/element/base.rb, line 76
def enter(t = nil)
  if t
    @enter = _convert(t)
    self
  else
    @enter
  end
end
exit(t = nil) click to toggle source

Specify or return the exit time for this element, relative to the beginning of the scene.

# File lib/castaway/element/base.rb, line 87
def exit(t = nil)
  if t
    @exit = _convert(t)
    self
  else
    @exit
  end
end
gravity(specification) click to toggle source
# File lib/castaway/element/base.rb, line 112
def gravity(specification)
  s = size

  left = 0
  hcenter = (production.resolution.width - s.width) / 2.0
  right = production.resolution.width - s.width

  top = 0
  vcenter = (production.resolution.height - s.height) / 2.0
  bottom = production.resolution.height - s.height

  x, y = case specification
    when :northwest then [left,    top    ]
    when :north     then [hcenter, top    ]
    when :northeast then [right,   top    ]
    when :west      then [left,    vcenter]
    when :center    then [hcenter, vcenter]
    when :east      then [right,   vcenter]
    when :southwest then [left,    bottom ]
    when :south     then [hcenter, bottom ]
    when :southeast then [right,   bottom ]
    else
      raise ArgumentError, "invalid gravity #{specification.inspect}"
    end

  at(x, y)
end
in(type, options = {}) click to toggle source
# File lib/castaway/element/base.rb, line 168
def in(type, options = {})
  effect(:"#{type}_in", options)
end
out(type, options = {}) click to toggle source
# File lib/castaway/element/base.rb, line 172
def out(type, options = {})
  effect(:"#{type}_out", options)
end
path(points) click to toggle source
# File lib/castaway/element/base.rb, line 188
def path(points)
  current = @position # not #position, which may give us a translated point
  prior_t = 0
  p0 = Castaway::Point.new(0, 0)

  points.keys.sort.each do |time|
    delta = points[time] - current

    animate(:position, type: :linear, from: prior_t, to: time,
                       initial: p0, final: delta)

    current = points[time]
    prior_t = time
  end
end
render_at(t, canvas) click to toggle source

`t` is the global time value, relative to the beginning of the production.

# File lib/castaway/element/base.rb, line 210
def render_at(t, canvas)
  _evaluate_attributes!(t)

  alpha    = attributes[:alpha] || 1.0
  size     = attributes[:size] || production.resolution
  position = attributes[:position] || Castaway::Point.new(0, 0)

  return if alpha <= 0.0 || size.empty?

  canvas.stack do |stack|
    _prepare_canvas(t, stack)
    stack.geometry size.to_geometry
    _transform(stack)
    stack.geometry position.to_geometry unless position.zero?
  end

  _composite(canvas, alpha)
end
rotate(angle) click to toggle source
# File lib/castaway/element/base.rb, line 163
def rotate(angle)
  @angle = angle
  self
end
scale(scale) click to toggle source
# File lib/castaway/element/base.rb, line 158
def scale(scale)
  @scale = scale
  self
end
t1() click to toggle source

Return start time for this element, relative to the beginning of the production.

# File lib/castaway/element/base.rb, line 64
def t1
  _absolute(enter)
end
t2() click to toggle source

Return exit time for this element, relative to the beginning of the production.

# File lib/castaway/element/base.rb, line 70
def t2
  _absolute(exit)
end
tail(value = 0.0) click to toggle source
# File lib/castaway/element/base.rb, line 204
def tail(value = 0.0)
  Tail.new(self, value)
end