Compare commits

..

5 Commits

Author SHA1 Message Date
CakeLancelot
a3856cdc9d
Merge pull request #2 from CakeLancelot/main
dx2cg: Allow usage as module and handle a few more features used by built-in Unity shaders
2024-02-14 05:11:14 -06:00
CakeLancelot
672d7e2b42 Address PR review comments 2024-02-14 03:15:09 -06:00
CakeLancelot
d5b58d96da dx2cg: Implement RECT, CUBE texture types
Also tried to implement 3D texture type, but that will likely require a few other instructions to get working - namely texldp and dcl_volume.
2024-02-13 03:18:19 -06:00
CakeLancelot
06869164a1 dx2cg: Implement mov_sat instruction
Basically just mov but clamp the result.
https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx9-graphics-reference-asm-ps-instructions-modifiers-ps-2-0#saturate
2024-02-13 03:18:19 -06:00
CakeLancelot
99c80c9c7b dx2cg: Allow usage as Python module
e.g.
from dx2cg.swapper import process_shader
cg_shader = process_shader(text)
2024-02-13 01:40:07 -06:00
4 changed files with 40 additions and 11 deletions

0
dx2cg/__init__.py Normal file
View File

View File

@ -41,6 +41,7 @@ decls = {
ops = { ops = {
"mov": "{0} = {1};", "mov": "{0} = {1};",
"mov_sat": "{0} = clamp({1}, 0.0, 1.0)",
"add": "{0} = {1} + {2};", "add": "{0} = {1} + {2};",
"mul": "{0} = {1} * {2};", "mul": "{0} = {1} * {2};",
"mad": "{0} = {1} * {2} + {3};", "mad": "{0} = {1} * {2} + {3};",
@ -53,7 +54,7 @@ ops = {
"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);", "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);", "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}));", "rcp": "{0} = ({1} == 0.0f) ? FLT_MAX : (({1} == 1.0f) ? {1} : (1 / {1}));",
"texld": "{0} = tex2D({2}, (float2){1});", "texld": "{0} = {3}({2}, (float2){1});",
} }
struct_a2v = """struct a2v { struct_a2v = """struct a2v {
@ -185,12 +186,20 @@ def process_header(prog):
i = i - 1 i = i - 1
elif line.startswith("SetTexture"): elif line.startswith("SetTexture"):
dec = line.split(' ') dec = line.split(' ')
if dec[2] != "{2D}": if dec[2] == "{2D}":
texture_type = "sampler2D"
elif dec[2] == "{3D}":
texture_type = "sampler3D"
elif dec[2] == "{RECT}":
texture_type = "samplerRECT"
elif dec[2] == "{CUBE}":
texture_type = "samplerCUBE"
else:
raise ValueError(f"Unknown texture type {dec[2]}") raise ValueError(f"Unknown texture type {dec[2]}")
key = f"s{textures}" key = f"s{textures}"
val = dec[1][1:-1] val = dec[1][1:-1]
loctab[key] = val loctab[key] = val
locdecl.append(f"sampler2D {val};") locdecl.append(f"{texture_type} {val};")
textures = textures + 1 textures = textures + 1
del prog[i] del prog[i]
@ -238,7 +247,23 @@ def resolve_args(args, loctab, consts):
args[a] = neg + arg + swiz args[a] = neg + arg + swiz
def decode(code, args): def get_cgtex_type(name, locdecl):
for loc in locdecl:
loc = loc.split(' ')
if name == loc[1][:-1]:
if loc[0] == 'sampler2D':
return "tex2D"
elif loc[0] == 'sampler3D':
return "tex3D"
elif loc[0] == 'samplerCUBE':
return "texCUBE"
elif loc[0] == 'samplerRECT':
return "texRECT"
else:
raise ValueError(f"Unknown CG texture type {loc[0]}")
raise ValueError(f"Could not find texture {name} in locals")
def decode(code, args, locdecl):
if code in decls: if code in decls:
return [decls[code].format(*args)] return [decls[code].format(*args)]
elif code in ops: elif code in ops:
@ -253,14 +278,18 @@ def decode(code, args):
else: else:
swiz = "xyzw" swiz = "xyzw"
lines = [ops[code].format("tmp", *args[1:])] if code == "texld":
lines = [ops[code].format("tmp", *args[1:], get_cgtex_type(args[2], locdecl))]
else:
lines = [ops[code].format("tmp", *args[1:])]
for c in swiz: for c in swiz:
lines.append(f"{target}.{c} = tmp.{c};") lines.append(f"{target}.{c} = tmp.{c};")
return lines return lines
else: else:
raise ValueError(f"Unknown opcode {code}") raise ValueError(f"Unknown opcode {code}")
def process_asm(asm, loctab): def process_asm(asm, loctab, locdecl):
shadertype = "" shadertype = ""
if asm[0] == "\"vs_1_1": if asm[0] == "\"vs_1_1":
shadertype = "vertex" shadertype = "vertex"
@ -293,7 +322,7 @@ def process_asm(asm, loctab):
code = code[:pp] code = code[:pp]
resolve_args(args, loctab, consts) resolve_args(args, loctab, consts)
disasm = decode(code, args) disasm = decode(code, args, locdecl)
# print(f"{instruction} \t==>\t{disasm}") # print(f"{instruction} \t==>\t{disasm}")
disasm.insert(0, f"// {instruction}") disasm.insert(0, f"// {instruction}")
translated.extend(disasm) translated.extend(disasm)
@ -316,7 +345,7 @@ def disassemble(blocks):
binds.update(bds) binds.update(bds)
lighting |= light lighting |= light
(shadertype, disasm) = process_asm(asm, ltab) (shadertype, disasm) = process_asm(asm, ltab, locdecl)
shaders[shadertype] = disasm shaders[shadertype] = disasm
text = "" text = ""

View File

@ -3,7 +3,7 @@
import os import os
import sys import sys
from swapper import process from .swapper import process
def process_file(filename, suffix): def process_file(filename, suffix):
dot = filename.rfind(".") dot = filename.rfind(".")

View File

@ -5,7 +5,7 @@
import re import re
import sys import sys
from disassembler import disassemble from .disassembler import disassemble
tabs = 3 tabs = 3
def indent(block): def indent(block):