flame_channel_parser 3.0.0 → 4.0.0

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.
Files changed (47) hide show
  1. data/.travis.yml +4 -0
  2. data/Gemfile +10 -0
  3. data/History.txt +5 -0
  4. data/README.rdoc +4 -2
  5. data/Rakefile +23 -10
  6. data/bin/{bake_flame_timewarp → framecurve_from_flame} +5 -1
  7. data/bin/framecurve_to_flame +22 -0
  8. data/flame_channel_parser.gemspec +130 -0
  9. data/lib/builder.rb +86 -0
  10. data/lib/flame_channel_parser.rb +31 -4
  11. data/lib/framecurve_writers/base.rb +49 -0
  12. data/lib/framecurve_writers/batch_timewarp.rb +41 -0
  13. data/lib/framecurve_writers/kronos.rb +23 -0
  14. data/lib/framecurve_writers/softfx_timewarp.rb +82 -0
  15. data/lib/framecurve_writers/templates/BatchTW.xml +118 -0
  16. data/lib/framecurve_writers/templates/SampleKronos.F_Kronos +376 -0
  17. data/lib/framecurve_writers/templates/TW_Sample.timewarp +79 -0
  18. data/lib/framecurve_writers/templates/key.xml +10 -0
  19. data/lib/timewarp_extractor.rb +18 -2
  20. data/lib/xml_parser.rb +90 -0
  21. data/test/helper.rb +18 -0
  22. data/test/snaps/BatchTimewar_proper.xml +157 -0
  23. data/test/snaps/BatchTimewarp_ext1.timewarp_node +1 -0
  24. data/test/test_base_timewarp_writer.rb +22 -0
  25. data/test/test_batch_timewarp_writer.rb +18 -0
  26. data/test/test_channel.rb +1 -2
  27. data/test/test_cli.rb +14 -13
  28. data/test/test_cli_framecurve_to_flame.rb +45 -0
  29. data/test/test_cli_timewarp_extractor.rb +19 -9
  30. data/test/test_extractor.rb +1 -3
  31. data/test/test_flame_builder.rb +68 -0
  32. data/test/test_flame_channel_parser.rb +2 -2
  33. data/test/test_interpolator.rb +15 -5
  34. data/test/test_key.rb +2 -2
  35. data/test/test_kronos_timewarp_writer.rb +16 -0
  36. data/test/test_segments.rb +1 -2
  37. data/test/test_softfx_timewarp_writer.rb +16 -0
  38. data/test/test_timewarp_extractor.rb +2 -4
  39. data/test/test_xml_setup.rb +37 -0
  40. data/test/timewarp_examples/TW_16_010_v01.output.txt +430 -428
  41. data/test/timewarp_examples/simple.framecurve.txt +32 -0
  42. data/test/timewarp_export_samples/BatchTW.timewarp_node +145 -0
  43. data/test/timewarp_export_samples/Kronos.F_Kronos +403 -0
  44. data/test/timewarp_export_samples/SoftFX.timewarp +81 -0
  45. metadata +127 -168
  46. data/.gemtest +0 -0
  47. data/Manifest.txt +0 -52
@@ -0,0 +1,4 @@
1
+ rvm:
2
+ - 1.8.7
3
+ - 1.9.2
4
+ - 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source :rubygems
2
+
3
+ gem "update_hints", "~> 1.0"
4
+ gem "framecurve", "~> 1.0.1"
5
+
6
+ group :development do
7
+ gem "jeweler"
8
+ gem "rake"
9
+ gem "cli_test", "~>1.0"
10
+ end
@@ -1,3 +1,8 @@
1
+ === 4.0.0 / 2011-09-11
2
+
3
+ * Integrate the Framecurve library. Parse TO framecurve as well as FROM to all supported timewarpers
4
+ * Support new XML batch node setups
5
+
1
6
  === 3.0.0 / 2011-09-11
2
7
 
3
8
  * Allow for channels to be passed to a block instead of being collected into an array
@@ -18,9 +18,11 @@ To just bake a specific channel, use the bake_flame_channel binary.
18
18
 
19
19
  $bake_flame_channel --channel Timing/Timing -e 123 /usr/discreet/projects/BZO/timewarp/s02_tw.timewarp > /mnt/3d/curves/shot2_tw.framecurve.txt
20
20
 
21
- If you just need to process a timewarp, use the bake_flame_timewarp which autodetects most of the settings by itself
21
+ If you just need to process a timewarp, use the bake_flame_timewarp which autodetects most of the settings by itself and gives you a nice .framecurve.txt file
22
22
 
23
- $bake_flame_timewarp /usr/discreet/projects/BZO/timewarp/s02_tw.timewarp > /mnt/3d/curves/shot2_tw.framecurve.txt
23
+ $framecurve_from_flame /usr/discreet/projects/BZO/timewarp/s02_tw.timewarp
24
+
25
+ This will create a framecurve file called s02_tw.timewarp.framecurve.txt next to the setup
24
26
 
25
27
  To use the library:
26
28
 
data/Rakefile CHANGED
@@ -1,17 +1,30 @@
1
1
  # -*- ruby -*-
2
2
 
3
3
  require 'rubygems'
4
- require 'hoe'
4
+ require 'jeweler'
5
+ require './lib/flame_channel_parser'
5
6
 
6
- Hoe::RUBY_FLAGS.gsub!(/^\-w/, '') # No thanks undefined ivar warnings
7
- Hoe.spec 'flame_channel_parser' do | p |
8
- p.developer('Julik Tarkhanov', 'me@julik.nl')
9
-
10
- p.readme_file = 'README.rdoc'
11
- p.extra_rdoc_files = FileList['*.rdoc'] + FileList['*.txt']
12
- p.extra_deps = {"update_hints" => ">=0" }
13
- p.extra_dev_deps = {"cli_test" => "~> 1.0.0" }
14
- p.clean_globs = File.read(".gitignore").split("\n")
7
+ Jeweler::Tasks.new do |gem|
8
+ gem.version = FlameChannelParser::VERSION
9
+ gem.name = "flame_channel_parser"
10
+ gem.summary = "A parser/interpolator for Flame/Smoke animation curves"
11
+ gem.description = "Reads and interpolates animation channels in IFFS setups"
12
+ gem.email = "me@julik.nl"
13
+ gem.homepage = "http://guerilla-di.org/flame-channel-parser/"
14
+ gem.authors = ["Julik Tarkhanov"]
15
+ gem.license = 'MIT'
15
16
  end
16
17
 
18
+ Jeweler::RubygemsDotOrgTasks.new
19
+
20
+ require 'rake/testtask'
21
+ desc "Run all tests"
22
+ Rake::TestTask.new("test") do |t|
23
+ t.libs << "test"
24
+ t.pattern = 'test/**/test_*.rb'
25
+ t.verbose = true
26
+ end
27
+
28
+ task :default => [ :test ]
29
+
17
30
  # vim: syntax=ruby
@@ -28,6 +28,10 @@ unless File.exist?(setup_path)
28
28
  exit -1
29
29
  end
30
30
 
31
- FlameChannelParser::TimewarpExtractor.new.extract(setup_path, options)
31
+ # Setup the destination
32
+ destination_path = setup_path.gsub(/\.(\w+)$/, '.framecurve.txt')
33
+ File.open(destination_path, "wb") do | f |
34
+ FlameChannelParser::TimewarpExtractor.new.extract(setup_path, options.merge(:destination => f))
35
+ end
32
36
 
33
37
  UpdateHints.version_check("flame_channel_parser", FlameChannelParser::VERSION, $stderr)
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path(File.dirname(__FILE__)) + '/../lib/flame_channel_parser'
3
+ require 'optparse'
4
+ require "update_hints"
5
+
6
+ op = OptionParser.new
7
+ op.banner = "Usage: framecurve_to_flame /usr/discreet/projects/ExpensiveDildo/timewarp/shot2_tw.framecurve.txt"
8
+ op.parse!
9
+
10
+ fc_path = ARGV.shift
11
+ fail("No input file path provided.") unless fc_path
12
+ fail("File %s does not exist." % fc_path) unless File.exist?(fc_path)
13
+
14
+ curve = Framecurve::Parser.new.parse(fc_path)
15
+ FlameChannelParser::FramecurveWriters::Base.with_each_writer do | writer_class |
16
+ filename = [fc_path, writer_class.extension].join
17
+ File.open(filename, "wb") do | f |
18
+ writer_class.new.run_export_from_framecurve(f, curve)
19
+ end
20
+ end
21
+
22
+ UpdateHints.version_check("flame_channel_parser", FlameChannelParser::VERSION, $stderr)
@@ -0,0 +1,130 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "flame_channel_parser"
8
+ s.version = "4.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Julik Tarkhanov"]
12
+ s.date = "2011-12-30"
13
+ s.description = "Reads and interpolates animation channels in IFFS setups"
14
+ s.email = "me@julik.nl"
15
+ s.executables = ["bake_flame_channel", "framecurve_from_flame", "framecurve_to_flame"]
16
+ s.extra_rdoc_files = [
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".autotest",
21
+ ".travis.yml",
22
+ "Gemfile",
23
+ "History.txt",
24
+ "README.rdoc",
25
+ "Rakefile",
26
+ "bin/bake_flame_channel",
27
+ "bin/framecurve_from_flame",
28
+ "bin/framecurve_to_flame",
29
+ "flame_channel_parser.gemspec",
30
+ "lib/builder.rb",
31
+ "lib/channel.rb",
32
+ "lib/extractor.rb",
33
+ "lib/flame_channel_parser.rb",
34
+ "lib/framecurve_writers/base.rb",
35
+ "lib/framecurve_writers/batch_timewarp.rb",
36
+ "lib/framecurve_writers/kronos.rb",
37
+ "lib/framecurve_writers/softfx_timewarp.rb",
38
+ "lib/framecurve_writers/templates/BatchTW.xml",
39
+ "lib/framecurve_writers/templates/SampleKronos.F_Kronos",
40
+ "lib/framecurve_writers/templates/TW_Sample.timewarp",
41
+ "lib/framecurve_writers/templates/key.xml",
42
+ "lib/interpolator.rb",
43
+ "lib/key.rb",
44
+ "lib/parser.rb",
45
+ "lib/segments.rb",
46
+ "lib/timewarp_extractor.rb",
47
+ "lib/xml_parser.rb",
48
+ "test/channel_with_constants.dat",
49
+ "test/helper.rb",
50
+ "test/sample_channel.dat",
51
+ "test/snaps/BatchTimewar_proper.xml",
52
+ "test/snaps/BatchTimewarp_ext1.timewarp_node",
53
+ "test/snaps/Cycle_and_revcycle.action",
54
+ "test/snaps/FLEM_BrokenTangents.action",
55
+ "test/snaps/FLEM_advanced_curve.png",
56
+ "test/snaps/FLEM_advanced_curve_example_FL2012.action",
57
+ "test/snaps/FLEM_baked_curve.png",
58
+ "test/snaps/FLEM_curves_example.action",
59
+ "test/snaps/FLEM_curves_example_migrated_to_2012.action",
60
+ "test/snaps/FLEM_std_curve.png",
61
+ "test/snaps/RefT_Steadicam.timewarp",
62
+ "test/snaps/RefT_Steadicam_Baked.timewarp",
63
+ "test/snaps/RefT_Steadicam_Extraction.txt",
64
+ "test/snaps/RefT_Steadicam_Extraction_F19_to_347.txt",
65
+ "test/snaps/RefT_Steadicam_TwoKFs.timewarp",
66
+ "test/snaps/RefT_Steadicam_TwoKFs_AnotherSlope.timewarp",
67
+ "test/snaps/RefT_Steadicam_TwoKFs_HermiteAtBegin.timewarp",
68
+ "test/snaps/TW.timewarp",
69
+ "test/snaps/TW_015_010_v03.timewarp",
70
+ "test/snaps/TW_SingleFrameExtrapolated_from2011.timewarp",
71
+ "test/snaps/TW_TEST.F_Kronos",
72
+ "test/snaps/timewarp_where_interp_fails_at_end.timewarp",
73
+ "test/test_base_timewarp_writer.rb",
74
+ "test/test_batch_timewarp_writer.rb",
75
+ "test/test_channel.rb",
76
+ "test/test_cli.rb",
77
+ "test/test_cli_framecurve_to_flame.rb",
78
+ "test/test_cli_timewarp_extractor.rb",
79
+ "test/test_extractor.rb",
80
+ "test/test_flame_builder.rb",
81
+ "test/test_flame_channel_parser.rb",
82
+ "test/test_interpolator.rb",
83
+ "test/test_key.rb",
84
+ "test/test_kronos_timewarp_writer.rb",
85
+ "test/test_segments.rb",
86
+ "test/test_softfx_timewarp_writer.rb",
87
+ "test/test_timewarp_extractor.rb",
88
+ "test/test_xml_setup.rb",
89
+ "test/timewarp_examples/TW_015_010_v01_Baked.timewarp",
90
+ "test/timewarp_examples/TW_016_010_v01.timewarp",
91
+ "test/timewarp_examples/TW_016_010_v01_Baked.timewarp",
92
+ "test/timewarp_examples/TW_16_010_v01.output.txt",
93
+ "test/timewarp_examples/TW_TEST.F_Kronos",
94
+ "test/timewarp_examples/output.txt",
95
+ "test/timewarp_examples/simple.framecurve.txt",
96
+ "test/timewarp_export_samples/BatchTW.timewarp_node",
97
+ "test/timewarp_export_samples/Kronos.F_Kronos",
98
+ "test/timewarp_export_samples/SoftFX.timewarp"
99
+ ]
100
+ s.homepage = "http://guerilla-di.org/flame-channel-parser/"
101
+ s.licenses = ["MIT"]
102
+ s.require_paths = ["lib"]
103
+ s.rubygems_version = "1.8.11"
104
+ s.summary = "A parser/interpolator for Flame/Smoke animation curves"
105
+
106
+ if s.respond_to? :specification_version then
107
+ s.specification_version = 3
108
+
109
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
110
+ s.add_runtime_dependency(%q<update_hints>, ["~> 1.0"])
111
+ s.add_runtime_dependency(%q<framecurve>, ["~> 1.0.1"])
112
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
113
+ s.add_development_dependency(%q<rake>, [">= 0"])
114
+ s.add_development_dependency(%q<cli_test>, ["~> 1.0"])
115
+ else
116
+ s.add_dependency(%q<update_hints>, ["~> 1.0"])
117
+ s.add_dependency(%q<framecurve>, ["~> 1.0.1"])
118
+ s.add_dependency(%q<jeweler>, [">= 0"])
119
+ s.add_dependency(%q<rake>, [">= 0"])
120
+ s.add_dependency(%q<cli_test>, ["~> 1.0"])
121
+ end
122
+ else
123
+ s.add_dependency(%q<update_hints>, ["~> 1.0"])
124
+ s.add_dependency(%q<framecurve>, ["~> 1.0.1"])
125
+ s.add_dependency(%q<jeweler>, [">= 0"])
126
+ s.add_dependency(%q<rake>, [">= 0"])
127
+ s.add_dependency(%q<cli_test>, ["~> 1.0"])
128
+ end
129
+ end
130
+
@@ -0,0 +1,86 @@
1
+ # A Builder-like class for exporting Flame setups
2
+ class FlameChannelParser::Builder #< BasicObject
3
+ INDENT = "\t"
4
+
5
+ def initialize(io, indent = 0)
6
+ @io, @indent = io, indent
7
+ end
8
+
9
+ # Writes a block of values delimited by "End" terminators.
10
+ # Will yield a nested Builder objectg which
11
+ def write_block!(name, value = nil, &blk)
12
+ value.nil? ? write_loose!(name) : write_tuple!(name, value)
13
+ yield(self.class.new(@io, @indent + 1))
14
+ @io.puts(INDENT * (@indent + 1) + "End")
15
+ end
16
+
17
+ # Write an unterminated block of values
18
+ def write_unterminated_block!(name, value = nil, &blk)
19
+ value.nil? ? write_loose!(name) : write_tuple!(name, value)
20
+ yield(self.class.new(@io, @indent + 1))
21
+ end
22
+
23
+ # Write a tuple of "Parameter Value", like "Frame 13"
24
+ def write_tuple!(key, value)
25
+ @io.puts("%s%s %s" % [INDENT * @indent, __camelize(key), __flameize(value)])
26
+ end
27
+
28
+ # Write a number of linebreaks
29
+ def write_loose!(value)
30
+ @io.puts("%s%s" % [INDENT * @indent, __camelize(value)])
31
+ end
32
+
33
+ # Write a number of linebreaks
34
+ def linebreak!(how_many = 1)
35
+ @io.write("\n" * how_many)
36
+ end
37
+
38
+ # Write a color hash with the right order of values
39
+ def color_hash!(name, red, green, blue)
40
+ write_unterminated_block!(name) do | b |
41
+ b.red(red)
42
+ b.green(green)
43
+ b.blue(blue)
44
+ end
45
+ end
46
+
47
+ # Append the text passed to the setup. The appended
48
+ # lines will be prepended by the indent of the current builder
49
+ def <<(some_verbatim_string)
50
+ some_verbatim_string.split("\n").each do | line |
51
+ @io.puts(["\t" * @indent, line].join)
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def method_missing(meth, arg = nil)
58
+ if block_given?
59
+ write_block!(meth, arg) {|c| yield(c) }
60
+ else
61
+ if arg.nil?
62
+ write_loose!(meth)
63
+ else
64
+ write_tuple!(meth, arg)
65
+ end
66
+ end
67
+ end
68
+
69
+ def __camelize(s)
70
+ @@camelizations ||= {}
71
+ @@camelizations[s] ||= s.to_s.gsub(/(^|_)(.)/) { $2.upcase }
72
+ end
73
+
74
+ def __flameize(v)
75
+ case v
76
+ when Float
77
+ "%.3f" % v
78
+ when TrueClass
79
+ "yes"
80
+ when FalseClass
81
+ "no"
82
+ else
83
+ v.to_s
84
+ end
85
+ end
86
+ end
@@ -1,18 +1,45 @@
1
1
  module FlameChannelParser
2
- VERSION = '3.0.0'
2
+ VERSION = '4.0.0'
3
+
4
+ module FramecurveWriters; end
3
5
 
4
6
  # Parse a Flame setup into an array of Channel objects.
5
7
  # If a block is given to the method it will yield Channel
6
8
  # objects one by one instead of accumulating them into an array (useful for big setups)
7
9
  def self.parse(io)
10
+ c = get_parser_class(io)
8
11
  if block_given?
9
- Parser.new.parse(io, &Proc.new)
12
+ c.new.parse(io, &Proc.new)
10
13
  else
11
- Parser.new.parse(io)
14
+ c.new.parse(io)
12
15
  end
13
16
  end
17
+
18
+ # Parse a Flame setup at passed path. Will return the channels instead of yielding them
19
+ def self.parse_file_at(path)
20
+ File.open(path, &method(:parse))
21
+ end
22
+
23
+ private
24
+
25
+ # Returns the XML parser class for XML setups
26
+ def self.get_parser_class(for_io)
27
+ tokens = %w( <Setup> <?xml )
28
+ current = for_io.pos
29
+ tokens.each do | token |
30
+ for_io.rewind
31
+ return XMLParser if for_io.read(token.size) == token
32
+ end
33
+ return Parser
34
+ ensure
35
+ for_io.seek(current)
36
+ end
14
37
  end
15
38
 
16
39
  %w(
17
- key channel parser segments interpolator extractor timewarp_extractor
40
+ key channel parser segments interpolator extractor timewarp_extractor builder xml_parser
18
41
  ).each {|f| require File.expand_path(File.dirname(__FILE__) + "/" + f ) }
42
+
43
+ %w(
44
+ base softfx_timewarp batch_timewarp kronos
45
+ ).each {|f| require File.expand_path(File.dirname(__FILE__) + "/framecurve_writers/" + f ) }
@@ -0,0 +1,49 @@
1
+ # Writes out a framecurve setup
2
+ class FlameChannelParser::FramecurveWriters::Base
3
+ class KeyWriter
4
+ attr_reader :keys
5
+ def initialize
6
+ @keys = []
7
+ end
8
+
9
+ def key(at, value)
10
+ @keys.push([at.to_i,value.to_f])
11
+ end
12
+
13
+ end
14
+
15
+ def self.inherited(by)
16
+ @@writers ||= []
17
+ @@writers.push(by)
18
+ end
19
+
20
+ # Yields each defined writer class to the block
21
+ def self.with_each_writer
22
+ @@writers.each(&Proc.new)
23
+ end
24
+
25
+ # Should return the desired extension for the exported file
26
+ def self.extension
27
+ '.timewarp'
28
+ end
29
+
30
+ # Run the exporter writing the result to the passed IO. Will yield a KeyWriter
31
+ # to the caller for writing frames (call key(at, value) on it)
32
+ def run_export(io)
33
+ w = KeyWriter.new
34
+ yield(w)
35
+ w.keys.each do | at, value |
36
+ io.puts("%d %.5f" % [at, value])
37
+ end
38
+ end
39
+
40
+ # Run the exporter writing the result to it, and pulling framecurve frames from the passed Curve
41
+ # object
42
+ def run_export_from_framecurve(io, curve)
43
+ run_export(io) do | writer |
44
+ curve.to_materialized_curve.each_tuple do | t |
45
+ writer.key(t.at, t.value)
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,41 @@
1
+ # Writes out a Batch timewarp node setup
2
+ class FlameChannelParser::FramecurveWriters::BatchTimewarp < FlameChannelParser::FramecurveWriters::SoftfxTimewarp
3
+
4
+ TEMPLATE = File.dirname(__FILE__) + "/templates/BatchTW.xml"
5
+ TEMPLATE_KEY = File.dirname(__FILE__) + "/templates/key.xml"
6
+
7
+ def self.extension
8
+ '.timewarp_node'
9
+ end
10
+
11
+ def run_export(io)
12
+ w = KeyWriter.new
13
+ yield(w)
14
+ keys = w.keys
15
+
16
+ keys_data = ''
17
+ keys.each_with_index do | k, idx |
18
+ keys_data << templatize(TEMPLATE_KEY, :frame => k[0].to_i, :value => k[1].to_f, :idx => idx)
19
+ end
20
+
21
+ # Whole range BOTH in the source and destination
22
+ used_frames = (keys.map{|k| k[1]} + keys.map{|k| k[0]}).sort
23
+ first_frame, last_frame = used_frames[0], used_frames[-1]
24
+
25
+ info = {:start_frame => first_frame, :last_frame => last_frame, :first_value => keys[0][1], :key_size => keys.size, :keys => keys_data }
26
+ io.write(templatize(TEMPLATE, info))
27
+ end
28
+
29
+ private
30
+ def templatize(file, hash)
31
+ t = File.read(file)
32
+ hash.each_pair do | pattern, value |
33
+ p = Regexp.escape('$%s' % pattern)
34
+ handle = Regexp.new(p, [Regexp::MULTILINE, Regexp::EXTENDED])
35
+ t.gsub!(handle, value.to_s)
36
+ end
37
+ raise "Not all substitutions done" if t.include?('$')
38
+
39
+ return t
40
+ end
41
+ end