forked from LeenkxTeam/LNXSDK
Update Export
This commit is contained in:
@ -1,5 +1,7 @@
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from typing import Dict, List, Tuple
|
||||
|
||||
import bpy
|
||||
@ -46,6 +48,32 @@ else:
|
||||
rpass_hook = None
|
||||
|
||||
|
||||
def cache_hit(cached, wrd, full_path, matname):
|
||||
mat_state.features = dict(cached['features'])
|
||||
mat_state.emission_type = cached['emission_type']
|
||||
mat_state.texture_grad = cached['texture_grad']
|
||||
mat_state.data = cached['shader_data']
|
||||
|
||||
if cached['world_defs_delta']:
|
||||
for define in re.findall(r'_[A-Za-z0-9]+', cached['world_defs_delta']):
|
||||
assets.add_world_def(wrd, define)
|
||||
|
||||
for d in cached['khafile_defs_delta']:
|
||||
assets.add_khafile_def(d)
|
||||
|
||||
for shader_path in cached['shader_paths']:
|
||||
assets.add_shader(shader_path)
|
||||
|
||||
shader_data_name = cached['shader_data_name']
|
||||
if wrd.lnx_single_data_file:
|
||||
pass
|
||||
else:
|
||||
shader_data_path = lnx.utils.get_fp_build() + '/compiled/Shaders/' + shader_data_name + '.lnx'
|
||||
assets.add_shader_data(shader_data_path)
|
||||
|
||||
return cached['rpasses'], mat_state.data, shader_data_name, cached['bind_constants'], cached['bind_textures']
|
||||
|
||||
|
||||
def build(material: Material, mat_users: Dict[Material, List[Object]], mat_lnxusers) -> Tuple:
|
||||
mat_state.mat_users = mat_users
|
||||
mat_state.mat_lnxusers = mat_lnxusers
|
||||
@ -68,8 +96,22 @@ def build(material: Material, mat_users: Dict[Material, List[Object]], mat_lnxus
|
||||
|
||||
make_instancing_and_skinning(material, mat_users)
|
||||
|
||||
cache_key = None
|
||||
cached = None
|
||||
if material.signature:
|
||||
global_elems_key = tuple((e['name'], e['data']) for e in mat_state.data.global_elems)
|
||||
cache_key = (material.signature, mat_state.uses_instancing, tuple(rpasses), global_elems_key)
|
||||
cached = mat_state.material_cache.get(cache_key)
|
||||
|
||||
if cached is not None:
|
||||
return cache_hit(cached, wrd, full_path, matname)
|
||||
|
||||
world_defs_before = wrd.world_defs
|
||||
khafile_defs_before = set(assets.khafile_defs)
|
||||
|
||||
bind_constants = dict()
|
||||
bind_textures = dict()
|
||||
all_shader_paths = []
|
||||
|
||||
for rp in rpasses:
|
||||
car = []
|
||||
@ -117,7 +159,9 @@ def build(material: Material, mat_users: Dict[Material, List[Object]], mat_lnxus
|
||||
elif rpass_hook is not None:
|
||||
con = rpass_hook(rp)
|
||||
|
||||
write_shaders(rel_path, con, rp, matname)
|
||||
if con is not None:
|
||||
rp_shader_paths = write_shaders(rel_path, con, rp, matname)
|
||||
all_shader_paths.extend(rp_shader_paths)
|
||||
|
||||
shader_data_name = matname + '_data'
|
||||
|
||||
@ -130,16 +174,85 @@ def build(material: Material, mat_users: Dict[Material, List[Object]], mat_lnxus
|
||||
shader_data_path = lnx.utils.get_fp_build() + '/compiled/Shaders/' + shader_data_name + '.lnx'
|
||||
assets.add_shader_data(shader_data_path)
|
||||
|
||||
if cache_key is not None:
|
||||
world_defs_delta = wrd.world_defs[len(world_defs_before):]
|
||||
khafile_defs_delta = [d for d in assets.khafile_defs if d not in khafile_defs_before]
|
||||
mat_state.material_cache[cache_key] = {
|
||||
'shader_data': mat_state.data,
|
||||
'shader_data_name': shader_data_name,
|
||||
'bind_constants': bind_constants,
|
||||
'bind_textures': bind_textures,
|
||||
'features': dict(mat_state.features),
|
||||
'emission_type': mat_state.emission_type,
|
||||
'texture_grad': mat_state.texture_grad,
|
||||
'shader_paths': all_shader_paths,
|
||||
'world_defs_delta': world_defs_delta,
|
||||
'khafile_defs_delta': khafile_defs_delta,
|
||||
'rpasses': rpasses,
|
||||
}
|
||||
|
||||
return rpasses, mat_state.data, shader_data_name, bind_constants, bind_textures
|
||||
|
||||
|
||||
def write_shaders(rel_path: str, con: ShaderContext, rpass: str, matname: str) -> None:
|
||||
def write_shaders(rel_path: str, con: ShaderContext, rpass: str, matname: str) -> List[str]:
|
||||
keep_cache = mat_state.material.lnx_cached
|
||||
write_shader(rel_path, con.vert, 'vert', rpass, matname, keep_cache=keep_cache)
|
||||
write_shader(rel_path, con.frag, 'frag', rpass, matname, keep_cache=keep_cache)
|
||||
write_shader(rel_path, con.geom, 'geom', rpass, matname, keep_cache=keep_cache)
|
||||
write_shader(rel_path, con.tesc, 'tesc', rpass, matname, keep_cache=keep_cache)
|
||||
write_shader(rel_path, con.tese, 'tese', rpass, matname, keep_cache=keep_cache)
|
||||
shaders = [con.vert, con.frag, con.geom, con.tesc, con.tese]
|
||||
exts = ['vert', 'frag', 'geom', 'tesc', 'tese']
|
||||
shader_paths = []
|
||||
|
||||
write_tasks = []
|
||||
for shader, ext in zip(shaders, exts):
|
||||
if shader is None or shader.is_linked:
|
||||
continue
|
||||
|
||||
validation_issues = shader.validate()
|
||||
if validation_issues:
|
||||
for issue in validation_issues:
|
||||
log.warn(f"Shader validation issue in {matname}_{rpass}.{ext}: {issue}. ")
|
||||
|
||||
output_rpass = rpass
|
||||
if output_rpass == 'mesh' and mat_state.material.lnx_blending:
|
||||
output_rpass = 'blend'
|
||||
|
||||
output_ext = '.glsl'
|
||||
output_rel_path = rel_path
|
||||
if shader.noprocessing:
|
||||
hlsl_dir = lnx.utils.build_dir() + '/compiled/Hlsl/'
|
||||
os.makedirs(hlsl_dir, exist_ok=True)
|
||||
output_ext = '.hlsl'
|
||||
output_rel_path = rel_path.replace('/compiled/Shaders/', '/compiled/Hlsl/')
|
||||
|
||||
shader_file = matname + '_' + output_rpass + '.' + ext + output_ext
|
||||
shader_path = lnx.utils.get_fp() + '/' + output_rel_path + '/' + shader_file
|
||||
assets.add_shader(shader_path)
|
||||
shader_paths.append(shader_path)
|
||||
|
||||
if os.path.isfile(shader_path) and keep_cache:
|
||||
continue
|
||||
|
||||
content = shader.get()
|
||||
|
||||
if shader.noprocessing:
|
||||
written = lnx.utils.write_if_changed(shader_path, content)
|
||||
if written:
|
||||
cwd = os.getcwd()
|
||||
os.chdir(lnx.utils.get_fp() + '/' + output_rel_path)
|
||||
hlslbin_path = lnx.utils.get_sdk_path() + '/lib/leenkx_tools/hlslbin/hlslbin.exe'
|
||||
prof = 'vs_5_0' if ext == 'vert' else 'ps_5_0' if ext == 'frag' else 'gs_5_0'
|
||||
args = [hlslbin_path.replace('/', '\\').replace('\\\\', '\\'), shader_file, shader_file[:-4] + 'glsl', prof]
|
||||
if ext == 'vert':
|
||||
args.append('-i')
|
||||
args.append('pos')
|
||||
proc = subprocess.call(args)
|
||||
os.chdir(cwd)
|
||||
else:
|
||||
write_tasks.append((shader_path, content))
|
||||
|
||||
if write_tasks:
|
||||
with ThreadPoolExecutor(max_workers=min(5, len(write_tasks))) as pool:
|
||||
list(pool.map(lambda t: lnx.utils.write_if_changed(t[0], t[1]), write_tasks))
|
||||
|
||||
return shader_paths
|
||||
|
||||
|
||||
def write_shader(rel_path: str, shader: Shader, ext: str, rpass: str, matname: str, keep_cache=True) -> None:
|
||||
@ -159,8 +272,7 @@ def write_shader(rel_path: str, shader: Shader, ext: str, rpass: str, matname: s
|
||||
if shader.noprocessing:
|
||||
# Use hlsl directly
|
||||
hlsl_dir = lnx.utils.build_dir() + '/compiled/Hlsl/'
|
||||
if not os.path.exists(hlsl_dir):
|
||||
os.makedirs(hlsl_dir)
|
||||
os.makedirs(hlsl_dir, exist_ok=True)
|
||||
file_ext = '.hlsl'
|
||||
rel_path = rel_path.replace('/compiled/Shaders/', '/compiled/Hlsl/')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user