class Tracksperanto::Import::FlameStabilizer

Public Class Methods

autodetects_size?() click to toggle source

Flame setups contain clear size indications

# File lib/import/flame_stabilizer.rb, line 6
def self.autodetects_size?
  true
end
distinct_file_ext() click to toggle source
# File lib/import/flame_stabilizer.rb, line 10
def self.distinct_file_ext
  ".stabilizer"
end
human_name() click to toggle source
# File lib/import/flame_stabilizer.rb, line 14
def self.human_name
  "Flame .stabilizer file"
end

Public Instance Methods

each() { |t| ... } click to toggle source
# File lib/import/flame_stabilizer.rb, line 18
def each
  report_progress("Extracting setup size")
  self.width, self.height = extract_width_and_height_from_stream(@io)
  report_progress("Extracting all animation channels")
  channels, names = extract_channels_from_stream(@io)
  
  begin
    report_progress("Assembling tracker curves from channels")
    scavenge_trackers_from_channels(channels, names) {|t| yield(t) }
  ensure
    channels.clear
  end
end

Private Instance Methods

channel_to_frames_and_values(chan) click to toggle source
# File lib/import/flame_stabilizer.rb, line 100
def channel_to_frames_and_values(chan)
  chan.map{|key| [key.frame, key.value]}
end
extract_channels_from_stream(io) click to toggle source

Extracts the animation channels and stores them in Obufs keyed by the channel path (like “tracker1/ref/x”)

# File lib/import/flame_stabilizer.rb, line 64
def extract_channels_from_stream(io)
  parser = StabilizerParser.new
  parser.logger_proc = method(:report_progress)
  
  channel_map = {}
  parser.parse(io) do | channel |
    # Serialize the channel and store it on disk.
    # Flame stabilizers are NOT likely to contain hundreds of
    # trackers unless they were machine-exported from something,
    # but we need to be memory-aware when we do things like this.
    # On our test suite we lose half a second on disk IO overhead
    # of the Obuf here, which is an acceptable compromise.
    # To get rid of the disk-based cache just toss the outer
    # Obuf constructor and pass in an Array
    channel_map[channel.path] = Obuf.new([channel])
  end
  
  channel_map
end
extract_width_and_height_from_stream(io) click to toggle source
# File lib/import/flame_stabilizer.rb, line 33
def extract_width_and_height_from_stream(io)
  w, h = nil, nil
  
  w_matcher = /FrameWidth (\d+)/
  h_matcher = /FrameHeight (\d+)/
  
  until io.eof?
    line = io.gets
    if line =~ w_matcher
      w = $1
    elsif line =~ h_matcher
      h = $1
    end
    
    return [w, h] if (w && h)
  end
  
end
find_base_x_and_y(ref_tuples, shift_tuples) click to toggle source
# File lib/import/flame_stabilizer.rb, line 137
def find_base_x_and_y(ref_tuples, shift_tuples)
  base_ref_tuple = ref_tuples.find do | track_tuple |
    shift_tuples.find { |shift_tuple| shift_tuple[0] == track_tuple[0] }
  end
  (base_ref_tuple || ref_tuples[0])[1..2]
end
grab_tracker(channel_map, ref_x_channel_name) click to toggle source
# File lib/import/flame_stabilizer.rb, line 104
def grab_tracker(channel_map, ref_x_channel_name)
  t = Tracksperanto::Tracker.new(:name => ref_x_channel_name.split('/').shift)
  
  report_progress("Extracting tracker #{t.name}")
  
  shift_x = channel_map["#{t.name}/shift/x"][0]
  shift_y = channel_map["#{t.name}/shift/y"][0]
  ref_x = channel_map["#{t.name}/ref/x"][0]
  ref_y = channel_map["#{t.name}/ref/y"][0]
  
  # Collapse separate X and Y curves into series of XY values
  shift_tuples = zip_curve_tuples(channel_to_frames_and_values(shift_x), channel_to_frames_and_values(shift_y))
  ref_tuples = zip_curve_tuples(channel_to_frames_and_values(ref_x), channel_to_frames_and_values(ref_y))
  
  # If the channels are just empty go to next tracker
  return if shift_tuples.empty? || ref_tuples.empty?
  
  report_progress("Detecting base value")
  base_x, base_y =  find_base_x_and_y(ref_tuples, shift_tuples)
  
  total_kf = 1
  t.keyframes = shift_tuples.map do | (at, x, y) |
    # Flame keyframes are sort of minus-one based, so to start at frame 0
    # we need to decrement one frame, always. Also, the shift value is inverted!
    kf_x, kf_y = base_x - x.to_f, base_y - y.to_f
    
    report_progress("Extracting keyframe #{total_kf += 1} of #{t.name}")
    Tracksperanto::Keyframe.new(:frame => (at - 1), :abs_x => kf_x, :abs_y => kf_y)
  end
  
  return t
end
scavenge_trackers_from_channels(channel_map, names) { |extracted_tracker| ... } click to toggle source
# File lib/import/flame_stabilizer.rb, line 84
def scavenge_trackers_from_channels(channel_map, names)
  # Use Hash#keys.sort because we want a consistent export order
  # irregardless of the Ruby version in use
  # (hash keys are ordered on 1.9 and not ordered on 1.8)
  channel_map.keys.sort.each do |c|
    next unless c =~ /\/ref\/x$/
    
    report_progress("Detected reference channel #{c.inspect}")
    
    extracted_tracker = grab_tracker(channel_map, c)
    if extracted_tracker
      yield(extracted_tracker)
    end
  end
end