Files
gtav-src/tools_ng/lib/util/anim/cutscene_cam_parser.rb
2025-09-29 00:52:08 +02:00

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)