diff --git a/tools/ShaderToyProcessor.py b/tools/ShaderToyProcessor.py new file mode 100644 index 0000000..51b22c8 --- /dev/null +++ b/tools/ShaderToyProcessor.py @@ -0,0 +1,271 @@ +# This file was originally part of the KDE Shader Wallpaper Project + +import os +import re +import shutil +import argparse +import sys +import subprocess + +# Specify the directory where your .frag files are located +source_directory = 'src' +temp_directory = 'processed' +output_directory = 'build' +dirname = '' + +DELETE_AFTER_COMPILATION = False + +# List of variables to update +variables_to_update = [ + 'iTime', 'iTimeDelta', 'iFrameRate', 'iSampleRate', + 'iFrame', 'iDate', 'iMouse', 'iResolution', + r'iChannelTime', r'iChannelResolution' +] + +# Header to be prepended to the shader file +header = '''#version 450 + +layout(location = 0) in vec2 qt_TexCoord0; +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 0) uniform buf { + mat4 qt_Matrix; + float qt_Opacity; + float iTime; + float iTimeDelta; + float iFrameRate; + float iSampleRate; + int iFrame; + vec4 iDate; + vec4 iMouse; + vec3 iResolution; + float iChannelTime[4]; + vec3 iChannelResolution[4]; +} ubuf; + +layout(binding = 1) uniform sampler2D iChannel0; +layout(binding = 2) uniform sampler2D iChannel1; +layout(binding = 3) uniform sampler2D iChannel2; +layout(binding = 4) uniform sampler2D iChannel3; + +vec2 fragCoord = vec2(qt_TexCoord0.x, 1.0 - qt_TexCoord0.y) * ubuf.iResolution.xy; +''' + +# Footer to be appended, containing the main entry point +footer = ''' +void main() { + vec4 color = vec4(0.0); + mainImage(color, fragCoord); + fragColor = color; +} +''' + +def parse_arguments(): + parser = argparse.ArgumentParser( + description='A shader processor for ShaderToy', + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Examples: + python ShaderToyProcessor.py -i ./src/deadly_halftones + """ + ) + + parser.add_argument('-i', '--input', + help='Input directory to process') + + parser.add_argument('-v', '--verbose', + action='store_true', + help='Enable verbose output') + + parser.add_argument('-o', '--output', + default='build', + help='Output Directory') + + parser.add_argument('-t', '--temp', + default='processed', + help='Temporary Files Directory') + + return parser.parse_args() + +def process(): + args = parse_arguments() + + if args.temp: + temp_directory = args.temp + + if args.input: + source_directory = args.input + else: + print(f"No input directory given") + sys.exit(1) + + if args.verbose: + print(f"Input directory: {source_directory}") + print(f"Output directory: {temp_directory}") + + try: + for root, dirs, files in os.walk(source_directory): + + # Grab the Common shader file, if it exists + common_file_path = os.path.join(root, 'Common.frag') + common_file_contents = "" + + if os.path.exists(common_file_path): + with open(common_file_path, 'r') as f: + common_file_contents = f.read() + + # 1. Remove any existing #version directive to avoid conflicts + common_file_contents = re.sub(r'^\s*#version\s+.*?\n', '', common_file_contents, flags=re.MULTILINE) + + # 2. Remove any pre-existing main() function + common_file_contents = re.sub(r'void\s+main\s*\([^)]*\)\s*\{[\s\S]*?\}', '', common_file_contents) + + # 3. Prepend 'ubuf.' to all shadertoy uniforms + for var in variables_to_update: + pattern = r'(?