lib/import/flame_stabilizer.rb in tracksperanto-3.3.6 vs lib/import/flame_stabilizer.rb in tracksperanto-3.3.7

- old
+ new

@@ -63,62 +63,71 @@ def channel_is_useful?(channel_name) USEFUL_CHANNELS.any?{|e| channel_name =~ e } end end + # Extracts the animation channels and stores them in Obufs + # keyed by the channel path (like "tracker1/ref/x") def extract_channels_from_stream(io) parser = StabilizerParser.new parser.logger_proc = method(:report_progress) - channels = Obuf.new - names = [] + channel_map = {} parser.parse(io) do | channel | - channels.push(channel) - names.push(channel.path) + # 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 - [channels, names] + channel_map end - def scavenge_trackers_from_channels(channels, names) - channels.each do |c| - next unless c.name =~ /\/ref\/x/ + 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.name}") + report_progress("Detected reference channel #{c.inspect}") - t = grab_tracker(channels, c, names) - yield(t) if t + extracted_tracker = grab_tracker(channel_map, c) + if extracted_tracker + yield(extracted_tracker) + end end end def channel_to_frames_and_values(chan) chan.map{|key| [key.frame, key.value]} end - def grab_tracker(channels, track_x, names) - t = Tracksperanto::Tracker.new(:name => track_x.name.split('/').shift) + 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}") - # This takes a LONG time when we have alot of channels, we need a precache of - # some sort to do this - ref_idx = names.index("#{t.name}/ref/y") - shift_x_idx = names.index("#{t.name}/shift/x") - shift_y_idx = names.index("#{t.name}/shift/y") + 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] - track_y = channels[ref_idx] - shift_x = channels[shift_x_idx] - shift_y = channels[shift_y_idx] - + # 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)) - track_tuples = zip_curve_tuples(channel_to_frames_and_values(track_x), channel_to_frames_and_values(track_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? || track_tuples.empty? + return if shift_tuples.empty? || ref_tuples.empty? report_progress("Detecting base value") - base_x, base_y = find_base_x_and_y(track_tuples, shift_tuples) + 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! @@ -129,12 +138,12 @@ end return t end - def find_base_x_and_y(track_tuples, shift_tuples) - base_track_tuple = track_tuples.find do | track_tuple | + 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_track_tuple || track_tuples[0])[1..2] + (base_ref_tuple || ref_tuples[0])[1..2] end end