diff --git a/src/main/java/com/jozufozu/flywheel/backend/loading/TaggedStruct.java b/src/main/java/com/jozufozu/flywheel/backend/loading/TaggedStruct.java index eac1ee079..419736645 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/loading/TaggedStruct.java +++ b/src/main/java/com/jozufozu/flywheel/backend/loading/TaggedStruct.java @@ -10,13 +10,13 @@ import java.util.regex.Pattern; public class TaggedStruct { // https://regexr.com/5t207 - static final Pattern taggedStruct = Pattern.compile("#\\[(\\w*)]\\s*struct\\s+([\\w\\d]*)\\s*\\{([\\w\\d \\t#\\[\\](),;\\n]*)}\\s*;"); + public static final Pattern taggedStruct = Pattern.compile("#\\[(\\w*)]\\s*struct\\s+([\\w\\d]*)\\s*\\{([\\w\\d \\t#\\[\\](),;\\n]*)}\\s*;"); - int srcStart, srcEnd; - String source; - String tag; - String name; - String body; + public int srcStart, srcEnd; + public String source; + public String tag; + public String name; + public String body; List fields = new ArrayList<>(4); Map fields2Types = new HashMap<>(); diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/ShaderFunction.java b/src/main/java/com/jozufozu/flywheel/backend/pipeline/ShaderFunction.java new file mode 100644 index 000000000..d9ca0564c --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/pipeline/ShaderFunction.java @@ -0,0 +1,20 @@ +package com.jozufozu.flywheel.backend.pipeline; + +import com.jozufozu.flywheel.backend.pipeline.span.Span; + +import java.util.regex.Pattern; + +public class ShaderFunction { + + public static final Pattern assignment = Pattern.compile("(\\w+)\\s*="); + + private final Span returnType; + private final Span name; + private final Span body; + + public ShaderFunction(Span self, Span returnType, Span name, Span body) { + this.returnType = returnType; + this.name = name; + this.body = body; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/ShaderStruct.java b/src/main/java/com/jozufozu/flywheel/backend/pipeline/ShaderStruct.java new file mode 100644 index 000000000..7f7f12fa6 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/pipeline/ShaderStruct.java @@ -0,0 +1,42 @@ +package com.jozufozu.flywheel.backend.pipeline; + +import com.jozufozu.flywheel.backend.loading.Program; +import com.jozufozu.flywheel.backend.loading.TaggedField; +import com.jozufozu.flywheel.backend.loading.TypeHelper; +import com.jozufozu.flywheel.backend.pipeline.span.Span; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ShaderStruct { + + // https://regexr.com/5t207 + public static final Pattern struct = Pattern.compile("struct\\s+([\\w\\d]*)\\s*\\{([\\w\\d \\t#\\[\\](),;\\n]*)}\\s*;"); + + public Span name; + public Span body; + + List fields = new ArrayList<>(4); + Map fields2Types = new HashMap<>(); + + public ShaderStruct(Span self, Span name, Span body) { + Matcher fielder = StructField.fieldPattern.matcher(body.getValue()); + + while (fielder.find()) { + fields.add(new StructField(fielder)); + fields2Types.put(fielder.group(2), fielder.group(1)); + } + } + + public void addPrefixedAttributes(Program builder, String prefix) { + for (StructField field : fields) { + int attributeCount = TypeHelper.getAttributeCount(field.type); + + builder.addAttribute(prefix + field.name, attributeCount); + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/SourceFile.java b/src/main/java/com/jozufozu/flywheel/backend/pipeline/SourceFile.java new file mode 100644 index 000000000..9d998c9f2 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/pipeline/SourceFile.java @@ -0,0 +1,108 @@ +package com.jozufozu.flywheel.backend.pipeline; + +import java.io.BufferedReader; +import java.io.StringReader; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Stream; + +import com.jozufozu.flywheel.backend.ShaderSources; + +import com.jozufozu.flywheel.backend.pipeline.span.ErrorSpan; +import com.jozufozu.flywheel.backend.pipeline.span.Span; + +import com.jozufozu.flywheel.backend.pipeline.span.StringSpan; + +import net.minecraft.util.ResourceLocation; + +public class SourceFile { + // #use "valid_namespace:valid/path_to_file.glsl" + private static final Pattern includePattern = Pattern.compile("#use \"(\\w+:[\\w./]+)\""); + + // https://regexr.com/60n3d + public static final Pattern functionDeclaration = Pattern.compile("(\\w+)\\s+(\\w+)\\s*\\(([\\w,\\s]*)\\)\\s*\\{"); + + public static final Pattern versionDetector = Pattern.compile("#version[^\\n]*"); + + public final ResourceLocation name; + private final String source; + private final ShaderSources loader; + + private final Map functions = new HashMap<>(); + + public SourceFile(ShaderSources loader, ResourceLocation name, String source) { + this.loader = loader; + this.name = name; + this.source = source; + + parseFunctions(); + } + + public String getSource() { + return source; + } + + protected void parseFunctions() { + Matcher matcher = functionDeclaration.matcher(source); + + while (matcher.find()) { + Span type = Span.fromMatcherGroup(this, matcher, 1); + Span name = Span.fromMatcherGroup(this, matcher, 2); + + int blockStart = matcher.end(); + int blockEnd = findEndOfBlock(blockStart); + + Span self; + Span body; + if (blockEnd > blockStart) { + self = new StringSpan(this, matcher.start(), blockEnd); + body = new StringSpan(this, blockStart, blockEnd); + } else { + self = new ErrorSpan(this, matcher.start(), matcher.end()); + body = new ErrorSpan(this, blockStart); + } + + ShaderFunction function = new ShaderFunction(self, type, name, body); + + functions.put(name.getValue(), function); + } + } + + private int findEndOfBlock(int end) { + char[] rest = source.substring(end).toCharArray(); + + int blockDepth = 0; + for (int i = 0; i < rest.length; i++) { + char ch = rest[i]; + + if (ch == '{') blockDepth++; + if (ch == '}') blockDepth--; + + if (blockDepth < 0) { + return end + i; + } + } + + return -1; + } + + public String printSource() { + StringBuilder builder = new StringBuilder(); + + builder.append("Source for shader '").append(name).append("':\n"); + int i = 1; + for (String s : source.split("\n")) { + builder.append(String.format("%1$4s: ", i++)) + .append(s) + .append('\n'); + } + + return builder.toString(); + } + + public static Stream lines(String s) { + return new BufferedReader(new StringReader(s)).lines(); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/StructField.java b/src/main/java/com/jozufozu/flywheel/backend/pipeline/StructField.java new file mode 100644 index 000000000..180f7470a --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/pipeline/StructField.java @@ -0,0 +1,35 @@ +package com.jozufozu.flywheel.backend.pipeline; + +import com.jozufozu.flywheel.backend.loading.LayoutTag; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class StructField { + public static final Pattern fieldPattern = Pattern.compile("(\\S+)\\s*(\\S+);"); + + public String name; + public String type; + public LayoutTag layout; + + public StructField(Matcher fieldMatcher) { + type = fieldMatcher.group(2); + name = fieldMatcher.group(3); + } + + public String getName() { + return name; + } + + public String getType() { + return type; + } + + @Override + public String toString() { + return "TaggedField{" + + "name='" + name + '\'' + + ", type='" + type + '\'' + + '}'; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/WorldShaderPipeline.java b/src/main/java/com/jozufozu/flywheel/backend/pipeline/WorldShaderPipeline.java new file mode 100644 index 000000000..f16426f2a --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/pipeline/WorldShaderPipeline.java @@ -0,0 +1,16 @@ +package com.jozufozu.flywheel.backend.pipeline; + +import com.jozufozu.flywheel.core.shader.IMultiProgram; +import com.jozufozu.flywheel.core.shader.StateSensitiveMultiProgram; +import com.jozufozu.flywheel.core.shader.WorldProgram; + +import javax.annotation.Nullable; + +public class WorldShaderPipeline

{ + + @Nullable // TODO: temporary null return + public IMultiProgram

compile(SourceFile file) { + + return null; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/package-info.java b/src/main/java/com/jozufozu/flywheel/backend/pipeline/package-info.java new file mode 100644 index 000000000..6cc5bc974 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/pipeline/package-info.java @@ -0,0 +1,7 @@ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +package com.jozufozu.flywheel.backend.pipeline; + +import mcp.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/span/ErrorSpan.java b/src/main/java/com/jozufozu/flywheel/backend/pipeline/span/ErrorSpan.java new file mode 100644 index 000000000..227328e50 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/pipeline/span/ErrorSpan.java @@ -0,0 +1,18 @@ +package com.jozufozu.flywheel.backend.pipeline.span; + +import com.jozufozu.flywheel.backend.pipeline.SourceFile; + +public class ErrorSpan extends Span { + public ErrorSpan(SourceFile in, int loc) { + super(in, loc, loc); + } + + public ErrorSpan(SourceFile in, int start, int end) { + super(in, start, end); + } + + @Override + public String getValue() { + return ""; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/span/Span.java b/src/main/java/com/jozufozu/flywheel/backend/pipeline/span/Span.java new file mode 100644 index 000000000..f3f06c658 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/pipeline/span/Span.java @@ -0,0 +1,40 @@ +package com.jozufozu.flywheel.backend.pipeline.span; + +import com.jozufozu.flywheel.backend.pipeline.SourceFile; + +import java.util.regex.Matcher; + +public abstract class Span { + + protected final SourceFile in; + protected final int start; + protected final int end; + + public Span(SourceFile in, int start, int end) { + this.in = in; + this.start = start; + this.end = end; + } + + public SourceFile getSourceFile() { + return in; + } + + public int getStart() { + return start; + } + + public int getEnd() { + return end; + } + + public abstract String getValue(); + + public static Span fromMatcherGroup(SourceFile src, Matcher m, int group) { + return new StringSpan(src, m.start(group), m.end(group)); + } + + public static Span fromMatcher(SourceFile src, Matcher m) { + return new StringSpan(src, m.start(), m.end()); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/pipeline/span/StringSpan.java b/src/main/java/com/jozufozu/flywheel/backend/pipeline/span/StringSpan.java new file mode 100644 index 000000000..434f0f649 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/pipeline/span/StringSpan.java @@ -0,0 +1,15 @@ +package com.jozufozu.flywheel.backend.pipeline.span; + +import com.jozufozu.flywheel.backend.pipeline.SourceFile; + +public class StringSpan extends Span { + + public StringSpan(SourceFile in, int start, int end) { + super(in, start, end); + } + + @Override + public String getValue() { + return in.getSource().substring(start, end); + } +}