mirror of
				https://github.com/OpenFusionProject/scripts.git
				synced 2025-11-03 20:40:34 +00:00 
			
		
		
		
	Compare commits
	
		
			6 Commits
		
	
	
		
			08c7ec1278
			...
			869d5b1976
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					869d5b1976 | ||
| 
						 | 
					8725dd1e4e | ||
| 
						 | 
					8fbe59e5a1 | ||
| 
						 | 
					a53fb21621 | ||
| 
						 | 
					9dd5db86eb | ||
| 
						 | 
					4ace5f065f | 
							
								
								
									
										2
									
								
								dx2cg/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								dx2cg/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
__pycache__
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										11
									
								
								dx2cg/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								dx2cg/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
# dx2cg
 | 
			
		||||
Tools for converting d3d9 shader assembly to HLSL/Cg.
 | 
			
		||||
- `disassembler.py`: Takes in d3d9 assembly and gives back the HLSL equivalent.
 | 
			
		||||
- `swapper.py`: Searches a shader file for d3d9 assembly and calls the disassembler to replace it with HLSL.
 | 
			
		||||
- `main.py`: Executes the swapper on every file in a path, writing the changes to new files.
 | 
			
		||||
 | 
			
		||||
## Known issues
 | 
			
		||||
- Only vertex shaders with profile `vs_1_1` are supported
 | 
			
		||||
- No fragment shaders are supported yet
 | 
			
		||||
- Only one subprogram in a subshader will be converted (for now)
 | 
			
		||||
- Only a limited set of instructions (those used by FF and Unity 2.6) are supported
 | 
			
		||||
							
								
								
									
										308
									
								
								dx2cg/disassembler.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										308
									
								
								dx2cg/disassembler.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,308 @@
 | 
			
		||||
#!/usr/bin/env python
 | 
			
		||||
# coding: utf-8
 | 
			
		||||
# d3d9 to cg crude dissassembler
 | 
			
		||||
# ycc 08/08/2022
 | 
			
		||||
 | 
			
		||||
import re
 | 
			
		||||
import sys
 | 
			
		||||
 | 
			
		||||
legacy = False # True for 2.6
 | 
			
		||||
 | 
			
		||||
reserved = {
 | 
			
		||||
    "_Time",
 | 
			
		||||
    "_SinTime",
 | 
			
		||||
    "_CosTime",
 | 
			
		||||
    
 | 
			
		||||
    "_ProjectionParams",
 | 
			
		||||
    
 | 
			
		||||
    "_PPLAmbient",
 | 
			
		||||
    
 | 
			
		||||
    "_ObjectSpaceCameraPos",
 | 
			
		||||
    "_ObjectSpaceLightPos0",
 | 
			
		||||
    "_ModelLightColor0",
 | 
			
		||||
    "_SpecularLightColor0",
 | 
			
		||||
    
 | 
			
		||||
    "_Light2World0", "_World2Light0", "_Object2World", "_World2Object", "_Object2Light0",
 | 
			
		||||
    
 | 
			
		||||
    "_LightDirectionBias",
 | 
			
		||||
    "_LightPositionRange",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
decls = {
 | 
			
		||||
    "dcl_position": "float4 {0} = vardat.vertex;",
 | 
			
		||||
    "dcl_normal": "float4 {0} = float4(vardat.normal.x, vardat.normal.y, vardat.normal.z, 0);",
 | 
			
		||||
    "dcl_texcoord0": "float4 {0} = vardat.texcoord;",
 | 
			
		||||
    "dcl_texcoord1": "float4 {0} = vardat.texcoord1;",
 | 
			
		||||
    "dcl_color": "float4 {0} = vardat.color;",
 | 
			
		||||
    "def": "const float4 {0} = float4({1}, {2}, {3}, {4});",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ops = {
 | 
			
		||||
    "mov": "{0} = {1};",
 | 
			
		||||
    "add": "{0} = {1} + {2};",
 | 
			
		||||
    "mul": "{0} = {1} * {2};",
 | 
			
		||||
    "mad": "{0} = {1} * {2} + {3};",
 | 
			
		||||
    "dp4": "{0} = dot((float4){1}, (float4){2});",
 | 
			
		||||
    "dp3": "{0} = dot((float3){1}, (float3){2});",
 | 
			
		||||
    "min": "{0} = min({1}, {2});",
 | 
			
		||||
    "max": "{0} = max({1}, {2});",
 | 
			
		||||
    "rsq": "{0} = rsqrt({1});",
 | 
			
		||||
    "frc": "{0} = float4({1}.x - (float)floor({1}.x), {1}.y - (float)floor({1}.y), {1}.z - (float)floor({1}.z), {1}.w - (float)floor({1}.w));",
 | 
			
		||||
    "slt": "{0} = float4(({1}.x < {2}.x) ? 1.0f : 0.0f, ({1}.y < {2}.y) ? 1.0f : 0.0f, ({1}.z < {2}.z) ? 1.0f : 0.0f, ({1}.w < {2}.w) ? 1.0f : 0.0f);",
 | 
			
		||||
    "sge": "{0} = float4(({1}.x >= {2}.x) ? 1.0f : 0.0f, ({1}.y >= {2}.y) ? 1.0f : 0.0f, ({1}.z >= {2}.z) ? 1.0f : 0.0f, ({1}.w >= {2}.w) ? 1.0f : 0.0f);",
 | 
			
		||||
    "rcp": "{0} = ({1} == 0.0f) ? FLT_MAX : (({1} == 1.0f) ? {1} : (1 / {1}));",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct_appdata = """struct appdata {
 | 
			
		||||
\tfloat4 vertex : POSITION;
 | 
			
		||||
\tfloat3 normal : NORMAL;
 | 
			
		||||
\tfloat4 texcoord : TEXCOORD0;
 | 
			
		||||
\tfloat4 texcoord1 : TEXCOORD1;
 | 
			
		||||
\tfloat4 tangent : TANGENT;
 | 
			
		||||
\tfloat4 color : COLOR;
 | 
			
		||||
};
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
v2f_postype = "POSITION" if legacy else "SV_POSITION"
 | 
			
		||||
struct_v2f = f"""struct v2f {{
 | 
			
		||||
\tfloat4 pos : {v2f_postype};
 | 
			
		||||
\tfloat4 t0 : TEXCOORD0;
 | 
			
		||||
\tfloat4 t1 : TEXCOORD1;
 | 
			
		||||
\tfloat4 t2 : TEXCOORD2;
 | 
			
		||||
\tfloat4 t3 : TEXCOORD3;
 | 
			
		||||
\tfloat fog : FOG;
 | 
			
		||||
\tfloat4 d0 : COLOR0;
 | 
			
		||||
\tfloat4 d1 : COLOR1;
 | 
			
		||||
}};
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
cg_header = """CGPROGRAM
 | 
			
		||||
#include "UnityCG.cginc"
 | 
			
		||||
#pragma exclude_renderers xbox360 ps3 gles
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
cg_footer = """ENDCG"""
 | 
			
		||||
 | 
			
		||||
vertex_header = """v2f vert(appdata vardat) {
 | 
			
		||||
\tfloat4 r0, r1, r2, r3, r4;
 | 
			
		||||
\tfloat4 tmp;
 | 
			
		||||
\tv2f o;
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
vertex_footer = """\treturn o;
 | 
			
		||||
}"""
 | 
			
		||||
 | 
			
		||||
def process_header(prog):
 | 
			
		||||
    keywords = []
 | 
			
		||||
    header = []
 | 
			
		||||
    loctab = {}
 | 
			
		||||
    locdecl = []
 | 
			
		||||
    binds = []
 | 
			
		||||
    i = 0
 | 
			
		||||
    lighting = False
 | 
			
		||||
    textures = 0
 | 
			
		||||
    while i < len(prog):
 | 
			
		||||
        line = prog[i]
 | 
			
		||||
        if line.startswith("Keywords"):
 | 
			
		||||
            keywords = re.findall("\"[\w\d]+\"", line)
 | 
			
		||||
            del prog[i]
 | 
			
		||||
            i = i - 1
 | 
			
		||||
        elif line.startswith("Bind"):
 | 
			
		||||
            binds.append(line)
 | 
			
		||||
            del prog[i]
 | 
			
		||||
            i = i - 1
 | 
			
		||||
        elif line.startswith("Local") or line.startswith("Matrix"):
 | 
			
		||||
            dec = line.split(' ')
 | 
			
		||||
            key = int(dec[1][:-1])
 | 
			
		||||
            if dec[2][0] == '[':
 | 
			
		||||
                # singleton
 | 
			
		||||
                val = dec[2][1:-1]
 | 
			
		||||
                if val[0] == '_' and val not in reserved:
 | 
			
		||||
                    loctype = "float4" if dec[0] == "Local" else "float4x4"
 | 
			
		||||
                    locdecl.append(f"{loctype} {val};")
 | 
			
		||||
            elif dec[2][0] == '(':
 | 
			
		||||
                #components
 | 
			
		||||
                vals = dec[2][1:-1].split(',')
 | 
			
		||||
                for j, v in enumerate(vals):
 | 
			
		||||
                    if v[0] == '[':
 | 
			
		||||
                        vals[j] = v[1:-1]
 | 
			
		||||
                        if vals[j][0] == '_' and vals[j] not in reserved:
 | 
			
		||||
                            locdecl.append(f"float {vals[j]};")
 | 
			
		||||
                val = f"float4({vals[0]},{vals[1]},{vals[2]},{vals[3]})"
 | 
			
		||||
            
 | 
			
		||||
            lightval = re.match("glstate_light(\d)_([a-zA-Z]+)", val)
 | 
			
		||||
            if lightval:
 | 
			
		||||
                val = f"glstate.light[{lightval[1]}].{lightval[2]}"
 | 
			
		||||
                lighting = True
 | 
			
		||||
            elif val == "glstate_lightmodel_ambient":
 | 
			
		||||
                val = "glstate.lightmodel.ambient"
 | 
			
		||||
                lighting = True
 | 
			
		||||
            elif val.startswith("glstate_matrix_texture"):
 | 
			
		||||
                val = f"glstate.matrix.texture[{val[-1]}]" if legacy else f"UNITY_MATRIX_TEXTURE{val[-1]}"
 | 
			
		||||
            elif val == "glstate_matrix_mvp":
 | 
			
		||||
                val = "glstate.matrix.mvp" if legacy else "UNITY_MATRIX_MVP"
 | 
			
		||||
            elif val == "glstate_matrix_modelview0":
 | 
			
		||||
                val = "glstate.matrix.modelview[0]" if legacy else "UNITY_MATRIX_MV"
 | 
			
		||||
            elif val == "glstate_matrix_transpose_modelview0":
 | 
			
		||||
                val = "glstate.matrix.transpose.modelview[0]" if legacy else "UNITY_MATRIX_T_MV"
 | 
			
		||||
            elif val == "glstate_matrix_invtrans_modelview0":
 | 
			
		||||
                val = "glstate.matrix.invtrans.modelview[0]" if legacy else "UNITY_MATRIX_IT_MV"
 | 
			
		||||
            elif val.startswith("glstate"):
 | 
			
		||||
                raise ValueError(f"Unrecognized glstate: {val}")
 | 
			
		||||
                
 | 
			
		||||
            if dec[0] == "Local":
 | 
			
		||||
                loctab[f"c{key}"] = val
 | 
			
		||||
            elif dec[0] == "Matrix":
 | 
			
		||||
                for offset in range(0,4):
 | 
			
		||||
                    loctab[f"c{key + offset}"] = f"{val}[{offset}]"
 | 
			
		||||
            
 | 
			
		||||
            del prog[i]
 | 
			
		||||
            i = i - 1
 | 
			
		||||
        elif line.startswith("SetTexture"):
 | 
			
		||||
            dec = line.split(' ')
 | 
			
		||||
            if dec[2] !=  "{2D}":
 | 
			
		||||
                raise ValueError(f"Unknown texture type {dec[2]}")
 | 
			
		||||
            key = f"s{textures}"
 | 
			
		||||
            val = dec[1][1:-1]
 | 
			
		||||
            loctab[key] = val
 | 
			
		||||
            textures = textures + 1
 | 
			
		||||
 | 
			
		||||
            del prog[i]
 | 
			
		||||
            i = i - 1
 | 
			
		||||
        i = i + 1
 | 
			
		||||
        
 | 
			
		||||
    if len(binds) > 0:
 | 
			
		||||
        header.append("BindChannels {")
 | 
			
		||||
        for b in binds:
 | 
			
		||||
            header.append(f"\t{b}")
 | 
			
		||||
        header.append("}")
 | 
			
		||||
    
 | 
			
		||||
    if lighting:
 | 
			
		||||
        header.append("Lighting On")
 | 
			
		||||
 | 
			
		||||
    # print(loctab)
 | 
			
		||||
    
 | 
			
		||||
    return (keywords, header, loctab, locdecl)
 | 
			
		||||
 | 
			
		||||
def resolve_args(args, loctab, consts):
 | 
			
		||||
    for a in range(0, len(args)):
 | 
			
		||||
        arg = args[a]
 | 
			
		||||
        
 | 
			
		||||
        neg = ""
 | 
			
		||||
        if arg[0] == '-':
 | 
			
		||||
            arg = arg[1:]
 | 
			
		||||
            neg = "-"
 | 
			
		||||
        
 | 
			
		||||
        # save swizzler!
 | 
			
		||||
        dot = arg.find(".")
 | 
			
		||||
        if dot > -1:
 | 
			
		||||
            swiz = arg[dot:]
 | 
			
		||||
            arg = arg[:dot]
 | 
			
		||||
        else:
 | 
			
		||||
            swiz = ""
 | 
			
		||||
        
 | 
			
		||||
        if arg[0] == 'r':
 | 
			
		||||
            pass
 | 
			
		||||
        elif arg[0] == 'v':
 | 
			
		||||
            pass
 | 
			
		||||
        elif arg[0] == 'c':
 | 
			
		||||
            if arg not in consts:
 | 
			
		||||
                arg = loctab[arg]
 | 
			
		||||
        elif arg[0] == 's':
 | 
			
		||||
            arg = loctab[arg]
 | 
			
		||||
        elif arg[0] == 'o':
 | 
			
		||||
            arg = f"o.{arg[1:].lower()}"
 | 
			
		||||
        elif re.match("[+-]?([0-9]*[.])?[0-9]+", arg):
 | 
			
		||||
            pass
 | 
			
		||||
        else:
 | 
			
		||||
            raise ValueError(f"Unknown arg {arg}")
 | 
			
		||||
        
 | 
			
		||||
        args[a] = neg + arg + swiz
 | 
			
		||||
 | 
			
		||||
def decode(code, args):
 | 
			
		||||
    if code in decls:
 | 
			
		||||
        return [decls[code].format(*args)]
 | 
			
		||||
    elif code in ops:
 | 
			
		||||
        target = args[0]
 | 
			
		||||
        if target == "o.fog":
 | 
			
		||||
            return [ops[code].format(*args)]
 | 
			
		||||
        
 | 
			
		||||
        dot = re.search("\.[xyzw]+", target)
 | 
			
		||||
        if dot:
 | 
			
		||||
            swiz = target[dot.start()+1:]
 | 
			
		||||
            target = target[:dot.start()]
 | 
			
		||||
        else:
 | 
			
		||||
            swiz = "xyzw"
 | 
			
		||||
        
 | 
			
		||||
        lines = [ops[code].format("tmp", *args[1:])]
 | 
			
		||||
        for c in swiz:
 | 
			
		||||
            lines.append(f"{target}.{c} = tmp.{c};")
 | 
			
		||||
        return lines
 | 
			
		||||
    else:
 | 
			
		||||
        raise ValueError(f"Unknown code {code}")
 | 
			
		||||
 | 
			
		||||
def process_asm(asm, loctab):
 | 
			
		||||
    shadertype = ""
 | 
			
		||||
    if asm[0] == "\"vs_1_1":
 | 
			
		||||
        shadertype = "vertex"
 | 
			
		||||
    else:
 | 
			
		||||
        raise ValueError(f"Unsupported shader type: {asm[0][1:]}")
 | 
			
		||||
    
 | 
			
		||||
    consts = set()
 | 
			
		||||
    translated = []
 | 
			
		||||
    i = 1
 | 
			
		||||
    while i < len(asm):
 | 
			
		||||
        instruction = asm[i]
 | 
			
		||||
        if instruction == "\"":
 | 
			
		||||
            break
 | 
			
		||||
        
 | 
			
		||||
        space = instruction.find(" ")
 | 
			
		||||
        if space == -1:
 | 
			
		||||
            code = instruction
 | 
			
		||||
            args = []
 | 
			
		||||
        else:
 | 
			
		||||
            code = instruction[:space]
 | 
			
		||||
            args = instruction[space+1:].split(", ")
 | 
			
		||||
 | 
			
		||||
        if code == "def":
 | 
			
		||||
            consts.add(args[0])
 | 
			
		||||
            
 | 
			
		||||
        resolve_args(args, loctab, consts)
 | 
			
		||||
        disasm = decode(code, args)
 | 
			
		||||
        # print(f"{instruction} \t==>\t{disasm}")
 | 
			
		||||
        disasm.insert(0, f"// {instruction}")
 | 
			
		||||
        translated.extend(disasm)
 | 
			
		||||
        i = i + 1
 | 
			
		||||
    
 | 
			
		||||
    return (shadertype, translated)
 | 
			
		||||
 | 
			
		||||
def disassemble(text):
 | 
			
		||||
    asm = text.split('\n')[1:-1]
 | 
			
		||||
    (keywords, header, loctab, locdecl) = process_header(asm)
 | 
			
		||||
    (shadertype, disasm) = process_asm(asm, loctab)
 | 
			
		||||
    
 | 
			
		||||
    text = "\n".join(header) + "\n"
 | 
			
		||||
    text += cg_header
 | 
			
		||||
    if keywords:
 | 
			
		||||
        text += "#pragma multi_compile " + " ".join(keywords)
 | 
			
		||||
    if shadertype == "vertex":
 | 
			
		||||
        text += "#pragma vertex vert\n\n"
 | 
			
		||||
        text += struct_appdata + "\n"
 | 
			
		||||
        text += struct_v2f + "\n"
 | 
			
		||||
    text += "\n".join(locdecl) + "\n"
 | 
			
		||||
    if shadertype == "vertex":
 | 
			
		||||
        text += vertex_header + "\n"
 | 
			
		||||
    text += "\t" + "\n\t".join(disasm) + "\n\n"
 | 
			
		||||
    if shadertype == "vertex":
 | 
			
		||||
        text += vertex_footer + "\n"
 | 
			
		||||
    text += cg_footer
 | 
			
		||||
    return text
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    if len(sys.argv) < 2:
 | 
			
		||||
        print("Usage: disassembler.py <filename>")
 | 
			
		||||
    else:
 | 
			
		||||
        with open(sys.argv[1], "r") as fi:
 | 
			
		||||
            buf = fi.read()
 | 
			
		||||
        disasm = disassemble(buf)
 | 
			
		||||
        print(disasm)
 | 
			
		||||
							
								
								
									
										37
									
								
								dx2cg/main.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								dx2cg/main.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
#!/usr/bin/env python
 | 
			
		||||
# coding: utf-8
 | 
			
		||||
 | 
			
		||||
import os
 | 
			
		||||
import sys
 | 
			
		||||
from swapper import process
 | 
			
		||||
 | 
			
		||||
def process_file(filename, suffix):
 | 
			
		||||
    dot = filename.rfind(".")
 | 
			
		||||
    if dot > -1:
 | 
			
		||||
        outfile_name = filename[:dot] + suffix + filename[dot:]
 | 
			
		||||
    else:
 | 
			
		||||
        outfile_name = filename + suffix
 | 
			
		||||
    return process(filename, outfile_name)
 | 
			
		||||
 | 
			
		||||
def process_batch(path, suffix="_hlsl"):
 | 
			
		||||
    files = os.listdir(path)
 | 
			
		||||
    for f in files:
 | 
			
		||||
        if os.path.isdir(f):
 | 
			
		||||
            process_batch(f"{path}/{f}")
 | 
			
		||||
        else:
 | 
			
		||||
            try:
 | 
			
		||||
                if process_file(f"{path}/{f}", suffix):
 | 
			
		||||
                    print(f"Processed {f}")
 | 
			
		||||
                else:
 | 
			
		||||
                    print(f"Skipping {f}")
 | 
			
		||||
            except ValueError as err:
 | 
			
		||||
                print(f"Failed to process {f}: {err}")
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    if len(sys.argv) < 2:
 | 
			
		||||
        print("Usage: main.py <folder> [outfile-suffix]")
 | 
			
		||||
    elif len(sys.argv) == 2:
 | 
			
		||||
        process_batch(sys.argv[1])
 | 
			
		||||
    else:
 | 
			
		||||
        process_batch(*sys.argv[1:3])
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										71
									
								
								dx2cg/swapper.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								dx2cg/swapper.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
			
		||||
#!/usr/bin/env python
 | 
			
		||||
# coding: utf-8
 | 
			
		||||
# parser for replacing d3d9 subprograms in shaderlab files with HLSL/CG
 | 
			
		||||
# ycc 08/08/2022
 | 
			
		||||
 | 
			
		||||
import re
 | 
			
		||||
import sys
 | 
			
		||||
from disassembler import disassemble
 | 
			
		||||
 | 
			
		||||
tabs = 3
 | 
			
		||||
def indent(block):
 | 
			
		||||
    lines = block.split('\n')
 | 
			
		||||
    for i in range(0, len(lines)-1):
 | 
			
		||||
        lines[i] = tabs * "\t" + lines[i]
 | 
			
		||||
    return "\n".join(lines)
 | 
			
		||||
 | 
			
		||||
def find_closing_bracket(block, i):
 | 
			
		||||
    count = 0
 | 
			
		||||
    while i < len(block):
 | 
			
		||||
        if block[i] == '{':
 | 
			
		||||
            count = count + 1
 | 
			
		||||
        if block[i] == '}':
 | 
			
		||||
            count = count - 1
 | 
			
		||||
            if count == 0:
 | 
			
		||||
                return i
 | 
			
		||||
        i = i + 1
 | 
			
		||||
    raise ValueError(f"Block at {i} has no closing bracket")
 | 
			
		||||
 | 
			
		||||
def process_program(prog):
 | 
			
		||||
    subprog_index = prog.find("SubProgram \"d3d9")
 | 
			
		||||
    if subprog_index == -1:
 | 
			
		||||
        raise ValueError(f"Program has no d3d9 subprogram")
 | 
			
		||||
    subprog_end_index = find_closing_bracket(prog, subprog_index)
 | 
			
		||||
    subprog = prog[subprog_index:subprog_end_index+1]
 | 
			
		||||
    processed = disassemble(subprog) + "\n"
 | 
			
		||||
    return indent(processed)
 | 
			
		||||
 | 
			
		||||
def process_shader(shader):
 | 
			
		||||
    buf = shader
 | 
			
		||||
    processed = ''
 | 
			
		||||
    program_index = buf.find('Program')
 | 
			
		||||
    while program_index > -1:
 | 
			
		||||
        processed = processed + buf[:program_index]
 | 
			
		||||
        buf = buf[program_index:]
 | 
			
		||||
        line = re.search("#LINE [0-9]+\n", buf)
 | 
			
		||||
        if not line:
 | 
			
		||||
            raise ValueError(f"Program at {program_index} has no #LINE marker")
 | 
			
		||||
        end_index = line.end() + 1
 | 
			
		||||
        program_section = buf[program_index:end_index+1]
 | 
			
		||||
        processed = processed + process_program(program_section)
 | 
			
		||||
        buf = buf[end_index+1:]
 | 
			
		||||
        
 | 
			
		||||
        program_index = buf.find('Program')
 | 
			
		||||
    processed = processed + buf
 | 
			
		||||
    return processed
 | 
			
		||||
 | 
			
		||||
def process(fn_in, fn_out):
 | 
			
		||||
    with open(fn_in, "r") as fi:
 | 
			
		||||
        buf = fi.read()
 | 
			
		||||
        processed = process_shader(buf)
 | 
			
		||||
    if buf != processed:
 | 
			
		||||
        with open(fn_out, "w") as fo:
 | 
			
		||||
            fo.write(processed)
 | 
			
		||||
        return True
 | 
			
		||||
    return False
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    if len(sys.argv) < 3:
 | 
			
		||||
        print("Usage: swapper.py <file-in> <file-out>")
 | 
			
		||||
    else:
 | 
			
		||||
        process(*sys.argv[1:3])
 | 
			
		||||
		Reference in New Issue
	
	Block a user