flame_channel_parser 3.0.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +4 -0
- data/Gemfile +10 -0
- data/History.txt +5 -0
- data/README.rdoc +4 -2
- data/Rakefile +23 -10
- data/bin/{bake_flame_timewarp → framecurve_from_flame} +5 -1
- data/bin/framecurve_to_flame +22 -0
- data/flame_channel_parser.gemspec +130 -0
- data/lib/builder.rb +86 -0
- data/lib/flame_channel_parser.rb +31 -4
- data/lib/framecurve_writers/base.rb +49 -0
- data/lib/framecurve_writers/batch_timewarp.rb +41 -0
- data/lib/framecurve_writers/kronos.rb +23 -0
- data/lib/framecurve_writers/softfx_timewarp.rb +82 -0
- data/lib/framecurve_writers/templates/BatchTW.xml +118 -0
- data/lib/framecurve_writers/templates/SampleKronos.F_Kronos +376 -0
- data/lib/framecurve_writers/templates/TW_Sample.timewarp +79 -0
- data/lib/framecurve_writers/templates/key.xml +10 -0
- data/lib/timewarp_extractor.rb +18 -2
- data/lib/xml_parser.rb +90 -0
- data/test/helper.rb +18 -0
- data/test/snaps/BatchTimewar_proper.xml +157 -0
- data/test/snaps/BatchTimewarp_ext1.timewarp_node +1 -0
- data/test/test_base_timewarp_writer.rb +22 -0
- data/test/test_batch_timewarp_writer.rb +18 -0
- data/test/test_channel.rb +1 -2
- data/test/test_cli.rb +14 -13
- data/test/test_cli_framecurve_to_flame.rb +45 -0
- data/test/test_cli_timewarp_extractor.rb +19 -9
- data/test/test_extractor.rb +1 -3
- data/test/test_flame_builder.rb +68 -0
- data/test/test_flame_channel_parser.rb +2 -2
- data/test/test_interpolator.rb +15 -5
- data/test/test_key.rb +2 -2
- data/test/test_kronos_timewarp_writer.rb +16 -0
- data/test/test_segments.rb +1 -2
- data/test/test_softfx_timewarp_writer.rb +16 -0
- data/test/test_timewarp_extractor.rb +2 -4
- data/test/test_xml_setup.rb +37 -0
- data/test/timewarp_examples/TW_16_010_v01.output.txt +430 -428
- data/test/timewarp_examples/simple.framecurve.txt +32 -0
- data/test/timewarp_export_samples/BatchTW.timewarp_node +145 -0
- data/test/timewarp_export_samples/Kronos.F_Kronos +403 -0
- data/test/timewarp_export_samples/SoftFX.timewarp +81 -0
- metadata +127 -168
- data/.gemtest +0 -0
- data/Manifest.txt +0 -52
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/History.txt
CHANGED
@@ -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
|
data/README.rdoc
CHANGED
@@ -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
|
-
$
|
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 '
|
4
|
+
require 'jeweler'
|
5
|
+
require './lib/flame_channel_parser'
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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
|
-
|
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
|
+
|
data/lib/builder.rb
ADDED
@@ -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
|
data/lib/flame_channel_parser.rb
CHANGED
@@ -1,18 +1,45 @@
|
|
1
1
|
module FlameChannelParser
|
2
|
-
VERSION = '
|
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
|
-
|
12
|
+
c.new.parse(io, &Proc.new)
|
10
13
|
else
|
11
|
-
|
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
|