Patch_2
This commit is contained in:
@ -16,11 +16,13 @@
|
||||
#
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
from typing import Any, Dict, Optional, Tuple
|
||||
|
||||
import bpy
|
||||
import os
|
||||
|
||||
import lnx.assets
|
||||
import lnx.assets as assets
|
||||
import lnx.log as log
|
||||
import lnx.make_state
|
||||
import lnx.material.cycles_functions as c_functions
|
||||
@ -1003,7 +1005,12 @@ def make_texture(
|
||||
wrd = bpy.data.worlds['Lnx']
|
||||
max_size = int(wrd.lnx_max_texture_size)
|
||||
if max_size > 0 and image is not None:
|
||||
original_filepath = filepath
|
||||
filepath = resize_texture_if_needed(image, filepath, max_size)
|
||||
|
||||
if filepath != original_filepath:
|
||||
resized_filename = lnx.utils.extract_filename(filepath)
|
||||
tex['file'] = lnx.utils.safestr(resized_filename)
|
||||
|
||||
# Link image path to assets
|
||||
# TODO: Khamake converts .PNG to .jpg? Convert ext to lowercase on windows
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
from __future__ import annotations
|
||||
import bpy
|
||||
from bpy.types import NodeSocket
|
||||
|
||||
@ -36,12 +35,17 @@ def parse_mixshader(node: bpy.types.ShaderNodeMixShader, out_socket: NodeSocket,
|
||||
state.curshader.write('{0}float {1} = 1.0 - {2};'.format(prefix, fac_inv_var, fac_var))
|
||||
|
||||
mat_state.emission_type = mat_state.EmissionType.NO_EMISSION
|
||||
sss_before_1 = mat_state.needs_sss
|
||||
bc1, rough1, met1, occ1, spec1, opac1, ior1, emi1 = c.parse_shader_input(node.inputs[1])
|
||||
sss_1 = mat_state.needs_sss
|
||||
ek1 = mat_state.emission_type
|
||||
|
||||
mat_state.emission_type = mat_state.EmissionType.NO_EMISSION
|
||||
mat_state.needs_sss = sss_before_1 # Reset to state before parsing input 1
|
||||
bc2, rough2, met2, occ2, spec2, opac2, ior2, emi2 = c.parse_shader_input(node.inputs[2])
|
||||
sss_2 = mat_state.needs_sss
|
||||
ek2 = mat_state.emission_type
|
||||
mat_state.needs_sss = sss_1 or sss_2
|
||||
|
||||
if state.parse_surface:
|
||||
state.out_basecol = '({0} * {3} + {1} * {2})'.format(bc1, bc2, fac_var, fac_inv_var)
|
||||
@ -57,12 +61,17 @@ def parse_mixshader(node: bpy.types.ShaderNodeMixShader, out_socket: NodeSocket,
|
||||
|
||||
def parse_addshader(node: bpy.types.ShaderNodeAddShader, out_socket: NodeSocket, state: ParserState) -> None:
|
||||
mat_state.emission_type = mat_state.EmissionType.NO_EMISSION
|
||||
sss_before_1 = mat_state.needs_sss
|
||||
bc1, rough1, met1, occ1, spec1, opac1, ior1, emi1 = c.parse_shader_input(node.inputs[0])
|
||||
sss_1 = mat_state.needs_sss
|
||||
ek1 = mat_state.emission_type
|
||||
|
||||
mat_state.emission_type = mat_state.EmissionType.NO_EMISSION
|
||||
mat_state.needs_sss = sss_before_1 # Reset to state before parsing input 0
|
||||
bc2, rough2, met2, occ2, spec2, opac2, ior2, emi2 = c.parse_shader_input(node.inputs[1])
|
||||
sss_2 = mat_state.needs_sss
|
||||
ek2 = mat_state.emission_type
|
||||
mat_state.needs_sss = sss_1 or sss_2
|
||||
|
||||
if state.parse_surface:
|
||||
state.out_basecol = '({0} + {1})'.format(bc1, bc2)
|
||||
@ -82,6 +91,8 @@ if bpy.app.version < (2, 92, 0):
|
||||
if state.parse_surface:
|
||||
c.write_normal(node.inputs[20])
|
||||
state.out_basecol = c.parse_vector_input(node.inputs[0])
|
||||
if node.inputs[1].is_linked or node.inputs[1].default_value > 0.0:
|
||||
mat_state.needs_sss = True
|
||||
state.out_metallic = c.parse_value_input(node.inputs[4])
|
||||
state.out_specular = c.parse_value_input(node.inputs[5])
|
||||
state.out_roughness = c.parse_value_input(node.inputs[7])
|
||||
@ -103,7 +114,8 @@ if bpy.app.version >= (2, 92, 0) and bpy.app.version <= (4, 1, 0):
|
||||
if state.parse_surface:
|
||||
c.write_normal(node.inputs[22])
|
||||
state.out_basecol = c.parse_vector_input(node.inputs[0])
|
||||
# subsurface = c.parse_vector_input(node.inputs[1])
|
||||
if node.inputs[1].is_linked or node.inputs[1].default_value > 0.0:
|
||||
mat_state.needs_sss = True
|
||||
# subsurface_radius = c.parse_vector_input(node.inputs[2])
|
||||
# subsurface_color = c.parse_vector_input(node.inputs[3])
|
||||
state.out_metallic = c.parse_value_input(node.inputs[6])
|
||||
@ -138,14 +150,27 @@ if bpy.app.version > (4, 1, 0):
|
||||
if state.parse_surface:
|
||||
c.write_normal(node.inputs[5])
|
||||
state.out_basecol = c.parse_vector_input(node.inputs[0])
|
||||
|
||||
sss_input = node.inputs.get('Subsurface Weight') or node.inputs.get('Subsurface')
|
||||
if sss_input is not None:
|
||||
if sss_input.is_linked or sss_input.default_value > 0.0:
|
||||
mat_state.needs_sss = True
|
||||
|
||||
subsurface = c.parse_value_input(node.inputs[7])
|
||||
subsurface_radius = c.parse_vector_input(node.inputs[9])
|
||||
subsurface_color = c.parse_vector_input(node.inputs[8])
|
||||
state.out_metallic = c.parse_value_input(node.inputs[1])
|
||||
if bpy.app.version > (4, 2, 4):
|
||||
state.out_specular = c.parse_value_input(node.inputs[13])
|
||||
|
||||
specular_socket = node.inputs.get('Specular IOR Level')
|
||||
if specular_socket is not None:
|
||||
state.out_specular = f'({c.parse_value_input(specular_socket)} * 2.0)'
|
||||
else:
|
||||
state.out_specular = c.parse_value_input(node.inputs[12])
|
||||
specular_socket = node.inputs.get('Specular')
|
||||
if specular_socket is not None:
|
||||
state.out_specular = c.parse_value_input(specular_socket)
|
||||
else:
|
||||
state.out_specular = '1.0'
|
||||
|
||||
state.out_roughness = c.parse_value_input(node.inputs[2])
|
||||
# Prevent black material when metal = 1.0 and roughness = 0.0
|
||||
try:
|
||||
@ -278,6 +303,8 @@ def parse_bsdfrefraction(node: bpy.types.ShaderNodeBsdfRefraction, out_socket: N
|
||||
|
||||
def parse_subsurfacescattering(node: bpy.types.ShaderNodeSubsurfaceScattering, out_socket: NodeSocket, state: ParserState) -> None:
|
||||
if state.parse_surface:
|
||||
# Mark that this material needs SSS
|
||||
mat_state.needs_sss = True
|
||||
if bpy.app.version < (4, 1, 0):
|
||||
c.write_normal(node.inputs[4])
|
||||
else:
|
||||
|
||||
@ -8,6 +8,7 @@ import lnx.log as log
|
||||
import lnx.material.cycles as cycles
|
||||
import lnx.material.make_shader as make_shader
|
||||
import lnx.material.mat_batch as mat_batch
|
||||
import lnx.material.mat_state as mat_state
|
||||
import lnx.material.mat_utils as mat_utils
|
||||
import lnx.node_utils
|
||||
import lnx.utils
|
||||
@ -17,6 +18,7 @@ if lnx.is_reload(__name__):
|
||||
cycles = lnx.reload_module(cycles)
|
||||
make_shader = lnx.reload_module(make_shader)
|
||||
mat_batch = lnx.reload_module(mat_batch)
|
||||
mat_state = lnx.reload_module(mat_state)
|
||||
mat_utils = lnx.reload_module(mat_utils)
|
||||
lnx.node_utils = lnx.reload_module(lnx.node_utils)
|
||||
lnx.utils = lnx.reload_module(lnx.utils)
|
||||
@ -60,6 +62,7 @@ def parse(material: Material, mat_data, mat_users: Dict[Material, List[Object]],
|
||||
shader_data_name = material.lnx_custom_material
|
||||
bind_constants = {'mesh': []}
|
||||
bind_textures = {'mesh': []}
|
||||
mat_uses_sss = False
|
||||
|
||||
make_shader.make_instancing_and_skinning(material, mat_users)
|
||||
|
||||
@ -77,10 +80,11 @@ def parse(material: Material, mat_data, mat_users: Dict[Material, List[Object]],
|
||||
log.warn(f'Material "{material.name}": skipping export of bind texture at slot {idx + 1} ("{item.uniform_name}") with no image selected')
|
||||
|
||||
elif not wrd.lnx_batch_materials or material.name.startswith('lnxdefault'):
|
||||
rpasses, shader_data, shader_data_name, bind_constants, bind_textures = make_shader.build(material, mat_users, mat_lnxusers)
|
||||
rpasses, shader_data, shader_data_name, bind_constants, bind_textures, mat_uses_sss = make_shader.build(material, mat_users, mat_lnxusers)
|
||||
sd = shader_data.sd
|
||||
else:
|
||||
rpasses, shader_data, shader_data_name, bind_constants, bind_textures = mat_batch.get(material)
|
||||
result = mat_batch.get(material)
|
||||
rpasses, shader_data, shader_data_name, bind_constants, bind_textures, mat_uses_sss = result
|
||||
sd = shader_data.sd
|
||||
|
||||
sss_used = False
|
||||
@ -106,9 +110,12 @@ def parse(material: Material, mat_data, mat_users: Dict[Material, List[Object]],
|
||||
|
||||
elif rpdat.rp_sss_state != 'Off':
|
||||
const = {'name': 'materialID'}
|
||||
if needs_sss:
|
||||
# Use per-material SSS flag from shader build
|
||||
if mat_uses_sss:
|
||||
const['intValue'] = 2
|
||||
sss_used = True
|
||||
if '_SSS' not in wrd.world_defs:
|
||||
wrd.world_defs += '_SSS'
|
||||
else:
|
||||
const['intValue'] = 0
|
||||
c['bind_constants'].append(const)
|
||||
@ -167,4 +174,10 @@ def material_needs_sss(material: Material) -> bool:
|
||||
if sss_node is not None and sss_node.outputs[0].is_linked and (sss_node.inputs[8].is_linked or sss_node.inputs[8].default_value != 0.0):
|
||||
return True
|
||||
|
||||
for principled_node in lnx.node_utils.iter_nodes_by_type(material.node_tree, 'BSDF_PRINCIPLED'):
|
||||
if principled_node is not None and principled_node.outputs[0].is_linked:
|
||||
sss_input = principled_node.inputs.get('Subsurface Weight') or principled_node.inputs.get('Subsurface')
|
||||
if sss_input is not None and (sss_input.is_linked or sss_input.default_value > 0.0):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@ -107,7 +107,7 @@ def write(vert: shader.Shader, frag: shader.Shader):
|
||||
if '_MicroShadowing' in wrd.world_defs and not is_mobile:
|
||||
frag.write('\t, occlusion')
|
||||
if '_SSRS' in wrd.world_defs:
|
||||
frag.add_uniform('sampler2D gbufferD')
|
||||
frag.add_uniform('sampler2D gbufferD', top=True)
|
||||
frag.add_uniform('mat4 invVP', '_inverseViewProjectionMatrix')
|
||||
frag.add_uniform('vec3 eye', '_cameraPosition')
|
||||
frag.write(', gbufferD, invVP, eye')
|
||||
|
||||
@ -198,7 +198,7 @@ def make_deferred(con_mesh, rpasses):
|
||||
rpdat = lnx.utils.get_rp()
|
||||
|
||||
lnx_discard = mat_state.material.lnx_discard
|
||||
parse_opacity = lnx_discard or 'translucent' or 'refraction' in rpasses
|
||||
parse_opacity = lnx_discard or 'translucent' in rpasses or 'refraction' in rpasses
|
||||
|
||||
make_base(con_mesh, parse_opacity=parse_opacity)
|
||||
|
||||
@ -213,6 +213,7 @@ def make_deferred(con_mesh, rpasses):
|
||||
opac = '0.9999' # 1.0 - eps
|
||||
frag.write('if (opacity < {0}) discard;'.format(opac))
|
||||
|
||||
|
||||
frag.add_out(f'vec4 fragColor[GBUF_SIZE]')
|
||||
|
||||
if '_gbuffer2' in wrd.world_defs:
|
||||
@ -281,7 +282,7 @@ def make_deferred(con_mesh, rpasses):
|
||||
frag.write('#endif')
|
||||
|
||||
if '_SSRefraction' in wrd.world_defs or '_VoxelRefract' in wrd.world_defs:
|
||||
frag.write('fragColor[GBUF_IDX_REFRACTION] = vec4(1.0, 1.0, 0.0, 1.0);')
|
||||
frag.write('fragColor[GBUF_IDX_REFRACTION] = vec4(1.0, 0.0, 0.0, 1.0);')
|
||||
|
||||
return con_mesh
|
||||
|
||||
@ -559,7 +560,7 @@ def make_forward(con_mesh):
|
||||
frag.write('fragColor[0] = vec4(direct + indirect, packFloat2(occlusion, specular));')
|
||||
frag.write('fragColor[1] = vec4(n.xy, roughness, metallic);')
|
||||
if rpdat.rp_ss_refraction or rpdat.lnx_voxelgi_refract:
|
||||
frag.write(f'fragColor[2] = vec4(1.0, 1.0, 0.0, 0.0);')
|
||||
frag.write(f'fragColor[2] = vec4(1.0, 0.0, 0.0, 1.0);')
|
||||
|
||||
else:
|
||||
frag.add_out('vec4 fragColor[1]')
|
||||
@ -716,8 +717,12 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False):
|
||||
else:
|
||||
frag.write('vec3 indirect = envl;')
|
||||
|
||||
if '_VoxelShadow' in wrd.world_defs or '_VoxelGI' in wrd.world_defs:
|
||||
velocity_already_defined = '_gbuffer2' in wrd.world_defs and '_Veloc' in wrd.world_defs
|
||||
if not velocity_already_defined:
|
||||
frag.write('vec2 velocity = gl_FragCoord.xy;')
|
||||
|
||||
if '_VoxelGI' in wrd.world_defs:
|
||||
frag.write('vec2 velocity = gl_FragCoord.xy;')
|
||||
frag.write('vec4 diffuse_indirect = traceDiffuse(wposition, n, voxels, clipmaps);')
|
||||
frag.write('indirect = (diffuse_indirect.rgb * albedo * (1.0 - F) + envl * (1.0 - diffuse_indirect.a)) * voxelgiDiff;')
|
||||
frag.write('if (roughness < 1.0 && specular > 0.0) {')
|
||||
@ -810,12 +815,11 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False):
|
||||
frag.write(', true, spotData.x, spotData.y, spotDir, spotData.zw, spotRight')
|
||||
if '_VoxelShadow' in wrd.world_defs:
|
||||
frag.write(', voxels, voxelsSDF, clipmaps')
|
||||
if '_Veloc' in wrd.world_defs or '_VoxelShadow' in wrd.world_defs:
|
||||
frag.write(', velocity')
|
||||
if '_MicroShadowing' in wrd.world_defs:
|
||||
frag.write(', occlusion')
|
||||
if '_SSRS' in wrd.world_defs:
|
||||
frag.add_uniform('sampler2D gbufferD')
|
||||
frag.add_uniform('sampler2D gbufferD', top=True)
|
||||
frag.add_uniform('mat4 invVP', '_inverseViewProjectionMatrix')
|
||||
frag.add_uniform('vec3 eye', '_cameraPosition')
|
||||
frag.write(', gbufferD, invVP, eye')
|
||||
|
||||
@ -6,6 +6,8 @@ else:
|
||||
lnx.enable_reload(__name__)
|
||||
|
||||
def morph_pos(vert):
|
||||
if vert.has_attrib('vec2 texCoordMorph = morph * texUnpack;'):
|
||||
return
|
||||
rpdat = lnx.utils.get_rp()
|
||||
vert.add_include('compiled.inc')
|
||||
vert.add_include('std/morph_target.glsl')
|
||||
@ -22,6 +24,8 @@ def morph_pos(vert):
|
||||
vert.write_attrib('spos.xyz /= posUnpack;')
|
||||
|
||||
def morph_nor(vert, is_bone, prep):
|
||||
if vert.has_attrib('vec3 morphNor = vec3(0, 0, 0);'):
|
||||
return
|
||||
vert.write_attrib('vec3 morphNor = vec3(0, 0, 0);')
|
||||
vert.write_attrib('getMorphedNormal(texCoordMorph, vec3(nor.xy, pos.w), morphNor);')
|
||||
if not is_bone:
|
||||
|
||||
@ -18,7 +18,15 @@ else:
|
||||
|
||||
|
||||
def make(context_id):
|
||||
con_refract = mat_state.data.add_context({ 'name': context_id, 'depth_write': True, 'compare_mode': 'less', 'cull_mode': 'clockwise' })
|
||||
con_refract = mat_state.data.add_context({
|
||||
'name': context_id,
|
||||
'depth_write': False,
|
||||
'compare_mode': 'less',
|
||||
'cull_mode': 'clockwise',
|
||||
'blend_source': 'blend_one',
|
||||
'blend_destination': 'inverse_source_alpha',
|
||||
'blend_operation': 'add'
|
||||
})
|
||||
make_mesh.make_forward_base(con_refract, parse_opacity=True, transluc_pass=True)
|
||||
|
||||
vert = con_refract.vert
|
||||
@ -51,14 +59,16 @@ def make(context_id):
|
||||
frag.write('const uint matid = 0;')
|
||||
|
||||
if rpdat.rp_renderer == 'Deferred':
|
||||
frag.write('fragColor[0] = vec4(n.xy, roughness, packFloatInt16(metallic, matid));')
|
||||
frag.write('fragColor[1] = vec4(direct + indirect, packFloat2(occlusion, specular));')
|
||||
frag.write('fragColor[0] = vec4(n.xy, roughness, 1.0);')
|
||||
frag.write('vec3 finalColor = direct + indirect;')
|
||||
frag.write('fragColor[1] = vec4(finalColor * opacity, opacity);')
|
||||
else:
|
||||
frag.write('fragColor[0] = vec4(direct + indirect, packFloat2(occlusion, specular));')
|
||||
frag.write('fragColor[1] = vec4(n.xy, roughness, metallic);')
|
||||
frag.write('vec3 finalColor = direct + indirect;')
|
||||
frag.write('fragColor[0] = vec4(finalColor * opacity, opacity);')
|
||||
frag.write('fragColor[1] = vec4(n.xy, roughness, 1.0);')
|
||||
|
||||
frag.write('fragColor[2] = vec4(ior, opacity, 0.0, 1.0);')
|
||||
# frag.write('fragColor[2] = vec4(ior, opacity, packFloat2(basecol.r, basecol.g), basecol.b);')
|
||||
frag.write('fragColor[2] = vec4(ior, 1.0 - opacity, gl_FragCoord.z, 1.0);')
|
||||
# frag.write('fragColor[2] = vec4(ior, 1.0 - opacity, packFloat2(basecol.r, basecol.g), basecol.b);')
|
||||
|
||||
make_finalize.make(con_refract)
|
||||
|
||||
|
||||
@ -56,6 +56,9 @@ def build(material: Material, mat_users: Dict[Material, List[Object]], mat_lnxus
|
||||
if mat_state.output_node is None:
|
||||
# Place empty material output to keep compiler happy..
|
||||
mat_state.output_node = mat_state.nodes.new('ShaderNodeOutputMaterial')
|
||||
|
||||
# reset for each material
|
||||
mat_state.needs_sss = False
|
||||
|
||||
wrd = bpy.data.worlds['Lnx']
|
||||
rpdat = lnx.utils.get_rp()
|
||||
@ -130,7 +133,8 @@ 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)
|
||||
|
||||
return rpasses, mat_state.data, shader_data_name, bind_constants, bind_textures
|
||||
needs_sss_result = mat_state.needs_sss
|
||||
return rpasses, mat_state.data, shader_data_name, bind_constants, bind_textures, needs_sss_result
|
||||
|
||||
|
||||
def write_shaders(rel_path: str, con: ShaderContext, rpass: str, matname: str) -> None:
|
||||
@ -146,6 +150,11 @@ def write_shader(rel_path: str, shader: Shader, ext: str, rpass: str, matname: s
|
||||
if shader is None or shader.is_linked:
|
||||
return
|
||||
|
||||
validation_issues = shader.validate()
|
||||
if validation_issues:
|
||||
for issue in validation_issues:
|
||||
log.warn(f"Shader validation issue in {matname}_{rpass}.{ext}: {issue}. ")
|
||||
|
||||
# TODO: blend context
|
||||
if rpass == 'mesh' and mat_state.material.lnx_blending:
|
||||
rpass = 'blend'
|
||||
|
||||
@ -7,6 +7,9 @@ else:
|
||||
|
||||
|
||||
def skin_pos(vert):
|
||||
if vert.has_attrib('vec4 skinA;'):
|
||||
return
|
||||
|
||||
vert.add_include('compiled.inc')
|
||||
|
||||
rpdat = lnx.utils.get_rp()
|
||||
@ -25,6 +28,11 @@ def skin_pos(vert):
|
||||
|
||||
|
||||
def skin_nor(vert, is_morph, prep):
|
||||
morph_normal_code = 'wnormal = normalize(N * (morphNor + 2.0 * cross(skinA.xyz'
|
||||
static_normal_code = 'wnormal = normalize(N * (vec3(nor.xy, pos.w) + 2.0 * cross(skinA.xyz'
|
||||
if vert.has_attrib(morph_normal_code) or vert.has_attrib(static_normal_code):
|
||||
return
|
||||
|
||||
rpdat = lnx.utils.get_rp()
|
||||
if(is_morph):
|
||||
vert.write_attrib(prep + 'wnormal = normalize(N * (morphNor + 2.0 * cross(skinA.xyz, cross(skinA.xyz, morphNor) + skinA.w * morphNor)));')
|
||||
|
||||
@ -41,7 +41,7 @@ def make(context_id):
|
||||
frag.write('n /= (abs(n.x) + abs(n.y) + abs(n.z));')
|
||||
frag.write('n.xy = n.z >= 0.0 ? n.xy : octahedronWrap(n.xy);')
|
||||
|
||||
frag.write('vec4 premultipliedReflect = vec4(vec3(direct + indirect * 0.5) * opacity, opacity);');
|
||||
frag.write('vec4 premultipliedReflect = vec4(vec3(direct + indirect) * opacity, opacity);');
|
||||
frag.write('float w = clamp(pow(min(1.0, premultipliedReflect.a * 10.0) + 0.01, 3.0) * 1e8 * pow(1.0 - (gl_FragCoord.z) * 0.9, 3.0), 1e-2, 3e3);')
|
||||
frag.write('fragColor[0] = vec4(premultipliedReflect.rgb * w, premultipliedReflect.a);')
|
||||
frag.write('fragColor[1] = vec4(premultipliedReflect.a * w, 0.0, 0.0, 1.0);')
|
||||
|
||||
@ -38,3 +38,4 @@ texture_grad = False # Sample textures using textureGrad()
|
||||
con_mesh = None # Mesh context
|
||||
uses_instancing = False # Whether the current material has at least one user with instancing enabled
|
||||
emission_type = EmissionType.NO_EMISSION
|
||||
needs_sss = False
|
||||
|
||||
@ -361,9 +361,14 @@ class Shader:
|
||||
def write_header(self, s):
|
||||
self.header += s + '\n'
|
||||
|
||||
def write_attrib(self, s):
|
||||
def write_attrib(self, s, unique=False):
|
||||
if unique and s in self.main_attribs:
|
||||
return
|
||||
self.main_attribs += '\t' + s + '\n'
|
||||
|
||||
def has_attrib(self, s):
|
||||
return s in self.main_attribs
|
||||
|
||||
def is_equal(self, sh):
|
||||
self.vstruct_to_vsin()
|
||||
return self.ins == sh.ins and \
|
||||
@ -394,6 +399,25 @@ class Shader:
|
||||
for e in vs:
|
||||
self.add_in('vec' + self.data_size(e['data']) + ' ' + e['name'])
|
||||
|
||||
def validate(self):
|
||||
import re
|
||||
issues = []
|
||||
|
||||
# Check for duplicate variable declarations in main_attribs
|
||||
var_pattern = re.compile(r'\b(vec[234]|float|int|mat[234])\s+(\w+)\s*[;=]')
|
||||
declared_vars = {}
|
||||
|
||||
for line in self.main_attribs.split('\n'):
|
||||
match = var_pattern.search(line)
|
||||
if match:
|
||||
var_type, var_name = match.groups()
|
||||
if var_name in declared_vars:
|
||||
issues.append(f"Duplicate variable declaration: '{var_name}' (type: {var_type})")
|
||||
else:
|
||||
declared_vars[var_name] = var_type
|
||||
|
||||
return issues
|
||||
|
||||
def get(self):
|
||||
if self.noprocessing:
|
||||
return self.main
|
||||
|
||||
Reference in New Issue
Block a user