class FlameChannelParser::Extractor
Extracts and bakes a specific animation channel to a given buffer, one string per frame
Constants
- DEFAULTS
- DEFAULT_CHANNEL_TO_EXTRACT
- DEFAULT_START_FRAME
- SETUP_END_FRAME_PATTERN
- SETUP_START_FRAME_PATTERN
Public Class Methods
extract(path, options = {})
click to toggle source
Pass the path to Flame setup here and you will get the animation curve on the object passed in the :destionation option (defaults to STDOUT). The following options are accepted:
:destination - The object to write the output to, anything that responds to shovel (<<) will do :start_frame - From which frame the curve should be baked. Will default to the first keyframe of the curve :end_frame - Upto which frame to bake. Will default to the last keyframe of the curve :channel - Name of the channel to extract from the setup. Defaults to "Timing/Timing" (timewarp frame)
Note that start_frame and end_frame will be converted to integers. The output will look like this:
1 123.456 2 124.567
# File lib/extractor.rb, line 25 def self.extract(path, options = {}) new.extract(path, options) end
Public Instance Methods
extract(path, options)
click to toggle source
# File lib/extractor.rb, line 29 def extract(path, options) options = DEFAULTS.dup.merge(options) File.open(path) do |f| # Then parse channels = FlameChannelParser.parse(f) selected_channel = find_channel_in(channels, options[:channel]) interpolator = FlameChannelParser::Interpolator.new(selected_channel) # Configure the range configure_start_and_end_frame(f, options, interpolator) # And finally... write_channel(interpolator, options[:destination], options[:start_frame], options[:end_frame]) end end
Private Instance Methods
compose_channel_not_found_message(for_channel, other_channels)
click to toggle source
# File lib/extractor.rb, line 107 def compose_channel_not_found_message(for_channel, other_channels) message = "Channel #{for_channel.inspect} not found in this setup (set the channel with the :channel option). Found other channels though:" message << "\n" message += other_channels.map{|c| "\t%s\n" % c.path }.join end
configure_start_and_end_frame(f, options, interpolator)
click to toggle source
# File lib/extractor.rb, line 73 def configure_start_and_end_frame(f, options, interpolator) # If the settings specify last and first frame... if options[:on_curve_limits] options[:start_frame], options[:end_frame] = start_and_end_frame_from_curve_length(interpolator) else # Detect from the setup itself (the default) # First try to detect start and end frames from the known flags f.rewind detected_start, detected_end = detect_start_and_end_frame_in_io(f) options[:start_frame] = options[:start_frame] || detected_start || DEFAULT_START_FRAME options[:end_frame] ||= detected_end # If the setup does not contain that information retry with curve limits if !options[:start_frame] || !options[:end_frame] options[:on_curve_limits] = true configure_start_and_end_frame(f, options, interpolator) end end end
detect_start_and_end_frame_in_io(io)
click to toggle source
# File lib/extractor.rb, line 94 def detect_start_and_end_frame_in_io(io) cur_offset, s, e = io.pos, nil, nil io.rewind while line = io.gets if (elements = line.scan(SETUP_START_FRAME_PATTERN)).any? s = elements.flatten[-1].to_i elsif (elements = line.scan(SETUP_END_FRAME_PATTERN)).any? e = elements.flatten[-1].to_i return [s, e] end end end
find_channel_in(channels, channel_path)
click to toggle source
# File lib/extractor.rb, line 113 def find_channel_in(channels, channel_path) selected_channel = channels.find{|c| channel_path == c.path } unless selected_channel raise ChannelNotFoundError, compose_channel_not_found_message(channel_path, channels) end selected_channel end
start_and_end_frame_from_curve_length(interp)
click to toggle source
# File lib/extractor.rb, line 60 def start_and_end_frame_from_curve_length(interp) s, e = interp.first_defined_frame.to_i, interp.last_defined_frame.to_i if (!s || !e) raise NoKeyframesError, "This channel probably has no animation so there " + "is no way to automatically tell how many keyframes it has. " + "Please set the start and end frame explicitly." elsif s == e raise NoKeyframesError, "This channel has only one keyframe " + "at frame #{s}and baking it makes no sense." end [s, e] end
write_channel(interpolator, to_io, from_frame_i, to_frame_i)
click to toggle source
# File lib/extractor.rb, line 121 def write_channel(interpolator, to_io, from_frame_i, to_frame_i) if (to_frame_i - from_frame_i) == 1 $stderr.puts "WARNING: You are extracting one animation frame. Check the length of your setup, or set the range manually" end (from_frame_i..to_frame_i).each do | frame | write_frame(to_io, frame, interpolator.sample_at(frame)) end end
write_frame(to_io, frame, value)
click to toggle source
# File lib/extractor.rb, line 132 def write_frame(to_io, frame, value) line = "%d\t%.5f\n" % [frame, value] to_io << line end