233 lines
7.7 KiB
Ruby
Executable File
233 lines
7.7 KiB
Ruby
Executable File
|
|
|
|
|
|
# cutscene_cam_parser.rb
|
|
#
|
|
# Luke Openshaw <luke.openshaw@rockstarnorth.vom>
|
|
#
|
|
# Convert anim using anim2text and parse output to find FOV problem
|
|
# There is an instatiation of an AnimationParserManager at the foot
|
|
# of this script which passes true to the initialize fucntion to convert
|
|
# all camera anims in the cuts root
|
|
#
|
|
|
|
#-----------------------------------------------------------------------------
|
|
# Uses
|
|
#-----------------------------------------------------------------------------
|
|
require 'find'
|
|
require 'pipeline/os/path'
|
|
require 'fileutils'
|
|
|
|
|
|
module Animation
|
|
|
|
# == Description
|
|
#
|
|
# Manager for the converting anims and parsing for FOV issues
|
|
#
|
|
class AnimationParserManager
|
|
#-----------------------------------------------------------------------------
|
|
# Constants
|
|
#-----------------------------------------------------------------------------
|
|
|
|
CUTSCENE_ROOT = 'x:/gta/gta_assets/cuts/'
|
|
OUTPUT_ROOT = 'x:/streamgta/cutscene_cams/'
|
|
KEYNAME = 'camera'
|
|
TRACK_FOV = 136
|
|
TRACK_JUMPCUT = 144
|
|
FOV_TOLERANCE = 3.0
|
|
|
|
attr_reader :animtextlist
|
|
attr_reader :animtestlistfailed
|
|
attr_reader :tracks
|
|
attr_reader :animlist
|
|
attr_reader :bustedscenes
|
|
attr_reader :bustedscenesinfo
|
|
|
|
def initialize(convertanims)
|
|
@animlist = Array.new()
|
|
@animtextlist = Array.new()
|
|
@animtestlistfailed = Array.new()
|
|
@bustedscenes = Array.new()
|
|
@bustedscenesinfo = Array.new()
|
|
|
|
trackids = Array[TRACK_FOV, TRACK_JUMPCUT]
|
|
|
|
if convertanims
|
|
build_anim_list(@animlist, CUTSCENE_ROOT)
|
|
batch_anim_to_text()
|
|
else
|
|
build_anim_list(@animtextlist, OUTPUT_ROOT)
|
|
end
|
|
|
|
for animtext in @animtextlist do
|
|
tracks = AnimationParser.parse(animtext, trackids)
|
|
|
|
fovtrack = tracks[0]
|
|
jumptrack = tracks[1]
|
|
|
|
|
|
for j in 0..jumptrack.keys.length
|
|
|
|
if jumptrack.keys[j].to_s == '1.0'
|
|
|
|
if j + 2 < jumptrack.keys.length
|
|
curr = fovtrack.keys[j].to_f
|
|
currplus1 = fovtrack.keys[j+1].to_f
|
|
currplus2 = fovtrack.keys[j+2].to_f
|
|
diff = currplus2 - currplus1
|
|
|
|
if curr == currplus1 and currplus1 != currplus2 and diff.abs > FOV_TOLERANCE
|
|
@bustedscenesinfo.push(animtext + ": " + jumptrack.owner + ": " + j.to_s) #if @bustedscenes.rindex(jumptrack.owner) == nil
|
|
@bustedscenes.push(jumptrack.owner) if @bustedscenes.rindex(jumptrack.owner) == nil
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
print("SCENES\n")
|
|
@bustedscenes.each { |scenename|
|
|
print(scenename + "\n")
|
|
}
|
|
print("\n\n")
|
|
print("DETAILS\n")
|
|
@bustedscenesinfo.each { |info|
|
|
print(info + "\n")
|
|
}
|
|
end
|
|
|
|
def build_anim_list(animlist, rootpath)
|
|
|
|
Find.find( rootpath ) do |subpath|
|
|
if FileTest.file?( subpath )
|
|
subfile = Pipeline::OS::Path.get_basename(subpath)
|
|
if subfile[0,6] == KEYNAME
|
|
animlist.push(subpath)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
def batch_anim_to_text()
|
|
@animlist.each { |animfile|
|
|
anim_to_text(animfile)
|
|
}
|
|
end
|
|
|
|
def anim_to_text( file )
|
|
scenename = Pipeline::OS::Path.get_trailing_directory(file)
|
|
outputpath = OUTPUT_ROOT + scenename + "/"
|
|
FileUtils.mkdir_p outputpath if File.directory?(outputpath) == false
|
|
outputfile = outputpath + "/" + Pipeline::OS::Path.get_basename(file) + ".txt"
|
|
|
|
cmd = "x:/tools_release/gta_bin/anim2text.exe " + file + " " + outputfile
|
|
|
|
retval = system(cmd)
|
|
if retval
|
|
@animtextlist.push(outputfile)
|
|
else
|
|
@animtestlistfailed.push(outputfile)
|
|
end
|
|
end
|
|
|
|
|
|
end
|
|
|
|
#
|
|
# == Description
|
|
#
|
|
# Parser for output from anim2text
|
|
#
|
|
class AnimationParser
|
|
attr_reader :tracks
|
|
|
|
def AnimationParser.parse(filename, trackids)
|
|
@tracks = Array.new()
|
|
File.open( filename, 'r' ) { |animfile|
|
|
|
|
while animfile.eof == false do
|
|
currentline = animfile.readline
|
|
segs = currentline.split(':')
|
|
if segs.length == 2
|
|
if segs[0] == 'track type'
|
|
subsegs = segs[1].split(' ')
|
|
if subsegs.length == 2
|
|
trackid = subsegs[1].tr('()', '').to_i
|
|
for targettrackid in trackids do
|
|
if trackid == targettrackid
|
|
track = Track.new()
|
|
track.tracktype = trackid
|
|
|
|
track.owner = Pipeline::OS::Path.get_trailing_directory(filename)
|
|
|
|
@tracks.push(AnimationParser.build_track(animfile, track))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
}
|
|
@tracks
|
|
end
|
|
|
|
def AnimationParser.build_track(animfile, track)
|
|
|
|
track.keys = Array.new()
|
|
|
|
finished = false
|
|
currentline = animfile.readline
|
|
currentline = animfile.readline
|
|
while animfile.eof == false and finished == false do
|
|
segs = currentline.split(':')
|
|
if segs.length == 2
|
|
if segs[0].slice(0..2) == 'key'
|
|
track.keys.push(segs[1].to_f)
|
|
else
|
|
finished = true
|
|
end
|
|
else
|
|
finished = true
|
|
end
|
|
currentline = animfile.readline
|
|
end
|
|
track
|
|
end
|
|
|
|
end
|
|
#
|
|
# == Description
|
|
#
|
|
# Track class. Could really be a struct
|
|
#
|
|
class Track
|
|
attr_reader :owner
|
|
attr_reader :boneid
|
|
attr_reader :tracktype
|
|
attr_reader :keys
|
|
|
|
def owner=( value )
|
|
@owner = value
|
|
end
|
|
|
|
def boneid=( value )
|
|
@boneid = value
|
|
end
|
|
|
|
def tracktype=( value )
|
|
@tracktype = value
|
|
end
|
|
|
|
def keys=( value )
|
|
@keys = value
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
animparser = Animation::AnimationParserManager.new(true)
|
|
|