205 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			205 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 
								 | 
							
								import shutil
							 | 
						||
| 
								 | 
							
								import os
							 | 
						||
| 
								 | 
							
								import stat
							 | 
						||
| 
								 | 
							
								import bpy
							 | 
						||
| 
								 | 
							
								import lnx.utils
							 | 
						||
| 
								 | 
							
								from lnx import log
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								if lnx.is_reload(__name__):
							 | 
						||
| 
								 | 
							
								    log = lnx.reload_module(log)
							 | 
						||
| 
								 | 
							
								    lnx.utils = lnx.reload_module(lnx.utils)
							 | 
						||
| 
								 | 
							
								else:
							 | 
						||
| 
								 | 
							
								    lnx.enable_reload(__name__)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								assets = []
							 | 
						||
| 
								 | 
							
								reserved_names = ['return.']
							 | 
						||
| 
								 | 
							
								khafile_params = []
							 | 
						||
| 
								 | 
							
								khafile_defs = []
							 | 
						||
| 
								 | 
							
								khafile_defs_last = []
							 | 
						||
| 
								 | 
							
								embedded_data = []
							 | 
						||
| 
								 | 
							
								shaders = []
							 | 
						||
| 
								 | 
							
								shaders_last = []
							 | 
						||
| 
								 | 
							
								shaders_external = []
							 | 
						||
| 
								 | 
							
								shader_datas = []
							 | 
						||
| 
								 | 
							
								shader_passes = []
							 | 
						||
| 
								 | 
							
								shader_passes_assets = {}
							 | 
						||
| 
								 | 
							
								shader_cons = {}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def reset():
							 | 
						||
| 
								 | 
							
								    global assets
							 | 
						||
| 
								 | 
							
								    global khafile_params
							 | 
						||
| 
								 | 
							
								    global khafile_defs
							 | 
						||
| 
								 | 
							
								    global khafile_defs_last
							 | 
						||
| 
								 | 
							
								    global embedded_data
							 | 
						||
| 
								 | 
							
								    global shaders
							 | 
						||
| 
								 | 
							
								    global shaders_last
							 | 
						||
| 
								 | 
							
								    global shaders_external
							 | 
						||
| 
								 | 
							
								    global shader_datas
							 | 
						||
| 
								 | 
							
								    global shader_passes
							 | 
						||
| 
								 | 
							
								    global shader_cons
							 | 
						||
| 
								 | 
							
								    assets = []
							 | 
						||
| 
								 | 
							
								    khafile_params = []
							 | 
						||
| 
								 | 
							
								    khafile_defs_last = khafile_defs
							 | 
						||
| 
								 | 
							
								    khafile_defs = []
							 | 
						||
| 
								 | 
							
								    embedded_data = []
							 | 
						||
| 
								 | 
							
								    shaders_last = shaders
							 | 
						||
| 
								 | 
							
								    shaders = []
							 | 
						||
| 
								 | 
							
								    shaders_external = []
							 | 
						||
| 
								 | 
							
								    shader_datas = []
							 | 
						||
| 
								 | 
							
								    shader_passes = []
							 | 
						||
| 
								 | 
							
								    shader_cons = {}
							 | 
						||
| 
								 | 
							
								    shader_cons['mesh_vert'] = []
							 | 
						||
| 
								 | 
							
								    shader_cons['depth_vert'] = []
							 | 
						||
| 
								 | 
							
								    shader_cons['depth_frag'] = []
							 | 
						||
| 
								 | 
							
								    shader_cons['voxel_vert'] = []
							 | 
						||
| 
								 | 
							
								    shader_cons['voxel_frag'] = []
							 | 
						||
| 
								 | 
							
								    shader_cons['voxel_geom'] = []
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def add(asset_file):
							 | 
						||
| 
								 | 
							
								    global assets
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Asset already exists, do nothing
							 | 
						||
| 
								 | 
							
								    if asset_file in assets:
							 | 
						||
| 
								 | 
							
								        return
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    asset_file_base = os.path.basename(asset_file)
							 | 
						||
| 
								 | 
							
								    for f in assets:
							 | 
						||
| 
								 | 
							
								        f_file_base = os.path.basename(f)
							 | 
						||
| 
								 | 
							
								        if f_file_base == asset_file_base:
							 | 
						||
| 
								 | 
							
								            return
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    assets.append(asset_file)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Reserved file name
							 | 
						||
| 
								 | 
							
								    for f in reserved_names:
							 | 
						||
| 
								 | 
							
								        if f in asset_file:
							 | 
						||
| 
								 | 
							
								            log.warn(f'File "{asset_file}" contains reserved keyword, this will break C++ builds!')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def add_khafile_def(d):
							 | 
						||
| 
								 | 
							
								    global khafile_defs
							 | 
						||
| 
								 | 
							
								    if d not in khafile_defs:
							 | 
						||
| 
								 | 
							
								        khafile_defs.append(d)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def add_khafile_param(p):
							 | 
						||
| 
								 | 
							
								    global khafile_params
							 | 
						||
| 
								 | 
							
								    if p not in khafile_params:
							 | 
						||
| 
								 | 
							
								        khafile_params.append(p)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def add_embedded_data(file):
							 | 
						||
| 
								 | 
							
								    global embedded_data
							 | 
						||
| 
								 | 
							
								    if file not in embedded_data:
							 | 
						||
| 
								 | 
							
								        embedded_data.append(file)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def add_shader(file):
							 | 
						||
| 
								 | 
							
								    global shaders
							 | 
						||
| 
								 | 
							
								    global shaders_last
							 | 
						||
| 
								 | 
							
								    if file not in shaders:
							 | 
						||
| 
								 | 
							
								        shaders.append(file)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def add_shader_data(file):
							 | 
						||
| 
								 | 
							
								    global shader_datas
							 | 
						||
| 
								 | 
							
								    if file not in shader_datas:
							 | 
						||
| 
								 | 
							
								        shader_datas.append(file)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def add_shader_pass(data_name):
							 | 
						||
| 
								 | 
							
								    global shader_passes
							 | 
						||
| 
								 | 
							
								    # Shader data for passes are written into single shader_datas.lnx file
							 | 
						||
| 
								 | 
							
								    add_shader_data(lnx.utils.get_fp_build() + '/compiled/Shaders/shader_datas.lnx')
							 | 
						||
| 
								 | 
							
								    if data_name not in shader_passes:
							 | 
						||
| 
								 | 
							
								        shader_passes.append(data_name)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def add_shader_external(file):
							 | 
						||
| 
								 | 
							
								    global shaders_external
							 | 
						||
| 
								 | 
							
								    shaders_external.append(file)
							 | 
						||
| 
								 | 
							
								    name = file.split('/')[-1].split('\\')[-1]
							 | 
						||
| 
								 | 
							
								    add_shader(lnx.utils.get_fp_build() + '/compiled/Shaders/' + name)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								invalidate_enabled = True # Disable invalidating during build process
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def remove_readonly(func, path, excinfo):
							 | 
						||
| 
								 | 
							
								    os.chmod(path, stat.S_IWRITE)
							 | 
						||
| 
								 | 
							
								    func(path)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def invalidate_shader_cache(self, context):
							 | 
						||
| 
								 | 
							
								    # compiled.inc changed, recompile all shaders next time
							 | 
						||
| 
								 | 
							
								    global invalidate_enabled
							 | 
						||
| 
								 | 
							
								    if invalidate_enabled is False:
							 | 
						||
| 
								 | 
							
								        return
							 | 
						||
| 
								 | 
							
								    fp = lnx.utils.get_fp_build()
							 | 
						||
| 
								 | 
							
								    if os.path.isdir(fp + '/compiled/Shaders'):
							 | 
						||
| 
								 | 
							
								        shutil.rmtree(fp + '/compiled/Shaders', onerror=remove_readonly)
							 | 
						||
| 
								 | 
							
								    if os.path.isdir(fp + '/debug/html5-resources'):
							 | 
						||
| 
								 | 
							
								        shutil.rmtree(fp + '/debug/html5-resources', onerror=remove_readonly)
							 | 
						||
| 
								 | 
							
								    if os.path.isdir(fp + '/krom-resources'):
							 | 
						||
| 
								 | 
							
								        shutil.rmtree(fp + '/krom-resources', onerror=remove_readonly)
							 | 
						||
| 
								 | 
							
								    if os.path.isdir(fp + '/debug/krom-resources'):
							 | 
						||
| 
								 | 
							
								        shutil.rmtree(fp + '/debug/krom-resources', onerror=remove_readonly)
							 | 
						||
| 
								 | 
							
								    if os.path.isdir(fp + '/windows-resources'):
							 | 
						||
| 
								 | 
							
								        shutil.rmtree(fp + '/windows-resources', onerror=remove_readonly)
							 | 
						||
| 
								 | 
							
								    if os.path.isdir(fp + '/linux-resources'):
							 | 
						||
| 
								 | 
							
								        shutil.rmtree(fp + '/linux-resources', onerror=remove_readonly)
							 | 
						||
| 
								 | 
							
								    if os.path.isdir(fp + '/osx-resources'):
							 | 
						||
| 
								 | 
							
								        shutil.rmtree(fp + '/osx-resources', onerror=remove_readonly)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def invalidate_compiled_data(self, context):
							 | 
						||
| 
								 | 
							
								    global invalidate_enabled
							 | 
						||
| 
								 | 
							
								    if invalidate_enabled is False:
							 | 
						||
| 
								 | 
							
								        return
							 | 
						||
| 
								 | 
							
								    fp = lnx.utils.get_fp_build()
							 | 
						||
| 
								 | 
							
								    if os.path.isdir(fp + '/compiled'):
							 | 
						||
| 
								 | 
							
								        shutil.rmtree(fp + '/compiled', onerror=remove_readonly)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def invalidate_mesh_data(self, context):
							 | 
						||
| 
								 | 
							
								    fp = lnx.utils.get_fp_build()
							 | 
						||
| 
								 | 
							
								    if os.path.isdir(fp + '/compiled/Assets/meshes'):
							 | 
						||
| 
								 | 
							
								        shutil.rmtree(fp + '/compiled/Assets/meshes', onerror=remove_readonly)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def invalidate_envmap_data(self, context):
							 | 
						||
| 
								 | 
							
								    fp = lnx.utils.get_fp_build()
							 | 
						||
| 
								 | 
							
								    if os.path.isdir(fp + '/compiled/Assets/envmaps'):
							 | 
						||
| 
								 | 
							
								        shutil.rmtree(fp + '/compiled/Assets/envmaps', onerror=remove_readonly)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def invalidate_unpacked_data(self, context):
							 | 
						||
| 
								 | 
							
								    fp = lnx.utils.get_fp_build()
							 | 
						||
| 
								 | 
							
								    if os.path.isdir(fp + '/compiled/Assets/unpacked'):
							 | 
						||
| 
								 | 
							
								        shutil.rmtree(fp + '/compiled/Assets/unpacked', onerror=remove_readonly)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def invalidate_mesh_cache(self, context):
							 | 
						||
| 
								 | 
							
								    if context.object is None or context.object.data is None:
							 | 
						||
| 
								 | 
							
								        return
							 | 
						||
| 
								 | 
							
								    context.object.data.lnx_cached = False
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def invalidate_instance_cache(self, context):
							 | 
						||
| 
								 | 
							
								    if context.object is None or context.object.data is None:
							 | 
						||
| 
								 | 
							
								        return
							 | 
						||
| 
								 | 
							
								    invalidate_mesh_cache(self, context)
							 | 
						||
| 
								 | 
							
								    for slot in context.object.material_slots:
							 | 
						||
| 
								 | 
							
								        slot.material.lnx_cached = False
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def invalidate_compiler_cache(self, context):
							 | 
						||
| 
								 | 
							
								    bpy.data.worlds['Lnx'].lnx_recompile = True
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def shader_equal(sh, ar, shtype):
							 | 
						||
| 
								 | 
							
								    # Merge equal shaders
							 | 
						||
| 
								 | 
							
								    for e in ar:
							 | 
						||
| 
								 | 
							
								        if sh.is_equal(e):
							 | 
						||
| 
								 | 
							
								            sh.context.data[shtype] = e.context.data[shtype]
							 | 
						||
| 
								 | 
							
								            sh.is_linked = True
							 | 
						||
| 
								 | 
							
								            return
							 | 
						||
| 
								 | 
							
								    ar.append(sh)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def vs_equal(c, ar):
							 | 
						||
| 
								 | 
							
								    shader_equal(c.vert, ar, 'vertex_shader')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def fs_equal(c, ar):
							 | 
						||
| 
								 | 
							
								    shader_equal(c.frag, ar, 'fragment_shader')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def gs_equal(c, ar):
							 | 
						||
| 
								 | 
							
								    shader_equal(c.geom, ar, 'geometry_shader')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def tcs_equal(c, ar):
							 | 
						||
| 
								 | 
							
								    shader_equal(c.tesc, ar, 'tesscontrol_shader')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def tes_equal(c, ar):
							 | 
						||
| 
								 | 
							
								    shader_equal(c.tese, ar, 'tesseval_shader')
							 |