flame_channel_parser 1.4.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +11 -2
 - data/Manifest.txt +6 -2
 - data/README.rdoc +1 -1
 - data/Rakefile +2 -0
 - data/bin/bake_flame_channel +26 -5
 - data/lib/channel.rb +36 -0
 - data/lib/extractor.rb +12 -2
 - data/lib/flame_channel_parser.rb +6 -27
 - data/lib/interpolator.rb +27 -24
 - data/lib/key.rb +76 -0
 - data/lib/parser.rb +115 -0
 - data/test/test_channel.rb +22 -0
 - data/test/test_cli.rb +59 -0
 - data/test/test_flame_channel_parser.rb +1 -1
 - data/test/test_interpolator.rb +4 -5
 - data/test/test_key.rb +86 -0
 - data/test/test_segments.rb +7 -2
 - metadata +13 -27
 - data/lib/parser_2011.rb +0 -156
 - data/lib/parser_2012.rb +0 -59
 
    
        data/History.txt
    CHANGED
    
    | 
         @@ -1,3 +1,12 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            === 2.0.1 / 2011-23-06
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            * Fix the bake_flame_channel binary to use the proper extractor API
         
     | 
| 
      
 4 
     | 
    
         
            +
            * Add a test for the binary
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            === 2.0.0 / 2011-08-06
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            * Remove most of the Array methods from the Channel object
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
       1 
10 
     | 
    
         
             
            === 1.4.0 / 2011-06-06
         
     | 
| 
       2 
11 
     | 
    
         | 
| 
       3 
12 
     | 
    
         
             
            * Implement cycle and reverse-cycle extrapolation
         
     | 
| 
         @@ -6,11 +15,11 @@ 
     | 
|
| 
       6 
15 
     | 
    
         | 
| 
       7 
16 
     | 
    
         
             
            * Fix linear extrapolation occurring after linear keyframes, enforce the tangent/increment of zero for linear extrap. segments
         
     | 
| 
       8 
17 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
            === 1.3.1 / 2011-05 
     | 
| 
      
 18 
     | 
    
         
            +
            === 1.3.1 / 2011-30-05
         
     | 
| 
       10 
19 
     | 
    
         | 
| 
       11 
20 
     | 
    
         
             
            * Add minor fixes and imporvements to the curve extraction bin
         
     | 
| 
       12 
21 
     | 
    
         | 
| 
       13 
     | 
    
         
            -
            === 1.3.0 / 2011-05 
     | 
| 
      
 22 
     | 
    
         
            +
            === 1.3.0 / 2011-20-05
         
     | 
| 
       14 
23 
     | 
    
         | 
| 
       15 
24 
     | 
    
         
             
            * Added the Extractor class that does simple per-frame baking to STDOUT
         
     | 
| 
       16 
25 
     | 
    
         
             
            * Add bake_flame_channel binary
         
     | 
    
        data/Manifest.txt
    CHANGED
    
    | 
         @@ -4,11 +4,12 @@ Manifest.txt 
     | 
|
| 
       4 
4 
     | 
    
         
             
            README.rdoc
         
     | 
| 
       5 
5 
     | 
    
         
             
            Rakefile
         
     | 
| 
       6 
6 
     | 
    
         
             
            bin/bake_flame_channel
         
     | 
| 
      
 7 
     | 
    
         
            +
            lib/channel.rb
         
     | 
| 
       7 
8 
     | 
    
         
             
            lib/extractor.rb
         
     | 
| 
       8 
9 
     | 
    
         
             
            lib/flame_channel_parser.rb
         
     | 
| 
       9 
10 
     | 
    
         
             
            lib/interpolator.rb
         
     | 
| 
       10 
     | 
    
         
            -
            lib/ 
     | 
| 
       11 
     | 
    
         
            -
            lib/ 
     | 
| 
      
 11 
     | 
    
         
            +
            lib/key.rb
         
     | 
| 
      
 12 
     | 
    
         
            +
            lib/parser.rb
         
     | 
| 
       12 
13 
     | 
    
         
             
            lib/segments.rb
         
     | 
| 
       13 
14 
     | 
    
         
             
            test/channel_with_constants.dat
         
     | 
| 
       14 
15 
     | 
    
         
             
            test/sample_channel.dat
         
     | 
| 
         @@ -30,7 +31,10 @@ test/snaps/RefT_Steadicam_TwoKFs_HermiteAtBegin.timewarp 
     | 
|
| 
       30 
31 
     | 
    
         
             
            test/snaps/TW.timewarp
         
     | 
| 
       31 
32 
     | 
    
         
             
            test/snaps/TW_SingleFrameExtrapolated_from2011.timewarp
         
     | 
| 
       32 
33 
     | 
    
         
             
            test/snaps/timewarp_where_interp_fails_at_end.timewarp
         
     | 
| 
      
 34 
     | 
    
         
            +
            test/test_channel.rb
         
     | 
| 
      
 35 
     | 
    
         
            +
            test/test_cli.rb
         
     | 
| 
       33 
36 
     | 
    
         
             
            test/test_extractor.rb
         
     | 
| 
       34 
37 
     | 
    
         
             
            test/test_flame_channel_parser.rb
         
     | 
| 
       35 
38 
     | 
    
         
             
            test/test_interpolator.rb
         
     | 
| 
      
 39 
     | 
    
         
            +
            test/test_key.rb
         
     | 
| 
       36 
40 
     | 
    
         
             
            test/test_segments.rb
         
     | 
    
        data/README.rdoc
    CHANGED
    
    | 
         @@ -32,7 +32,7 @@ To use the library: 
     | 
|
| 
       32 
32 
     | 
    
         
             
                frame_channel = channels.find{|c| c.name == "Timing/Timing" }
         
     | 
| 
       33 
33 
     | 
    
         | 
| 
       34 
34 
     | 
    
         
             
                # Grab the interpolator object for this channel.
         
     | 
| 
       35 
     | 
    
         
            -
                interpolator =  
     | 
| 
      
 35 
     | 
    
         
            +
                interpolator = frame_channel.to_interpolator
         
     | 
| 
       36 
36 
     | 
    
         | 
| 
       37 
37 
     | 
    
         
             
                # Now sample from frame 20 to frame 250.
         
     | 
| 
       38 
38 
     | 
    
         
             
                # You can also sample at fractional frames if you want to.
         
     | 
    
        data/Rakefile
    CHANGED
    
    | 
         @@ -4,6 +4,8 @@ require 'rubygems' 
     | 
|
| 
       4 
4 
     | 
    
         
             
            require 'hoe'
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
6 
     | 
    
         
             
            Hoe.spec 'flame_channel_parser' do | p |
         
     | 
| 
      
 7 
     | 
    
         
            +
              Hoe::RUBY_FLAGS.gsub!(/^\-w/, '') # No thanks undefined ivar warnings
         
     | 
| 
      
 8 
     | 
    
         
            +
                
         
     | 
| 
       7 
9 
     | 
    
         
             
              p.readme_file   = 'README.rdoc'
         
     | 
| 
       8 
10 
     | 
    
         
             
              p.extra_rdoc_files  = FileList['*.rdoc'] + FileList['*.txt']
         
     | 
| 
       9 
11 
     | 
    
         
             
              p.extra_deps = {"update_hints" => ">=0" }
         
     | 
    
        data/bin/bake_flame_channel
    CHANGED
    
    | 
         @@ -1,8 +1,21 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            #!/usr/bin/env ruby
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
      
 2 
     | 
    
         
            +
            # == Synopsis
         
     | 
| 
      
 3 
     | 
    
         
            +
            # 
         
     | 
| 
      
 4 
     | 
    
         
            +
            # Extract an animation channel from a Flame setup
         
     | 
| 
      
 5 
     | 
    
         
            +
            #
         
     | 
| 
      
 6 
     | 
    
         
            +
            # == Usage
         
     | 
| 
      
 7 
     | 
    
         
            +
            # 
         
     | 
| 
      
 8 
     | 
    
         
            +
            #   bake_flame_channel TW_015_v03.timewarp
         
     | 
| 
      
 9 
     | 
    
         
            +
            #   
         
     | 
| 
      
 10 
     | 
    
         
            +
            # == Author
         
     | 
| 
      
 11 
     | 
    
         
            +
            #   Julik <me@julik.nl>
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            require File.expand_path(File.dirname(__FILE__)) + '/../lib/flame_channel_parser' unless defined?(FlameChannelParser)
         
     | 
| 
       3 
14 
     | 
    
         
             
            require 'optparse'
         
     | 
| 
      
 15 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 16 
     | 
    
         
            +
            require "update_hints"
         
     | 
| 
       4 
17 
     | 
    
         | 
| 
       5 
     | 
    
         
            -
            options = {}
         
     | 
| 
      
 18 
     | 
    
         
            +
            options = {:destination => $stdout}
         
     | 
| 
       6 
19 
     | 
    
         | 
| 
       7 
20 
     | 
    
         
             
            op = OptionParser.new
         
     | 
| 
       8 
21 
     | 
    
         
             
            op.banner = "Usage: bake_flame_channel --channel Timing/Timing -e 123 /usr/discreet/projects/Luxury/timewarp/shot2_tw.timewarp > /mnt/3d/curves/shot2_tw.framecurve.txt\n" +
         
     | 
| 
         @@ -23,9 +36,17 @@ op.on(" -f", "--to-file FILENAME",  String, 
     | 
|
| 
       23 
36 
     | 
    
         | 
| 
       24 
37 
     | 
    
         
             
            op.parse!
         
     | 
| 
       25 
38 
     | 
    
         
             
            setup_path = ARGV.shift
         
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
      
 39 
     | 
    
         
            +
            unless setup_path
         
     | 
| 
      
 40 
     | 
    
         
            +
              $stderr.puts "No input file path provided. Please see bake_flame_channel --help for usage information." 
         
     | 
| 
      
 41 
     | 
    
         
            +
              exit -1
         
     | 
| 
      
 42 
     | 
    
         
            +
            end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            unless File.exist?(setup_path)
         
     | 
| 
      
 45 
     | 
    
         
            +
              $stderr.puts "File does not exist." 
         
     | 
| 
      
 46 
     | 
    
         
            +
              exit -1
         
     | 
| 
      
 47 
     | 
    
         
            +
            end
         
     | 
| 
       27 
48 
     | 
    
         | 
| 
       28 
     | 
    
         
            -
            FlameChannelParser::Extractor. 
     | 
| 
      
 49 
     | 
    
         
            +
            FlameChannelParser::Extractor.extract(setup_path, options)
         
     | 
| 
       29 
50 
     | 
    
         
             
            options[:destination].close if options[:destination].respond_to?(:close)
         
     | 
| 
       30 
51 
     | 
    
         | 
| 
       31 
     | 
    
         
            -
            UpdateHints.version_check("flame_channel_parser", FlameChannelParser::VERSION)
         
     | 
| 
      
 52 
     | 
    
         
            +
            UpdateHints.version_check("flame_channel_parser", FlameChannelParser::VERSION, $stderr)
         
     | 
    
        data/lib/channel.rb
    ADDED
    
    | 
         @@ -0,0 +1,36 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "forwardable"
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module FlameChannelParser
         
     | 
| 
      
 4 
     | 
    
         
            +
              # Represents a channel parsed from the Flame setup. Contains
         
     | 
| 
      
 5 
     | 
    
         
            +
              # the channel metadata and keyframes (Key objects).
         
     | 
| 
      
 6 
     | 
    
         
            +
              # Supports the following standard Array methods:
         
     | 
| 
      
 7 
     | 
    
         
            +
              # :empty?, :size, :each, :[], :push
         
     | 
| 
      
 8 
     | 
    
         
            +
              class Channel
         
     | 
| 
      
 9 
     | 
    
         
            +
                include Enumerable
         
     | 
| 
      
 10 
     | 
    
         
            +
                extend Forwardable
         
     | 
| 
      
 11 
     | 
    
         
            +
                
         
     | 
| 
      
 12 
     | 
    
         
            +
                attr_reader :node_type, :node_name
         
     | 
| 
      
 13 
     | 
    
         
            +
                attr_accessor :base_value, :name, :extrapolation
         
     | 
| 
      
 14 
     | 
    
         
            +
                
         
     | 
| 
      
 15 
     | 
    
         
            +
                def_delegators :@keys, :empty?, :length, :each, :[], :push, :<<
         
     | 
| 
      
 16 
     | 
    
         
            +
                
         
     | 
| 
      
 17 
     | 
    
         
            +
                def initialize(channel_name, node_type, node_name)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  @keys = []
         
     | 
| 
      
 19 
     | 
    
         
            +
                  @node_type, @node_name, @name = node_type, node_name, channel_name.strip
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
                
         
     | 
| 
      
 22 
     | 
    
         
            +
                # Returns path to the channel (like axis1/position/x)
         
     | 
| 
      
 23 
     | 
    
         
            +
                def path
         
     | 
| 
      
 24 
     | 
    
         
            +
                  [@node_name, name].compact.join("/")
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
                
         
     | 
| 
      
 27 
     | 
    
         
            +
                # Get an Interpolator for this channel
         
     | 
| 
      
 28 
     | 
    
         
            +
                def to_interpolator
         
     | 
| 
      
 29 
     | 
    
         
            +
                  FlameChannelParser::Interpolator.new(self)
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
                
         
     | 
| 
      
 32 
     | 
    
         
            +
                def inspect
         
     | 
| 
      
 33 
     | 
    
         
            +
                  "<Channel (%s %s) with %d keys>" % [@node_type, path, @keys.size]
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
              end
         
     | 
| 
      
 36 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/extractor.rb
    CHANGED
    
    | 
         @@ -1,4 +1,4 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # Extracts and bakes a specific animation channel
         
     | 
| 
      
 1 
     | 
    
         
            +
            # Extracts and bakes a specific animation channel to a given buffer, one string per frame
         
     | 
| 
       2 
2 
     | 
    
         
             
            class FlameChannelParser::Extractor
         
     | 
| 
       3 
3 
     | 
    
         | 
| 
       4 
4 
     | 
    
         
             
              DEFAULT_CHANNEL_TO_EXTRACT = "Timing/Timing"
         
     | 
| 
         @@ -20,6 +20,12 @@ class FlameChannelParser::Extractor 
     | 
|
| 
       20 
20 
     | 
    
         
             
              #  :start_frame - From which frame the curve should be baked. Will default to the first keyframe of the curve
         
     | 
| 
       21 
21 
     | 
    
         
             
              #  :end_frame - Upto which frame to bake. Will default to the last keyframe of the curve
         
     | 
| 
       22 
22 
     | 
    
         
             
              #  :channel - Name of the channel to extract from the setup. Defaults to "Timing/Timing" (timewarp frame)
         
     | 
| 
      
 23 
     | 
    
         
            +
              #
         
     | 
| 
      
 24 
     | 
    
         
            +
              # Note that start_frame and end_frame will be converted to integers.
         
     | 
| 
      
 25 
     | 
    
         
            +
              # The output will look like this:
         
     | 
| 
      
 26 
     | 
    
         
            +
              #
         
     | 
| 
      
 27 
     | 
    
         
            +
              #   1  123.456
         
     | 
| 
      
 28 
     | 
    
         
            +
              #   2  124.567
         
     | 
| 
       23 
29 
     | 
    
         
             
              def self.extract(path, options = {})
         
     | 
| 
       24 
30 
     | 
    
         
             
                options = DEFAULTS.merge(options)
         
     | 
| 
       25 
31 
     | 
    
         
             
                File.open(path) do |f|
         
     | 
| 
         @@ -47,6 +53,7 @@ class FlameChannelParser::Extractor 
     | 
|
| 
       47 
53 
     | 
    
         | 
| 
       48 
54 
     | 
    
         
             
                from_frame = start_frame || interpolator.first_defined_frame
         
     | 
| 
       49 
55 
     | 
    
         
             
                to_frame =  end_frame || interpolator.last_defined_frame
         
     | 
| 
      
 56 
     | 
    
         
            +
                
         
     | 
| 
       50 
57 
     | 
    
         
             
                unless (from_frame && to_frame)
         
     | 
| 
       51 
58 
     | 
    
         
             
                  raise NoKeyframesError, "This channel probably has no animation so there is no way to automatically tell how many keyframes it has. " +
         
     | 
| 
       52 
59 
     | 
    
         
             
                    "Please set the start and end frame explicitly."
         
     | 
| 
         @@ -54,7 +61,10 @@ class FlameChannelParser::Extractor 
     | 
|
| 
       54 
61 
     | 
    
         | 
| 
       55 
62 
     | 
    
         
             
                raise EmptySegmentError, "The segment you are trying to bake is too small (it has nothing in it)" if to_frame - from_frame < 1
         
     | 
| 
       56 
63 
     | 
    
         | 
| 
       57 
     | 
    
         
            -
                 
     | 
| 
      
 64 
     | 
    
         
            +
                from_frame_i = from_frame.to_f.floor
         
     | 
| 
      
 65 
     | 
    
         
            +
                to_frame_i = to_frame.to_f.ceil
         
     | 
| 
      
 66 
     | 
    
         
            +
                
         
     | 
| 
      
 67 
     | 
    
         
            +
                (from_frame_i..to_frame_i).each do | frame |
         
     | 
| 
       58 
68 
     | 
    
         
             
                  line = "%d\t%.5f\n" % [frame, interpolator.sample_at(frame)]
         
     | 
| 
       59 
69 
     | 
    
         
             
                  to_io << line
         
     | 
| 
       60 
70 
     | 
    
         
             
                end
         
     | 
    
        data/lib/flame_channel_parser.rb
    CHANGED
    
    | 
         @@ -1,33 +1,12 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require "delegate"
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
1 
     | 
    
         
             
            module FlameChannelParser
         
     | 
| 
       4 
     | 
    
         
            -
              VERSION = ' 
     | 
| 
      
 2 
     | 
    
         
            +
              VERSION = '2.0.1'
         
     | 
| 
       5 
3 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
              # Parse a Flame setup into an array of  
     | 
| 
      
 4 
     | 
    
         
            +
              # Parse a Flame setup into an array of Channel
         
     | 
| 
       7 
5 
     | 
    
         
             
              def self.parse(io)
         
     | 
| 
       8 
     | 
    
         
            -
                 
     | 
| 
       9 
     | 
    
         
            -
                parser_class.new.parse(io)
         
     | 
| 
       10 
     | 
    
         
            -
              end
         
     | 
| 
       11 
     | 
    
         
            -
              
         
     | 
| 
       12 
     | 
    
         
            -
              private
         
     | 
| 
       13 
     | 
    
         
            -
              
         
     | 
| 
       14 
     | 
    
         
            -
              def self.detect_parser_class_from(io)
         
     | 
| 
       15 
     | 
    
         
            -
                # Scan the IO
         
     | 
| 
       16 
     | 
    
         
            -
                until io.eof?
         
     | 
| 
       17 
     | 
    
         
            -
                  str = io.gets
         
     | 
| 
       18 
     | 
    
         
            -
                  if str =~ /RHandleX/ # Flame 2012, use that parser
         
     | 
| 
       19 
     | 
    
         
            -
                    io.rewind
         
     | 
| 
       20 
     | 
    
         
            -
                    return Parser2012
         
     | 
| 
       21 
     | 
    
         
            -
                  end
         
     | 
| 
       22 
     | 
    
         
            -
                end
         
     | 
| 
       23 
     | 
    
         
            -
                
         
     | 
| 
       24 
     | 
    
         
            -
                io.rewind
         
     | 
| 
       25 
     | 
    
         
            -
                Parser2011
         
     | 
| 
      
 6 
     | 
    
         
            +
                Parser.new.parse(io)
         
     | 
| 
       26 
7 
     | 
    
         
             
              end
         
     | 
| 
       27 
8 
     | 
    
         
             
            end
         
     | 
| 
       28 
9 
     | 
    
         | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
            require File.expand_path(File.dirname(__FILE__) 
     | 
| 
       32 
     | 
    
         
            -
            require File.expand_path(File.dirname(__FILE__)) + "/interpolator"
         
     | 
| 
       33 
     | 
    
         
            -
            require File.expand_path(File.dirname(__FILE__)) + "/extractor"
         
     | 
| 
      
 10 
     | 
    
         
            +
            %w(
         
     | 
| 
      
 11 
     | 
    
         
            +
              key channel parser segments interpolator extractor
         
     | 
| 
      
 12 
     | 
    
         
            +
            ).each {|f| require File.expand_path(File.dirname(__FILE__) + "/" + f ) }
         
     | 
    
        data/lib/interpolator.rb
    CHANGED
    
    | 
         @@ -5,7 +5,7 @@ require File.expand_path(File.dirname(__FILE__)) + "/segments" 
     | 
|
| 
       5 
5 
     | 
    
         
             
            # frames.
         
     | 
| 
       6 
6 
     | 
    
         
             
            #
         
     | 
| 
       7 
7 
     | 
    
         
             
            #   i = Interpolator.new(parsed_channel)
         
     | 
| 
       8 
     | 
    
         
            -
            #   i.value_at(245.5) # => will interpolate and return the value
         
     | 
| 
      
 8 
     | 
    
         
            +
            #   i.value_at(245.5) # => will interpolate and return the value at frame 245.5
         
     | 
| 
       9 
9 
     | 
    
         
             
            class FlameChannelParser::Interpolator
         
     | 
| 
       10 
10 
     | 
    
         
             
              include FlameChannelParser::Segments
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
         @@ -19,20 +19,10 @@ class FlameChannelParser::Interpolator 
     | 
|
| 
       19 
19 
     | 
    
         
             
                @extrap = channel.extrapolation
         
     | 
| 
       20 
20 
     | 
    
         | 
| 
       21 
21 
     | 
    
         
             
                # Edge case - channel has no anim at all
         
     | 
| 
       22 
     | 
    
         
            -
                if channel.length.zero?
         
     | 
| 
       23 
     | 
    
         
            -
                   
     | 
| 
      
 22 
     | 
    
         
            +
                @segments = if channel.length.zero?
         
     | 
| 
      
 23 
     | 
    
         
            +
                  [ConstantFunction.new(channel.base_value)]
         
     | 
| 
       24 
24 
     | 
    
         
             
                else
         
     | 
| 
       25 
     | 
    
         
            -
                  
         
     | 
| 
       26 
     | 
    
         
            -
                  # First the prepolating segment
         
     | 
| 
       27 
     | 
    
         
            -
                  @segments << pick_prepolation(channel.extrapolation, channel[0], channel[1])
         
     | 
| 
       28 
     | 
    
         
            -
                  
         
     | 
| 
       29 
     | 
    
         
            -
                  # Then all the intermediate segments, one segment between each pair of keys
         
     | 
| 
       30 
     | 
    
         
            -
                  channel[0..-2].each_with_index do | key, index |
         
     | 
| 
       31 
     | 
    
         
            -
                    @segments << key_pair_to_segment(key, channel[index + 1])
         
     | 
| 
       32 
     | 
    
         
            -
                  end
         
     | 
| 
       33 
     | 
    
         
            -
                  
         
     | 
| 
       34 
     | 
    
         
            -
                  # so we just output it separately
         
     | 
| 
       35 
     | 
    
         
            -
                  @segments << pick_extrapolation(channel.extrapolation, channel[-2], channel[-1])
         
     | 
| 
      
 25 
     | 
    
         
            +
                  create_segments_from_channel(channel)
         
     | 
| 
       36 
26 
     | 
    
         
             
                end
         
     | 
| 
       37 
27 
     | 
    
         
             
              end
         
     | 
| 
       38 
28 
     | 
    
         | 
| 
         @@ -65,24 +55,37 @@ class FlameChannelParser::Interpolator 
     | 
|
| 
       65 
55 
     | 
    
         | 
| 
       66 
56 
     | 
    
         
             
              private
         
     | 
| 
       67 
57 
     | 
    
         | 
| 
      
 58 
     | 
    
         
            +
              def create_segments_from_channel(channel)
         
     | 
| 
      
 59 
     | 
    
         
            +
                # First the prepolating segment
         
     | 
| 
      
 60 
     | 
    
         
            +
                segments = [pick_prepolation(channel.extrapolation, channel[0], channel[1])]
         
     | 
| 
      
 61 
     | 
    
         
            +
                
         
     | 
| 
      
 62 
     | 
    
         
            +
                # Then all the intermediate segments, one segment between each pair of keys
         
     | 
| 
      
 63 
     | 
    
         
            +
                channel[0..-2].each_with_index do | key, index |
         
     | 
| 
      
 64 
     | 
    
         
            +
                  segments << key_pair_to_segment(key, channel[index + 1])
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
                
         
     | 
| 
      
 67 
     | 
    
         
            +
                # and the extrapolator
         
     | 
| 
      
 68 
     | 
    
         
            +
                segments << pick_extrapolation(channel.extrapolation, channel[-2], channel[-1])
         
     | 
| 
      
 69 
     | 
    
         
            +
              end
         
     | 
| 
      
 70 
     | 
    
         
            +
              
         
     | 
| 
       68 
71 
     | 
    
         
             
              def frame_number_in_revcycle(frame)
         
     | 
| 
       69 
72 
     | 
    
         
             
                animated_across = (last_defined_frame - first_defined_frame)
         
     | 
| 
       70 
     | 
    
         
            -
                 
     | 
| 
       71 
     | 
    
         
            -
                 
     | 
| 
       72 
     | 
    
         
            -
                
         
     | 
| 
       73 
     | 
    
         
            -
                 
     | 
| 
       74 
     | 
    
         
            -
                if ( 
     | 
| 
       75 
     | 
    
         
            -
                  first_defined_frame +  
     | 
| 
      
 73 
     | 
    
         
            +
                # Absolute offset from the first keyframe of the animated segment
         
     | 
| 
      
 74 
     | 
    
         
            +
                offset = (frame - first_defined_frame).abs
         
     | 
| 
      
 75 
     | 
    
         
            +
                absolute_unit = offset % animated_across
         
     | 
| 
      
 76 
     | 
    
         
            +
                cycles = (offset / animated_across).floor
         
     | 
| 
      
 77 
     | 
    
         
            +
                if (cycles % 2).zero?
         
     | 
| 
      
 78 
     | 
    
         
            +
                  first_defined_frame + absolute_unit
         
     | 
| 
       76 
79 
     | 
    
         
             
                else
         
     | 
| 
       77 
     | 
    
         
            -
                  last_defined_frame -  
     | 
| 
      
 80 
     | 
    
         
            +
                  last_defined_frame - absolute_unit
         
     | 
| 
       78 
81 
     | 
    
         
             
                end
         
     | 
| 
       79 
82 
     | 
    
         
             
              end
         
     | 
| 
       80 
83 
     | 
    
         | 
| 
       81 
84 
     | 
    
         
             
              def frame_number_in_cycle(frame)
         
     | 
| 
       82 
85 
     | 
    
         
             
                animated_across = (last_defined_frame - first_defined_frame)
         
     | 
| 
       83 
     | 
    
         
            -
                 
     | 
| 
       84 
     | 
    
         
            -
                 
     | 
| 
       85 
     | 
    
         
            -
                first_defined_frame +  
     | 
| 
      
 86 
     | 
    
         
            +
                offset = (frame - first_defined_frame)
         
     | 
| 
      
 87 
     | 
    
         
            +
                modulo = (offset % animated_across)
         
     | 
| 
      
 88 
     | 
    
         
            +
                first_defined_frame + modulo
         
     | 
| 
       86 
89 
     | 
    
         
             
              end
         
     | 
| 
       87 
90 
     | 
    
         | 
| 
       88 
91 
     | 
    
         
             
              def sample_from_segments(at_frame)
         
     | 
    
        data/lib/key.rb
    ADDED
    
    | 
         @@ -0,0 +1,76 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Represents a keyframe
         
     | 
| 
      
 2 
     | 
    
         
            +
            class FlameChannelParser::Key
         
     | 
| 
      
 3 
     | 
    
         
            +
              
         
     | 
| 
      
 4 
     | 
    
         
            +
              # Frame on which the keyframe is set
         
     | 
| 
      
 5 
     | 
    
         
            +
              attr_accessor :frame
         
     | 
| 
      
 6 
     | 
    
         
            +
              
         
     | 
| 
      
 7 
     | 
    
         
            +
              # Value at this keyframe
         
     | 
| 
      
 8 
     | 
    
         
            +
              attr_accessor :value
         
     | 
| 
      
 9 
     | 
    
         
            +
              
         
     | 
| 
      
 10 
     | 
    
         
            +
              # Inteprolation type from this key onwards
         
     | 
| 
      
 11 
     | 
    
         
            +
              attr_accessor :interpolation
         
     | 
| 
      
 12 
     | 
    
         
            +
              
         
     | 
| 
      
 13 
     | 
    
         
            +
              # Curve order (relevant for 2012 only)
         
     | 
| 
      
 14 
     | 
    
         
            +
              attr_accessor :curve_order, :curve_mode
         
     | 
| 
      
 15 
     | 
    
         
            +
              
         
     | 
| 
      
 16 
     | 
    
         
            +
              # Left and right slope (will return raw slope values for pre-2012, and computed ones for 2012)
         
     | 
| 
      
 17 
     | 
    
         
            +
              attr_accessor :left_slope, :right_slope
         
     | 
| 
      
 18 
     | 
    
         
            +
              
         
     | 
| 
      
 19 
     | 
    
         
            +
              # Whether the tangents are broken at this keyframe
         
     | 
| 
      
 20 
     | 
    
         
            +
              attr_accessor :break_slope
         
     | 
| 
      
 21 
     | 
    
         
            +
              
         
     | 
| 
      
 22 
     | 
    
         
            +
              # Coordinates of the handles for 2012 setups
         
     | 
| 
      
 23 
     | 
    
         
            +
              attr_accessor :l_handle_x, :l_handle_y, :r_handle_x, :r_handle_y
         
     | 
| 
      
 24 
     | 
    
         
            +
              
         
     | 
| 
      
 25 
     | 
    
         
            +
              # Default value is 0.f
         
     | 
| 
      
 26 
     | 
    
         
            +
              def value
         
     | 
| 
      
 27 
     | 
    
         
            +
                @value.to_f
         
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
              # Default frame is 1.0f
         
     | 
| 
      
 31 
     | 
    
         
            +
              def frame
         
     | 
| 
      
 32 
     | 
    
         
            +
                (@frame || 1).to_f
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
              
         
     | 
| 
      
 35 
     | 
    
         
            +
              # Returns the RightSlope parameter of the keyframe which we use for interpolations
         
     | 
| 
      
 36 
     | 
    
         
            +
              def left_slope
         
     | 
| 
      
 37 
     | 
    
         
            +
                return right_slope unless break_slope
         
     | 
| 
      
 38 
     | 
    
         
            +
                
         
     | 
| 
      
 39 
     | 
    
         
            +
                if has_2012_tangents? # 2012 setups do not have slopes but have tangents
         
     | 
| 
      
 40 
     | 
    
         
            +
                  dy = @value - @l_handle_y
         
     | 
| 
      
 41 
     | 
    
         
            +
                  dx = @l_handle_x.to_f - @frame
         
     | 
| 
      
 42 
     | 
    
         
            +
                  (dy / dx  * -1)
         
     | 
| 
      
 43 
     | 
    
         
            +
                else
         
     | 
| 
      
 44 
     | 
    
         
            +
                  @left_slope.to_f
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
              end
         
     | 
| 
      
 47 
     | 
    
         
            +
              
         
     | 
| 
      
 48 
     | 
    
         
            +
              # Returns the LeftSlope parameter of the keyframe which we use for interpolations
         
     | 
| 
      
 49 
     | 
    
         
            +
              def right_slope
         
     | 
| 
      
 50 
     | 
    
         
            +
                if has_2012_tangents?
         
     | 
| 
      
 51 
     | 
    
         
            +
                  dy = @value - @r_handle_y
         
     | 
| 
      
 52 
     | 
    
         
            +
                  dx = @frame.to_f - @r_handle_x
         
     | 
| 
      
 53 
     | 
    
         
            +
                  dy / dx
         
     | 
| 
      
 54 
     | 
    
         
            +
                else
         
     | 
| 
      
 55 
     | 
    
         
            +
                  (@right_slope || nil).to_f 
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
              end
         
     | 
| 
      
 58 
     | 
    
         
            +
              
         
     | 
| 
      
 59 
     | 
    
         
            +
              # Tells if this keyframe has 2012 tangents in it
         
     | 
| 
      
 60 
     | 
    
         
            +
              def has_2012_tangents?
         
     | 
| 
      
 61 
     | 
    
         
            +
                @has_tangents ||= !!(l_handle_x && l_handle_y)
         
     | 
| 
      
 62 
     | 
    
         
            +
              end
         
     | 
| 
      
 63 
     | 
    
         
            +
              
         
     | 
| 
      
 64 
     | 
    
         
            +
              # Adapter for old interpolation
         
     | 
| 
      
 65 
     | 
    
         
            +
              def interpolation
         
     | 
| 
      
 66 
     | 
    
         
            +
                # Just return the interpolation type for pre-2012 setups
         
     | 
| 
      
 67 
     | 
    
         
            +
                return (@interpolation || :constant) unless has_2012_tangents?
         
     | 
| 
      
 68 
     | 
    
         
            +
                
         
     | 
| 
      
 69 
     | 
    
         
            +
                return :constant if curve_order.to_s == "constant"
         
     | 
| 
      
 70 
     | 
    
         
            +
                return :hermite if curve_order.to_s == "cubic" && (curve_mode.to_s == "hermite" || curve_mode.to_s == "natural")
         
     | 
| 
      
 71 
     | 
    
         
            +
                return :bezier if curve_order.to_s == "cubic" && curve_mode.to_s == "bezier"
         
     | 
| 
      
 72 
     | 
    
         
            +
                return :linear if curve_order.to_s == "linear"
         
     | 
| 
      
 73 
     | 
    
         
            +
                
         
     | 
| 
      
 74 
     | 
    
         
            +
                raise "Cannot determine interpolation for #{inspect}"
         
     | 
| 
      
 75 
     | 
    
         
            +
              end
         
     | 
| 
      
 76 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/parser.rb
    ADDED
    
    | 
         @@ -0,0 +1,115 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "forwardable"
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            # Basic parser used for setups from versions up to 2011
         
     | 
| 
      
 4 
     | 
    
         
            +
            module FlameChannelParser
         
     | 
| 
      
 5 
     | 
    
         
            +
              class Parser
         
     | 
| 
      
 6 
     | 
    
         
            +
                # Parses the setup passed in the IO
         
     | 
| 
      
 7 
     | 
    
         
            +
                def parse(io)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  channels = []
         
     | 
| 
      
 9 
     | 
    
         
            +
                  node_name, node_type = nil, nil
         
     | 
| 
      
 10 
     | 
    
         
            +
                  
         
     | 
| 
      
 11 
     | 
    
         
            +
                  until io.eof?
         
     | 
| 
      
 12 
     | 
    
         
            +
                    line = io.gets
         
     | 
| 
      
 13 
     | 
    
         
            +
                    if line =~ NODE_TYPE_MATCHER
         
     | 
| 
      
 14 
     | 
    
         
            +
                      node_type = $1
         
     | 
| 
      
 15 
     | 
    
         
            +
                    elsif line =~ NODE_NAME_MATCHER
         
     | 
| 
      
 16 
     | 
    
         
            +
                      node_name = $1
         
     | 
| 
      
 17 
     | 
    
         
            +
                    elsif line =~ CHANNEL_MATCHER && channel_is_useful?($1)
         
     | 
| 
      
 18 
     | 
    
         
            +
                      channels << parse_channel(io, $1, node_type, node_name)
         
     | 
| 
      
 19 
     | 
    
         
            +
                    end
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
                  
         
     | 
| 
      
 22 
     | 
    
         
            +
                  channels
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
              
         
     | 
| 
      
 25 
     | 
    
         
            +
                # Override this method to skip some channels, this will speedup
         
     | 
| 
      
 26 
     | 
    
         
            +
                # your code alot
         
     | 
| 
      
 27 
     | 
    
         
            +
                def channel_is_useful?(channel_name)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  true
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
                
         
     | 
| 
      
 31 
     | 
    
         
            +
                # Defines a number of regular expression matchers applied to the file as it is being parsed
         
     | 
| 
      
 32 
     | 
    
         
            +
                def key_matchers #:nodoc:
         
     | 
| 
      
 33 
     | 
    
         
            +
                  [
         
     | 
| 
      
 34 
     | 
    
         
            +
                    # Previously:
         
     | 
| 
      
 35 
     | 
    
         
            +
                    
         
     | 
| 
      
 36 
     | 
    
         
            +
                    [:frame, :to_f,  /Frame ([\-\d\.]+)/],
         
     | 
| 
      
 37 
     | 
    
         
            +
                    [:value, :to_f,  /Value ([\-\d\.]+)/],
         
     | 
| 
      
 38 
     | 
    
         
            +
                    [:left_slope, :to_f, /LeftSlope ([\-\d\.]+)/],
         
     | 
| 
      
 39 
     | 
    
         
            +
                    [:right_slope, :to_f, /RightSlope ([\-\d\.]+)/],
         
     | 
| 
      
 40 
     | 
    
         
            +
                    [:interpolation, :to_s, /Interpolation (\w+)/],
         
     | 
| 
      
 41 
     | 
    
         
            +
                    [:break_slope, :to_s, /BreakSlope (\w+)/],
         
     | 
| 
      
 42 
     | 
    
         
            +
                    
         
     | 
| 
      
 43 
     | 
    
         
            +
                    # 2012 intoroduces:
         
     | 
| 
      
 44 
     | 
    
         
            +
                    
         
     | 
| 
      
 45 
     | 
    
         
            +
                    [:r_handle_x, :to_f, /RHandleX ([\-\d\.]+)/],
         
     | 
| 
      
 46 
     | 
    
         
            +
                    [:l_handle_x, :to_f, /LHandleX ([\-\d\.]+)/],
         
     | 
| 
      
 47 
     | 
    
         
            +
                    [:r_handle_y, :to_f, /RHandleY ([\-\d\.]+)/],
         
     | 
| 
      
 48 
     | 
    
         
            +
                    [:l_handle_y, :to_f, /LHandleY ([\-\d\.]+)/],
         
     | 
| 
      
 49 
     | 
    
         
            +
                    [:curve_mode, :to_s,  /CurveMode (\w+)/],
         
     | 
| 
      
 50 
     | 
    
         
            +
                    [:curve_order, :to_s,  /CurveOrder (\w+)/],
         
     | 
| 
      
 51 
     | 
    
         
            +
                  ]
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
                base_value_matcher = /Value ([\-\d\.]+)/
         
     | 
| 
      
 54 
     | 
    
         
            +
                keyframe_count_matcher = /Size (\d+)/
         
     | 
| 
      
 55 
     | 
    
         
            +
                
         
     | 
| 
      
 56 
     | 
    
         
            +
                BASE_VALUE_MATCHER = /Value ([\-\d\.]+)/
         
     | 
| 
      
 57 
     | 
    
         
            +
                KF_COUNT_MATCHER = /Size (\d+)/
         
     | 
| 
      
 58 
     | 
    
         
            +
                EXTRAP_MATCHER = /Extrapolation (\w+)/
         
     | 
| 
      
 59 
     | 
    
         
            +
                CHANNEL_MATCHER = /Channel (.+)\n/
         
     | 
| 
      
 60 
     | 
    
         
            +
                NODE_TYPE_MATCHER = /Node (\w+)/
         
     | 
| 
      
 61 
     | 
    
         
            +
                NODE_NAME_MATCHER = /Name (\w+)/
         
     | 
| 
      
 62 
     | 
    
         
            +
                LITERALS = %w( linear constant natural hermite cubic bezier cycle revcycle )
         
     | 
| 
      
 63 
     | 
    
         
            +
                
         
     | 
| 
      
 64 
     | 
    
         
            +
                def parse_channel(io, channel_name, node_type, node_name)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  c = Channel.new(channel_name, node_type, node_name)
         
     | 
| 
      
 66 
     | 
    
         
            +
                  
         
     | 
| 
      
 67 
     | 
    
         
            +
                  indent, end_mark = nil, "ENDMARK"
         
     | 
| 
      
 68 
     | 
    
         
            +
                  
         
     | 
| 
      
 69 
     | 
    
         
            +
                  while line = io.gets
         
     | 
| 
      
 70 
     | 
    
         
            +
                  
         
     | 
| 
      
 71 
     | 
    
         
            +
                    unless indent 
         
     | 
| 
      
 72 
     | 
    
         
            +
                      indent = line.scan(/^(\s+)/)[1]
         
     | 
| 
      
 73 
     | 
    
         
            +
                      end_mark = "#{indent}End"
         
     | 
| 
      
 74 
     | 
    
         
            +
                    end
         
     | 
| 
      
 75 
     | 
    
         
            +
                  
         
     | 
| 
      
 76 
     | 
    
         
            +
                    if line =~ KF_COUNT_MATCHER
         
     | 
| 
      
 77 
     | 
    
         
            +
                      $1.to_i.times { c.push(extract_key_from(io)) }
         
     | 
| 
      
 78 
     | 
    
         
            +
                    elsif line =~ BASE_VALUE_MATCHER# && empty?
         
     | 
| 
      
 79 
     | 
    
         
            +
                      c.base_value = $1.to_f
         
     | 
| 
      
 80 
     | 
    
         
            +
                    elsif line =~ EXTRAP_MATCHER
         
     | 
| 
      
 81 
     | 
    
         
            +
                      c.extrapolation = symbolize_literal($1)
         
     | 
| 
      
 82 
     | 
    
         
            +
                    elsif line.strip == end_mark
         
     | 
| 
      
 83 
     | 
    
         
            +
                      break
         
     | 
| 
      
 84 
     | 
    
         
            +
                    end
         
     | 
| 
      
 85 
     | 
    
         
            +
                  end
         
     | 
| 
      
 86 
     | 
    
         
            +
                  
         
     | 
| 
      
 87 
     | 
    
         
            +
                  return c
         
     | 
| 
      
 88 
     | 
    
         
            +
                end
         
     | 
| 
      
 89 
     | 
    
         
            +
                
         
     | 
| 
      
 90 
     | 
    
         
            +
                def extract_key_from(io)
         
     | 
| 
      
 91 
     | 
    
         
            +
                  frame = nil
         
     | 
| 
      
 92 
     | 
    
         
            +
                  end_matcher = /End/
         
     | 
| 
      
 93 
     | 
    
         
            +
                  key = Key.new
         
     | 
| 
      
 94 
     | 
    
         
            +
                  
         
     | 
| 
      
 95 
     | 
    
         
            +
                  until io.eof?
         
     | 
| 
      
 96 
     | 
    
         
            +
                    line = io.gets
         
     | 
| 
      
 97 
     | 
    
         
            +
                    if line =~ end_matcher
         
     | 
| 
      
 98 
     | 
    
         
            +
                      return key
         
     | 
| 
      
 99 
     | 
    
         
            +
                    else
         
     | 
| 
      
 100 
     | 
    
         
            +
                      key_matchers.each do | property, cast_method, pattern  |
         
     | 
| 
      
 101 
     | 
    
         
            +
                          if line =~ pattern
         
     | 
| 
      
 102 
     | 
    
         
            +
                            v = symbolize_literal($1.send(cast_method))
         
     | 
| 
      
 103 
     | 
    
         
            +
                            key.send("#{property}=", v) 
         
     | 
| 
      
 104 
     | 
    
         
            +
                          end
         
     | 
| 
      
 105 
     | 
    
         
            +
                      end
         
     | 
| 
      
 106 
     | 
    
         
            +
                    end
         
     | 
| 
      
 107 
     | 
    
         
            +
                  end
         
     | 
| 
      
 108 
     | 
    
         
            +
                  raise "Did not detect any keyframes!"
         
     | 
| 
      
 109 
     | 
    
         
            +
                end
         
     | 
| 
      
 110 
     | 
    
         
            +
                
         
     | 
| 
      
 111 
     | 
    
         
            +
                def symbolize_literal(v)
         
     | 
| 
      
 112 
     | 
    
         
            +
                  LITERALS.include?(v) ? v.to_sym : v
         
     | 
| 
      
 113 
     | 
    
         
            +
                end
         
     | 
| 
      
 114 
     | 
    
         
            +
              end
         
     | 
| 
      
 115 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,22 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "test/unit"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require File.dirname(__FILE__) + "/../lib/flame_channel_parser"
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            D = 0.001
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            class TestChannel < Test::Unit::TestCase
         
     | 
| 
      
 7 
     | 
    
         
            +
              def test_responds_to_array_methods
         
     | 
| 
      
 8 
     | 
    
         
            +
                c = FlameChannelParser::Channel.new("b/c", "d", "f")
         
     | 
| 
      
 9 
     | 
    
         
            +
                [:empty?, :length, :each, :[], :push, :<<].each {|m| assert c.respond_to?(m) }
         
     | 
| 
      
 10 
     | 
    
         
            +
              end
         
     | 
| 
      
 11 
     | 
    
         
            +
              
         
     | 
| 
      
 12 
     | 
    
         
            +
              def test_path_for_present_nodename
         
     | 
| 
      
 13 
     | 
    
         
            +
                c = FlameChannelParser::Channel.new("position/x", "Axis", "axis1")
         
     | 
| 
      
 14 
     | 
    
         
            +
                assert_equal "axis1/position/x", c.path
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
              
         
     | 
| 
      
 17 
     | 
    
         
            +
              def test_path_for_absent
         
     | 
| 
      
 18 
     | 
    
         
            +
                c = FlameChannelParser::Channel.new("Frame/Frame", nil, nil)
         
     | 
| 
      
 19 
     | 
    
         
            +
                assert_equal "Frame/Frame", c.path
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
              
         
     | 
| 
      
 22 
     | 
    
         
            +
            end
         
     | 
    
        data/test/test_cli.rb
    ADDED
    
    | 
         @@ -0,0 +1,59 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "test/unit"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require "stringio"
         
     | 
| 
      
 3 
     | 
    
         
            +
            require "tempfile"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            require File.dirname(__FILE__) + "/../lib/flame_channel_parser"
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            class CliTest < Test::Unit::TestCase
         
     | 
| 
      
 8 
     | 
    
         
            +
              BIN_P = File.expand_path(File.dirname(__FILE__) + "/../bin/bake_flame_channel")
         
     | 
| 
      
 9 
     | 
    
         
            +
              
         
     | 
| 
      
 10 
     | 
    
         
            +
              # Run the binary under test with passed options, and return [exit_code, stdout_content, stderr_content]
         
     | 
| 
      
 11 
     | 
    
         
            +
              def cli(commandline_arguments)
         
     | 
| 
      
 12 
     | 
    
         
            +
                old_stdout, old_stderr, old_argv = $stdout, $stderr, ARGV.dup
         
     | 
| 
      
 13 
     | 
    
         
            +
                os, es = StringIO.new, StringIO.new
         
     | 
| 
      
 14 
     | 
    
         
            +
                begin
         
     | 
| 
      
 15 
     | 
    
         
            +
                  $stdout, $stderr, verbosity = os, es, $VERBOSE
         
     | 
| 
      
 16 
     | 
    
         
            +
                  ARGV.replace(commandline_arguments.split)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  $VERBOSE = false
         
     | 
| 
      
 18 
     | 
    
         
            +
                  load(BIN_P)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  return [0, os.string, es.string]
         
     | 
| 
      
 20 
     | 
    
         
            +
                rescue SystemExit => boom # The binary uses exit(), we use that to preserve the output code
         
     | 
| 
      
 21 
     | 
    
         
            +
                  return [boom.status, os.string, es.string]
         
     | 
| 
      
 22 
     | 
    
         
            +
                ensure
         
     | 
| 
      
 23 
     | 
    
         
            +
                  $VERBOSE = verbosity
         
     | 
| 
      
 24 
     | 
    
         
            +
                  ARGV.replace(old_argv)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  $stdout, $stderr = old_stdout, old_stderr
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
              
         
     | 
| 
      
 29 
     | 
    
         
            +
              def test_cli_with_no_args_produces_usage
         
     | 
| 
      
 30 
     | 
    
         
            +
                status, o, e = cli('')
         
     | 
| 
      
 31 
     | 
    
         
            +
                assert_equal -1, status
         
     | 
| 
      
 32 
     | 
    
         
            +
                assert_match /No input file path provided/, e
         
     | 
| 
      
 33 
     | 
    
         
            +
                assert_match /--help for usage information/, e
         
     | 
| 
      
 34 
     | 
    
         
            +
              end
         
     | 
| 
      
 35 
     | 
    
         
            +
              
         
     | 
| 
      
 36 
     | 
    
         
            +
              def test_cli_with_nonexisting_file
         
     | 
| 
      
 37 
     | 
    
         
            +
                status, o, e = cli(" amazing.action")
         
     | 
| 
      
 38 
     | 
    
         
            +
                assert_equal -1, status
         
     | 
| 
      
 39 
     | 
    
         
            +
                assert_match /does not exist/, e
         
     | 
| 
      
 40 
     | 
    
         
            +
              end
         
     | 
| 
      
 41 
     | 
    
         
            +
              
         
     | 
| 
      
 42 
     | 
    
         
            +
              def test_cli_with_proper_output
         
     | 
| 
      
 43 
     | 
    
         
            +
                full_path = File.expand_path(File.dirname(__FILE__)) + "/snaps/TW.timewarp"
         
     | 
| 
      
 44 
     | 
    
         
            +
                status, output, e = cli(" " + full_path)
         
     | 
| 
      
 45 
     | 
    
         
            +
                assert_equal 0, status
         
     | 
| 
      
 46 
     | 
    
         
            +
                assert_equal 816, output.split("\n").length, "Should have output 816 frames"
         
     | 
| 
      
 47 
     | 
    
         
            +
              end
         
     | 
| 
      
 48 
     | 
    
         
            +
              
         
     | 
| 
      
 49 
     | 
    
         
            +
              def test_cli_with_output_to_file
         
     | 
| 
      
 50 
     | 
    
         
            +
                tf = Tempfile.new("experiment")
         
     | 
| 
      
 51 
     | 
    
         
            +
                full_path = File.expand_path(File.dirname(__FILE__)) + "/snaps/TW.timewarp"
         
     | 
| 
      
 52 
     | 
    
         
            +
                status, output, e = cli(" --to-file " + tf.path + " " + full_path)
         
     | 
| 
      
 53 
     | 
    
         
            +
              
         
     | 
| 
      
 54 
     | 
    
         
            +
                assert_equal 0, status
         
     | 
| 
      
 55 
     | 
    
         
            +
                assert_equal 816, File.read(tf.path).split("\n").length, "Should have output 816 frames"
         
     | 
| 
      
 56 
     | 
    
         
            +
              ensure
         
     | 
| 
      
 57 
     | 
    
         
            +
                tf.close!
         
     | 
| 
      
 58 
     | 
    
         
            +
              end
         
     | 
| 
      
 59 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -18,7 +18,7 @@ class TestFlameChannelParser < Test::Unit::TestCase 
     | 
|
| 
       18 
18 
     | 
    
         
             
                assert_kind_of Array, channels
         
     | 
| 
       19 
19 
     | 
    
         
             
                assert_equal 1, channels.length, "Should find one channel"
         
     | 
| 
       20 
20 
     | 
    
         | 
| 
       21 
     | 
    
         
            -
                assert_kind_of FlameChannelParser:: 
     | 
| 
      
 21 
     | 
    
         
            +
                assert_kind_of FlameChannelParser::Channel, channels[0]
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
                ch = channels[0]
         
     | 
| 
       24 
24 
     | 
    
         
             
                assert_equal 4, ch.length
         
     | 
    
        data/test/test_interpolator.rb
    CHANGED
    
    | 
         @@ -57,11 +57,11 @@ class TestInterpolator < Test::Unit::TestCase 
     | 
|
| 
       57 
57 
     | 
    
         | 
| 
       58 
58 
     | 
    
         
             
              def test_simple_setup_from_2011
         
     | 
| 
       59 
59 
     | 
    
         
             
                data = File.open(File.dirname(__FILE__) + "/snaps/FLEM_curves_example.action")
         
     | 
| 
       60 
     | 
    
         
            -
                channels_in_action = FlameChannelParser 
     | 
| 
      
 60 
     | 
    
         
            +
                channels_in_action = FlameChannelParser.parse(data)
         
     | 
| 
       61 
61 
     | 
    
         
             
                channels_in_action.reject!{|c| c.length < 4 }
         
     | 
| 
       62 
62 
     | 
    
         | 
| 
       63 
     | 
    
         
            -
                reference = channels_in_action.find{|c| c. 
     | 
| 
       64 
     | 
    
         
            -
                sampled = channels_in_action.find{|c| c. 
     | 
| 
      
 63 
     | 
    
         
            +
                reference = channels_in_action.find{|c| c.path == "axis1/position/x" }
         
     | 
| 
      
 64 
     | 
    
         
            +
                sampled = channels_in_action.find{|c| c.path == "axis1/position/y"}
         
     | 
| 
       65 
65 
     | 
    
         
             
                assert_same_interpolation(1..200, reference, sampled)
         
     | 
| 
       66 
66 
     | 
    
         
             
              end
         
     | 
| 
       67 
67 
     | 
    
         | 
| 
         @@ -121,7 +121,7 @@ class TestInterpolator < Test::Unit::TestCase 
     | 
|
| 
       121 
121 
     | 
    
         
             
                channels_in_tw = FlameChannelParser.parse(data)
         
     | 
| 
       122 
122 
     | 
    
         
             
                chan = channels_in_tw.find{|c| c.name == "Timing/Timing"}
         
     | 
| 
       123 
123 
     | 
    
         
             
                interp = chan.to_interpolator
         
     | 
| 
       124 
     | 
    
         
            -
                assert_in_delta -7, interp.sample_at(1), DELTA
         
     | 
| 
      
 124 
     | 
    
         
            +
                assert_in_delta( -7, interp.sample_at(1), DELTA)
         
     | 
| 
       125 
125 
     | 
    
         
             
                assert_in_delta 492, interp.sample_at(502), DELTA
         
     | 
| 
       126 
126 
     | 
    
         
             
                assert_in_delta 492, interp.sample_at(502), DELTA
         
     | 
| 
       127 
127 
     | 
    
         
             
                assert_in_delta 494, interp.sample_at(504), DELTA
         
     | 
| 
         @@ -159,7 +159,6 @@ class TestInterpolator < Test::Unit::TestCase 
     | 
|
| 
       159 
159 
     | 
    
         
             
                assert_in_delta 683.772, interp.sample_at(1), DELTA
         
     | 
| 
       160 
160 
     | 
    
         
             
              end
         
     | 
| 
       161 
161 
     | 
    
         | 
| 
       162 
     | 
    
         
            -
              
         
     | 
| 
       163 
162 
     | 
    
         
             
              def test_cycle_extrapolation
         
     | 
| 
       164 
163 
     | 
    
         
             
                data = File.open(File.dirname(__FILE__) + "/snaps/Cycle_and_revcycle.action")
         
     | 
| 
       165 
164 
     | 
    
         
             
                channels_in_ac = FlameChannelParser.parse(data)
         
     | 
    
        data/test/test_key.rb
    ADDED
    
    | 
         @@ -0,0 +1,86 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "test/unit"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require File.dirname(__FILE__) + "/../lib/flame_channel_parser"
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            class TestKey < Test::Unit::TestCase
         
     | 
| 
      
 5 
     | 
    
         
            +
              D = 0.001
         
     | 
| 
      
 6 
     | 
    
         
            +
              def test_default_values
         
     | 
| 
      
 7 
     | 
    
         
            +
                k = FlameChannelParser::Key.new
         
     | 
| 
      
 8 
     | 
    
         
            +
                assert_in_delta 1.0, k.frame, D
         
     | 
| 
      
 9 
     | 
    
         
            +
                assert_in_delta 0.0, k.value, D
         
     | 
| 
      
 10 
     | 
    
         
            +
                assert_equal :constant, k.interpolation
         
     | 
| 
      
 11 
     | 
    
         
            +
                assert_equal false, k.has_2012_tangents?
         
     | 
| 
      
 12 
     | 
    
         
            +
                
         
     | 
| 
      
 13 
     | 
    
         
            +
                assert_nil k.l_handle_x 
         
     | 
| 
      
 14 
     | 
    
         
            +
                assert_nil k.l_handle_y 
         
     | 
| 
      
 15 
     | 
    
         
            +
                assert_nil k.r_handle_y 
         
     | 
| 
      
 16 
     | 
    
         
            +
                assert_nil k.r_handle_x 
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
              
         
     | 
| 
      
 19 
     | 
    
         
            +
              def test_constant_curve_mode_translated_to_interpolation
         
     | 
| 
      
 20 
     | 
    
         
            +
                k = FlameChannelParser::Key.new
         
     | 
| 
      
 21 
     | 
    
         
            +
                k.curve_mode = :constant
         
     | 
| 
      
 22 
     | 
    
         
            +
                assert_equal :constant, k.interpolation
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
              def test_hermite_curve_mode_translated_to_interpolation
         
     | 
| 
      
 26 
     | 
    
         
            +
                k = FlameChannelParser::Key.new
         
     | 
| 
      
 27 
     | 
    
         
            +
                assign_tangents_to(k)
         
     | 
| 
      
 28 
     | 
    
         
            +
                
         
     | 
| 
      
 29 
     | 
    
         
            +
                k.curve_order = :cubic
         
     | 
| 
      
 30 
     | 
    
         
            +
                k.curve_mode = :hermite
         
     | 
| 
      
 31 
     | 
    
         
            +
                assert_equal :hermite, k.interpolation
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
              def test_natural_curve_mode_translated_to_interpolation
         
     | 
| 
      
 35 
     | 
    
         
            +
                k = FlameChannelParser::Key.new
         
     | 
| 
      
 36 
     | 
    
         
            +
                assign_tangents_to(k)
         
     | 
| 
      
 37 
     | 
    
         
            +
                
         
     | 
| 
      
 38 
     | 
    
         
            +
                k.curve_order = :cubic
         
     | 
| 
      
 39 
     | 
    
         
            +
                k.curve_mode = :natural
         
     | 
| 
      
 40 
     | 
    
         
            +
                assert_equal :hermite, k.interpolation
         
     | 
| 
      
 41 
     | 
    
         
            +
              end
         
     | 
| 
      
 42 
     | 
    
         
            +
              
         
     | 
| 
      
 43 
     | 
    
         
            +
              def test_bezier_curve_mode
         
     | 
| 
      
 44 
     | 
    
         
            +
                k = FlameChannelParser::Key.new
         
     | 
| 
      
 45 
     | 
    
         
            +
                assign_tangents_to(k)
         
     | 
| 
      
 46 
     | 
    
         
            +
                
         
     | 
| 
      
 47 
     | 
    
         
            +
                k.curve_order = :cubic
         
     | 
| 
      
 48 
     | 
    
         
            +
                k.curve_mode = :bezier
         
     | 
| 
      
 49 
     | 
    
         
            +
                assert_equal :bezier, k.interpolation
         
     | 
| 
      
 50 
     | 
    
         
            +
              end
         
     | 
| 
      
 51 
     | 
    
         
            +
              
         
     | 
| 
      
 52 
     | 
    
         
            +
              def test_tangent_computed_from_right_handle
         
     | 
| 
      
 53 
     | 
    
         
            +
                k = FlameChannelParser::Key.new
         
     | 
| 
      
 54 
     | 
    
         
            +
                k.frame = 123
         
     | 
| 
      
 55 
     | 
    
         
            +
                k.value = 123
         
     | 
| 
      
 56 
     | 
    
         
            +
                
         
     | 
| 
      
 57 
     | 
    
         
            +
                k.l_handle_x = 120
         
     | 
| 
      
 58 
     | 
    
         
            +
                k.l_handle_y = 110
         
     | 
| 
      
 59 
     | 
    
         
            +
                k.r_handle_x = 124
         
     | 
| 
      
 60 
     | 
    
         
            +
                k.r_handle_y = 145
         
     | 
| 
      
 61 
     | 
    
         
            +
                
         
     | 
| 
      
 62 
     | 
    
         
            +
                assert_in_delta 22, k.right_slope, D
         
     | 
| 
      
 63 
     | 
    
         
            +
                assert_in_delta 22, k.left_slope, D
         
     | 
| 
      
 64 
     | 
    
         
            +
              end
         
     | 
| 
      
 65 
     | 
    
         
            +
              
         
     | 
| 
      
 66 
     | 
    
         
            +
              def test_tangent_computed_from_right_handle_with_broken_slope
         
     | 
| 
      
 67 
     | 
    
         
            +
                k = FlameChannelParser::Key.new
         
     | 
| 
      
 68 
     | 
    
         
            +
                k.frame = 123
         
     | 
| 
      
 69 
     | 
    
         
            +
                k.value = 123
         
     | 
| 
      
 70 
     | 
    
         
            +
                k.break_slope = true
         
     | 
| 
      
 71 
     | 
    
         
            +
                
         
     | 
| 
      
 72 
     | 
    
         
            +
                k.l_handle_x = 120
         
     | 
| 
      
 73 
     | 
    
         
            +
                k.l_handle_y = 110
         
     | 
| 
      
 74 
     | 
    
         
            +
                k.r_handle_x = 124
         
     | 
| 
      
 75 
     | 
    
         
            +
                k.r_handle_y = 145
         
     | 
| 
      
 76 
     | 
    
         
            +
                
         
     | 
| 
      
 77 
     | 
    
         
            +
                assert_in_delta 22, k.right_slope, D
         
     | 
| 
      
 78 
     | 
    
         
            +
                assert_in_delta 4.333, k.left_slope, D
         
     | 
| 
      
 79 
     | 
    
         
            +
              end
         
     | 
| 
      
 80 
     | 
    
         
            +
              
         
     | 
| 
      
 81 
     | 
    
         
            +
              private
         
     | 
| 
      
 82 
     | 
    
         
            +
              
         
     | 
| 
      
 83 
     | 
    
         
            +
              def assign_tangents_to(to_key)
         
     | 
| 
      
 84 
     | 
    
         
            +
                to_key.l_handle_x = to_key.l_handle_y = to_key.r_handle_x = to_key.r_handle_y = 1
         
     | 
| 
      
 85 
     | 
    
         
            +
              end
         
     | 
| 
      
 86 
     | 
    
         
            +
            end
         
     | 
    
        data/test/test_segments.rb
    CHANGED
    
    | 
         @@ -1,11 +1,11 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require "test/unit"
         
     | 
| 
       2 
2 
     | 
    
         
             
            require File.dirname(__FILE__) + "/../lib/flame_channel_parser"
         
     | 
| 
       3 
3 
     | 
    
         | 
| 
       4 
     | 
    
         
            -
            D = 0.001
         
     | 
| 
       5 
4 
     | 
    
         | 
| 
       6 
5 
     | 
    
         
             
            include FlameChannelParser::Segments
         
     | 
| 
       7 
6 
     | 
    
         | 
| 
       8 
7 
     | 
    
         
             
            class TestConstantFunction < Test::Unit::TestCase
         
     | 
| 
      
 8 
     | 
    
         
            +
              D = 0.001
         
     | 
| 
       9 
9 
     | 
    
         
             
              def test_segment
         
     | 
| 
       10 
10 
     | 
    
         
             
                seg = ConstantFunction.new(123.4)
         
     | 
| 
       11 
11 
     | 
    
         
             
                assert seg.defines?(-1), "The segment should define this frame"
         
     | 
| 
         @@ -16,6 +16,7 @@ end 
     | 
|
| 
       16 
16 
     | 
    
         | 
| 
       17 
17 
     | 
    
         | 
| 
       18 
18 
     | 
    
         
             
            class TestConstantSegment < Test::Unit::TestCase
         
     | 
| 
      
 19 
     | 
    
         
            +
              D = 0.001
         
     | 
| 
       19 
20 
     | 
    
         
             
              def test_segment
         
     | 
| 
       20 
21 
     | 
    
         
             
                seg = ConstantSegment.new(12, 25, 2.5)
         
     | 
| 
       21 
22 
     | 
    
         | 
| 
         @@ -31,7 +32,7 @@ class TestConstantSegment < Test::Unit::TestCase 
     | 
|
| 
       31 
32 
     | 
    
         
             
            end
         
     | 
| 
       32 
33 
     | 
    
         | 
| 
       33 
34 
     | 
    
         
             
            class TestBezierSegment < Test::Unit::TestCase
         
     | 
| 
       34 
     | 
    
         
            -
              
         
     | 
| 
      
 35 
     | 
    
         
            +
              D = 0.001
         
     | 
| 
       35 
36 
     | 
    
         
             
              def test_segment
         
     | 
| 
       36 
37 
     | 
    
         
             
                seg = BezierSegment.new(
         
     | 
| 
       37 
38 
     | 
    
         
             
                  frame_from = 117,
         
     | 
| 
         @@ -54,6 +55,8 @@ class TestBezierSegment < Test::Unit::TestCase 
     | 
|
| 
       54 
55 
     | 
    
         
             
            end
         
     | 
| 
       55 
56 
     | 
    
         | 
| 
       56 
57 
     | 
    
         
             
            class TestLinearSegment < Test::Unit::TestCase
         
     | 
| 
      
 58 
     | 
    
         
            +
              D = 0.001
         
     | 
| 
      
 59 
     | 
    
         
            +
              
         
     | 
| 
       57 
60 
     | 
    
         
             
              def test_segment
         
     | 
| 
       58 
61 
     | 
    
         
             
                seg = LinearSegment.new(12, 25, 2.5, 4.5)
         
     | 
| 
       59 
62 
     | 
    
         | 
| 
         @@ -80,6 +83,8 @@ class TestConstantPrepolate < Test::Unit::TestCase 
     | 
|
| 
       80 
83 
     | 
    
         
             
            end
         
     | 
| 
       81 
84 
     | 
    
         | 
| 
       82 
85 
     | 
    
         
             
            class TestHermiteSegment < Test::Unit::TestCase
         
     | 
| 
      
 86 
     | 
    
         
            +
              D = 0.001
         
     | 
| 
      
 87 
     | 
    
         
            +
              
         
     | 
| 
       83 
88 
     | 
    
         
             
              def test_last_curve_segment
         
     | 
| 
       84 
89 
     | 
    
         
             
                refdata = %w(
         
     | 
| 
       85 
90 
     | 
    
         
             
                  258.239
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,13 +1,8 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification 
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: flame_channel_parser
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version 
         
     | 
| 
       4 
     | 
    
         
            -
              hash: 7
         
     | 
| 
       5 
4 
     | 
    
         
             
              prerelease: 
         
     | 
| 
       6 
     | 
    
         
            -
               
     | 
| 
       7 
     | 
    
         
            -
              - 1
         
     | 
| 
       8 
     | 
    
         
            -
              - 4
         
     | 
| 
       9 
     | 
    
         
            -
              - 0
         
     | 
| 
       10 
     | 
    
         
            -
              version: 1.4.0
         
     | 
| 
      
 5 
     | 
    
         
            +
              version: 2.0.1
         
     | 
| 
       11 
6 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       12 
7 
     | 
    
         
             
            authors: 
         
     | 
| 
       13 
8 
     | 
    
         
             
            - Julik Tarkhanov
         
     | 
| 
         @@ -15,8 +10,7 @@ autorequire: 
     | 
|
| 
       15 
10 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       16 
11 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       17 
12 
     | 
    
         | 
| 
       18 
     | 
    
         
            -
            date: 2011-06- 
     | 
| 
       19 
     | 
    
         
            -
            default_executable: 
         
     | 
| 
      
 13 
     | 
    
         
            +
            date: 2011-06-23 00:00:00 Z
         
     | 
| 
       20 
14 
     | 
    
         
             
            dependencies: 
         
     | 
| 
       21 
15 
     | 
    
         
             
            - !ruby/object:Gem::Dependency 
         
     | 
| 
       22 
16 
     | 
    
         
             
              name: update_hints
         
     | 
| 
         @@ -26,9 +20,6 @@ dependencies: 
     | 
|
| 
       26 
20 
     | 
    
         
             
                requirements: 
         
     | 
| 
       27 
21 
     | 
    
         
             
                - - ">="
         
     | 
| 
       28 
22 
     | 
    
         
             
                  - !ruby/object:Gem::Version 
         
     | 
| 
       29 
     | 
    
         
            -
                    hash: 3
         
     | 
| 
       30 
     | 
    
         
            -
                    segments: 
         
     | 
| 
       31 
     | 
    
         
            -
                    - 0
         
     | 
| 
       32 
23 
     | 
    
         
             
                    version: "0"
         
     | 
| 
       33 
24 
     | 
    
         
             
              type: :runtime
         
     | 
| 
       34 
25 
     | 
    
         
             
              version_requirements: *id001
         
     | 
| 
         @@ -40,12 +31,7 @@ dependencies: 
     | 
|
| 
       40 
31 
     | 
    
         
             
                requirements: 
         
     | 
| 
       41 
32 
     | 
    
         
             
                - - ">="
         
     | 
| 
       42 
33 
     | 
    
         
             
                  - !ruby/object:Gem::Version 
         
     | 
| 
       43 
     | 
    
         
            -
                     
     | 
| 
       44 
     | 
    
         
            -
                    segments: 
         
     | 
| 
       45 
     | 
    
         
            -
                    - 2
         
     | 
| 
       46 
     | 
    
         
            -
                    - 9
         
     | 
| 
       47 
     | 
    
         
            -
                    - 1
         
     | 
| 
       48 
     | 
    
         
            -
                    version: 2.9.1
         
     | 
| 
      
 34 
     | 
    
         
            +
                    version: 2.9.4
         
     | 
| 
       49 
35 
     | 
    
         
             
              type: :development
         
     | 
| 
       50 
36 
     | 
    
         
             
              version_requirements: *id002
         
     | 
| 
       51 
37 
     | 
    
         
             
            description: |-
         
     | 
| 
         @@ -68,11 +54,12 @@ files: 
     | 
|
| 
       68 
54 
     | 
    
         
             
            - README.rdoc
         
     | 
| 
       69 
55 
     | 
    
         
             
            - Rakefile
         
     | 
| 
       70 
56 
     | 
    
         
             
            - bin/bake_flame_channel
         
     | 
| 
      
 57 
     | 
    
         
            +
            - lib/channel.rb
         
     | 
| 
       71 
58 
     | 
    
         
             
            - lib/extractor.rb
         
     | 
| 
       72 
59 
     | 
    
         
             
            - lib/flame_channel_parser.rb
         
     | 
| 
       73 
60 
     | 
    
         
             
            - lib/interpolator.rb
         
     | 
| 
       74 
     | 
    
         
            -
            - lib/ 
     | 
| 
       75 
     | 
    
         
            -
            - lib/ 
     | 
| 
      
 61 
     | 
    
         
            +
            - lib/key.rb
         
     | 
| 
      
 62 
     | 
    
         
            +
            - lib/parser.rb
         
     | 
| 
       76 
63 
     | 
    
         
             
            - lib/segments.rb
         
     | 
| 
       77 
64 
     | 
    
         
             
            - test/channel_with_constants.dat
         
     | 
| 
       78 
65 
     | 
    
         
             
            - test/sample_channel.dat
         
     | 
| 
         @@ -94,12 +81,14 @@ files: 
     | 
|
| 
       94 
81 
     | 
    
         
             
            - test/snaps/TW.timewarp
         
     | 
| 
       95 
82 
     | 
    
         
             
            - test/snaps/TW_SingleFrameExtrapolated_from2011.timewarp
         
     | 
| 
       96 
83 
     | 
    
         
             
            - test/snaps/timewarp_where_interp_fails_at_end.timewarp
         
     | 
| 
      
 84 
     | 
    
         
            +
            - test/test_channel.rb
         
     | 
| 
      
 85 
     | 
    
         
            +
            - test/test_cli.rb
         
     | 
| 
       97 
86 
     | 
    
         
             
            - test/test_extractor.rb
         
     | 
| 
       98 
87 
     | 
    
         
             
            - test/test_flame_channel_parser.rb
         
     | 
| 
       99 
88 
     | 
    
         
             
            - test/test_interpolator.rb
         
     | 
| 
      
 89 
     | 
    
         
            +
            - test/test_key.rb
         
     | 
| 
       100 
90 
     | 
    
         
             
            - test/test_segments.rb
         
     | 
| 
       101 
91 
     | 
    
         
             
            - .gemtest
         
     | 
| 
       102 
     | 
    
         
            -
            has_rdoc: true
         
     | 
| 
       103 
92 
     | 
    
         
             
            homepage: http://guerilla-di.org/flame-channel-parser
         
     | 
| 
       104 
93 
     | 
    
         
             
            licenses: []
         
     | 
| 
       105 
94 
     | 
    
         | 
| 
         @@ -114,28 +103,25 @@ required_ruby_version: !ruby/object:Gem::Requirement 
     | 
|
| 
       114 
103 
     | 
    
         
             
              requirements: 
         
     | 
| 
       115 
104 
     | 
    
         
             
              - - ">="
         
     | 
| 
       116 
105 
     | 
    
         
             
                - !ruby/object:Gem::Version 
         
     | 
| 
       117 
     | 
    
         
            -
                  hash: 3
         
     | 
| 
       118 
     | 
    
         
            -
                  segments: 
         
     | 
| 
       119 
     | 
    
         
            -
                  - 0
         
     | 
| 
       120 
106 
     | 
    
         
             
                  version: "0"
         
     | 
| 
       121 
107 
     | 
    
         
             
            required_rubygems_version: !ruby/object:Gem::Requirement 
         
     | 
| 
       122 
108 
     | 
    
         
             
              none: false
         
     | 
| 
       123 
109 
     | 
    
         
             
              requirements: 
         
     | 
| 
       124 
110 
     | 
    
         
             
              - - ">="
         
     | 
| 
       125 
111 
     | 
    
         
             
                - !ruby/object:Gem::Version 
         
     | 
| 
       126 
     | 
    
         
            -
                  hash: 3
         
     | 
| 
       127 
     | 
    
         
            -
                  segments: 
         
     | 
| 
       128 
     | 
    
         
            -
                  - 0
         
     | 
| 
       129 
112 
     | 
    
         
             
                  version: "0"
         
     | 
| 
       130 
113 
     | 
    
         
             
            requirements: []
         
     | 
| 
       131 
114 
     | 
    
         | 
| 
       132 
115 
     | 
    
         
             
            rubyforge_project: flame_channel_parser
         
     | 
| 
       133 
     | 
    
         
            -
            rubygems_version: 1. 
     | 
| 
      
 116 
     | 
    
         
            +
            rubygems_version: 1.8.5
         
     | 
| 
       134 
117 
     | 
    
         
             
            signing_key: 
         
     | 
| 
       135 
118 
     | 
    
         
             
            specification_version: 3
         
     | 
| 
       136 
119 
     | 
    
         
             
            summary: Includes a small library for extracting, parsing and baking animation curves made on Discrodesk Floke/Inflinto, also known as flame
         
     | 
| 
       137 
120 
     | 
    
         
             
            test_files: 
         
     | 
| 
      
 121 
     | 
    
         
            +
            - test/test_channel.rb
         
     | 
| 
      
 122 
     | 
    
         
            +
            - test/test_cli.rb
         
     | 
| 
       138 
123 
     | 
    
         
             
            - test/test_extractor.rb
         
     | 
| 
       139 
124 
     | 
    
         
             
            - test/test_flame_channel_parser.rb
         
     | 
| 
       140 
125 
     | 
    
         
             
            - test/test_interpolator.rb
         
     | 
| 
      
 126 
     | 
    
         
            +
            - test/test_key.rb
         
     | 
| 
       141 
127 
     | 
    
         
             
            - test/test_segments.rb
         
     | 
    
        data/lib/parser_2011.rb
    DELETED
    
    | 
         @@ -1,156 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require "delegate"
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            # Basic parser used for setups from versions up to 2011
         
     | 
| 
       4 
     | 
    
         
            -
            class FlameChannelParser::Parser2011
         
     | 
| 
       5 
     | 
    
         
            -
              
         
     | 
| 
       6 
     | 
    
         
            -
              # Represents a keyframe
         
     | 
| 
       7 
     | 
    
         
            -
              class Key < Struct.new(:frame, :value, :interpolation, :extrapolation, :left_slope, :right_slope, :break_slope)
         
     | 
| 
       8 
     | 
    
         
            -
                
         
     | 
| 
       9 
     | 
    
         
            -
                # Unless the key is broken? we should just use the right slope
         
     | 
| 
       10 
     | 
    
         
            -
                def left_slope
         
     | 
| 
       11 
     | 
    
         
            -
                  return right_slope unless broken?
         
     | 
| 
       12 
     | 
    
         
            -
                  super
         
     | 
| 
       13 
     | 
    
         
            -
                end
         
     | 
| 
       14 
     | 
    
         
            -
                
         
     | 
| 
       15 
     | 
    
         
            -
                # Tells whether the slope of this keyframe is broken (not smooth)
         
     | 
| 
       16 
     | 
    
         
            -
                def broken?
         
     | 
| 
       17 
     | 
    
         
            -
                  break_slope
         
     | 
| 
       18 
     | 
    
         
            -
                end
         
     | 
| 
       19 
     | 
    
         
            -
              end
         
     | 
| 
       20 
     | 
    
         
            -
              
         
     | 
| 
       21 
     | 
    
         
            -
              # Defines a number of regular expression matchers applied to the file as it is being parsed
         
     | 
| 
       22 
     | 
    
         
            -
              def matchers
         
     | 
| 
       23 
     | 
    
         
            -
                [
         
     | 
| 
       24 
     | 
    
         
            -
                  [:frame, :to_i,  /Frame ([\-\d\.]+)/],
         
     | 
| 
       25 
     | 
    
         
            -
                  [:value, :to_f,  /Value ([\-\d\.]+)/],
         
     | 
| 
       26 
     | 
    
         
            -
                  [:left_slope, :to_f, /LeftSlope ([\-\d\.]+)/],
         
     | 
| 
       27 
     | 
    
         
            -
                  [:right_slope, :to_f, /RightSlope ([\-\d\.]+)/],
         
     | 
| 
       28 
     | 
    
         
            -
                  [:interpolation, :to_s, /Interpolation (\w+)/],
         
     | 
| 
       29 
     | 
    
         
            -
                  [:extrapolation, :to_s, /Extrapolation (\w+)/],
         
     | 
| 
       30 
     | 
    
         
            -
                  [:break_slope, :to_s, /BreakSlope (\w+)/]
         
     | 
| 
       31 
     | 
    
         
            -
                ]
         
     | 
| 
       32 
     | 
    
         
            -
              end
         
     | 
| 
       33 
     | 
    
         
            -
              
         
     | 
| 
       34 
     | 
    
         
            -
              def create_key
         
     | 
| 
       35 
     | 
    
         
            -
                Key.new
         
     | 
| 
       36 
     | 
    
         
            -
              end
         
     | 
| 
       37 
     | 
    
         
            -
              
         
     | 
| 
       38 
     | 
    
         
            -
              # Represents a channel parsed from the Flame setup. Contains
         
     | 
| 
       39 
     | 
    
         
            -
              # the channel metadata and keyframes
         
     | 
| 
       40 
     | 
    
         
            -
              class Channel < DelegateClass(Array)
         
     | 
| 
       41 
     | 
    
         
            -
                attr_reader :node_type
         
     | 
| 
       42 
     | 
    
         
            -
                attr_reader :node_name
         
     | 
| 
       43 
     | 
    
         
            -
                attr_accessor :base_value
         
     | 
| 
       44 
     | 
    
         
            -
                attr_accessor :name
         
     | 
| 
       45 
     | 
    
         
            -
                attr_accessor :extrapolation
         
     | 
| 
       46 
     | 
    
         
            -
                
         
     | 
| 
       47 
     | 
    
         
            -
                def initialize(io, channel_name, parent_parser, node_type, node_name)
         
     | 
| 
       48 
     | 
    
         
            -
                  super([])
         
     | 
| 
       49 
     | 
    
         
            -
                  
         
     | 
| 
       50 
     | 
    
         
            -
                  @node_type = node_type
         
     | 
| 
       51 
     | 
    
         
            -
                  @node_name = node_name
         
     | 
| 
       52 
     | 
    
         
            -
                  @parser = parent_parser
         
     | 
| 
       53 
     | 
    
         
            -
                  @name = channel_name.strip
         
     | 
| 
       54 
     | 
    
         
            -
                  
         
     | 
| 
       55 
     | 
    
         
            -
                  base_value_matcher = /Value ([\-\d\.]+)/
         
     | 
| 
       56 
     | 
    
         
            -
                  keyframe_count_matcher = /Size (\d+)/
         
     | 
| 
       57 
     | 
    
         
            -
                  extrapolation_matcher = /Extrapolation (\w+)/
         
     | 
| 
       58 
     | 
    
         
            -
                  
         
     | 
| 
       59 
     | 
    
         
            -
                  indent = nil
         
     | 
| 
       60 
     | 
    
         
            -
                  
         
     | 
| 
       61 
     | 
    
         
            -
                  while line = io.gets
         
     | 
| 
       62 
     | 
    
         
            -
                    
         
     | 
| 
       63 
     | 
    
         
            -
                    unless indent 
         
     | 
| 
       64 
     | 
    
         
            -
                      indent = line.scan(/^(\s+)/)[1]
         
     | 
| 
       65 
     | 
    
         
            -
                      end_mark = "#{indent}End"
         
     | 
| 
       66 
     | 
    
         
            -
                    end
         
     | 
| 
       67 
     | 
    
         
            -
                    
         
     | 
| 
       68 
     | 
    
         
            -
                    if line =~ keyframe_count_matcher
         
     | 
| 
       69 
     | 
    
         
            -
                      $1.to_i.times { push(extract_key_from(io)) }
         
     | 
| 
       70 
     | 
    
         
            -
                    elsif line =~ base_value_matcher && empty?
         
     | 
| 
       71 
     | 
    
         
            -
                      self.base_value = $1.to_f
         
     | 
| 
       72 
     | 
    
         
            -
                    elsif line =~ extrapolation_matcher
         
     | 
| 
       73 
     | 
    
         
            -
                      self.extrapolation = symbolize_literal($1)
         
     | 
| 
       74 
     | 
    
         
            -
                    elsif line.strip == end_mark
         
     | 
| 
       75 
     | 
    
         
            -
                      break
         
     | 
| 
       76 
     | 
    
         
            -
                    end
         
     | 
| 
       77 
     | 
    
         
            -
                  end
         
     | 
| 
       78 
     | 
    
         
            -
                  
         
     | 
| 
       79 
     | 
    
         
            -
                end
         
     | 
| 
       80 
     | 
    
         
            -
                
         
     | 
| 
       81 
     | 
    
         
            -
                def path
         
     | 
| 
       82 
     | 
    
         
            -
                  [@node_name, name].compact.join("/")
         
     | 
| 
       83 
     | 
    
         
            -
                end
         
     | 
| 
       84 
     | 
    
         
            -
                
         
     | 
| 
       85 
     | 
    
         
            -
                # Get an Interpolator from this channel
         
     | 
| 
       86 
     | 
    
         
            -
                def to_interpolator
         
     | 
| 
       87 
     | 
    
         
            -
                  FlameChannelParser::Interpolator.new(self)
         
     | 
| 
       88 
     | 
    
         
            -
                end
         
     | 
| 
       89 
     | 
    
         
            -
                
         
     | 
| 
       90 
     | 
    
         
            -
                private
         
     | 
| 
       91 
     | 
    
         
            -
                
         
     | 
| 
       92 
     | 
    
         
            -
                def create_key
         
     | 
| 
       93 
     | 
    
         
            -
                  Key.new
         
     | 
| 
       94 
     | 
    
         
            -
                end
         
     | 
| 
       95 
     | 
    
         
            -
                
         
     | 
| 
       96 
     | 
    
         
            -
                INTERPS = [:constant, :linear, :hermite, :natural, :bezier]
         
     | 
| 
       97 
     | 
    
         
            -
                
         
     | 
| 
       98 
     | 
    
         
            -
                def extract_key_from(io)
         
     | 
| 
       99 
     | 
    
         
            -
                  frame = nil
         
     | 
| 
       100 
     | 
    
         
            -
                  end_matcher = /End/
         
     | 
| 
       101 
     | 
    
         
            -
                  
         
     | 
| 
       102 
     | 
    
         
            -
                  key = @parser.create_key
         
     | 
| 
       103 
     | 
    
         
            -
                  matchers = @parser.matchers
         
     | 
| 
       104 
     | 
    
         
            -
                  
         
     | 
| 
       105 
     | 
    
         
            -
                  until io.eof?
         
     | 
| 
       106 
     | 
    
         
            -
                    line = io.gets
         
     | 
| 
       107 
     | 
    
         
            -
                    if line =~ end_matcher
         
     | 
| 
       108 
     | 
    
         
            -
                      return key
         
     | 
| 
       109 
     | 
    
         
            -
                    else
         
     | 
| 
       110 
     | 
    
         
            -
                      matchers.each do | property, cast_method, pattern  |
         
     | 
| 
       111 
     | 
    
         
            -
                          if line =~ pattern
         
     | 
| 
       112 
     | 
    
         
            -
                            v = symbolize_literal($1.send(cast_method))
         
     | 
| 
       113 
     | 
    
         
            -
                            key.send("#{property}=", v) 
         
     | 
| 
       114 
     | 
    
         
            -
                          end
         
     | 
| 
       115 
     | 
    
         
            -
                      end
         
     | 
| 
       116 
     | 
    
         
            -
                    end
         
     | 
| 
       117 
     | 
    
         
            -
                  end
         
     | 
| 
       118 
     | 
    
         
            -
                  raise "Did not detect any keyframes!"
         
     | 
| 
       119 
     | 
    
         
            -
                end
         
     | 
| 
       120 
     | 
    
         
            -
                
         
     | 
| 
       121 
     | 
    
         
            -
                LITERALS = %w( linear constant natural hermite cubic bezier cycle revcycle )
         
     | 
| 
       122 
     | 
    
         
            -
                
         
     | 
| 
       123 
     | 
    
         
            -
                def symbolize_literal(v)
         
     | 
| 
       124 
     | 
    
         
            -
                  LITERALS.include?(v) ? v.to_sym : v
         
     | 
| 
       125 
     | 
    
         
            -
                end
         
     | 
| 
       126 
     | 
    
         
            -
                
         
     | 
| 
       127 
     | 
    
         
            -
              end
         
     | 
| 
       128 
     | 
    
         
            -
              
         
     | 
| 
       129 
     | 
    
         
            -
              CHANNEL_MATCHER = /Channel (.+)\n/
         
     | 
| 
       130 
     | 
    
         
            -
              NODE_TYPE_MATCHER = /Node (\w+)/
         
     | 
| 
       131 
     | 
    
         
            -
              NODE_NAME_MATCHER = /Name (\w+)/
         
     | 
| 
       132 
     | 
    
         
            -
              
         
     | 
| 
       133 
     | 
    
         
            -
              def parse(io)
         
     | 
| 
       134 
     | 
    
         
            -
                channels = []
         
     | 
| 
       135 
     | 
    
         
            -
                node_name, node_type = nil, nil
         
     | 
| 
       136 
     | 
    
         
            -
                
         
     | 
| 
       137 
     | 
    
         
            -
                until io.eof?
         
     | 
| 
       138 
     | 
    
         
            -
                  line = io.gets
         
     | 
| 
       139 
     | 
    
         
            -
                  if line =~ NODE_TYPE_MATCHER
         
     | 
| 
       140 
     | 
    
         
            -
                    node_type = $1
         
     | 
| 
       141 
     | 
    
         
            -
                  elsif line =~ NODE_NAME_MATCHER
         
     | 
| 
       142 
     | 
    
         
            -
                    node_name = $1
         
     | 
| 
       143 
     | 
    
         
            -
                  elsif line =~ CHANNEL_MATCHER && channel_is_useful?($1)
         
     | 
| 
       144 
     | 
    
         
            -
                    channels << Channel.new(io, $1, self, node_type, node_name)
         
     | 
| 
       145 
     | 
    
         
            -
                  end
         
     | 
| 
       146 
     | 
    
         
            -
                end
         
     | 
| 
       147 
     | 
    
         
            -
                channels
         
     | 
| 
       148 
     | 
    
         
            -
              end
         
     | 
| 
       149 
     | 
    
         
            -
              
         
     | 
| 
       150 
     | 
    
         
            -
              # Override this method to skip some channels, this will speedup
         
     | 
| 
       151 
     | 
    
         
            -
              # your code alot
         
     | 
| 
       152 
     | 
    
         
            -
              def channel_is_useful?(channel_name)
         
     | 
| 
       153 
     | 
    
         
            -
                true
         
     | 
| 
       154 
     | 
    
         
            -
              end
         
     | 
| 
       155 
     | 
    
         
            -
              
         
     | 
| 
       156 
     | 
    
         
            -
            end
         
     | 
    
        data/lib/parser_2012.rb
    DELETED
    
    | 
         @@ -1,59 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require "delegate"
         
     | 
| 
       2 
     | 
    
         
            -
            require File.dirname(__FILE__) + "/interpolator"
         
     | 
| 
       3 
     | 
    
         
            -
             
     | 
| 
       4 
     | 
    
         
            -
            # This parser is automatically used for 2012 setups
         
     | 
| 
       5 
     | 
    
         
            -
            class FlameChannelParser::Parser2012 < FlameChannelParser::Parser2011
         
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
              class ModernKey < Struct.new(:frame, :value, :r_handle_x, :l_handle_x, :r_handle_y, :l_handle_y, :curve_mode, :curve_order, :break_slope)
         
     | 
| 
       8 
     | 
    
         
            -
                alias_method :to_s, :inspect
         
     | 
| 
       9 
     | 
    
         
            -
                
         
     | 
| 
       10 
     | 
    
         
            -
                # Adapter for old interpolation
         
     | 
| 
       11 
     | 
    
         
            -
                def interpolation
         
     | 
| 
       12 
     | 
    
         
            -
                  return :constant if curve_order.to_s == "constant"
         
     | 
| 
       13 
     | 
    
         
            -
                  return :hermite if curve_order.to_s == "cubic" && (curve_mode.to_s == "hermite" || curve_mode.to_s == "natural")
         
     | 
| 
       14 
     | 
    
         
            -
                  return :bezier if curve_order.to_s == "cubic" && curve_mode.to_s == "bezier"
         
     | 
| 
       15 
     | 
    
         
            -
                  return :linear if curve_order.to_s == "linear"
         
     | 
| 
       16 
     | 
    
         
            -
                  
         
     | 
| 
       17 
     | 
    
         
            -
                  raise "Cannot determine interpolation for #{self.inspect}"
         
     | 
| 
       18 
     | 
    
         
            -
                end
         
     | 
| 
       19 
     | 
    
         
            -
                
         
     | 
| 
       20 
     | 
    
         
            -
                # Compute pre-212 slope which we use for interpolations
         
     | 
| 
       21 
     | 
    
         
            -
                def left_slope
         
     | 
| 
       22 
     | 
    
         
            -
                  return right_slope unless broken?
         
     | 
| 
       23 
     | 
    
         
            -
                  
         
     | 
| 
       24 
     | 
    
         
            -
                  dy = value - l_handle_y
         
     | 
| 
       25 
     | 
    
         
            -
                  dx = l_handle_x - frame
         
     | 
| 
       26 
     | 
    
         
            -
                  dy / dx  * -1
         
     | 
| 
       27 
     | 
    
         
            -
                end
         
     | 
| 
       28 
     | 
    
         
            -
                
         
     | 
| 
       29 
     | 
    
         
            -
                # Compute pre-212 slope which we use for interpolations
         
     | 
| 
       30 
     | 
    
         
            -
                def right_slope
         
     | 
| 
       31 
     | 
    
         
            -
                  dy = value - r_handle_y
         
     | 
| 
       32 
     | 
    
         
            -
                  dx = frame - r_handle_x
         
     | 
| 
       33 
     | 
    
         
            -
                  dy / dx
         
     | 
| 
       34 
     | 
    
         
            -
                end
         
     | 
| 
       35 
     | 
    
         
            -
                
         
     | 
| 
       36 
     | 
    
         
            -
                def broken?
         
     | 
| 
       37 
     | 
    
         
            -
                  break_slope
         
     | 
| 
       38 
     | 
    
         
            -
                end
         
     | 
| 
       39 
     | 
    
         
            -
              end
         
     | 
| 
       40 
     | 
    
         
            -
              
         
     | 
| 
       41 
     | 
    
         
            -
              def matchers
         
     | 
| 
       42 
     | 
    
         
            -
                 [
         
     | 
| 
       43 
     | 
    
         
            -
                   [:frame, :to_i,  /Frame ([\-\d\.]+)/],
         
     | 
| 
       44 
     | 
    
         
            -
                   [:value, :to_f,  /Value ([\-\d\.]+)/],
         
     | 
| 
       45 
     | 
    
         
            -
                   [:r_handle_x, :to_f, /RHandleX ([\-\d\.]+)/],
         
     | 
| 
       46 
     | 
    
         
            -
                   [:l_handle_x, :to_f, /LHandleX ([\-\d\.]+)/],
         
     | 
| 
       47 
     | 
    
         
            -
                   [:r_handle_y, :to_f, /RHandleY ([\-\d\.]+)/],
         
     | 
| 
       48 
     | 
    
         
            -
                   [:l_handle_y, :to_f, /LHandleY ([\-\d\.]+)/],
         
     | 
| 
       49 
     | 
    
         
            -
                   [:curve_mode, :to_s,  /CurveMode (\w+)/],
         
     | 
| 
       50 
     | 
    
         
            -
                   [:curve_order, :to_s,  /CurveOrder (\w+)/],
         
     | 
| 
       51 
     | 
    
         
            -
                   [:break_slope, :to_s,  /BreakSlope (\w+)/],
         
     | 
| 
       52 
     | 
    
         
            -
                 ]
         
     | 
| 
       53 
     | 
    
         
            -
               end
         
     | 
| 
       54 
     | 
    
         
            -
               
         
     | 
| 
       55 
     | 
    
         
            -
              
         
     | 
| 
       56 
     | 
    
         
            -
              def create_key
         
     | 
| 
       57 
     | 
    
         
            -
                ModernKey.new
         
     | 
| 
       58 
     | 
    
         
            -
              end
         
     | 
| 
       59 
     | 
    
         
            -
            end
         
     |