diff --git a/common/src/main/java/foundry/veil/impl/client/render/dynamicbuffer/DynamicBufferProcessor.java b/common/src/main/java/foundry/veil/impl/client/render/dynamicbuffer/DynamicBufferProcessor.java index 4ce9a28a..3729b8dd 100644 --- a/common/src/main/java/foundry/veil/impl/client/render/dynamicbuffer/DynamicBufferProcessor.java +++ b/common/src/main/java/foundry/veil/impl/client/render/dynamicbuffer/DynamicBufferProcessor.java @@ -6,6 +6,8 @@ import foundry.veil.impl.glsl.GlslInjectionPoint; import foundry.veil.impl.glsl.GlslParser; import foundry.veil.impl.glsl.GlslSyntaxException; +import foundry.veil.impl.glsl.grammar.GlslSpecifiedType; +import foundry.veil.impl.glsl.grammar.GlslTypeQualifier; import foundry.veil.impl.glsl.node.GlslNode; import foundry.veil.impl.glsl.node.GlslTree; import foundry.veil.impl.glsl.node.function.GlslFunctionNode; @@ -13,6 +15,8 @@ import foundry.veil.impl.glsl.visitor.GlslStringWriter; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import static org.lwjgl.opengl.GL20C.GL_FRAGMENT_SHADER; @@ -48,11 +52,58 @@ public String modify(Context ctx, String source) throws IOException { } if (modified) { + List outputs = new ArrayList<>(); + tree.fields().forEach(node -> { + GlslSpecifiedType type = node.getType(); + boolean valid = false; + for (GlslTypeQualifier qualifier : type.getQualifiers()) { + if (qualifier == GlslTypeQualifier.StorageType.OUT) { + valid = true; + break; + } + } + + if (!valid) { + return; + } + + for (GlslTypeQualifier qualifier : type.getQualifiers()) { + if (qualifier instanceof GlslTypeQualifier.Layout(List layoutIds)) { + for (GlslTypeQualifier.LayoutId layoutId : layoutIds) { + if ("location".equals(layoutId.identifier())) { + GlslNode expression = layoutId.expression(); + if (expression != null) { + try { + int location = Integer.parseInt(expression.getSourceString()); + if (location == 0) { + outputs.clear(); + return; + } + valid = false; + break; + } catch (NumberFormatException ignored) { + } + } + } + } + } + } + + if (valid) { + outputs.add(node); + } + }); + + for (GlslNewNode output : outputs) { + output.getType().addLayoutId("location", GlslNode.intConstant(0)); + } + GlslStringWriter writer = new GlslStringWriter(); tree.visit(writer); return writer.toString(); } - } catch (GlslSyntaxException e) { + } catch ( + GlslSyntaxException e) { Veil.LOGGER.error("Failed to transform shader: {}", ctx.name(), e); } return source; diff --git a/common/src/main/java/foundry/veil/impl/client/render/shader/ShaderProgramImpl.java b/common/src/main/java/foundry/veil/impl/client/render/shader/ShaderProgramImpl.java index 7fbe9c77..d1635035 100644 --- a/common/src/main/java/foundry/veil/impl/client/render/shader/ShaderProgramImpl.java +++ b/common/src/main/java/foundry/veil/impl/client/render/shader/ShaderProgramImpl.java @@ -125,6 +125,10 @@ private void clearShader() { } private void link() throws ShaderException { + this.uniforms.clear(); + this.uniformBlocks.clear(); + this.textures.clear(); + glLinkProgram(this.program); if (glGetProgrami(this.program, GL_LINK_STATUS) != GL_TRUE) { String log = glGetProgramInfoLog(this.program); diff --git a/common/src/main/java/foundry/veil/impl/glsl/GlslParser.java b/common/src/main/java/foundry/veil/impl/glsl/GlslParser.java index 83717035..644e777a 100644 --- a/common/src/main/java/foundry/veil/impl/glsl/GlslParser.java +++ b/common/src/main/java/foundry/veil/impl/glsl/GlslParser.java @@ -1145,7 +1145,7 @@ private static List parseParameterList(GlslTokenReader return null; } - return GlslTypeQualifier.layout(layoutQualifierIds.toArray(GlslTypeQualifier.LayoutId[]::new)); + return GlslTypeQualifier.layout(layoutQualifierIds); } private static @Nullable List parseTypeQualifiers(GlslTokenReader reader) { diff --git a/common/src/main/java/foundry/veil/impl/glsl/grammar/GlslSpecifiedType.java b/common/src/main/java/foundry/veil/impl/glsl/grammar/GlslSpecifiedType.java index 9761756c..eaf0d397 100644 --- a/common/src/main/java/foundry/veil/impl/glsl/grammar/GlslSpecifiedType.java +++ b/common/src/main/java/foundry/veil/impl/glsl/grammar/GlslSpecifiedType.java @@ -1,9 +1,9 @@ package foundry.veil.impl.glsl.grammar; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; +import foundry.veil.impl.glsl.node.GlslNode; +import org.jetbrains.annotations.Nullable; + +import java.util.*; /** * Specifies the full operand of something in GLSL in addition to all qualifiers. @@ -35,6 +35,24 @@ public GlslTypeSpecifier getSpecifier() { return this.specifier; } + /** + * Adds a layout id to the qualifier list, or adds to an existing layout. + * + * @param identifier The name of the identifier + * @param expression The value to assign it to + */ + public GlslSpecifiedType addLayoutId(String identifier, @Nullable GlslNode expression) { + for (GlslTypeQualifier qualifier : this.qualifiers) { + if (qualifier instanceof GlslTypeQualifier.Layout(List layoutIds)) { + layoutIds.add(new GlslTypeQualifier.LayoutId(identifier, expression)); + return this; + } + } + + this.qualifiers.addFirst(GlslTypeQualifier.layout(Collections.singleton(new GlslTypeQualifier.LayoutId(identifier, expression)))); + return this; + } + /** * @return The qualifiers applied to it, for example layout() or flat */ diff --git a/common/src/main/java/foundry/veil/impl/glsl/grammar/GlslTypeQualifier.java b/common/src/main/java/foundry/veil/impl/glsl/grammar/GlslTypeQualifier.java index 890ccca8..46b5d101 100644 --- a/common/src/main/java/foundry/veil/impl/glsl/grammar/GlslTypeQualifier.java +++ b/common/src/main/java/foundry/veil/impl/glsl/grammar/GlslTypeQualifier.java @@ -3,8 +3,7 @@ import foundry.veil.impl.glsl.node.GlslNode; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; -import java.util.Locale; +import java.util.*; public sealed interface GlslTypeQualifier { @@ -14,8 +13,8 @@ static GlslTypeQualifier storage(String[] typeNames) { return new StorageSubroutine(typeNames); } - static Layout layout(LayoutId... ids) { - return new Layout(ids); + static Layout layout(Collection ids) { + return new Layout(new ArrayList<>(ids)); } static LayoutId identifierLayoutId(String identifier, @Nullable GlslNode constantExpression) { @@ -48,7 +47,7 @@ public String getSourceString() { } } - record Layout(LayoutId[] layoutIds) implements GlslTypeQualifier { + record Layout(List layoutIds) implements GlslTypeQualifier { @Override public String getSourceString() { StringBuilder builder = new StringBuilder();