Files
PDModdingCommunity_PD-Loader/source-code/data/amd-tools/AFT Shader Patcher/aft_shader_patcher.py
T

122 lines
4.4 KiB
Python

import sys
from os import chdir, makedirs, get_terminal_size
from os.path import join as joinpath, splitext, isfile, exists, dirname, abspath
import pyfarc
import importlib, importlib.util
if getattr(sys, 'frozen', False):
datadir = dirname(sys.executable)
else:
datadir = dirname(__file__)
arbpatcher_dir = joinpath(datadir, 'ARB Patcher')
arbpatcher_gamesettings_dir = joinpath(arbpatcher_dir, 'gamesettings')
sys.path = [arbpatcher_dir] + sys.path
import main as ArbPatcher
sys.path = sys.path[1:]
game_settings_spec = importlib.util.spec_from_file_location('divaaft', joinpath(arbpatcher_gamesettings_dir, 'divaaft.py'))
game_settings_module = importlib.util.module_from_spec(game_settings_spec)
game_settings_spec.loader.exec_module(game_settings_module)
# not bothering to check for main here because it's just a glue script anyway
def get_args():
import argparse
parser = argparse.ArgumentParser(description='AFT Shader Patcher: Patches Nvidia-only ARB shaders from PDAFT to work on AMD. Patching techniques from Nezarn; implementation by somewhatlurker.')
parser.add_argument('-i', '--in_farc', default='shader.farc', help='input shader farc file (default: "shader.farc")')
parser.add_argument('-o', '--out_farc', default='shader_patched.farc', help='output shader farc file (default: "shader_patched.farc")')
parser.add_argument('-c', '--compress', action='store_true', help='force use of farc compression (this mey produce larger vcdiff files)')
parser.add_argument('-x', '--xdelta', action='store_true', help='generate a vcdiff patch file')
return parser.parse_args()
args = get_args()
print("AFT Shader Patcher")
print("==================")
print("Patching techniques from Nezarn; implementation by somewhatlurker")
print("=================================================================")
print("Input file: '{}'".format(args.in_farc))
print("Output file: '{}'".format(args.out_farc))
if not exists(args.in_farc):
print ("'{}' does not exist. Aborting".format(args.in_farc))
sys.exit()
elif not isfile(args.in_farc):
print ("'{}' is not a file. Aborting".format(args.in_farc))
sys.exit()
if exists(args.out_farc):
if not isfile(args.out_farc):
print ("'{}' already exists but is a directory. Aborting".format(args.out_farc))
sys.exit()
with open(args.in_farc, 'rb') as f:
farcdata = pyfarc.from_stream(f)
if args.xdelta:
f.seek(0)
from binascii import crc32
in_farc_crc_str = '{:08x}'.format(crc32(f.read()))
proc_count = 0
last_status_len = 0
for fname in farcdata['files']:
proc_count += 1
progress_val = proc_count / len(farcdata['files'])
progress_cnt_X = int(progress_val * 20)
status_str = '\r[{e:{s1}<{n1}}{e:{s2}<{n2}}]'.format(e='', s1='X', s2='-', n1=progress_cnt_X, n2=20-progress_cnt_X)
status_str += ' {:.2%}'.format(progress_val)
status_str += ' ' + fname
try:
terminal_width = get_terminal_size()[0]
except:
terminal_width = 120
if len(status_str) > terminal_width:
status_str = status_str[:terminal_width-3] + '...'
# fix characters left on screen from a previous longer line
# (without cursor staying off to the side)
this_status_len = len(status_str)
if this_status_len < last_status_len:
status_str = '{: <{l}}'.format(status_str, l=last_status_len)
last_status_len = this_status_len
print (status_str, end='')
if game_settings_module and game_settings_module.filename_filter:
openname = game_settings_module.filename_filter(fname)
else:
openname = fname
f_lines = farcdata['files'][openname]['data'].decode('utf-8').splitlines(keepends=True)
f_full = ArbPatcher.patch_shader(fname, f_lines, game_settings_module, True)
farcdata['files'][fname]['data'] = f_full.encode('utf-8')
print('')
if args.compress:
farcdata['farc_type'] = 'FArC'
with open(args.out_farc, 'wb') as f:
pyfarc.to_stream(farcdata, f, no_copy=True)
if args.xdelta:
import subprocess
# make paths absolute before running this (actually not needed)
#args.in_farc = abspath(args.in_farc)
#args.out_farc = abspath(args.out_farc)
subprocess.run([joinpath(datadir, 'xdelta3.exe'), '-e', '-f', '-S', 'none', '-s', args.in_farc, args.out_farc, joinpath(dirname(args.out_farc), in_farc_crc_str + '.vcdiff')], )
print ("Generated '{}.vcdiff'".format(in_farc_crc_str))