From bf03f084c3a2fde16d0bc6a8d1860226db7d3632 Mon Sep 17 00:00:00 2001 From: Jozufozu Date: Mon, 29 Aug 2022 21:21:52 -0700 Subject: [PATCH] Inderinstanced --- .../flywheel/api/pipeline/PipelineShader.java | 20 +- .../flywheel/api/struct/StructType.java | 2 - .../jozufozu/flywheel/backend/Backend.java | 3 + .../com/jozufozu/flywheel/backend/Loader.java | 40 +++- .../backend/gl/array/GlVertexArray.java | 2 +- .../backend/instancing/PipelineCompiler.java | 70 ++++--- .../indirect/ComputeCullerCompiler.java | 37 +++- .../indirect/IndirectCullingGroup.java | 7 +- .../instancing/InstancingEngine.java | 17 +- .../jozufozu/flywheel/config/FlwConfig.java | 2 + .../jozufozu/flywheel/core/BackendTypes.java | 3 +- .../jozufozu/flywheel/core/Components.java | 9 +- .../flywheel/core/FullscreenQuad.java | 2 +- .../flywheel/core/SourceComponent.java | 15 ++ .../flywheel/core/compile/CompileUtil.java | 8 +- .../flywheel/core/compile/DebugCompiler.java | 12 +- .../compile/ShaderCompilationException.java | 2 +- .../flywheel/core/layout/BufferLayout.java | 156 ++++++++++++++- .../flywheel/core/layout/CommonItems.java | 87 ++++++--- .../{LayoutItem.java => InputType.java} | 10 +- .../flywheel/core/layout/MatrixItem.java | 13 +- .../flywheel/core/layout/PrimitiveItem.java | 66 ++++++- .../core/source/CompilationContext.java | 62 ++++-- .../flywheel/core/source/SourceChecks.java | 4 +- .../flywheel/core/source/SourceFile.java | 98 +++------- .../core/source/error/ErrorBuilder.java | 5 + .../core/source/generate/GlslBuilder.java | 179 ++++++++++++++++++ .../core/source/generate/GlslExpr.java | 86 +++++++++ .../core/source/parse/ShaderFunction.java | 10 +- .../{Variable.java => ShaderVariable.java} | 4 +- .../core/structs/oriented/OrientedType.java | 12 +- .../structs/transformed/TransformedType.java | 11 +- .../flywheel/core/vertex/BlockVertex.java | 10 +- .../core/vertex/PosTexNormalVertex.java | 4 +- .../flywheel/flywheel/instance/oriented.vert | 25 ++- .../flywheel/instance/oriented_indirect.glsl | 32 ---- .../flywheel/instance/transformed.vert | 24 ++- .../instance/transformed_indirect.glsl | 27 --- .../flywheel/pipeline/indirect_cull.glsl | 6 +- .../flywheel/pipeline/indirect_draw.vert | 4 +- .../pipeline/instanced_arrays_draw.vert | 3 +- .../assets/flywheel/flywheel/util/types.glsl | 8 + 42 files changed, 895 insertions(+), 302 deletions(-) create mode 100644 src/main/java/com/jozufozu/flywheel/core/SourceComponent.java rename src/main/java/com/jozufozu/flywheel/core/layout/{LayoutItem.java => InputType.java} (51%) create mode 100644 src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBuilder.java create mode 100644 src/main/java/com/jozufozu/flywheel/core/source/generate/GlslExpr.java rename src/main/java/com/jozufozu/flywheel/core/source/parse/{Variable.java => ShaderVariable.java} (84%) delete mode 100644 src/main/resources/assets/flywheel/flywheel/instance/oriented_indirect.glsl delete mode 100644 src/main/resources/assets/flywheel/flywheel/instance/transformed_indirect.glsl diff --git a/src/main/java/com/jozufozu/flywheel/api/pipeline/PipelineShader.java b/src/main/java/com/jozufozu/flywheel/api/pipeline/PipelineShader.java index 155614856..393f8d263 100644 --- a/src/main/java/com/jozufozu/flywheel/api/pipeline/PipelineShader.java +++ b/src/main/java/com/jozufozu/flywheel/api/pipeline/PipelineShader.java @@ -1,8 +1,26 @@ package com.jozufozu.flywheel.api.pipeline; +import java.util.function.Function; + +import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.backend.gl.GLSLVersion; +import com.jozufozu.flywheel.core.SourceComponent; import com.jozufozu.flywheel.core.source.FileResolution; -public record PipelineShader(GLSLVersion glslVersion, FileResolution vertex, FileResolution fragment) { +public record PipelineShader(GLSLVersion glslVersion, FileResolution vertex, FileResolution fragment, + InstanceAssemblerFactory factory) { + /** + * Generate the source component necessary to convert a packed {@link StructType} into its shader representation. + * + * @param structType The struct type to convert. + * @return A source component defining functions that unpack a representation of the given struct type. + */ + public SourceComponent assemble(StructType structType) { + return factory.apply(structType); + } + + public interface InstanceAssemblerFactory extends Function, SourceComponent> { + + } } diff --git a/src/main/java/com/jozufozu/flywheel/api/struct/StructType.java b/src/main/java/com/jozufozu/flywheel/api/struct/StructType.java index 0c35a7124..5de8d85ec 100644 --- a/src/main/java/com/jozufozu/flywheel/api/struct/StructType.java +++ b/src/main/java/com/jozufozu/flywheel/api/struct/StructType.java @@ -31,8 +31,6 @@ public interface StructType { StorageBufferWriter getStorageBufferWriter(); - FileResolution getIndirectShader(); - interface VertexTransformer { void transform(MutableVertexList vertexList, S struct, ClientLevel level); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/Backend.java b/src/main/java/com/jozufozu/flywheel/backend/Backend.java index 62ed1f2c7..90f44788b 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Backend.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Backend.java @@ -88,6 +88,9 @@ public class Backend { private static BackendType chooseEngine() { var preferred = FlwConfig.get() .getBackendType(); + if (preferred == null) { + return BackendTypes.defaultForCurrentPC(); + } var actual = preferred.findFallback(); if (preferred != actual) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/Loader.java b/src/main/java/com/jozufozu/flywheel/backend/Loader.java index 7400c5cfa..588ee8bbb 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Loader.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Loader.java @@ -1,14 +1,20 @@ package com.jozufozu.flywheel.backend; +import java.util.List; + +import com.jozufozu.flywheel.api.context.ContextShader; import com.jozufozu.flywheel.api.material.Material; +import com.jozufozu.flywheel.api.pipeline.PipelineShader; import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; -import com.jozufozu.flywheel.core.ComponentRegistry; -import com.jozufozu.flywheel.api.context.ContextShader; import com.jozufozu.flywheel.backend.instancing.PipelineCompiler; +import com.jozufozu.flywheel.backend.instancing.indirect.ComputeCullerCompiler; +import com.jozufozu.flywheel.core.ComponentRegistry; import com.jozufozu.flywheel.core.Components; +import com.jozufozu.flywheel.core.compile.ShaderCompilationException; import com.jozufozu.flywheel.core.source.FileResolution; +import com.jozufozu.flywheel.core.source.ShaderLoadingException; import com.jozufozu.flywheel.core.source.ShaderSources; import com.jozufozu.flywheel.core.source.error.ErrorReporter; import com.jozufozu.flywheel.util.StringUtil; @@ -63,21 +69,45 @@ public class Loader implements ResourceManagerReloadListener { Backend.LOGGER.info("All shaders passed checks."); long compileStart = System.nanoTime(); + int programCounter = 0; + boolean crash = false; for (Material material : ComponentRegistry.materials) { for (StructType structType : ComponentRegistry.structTypes) { for (VertexType vertexType : ComponentRegistry.vertexTypes) { for (ContextShader contextShader : ComponentRegistry.contextShaders) { - var ctx = new PipelineCompiler.Context(vertexType, material, structType.getInstanceShader(), contextShader, Components.INSTANCED_ARRAYS); - PipelineCompiler.INSTANCE.getProgram(ctx); + for (PipelineShader pipelineShader : List.of(Components.INSTANCED_ARRAYS, Components.INDIRECT)) { + var ctx = new PipelineCompiler.Context(vertexType, material, structType, contextShader, pipelineShader); + try { + PipelineCompiler.INSTANCE.getProgram(ctx); + } catch (ShaderCompilationException e) { + Backend.LOGGER.error(e.errors); + crash = true; + } + programCounter++; + } } } } } + for (StructType structType : ComponentRegistry.structTypes) { + try { + ComputeCullerCompiler.INSTANCE.get(structType); + } catch (ShaderCompilationException e) { + Backend.LOGGER.error(e.errors); + crash = true; + } + programCounter++; + } + long compileEnd = System.nanoTime(); - Backend.LOGGER.info("Compiled all programs in " + StringUtil.formatTime(compileEnd - compileStart)); + Backend.LOGGER.info("Compiled " + programCounter + " programs in " + StringUtil.formatTime(compileEnd - compileStart)); + + if (crash) { + throw new ShaderLoadingException("Compilation failed"); + } ClientLevel world = Minecraft.getInstance().level; if (Backend.canUseInstancing(world)) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/array/GlVertexArray.java b/src/main/java/com/jozufozu/flywheel/backend/gl/array/GlVertexArray.java index 3abf7a7d0..d2ba0d15a 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/array/GlVertexArray.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/array/GlVertexArray.java @@ -82,7 +82,7 @@ public class GlVertexArray extends GlObject { int i = startAttrib; final int stride = type.getStride(); - for (var attribute : type.getAttributes()) { + for (var attribute : type.attributes()) { targets[i] = targetBuffer; attributes[i] = attribute; offsets[i] = offset; diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/PipelineCompiler.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/PipelineCompiler.java index ee78cc709..0551d09c6 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/PipelineCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/PipelineCompiler.java @@ -1,23 +1,24 @@ package com.jozufozu.flywheel.backend.instancing; +import java.util.LinkedHashSet; import java.util.List; import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.api.context.ContextShader; import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.pipeline.PipelineShader; +import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.gl.GLSLVersion; import com.jozufozu.flywheel.backend.gl.shader.GlProgram; import com.jozufozu.flywheel.backend.gl.shader.GlShader; import com.jozufozu.flywheel.backend.gl.shader.ShaderType; +import com.jozufozu.flywheel.core.SourceComponent; import com.jozufozu.flywheel.core.compile.CompileUtil; import com.jozufozu.flywheel.core.compile.Memoizer; import com.jozufozu.flywheel.core.compile.ProgramAssembler; import com.jozufozu.flywheel.core.compile.ShaderCompilationException; import com.jozufozu.flywheel.core.source.CompilationContext; -import com.jozufozu.flywheel.core.source.FileResolution; -import com.jozufozu.flywheel.core.source.SourceFile; import com.jozufozu.flywheel.event.ReloadRenderersEvent; import net.minecraft.resources.ResourceLocation; @@ -68,8 +69,8 @@ public class PipelineCompiler extends Memoizer structType, ContextShader contextShader, PipelineShader pipelineShader) { - ImmutableList getVertexComponents() { - return ImmutableList.of(vertexType.getLayoutShader().getFile(), instanceShader.getFile(), material.getVertexShader().getFile(), - contextShader.getVertexShader(), pipelineShader.vertex().getFile()); + ImmutableList getVertexComponents() { + var layout = vertexType.getLayoutShader() + .getFile(); + var instanceAssembly = pipelineShader.assemble(structType); + var instance = structType.getInstanceShader() + .getFile(); + var material = this.material.getVertexShader() + .getFile(); + var context = contextShader.getVertexShader(); + var pipeline = pipelineShader.vertex() + .getFile(); + return ImmutableList.of(layout, instanceAssembly, instance, material, context, pipeline); } - ImmutableList getFragmentComponents() { - return ImmutableList.of(material.getFragmentShader().getFile(), contextShader.getFragmentShader(), - pipelineShader.fragment().getFile()); + ImmutableList getFragmentComponents() { + var material = this.material.getFragmentShader() + .getFile(); + var context = contextShader.getFragmentShader(); + var pipeline = pipelineShader.fragment() + .getFile(); + return ImmutableList.of(material, context, pipeline); } } @@ -116,9 +130,7 @@ public class PipelineCompiler extends Memoizerbuilder(); - for (var file : key.components) { - finalSource.append(file.generateFinalSource(ctx)); - names.add(file.name); + var included = new LinkedHashSet(); // linked to preserve order + for (var component : key.sourceComponents) { + included.addAll(component.included()); + names.add(component.name()); + } + + for (var include : included) { + finalSource.append(include.source(ctx)); + } + + for (var component : key.sourceComponents) { + finalSource.append(component.source(ctx)); } try { @@ -144,14 +165,15 @@ public class PipelineCompiler extends Memoizer components) { + public record Context(GLSLVersion glslVersion, ShaderType shaderType, List sourceComponents) { public String generateHeader() { return CompileUtil.generateHeader(glslVersion, shaderType); } } + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/ComputeCullerCompiler.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/ComputeCullerCompiler.java index 5f664367b..57ac8c74c 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/ComputeCullerCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/ComputeCullerCompiler.java @@ -1,20 +1,26 @@ package com.jozufozu.flywheel.backend.instancing.indirect; +import java.util.LinkedHashSet; +import java.util.List; + import com.google.common.collect.ImmutableList; +import com.jozufozu.flywheel.api.struct.StructType; import com.jozufozu.flywheel.backend.gl.GLSLVersion; import com.jozufozu.flywheel.backend.gl.shader.GlProgram; import com.jozufozu.flywheel.backend.gl.shader.GlShader; import com.jozufozu.flywheel.backend.gl.shader.ShaderType; import com.jozufozu.flywheel.core.Components; +import com.jozufozu.flywheel.core.SourceComponent; import com.jozufozu.flywheel.core.compile.CompileUtil; import com.jozufozu.flywheel.core.compile.Memoizer; import com.jozufozu.flywheel.core.compile.ProgramAssembler; import com.jozufozu.flywheel.core.compile.ShaderCompilationException; import com.jozufozu.flywheel.core.source.CompilationContext; -import com.jozufozu.flywheel.core.source.FileResolution; import com.jozufozu.flywheel.event.ReloadRenderersEvent; -public class ComputeCullerCompiler extends Memoizer { +import net.minecraft.resources.ResourceLocation; + +public class ComputeCullerCompiler extends Memoizer, GlProgram> { public static final ComputeCullerCompiler INSTANCE = new ComputeCullerCompiler(); @@ -22,22 +28,35 @@ public class ComputeCullerCompiler extends Memoizer { } @Override - protected GlProgram _create(FileResolution file) { + protected GlProgram _create(StructType structType) { + var location = structType.getInstanceShader(); var finalSource = new StringBuilder(); CompilationContext context = new CompilationContext(); + var components = List.of(structType.getLayout() + .getIndirectComponent(), location.getFile(), Components.Pipeline.INDIRECT_CULL.getFile()); + + var names = ImmutableList.builder(); + var included = new LinkedHashSet(); // linked to preserve order + for (var component : components) { + included.addAll(component.included()); + names.add(component.name()); + } finalSource.append(CompileUtil.generateHeader(GLSLVersion.V460, ShaderType.COMPUTE)); - finalSource.append(file.getFile() - .generateFinalSource(context)); + for (var include : included) { + finalSource.append(include.source(context)); + } - finalSource.append(Components.Pipeline.INDIRECT_CULL.getFile() - .generateFinalSource(context)); + for (var component : components) { + finalSource.append(component.source(context)); + } try { - var shader = new GlShader(finalSource.toString(), ShaderType.COMPUTE, ImmutableList.of(file.getFileLoc())); + var fileLoc = location.getFileLoc(); + var shader = new GlShader(finalSource.toString(), ShaderType.COMPUTE, ImmutableList.of(fileLoc)); - return new ProgramAssembler(file.getFileLoc()).attachShader(shader) + return new ProgramAssembler(fileLoc).attachShader(shader) .link() .build(GlProgram::new); } catch (ShaderCompilationException e) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectCullingGroup.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectCullingGroup.java index f1d21bdca..38427e560 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectCullingGroup.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/indirect/IndirectCullingGroup.java @@ -64,9 +64,8 @@ public class IndirectCullingGroup { .quads2Tris(2048).buffer.handle(); setupVertexArray(); - var indirectShader = structType.getIndirectShader(); - compute = ComputeCullerCompiler.INSTANCE.get(indirectShader); - draw = PipelineCompiler.INSTANCE.get(new PipelineCompiler.Context(vertexType, Materials.SHULKER, indirectShader, Components.WORLD, Components.INDIRECT)); + compute = ComputeCullerCompiler.INSTANCE.get(structType); + draw = PipelineCompiler.INSTANCE.get(new PipelineCompiler.Context(vertexType, Materials.SHULKER, structType, Components.WORLD, Components.INDIRECT)); } private void setupVertexArray() { @@ -75,7 +74,7 @@ public class IndirectCullingGroup { var meshLayout = vertexType.getLayout(); var meshAttribs = meshLayout.getAttributeCount(); - var attributes = meshLayout.getAttributes(); + var attributes = meshLayout.attributes(); long offset = 0; for (int i = 0; i < meshAttribs; i++) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java index 23f5ba6df..a3bd99d58 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java @@ -9,10 +9,9 @@ import org.jetbrains.annotations.NotNull; import org.lwjgl.opengl.GL32; import com.jozufozu.flywheel.api.RenderStage; +import com.jozufozu.flywheel.api.context.ContextShader; import com.jozufozu.flywheel.api.instancer.InstancedPart; -import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.struct.StructType; -import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.gl.GlTextureUnit; import com.jozufozu.flywheel.backend.instancing.Engine; import com.jozufozu.flywheel.backend.instancing.InstanceManager; @@ -20,8 +19,6 @@ import com.jozufozu.flywheel.backend.instancing.PipelineCompiler; import com.jozufozu.flywheel.backend.instancing.TaskEngine; import com.jozufozu.flywheel.core.Components; import com.jozufozu.flywheel.core.RenderContext; -import com.jozufozu.flywheel.api.context.ContextShader; -import com.jozufozu.flywheel.core.source.FileResolution; import com.jozufozu.flywheel.core.uniform.UniformBuffer; import com.jozufozu.flywheel.util.WeakHashSet; import com.mojang.blaze3d.systems.RenderSystem; @@ -118,16 +115,16 @@ public class InstancingEngine implements Engine { } protected void setup(ShaderState desc) { - VertexType vertexType = desc.vertex(); - FileResolution instanceShader = desc.instance() - .getInstanceShader(); - Material material = desc.material(); + var vertexType = desc.vertex(); + var structType = desc.instance(); + var material = desc.material(); - var ctx = new PipelineCompiler.Context(vertexType, material, instanceShader, context, Components.INSTANCED_ARRAYS); + var ctx = new PipelineCompiler.Context(vertexType, material, structType, context, Components.INSTANCED_ARRAYS); PipelineCompiler.INSTANCE.getProgram(ctx) .bind(); - UniformBuffer.getInstance().sync(); + UniformBuffer.getInstance() + .sync(); } @Override diff --git a/src/main/java/com/jozufozu/flywheel/config/FlwConfig.java b/src/main/java/com/jozufozu/flywheel/config/FlwConfig.java index 2cc5f18df..f9318e3c3 100644 --- a/src/main/java/com/jozufozu/flywheel/config/FlwConfig.java +++ b/src/main/java/com/jozufozu/flywheel/config/FlwConfig.java @@ -1,6 +1,7 @@ package com.jozufozu.flywheel.config; import org.apache.commons.lang3.tuple.Pair; +import org.jetbrains.annotations.Nullable; import com.jozufozu.flywheel.backend.BackendType; import com.jozufozu.flywheel.core.BackendTypes; @@ -29,6 +30,7 @@ public class FlwConfig { return INSTANCE; } + @Nullable public BackendType getBackendType() { return BackendTypes.getBackendType(client.backend.get()); } diff --git a/src/main/java/com/jozufozu/flywheel/core/BackendTypes.java b/src/main/java/com/jozufozu/flywheel/core/BackendTypes.java index 5ea394179..3c80fd8b2 100644 --- a/src/main/java/com/jozufozu/flywheel/core/BackendTypes.java +++ b/src/main/java/com/jozufozu/flywheel/core/BackendTypes.java @@ -2,6 +2,7 @@ package com.jozufozu.flywheel.core; import java.util.Collection; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import org.jetbrains.annotations.Nullable; @@ -55,7 +56,7 @@ public class BackendTypes { @Nullable public static BackendType getBackendType(String name) { - return BACKEND_TYPES.get(name); + return BACKEND_TYPES.get(name.toLowerCase(Locale.ROOT)); } /** diff --git a/src/main/java/com/jozufozu/flywheel/core/Components.java b/src/main/java/com/jozufozu/flywheel/core/Components.java index ab85c20d4..a75dd70ca 100644 --- a/src/main/java/com/jozufozu/flywheel/core/Components.java +++ b/src/main/java/com/jozufozu/flywheel/core/Components.java @@ -29,8 +29,11 @@ public class Components { public static final ContextShader WORLD = ComponentRegistry.register(new ContextShader(WorldProgram::new, Files.WORLD_VERTEX, Files.WORLD_FRAGMENT)); public static final ContextShader CRUMBLING = ComponentRegistry.register(new ContextShader(CrumblingProgram::new, Files.WORLD_VERTEX, Files.CRUMBLING_FRAGMENT)); - public static final PipelineShader INSTANCED_ARRAYS = new PipelineShader(GLSLVersion.V420, Pipeline.INSTANCED_ARRAYS_DRAW, Pipeline.DRAW_FRAGMENT); - public static final PipelineShader INDIRECT = new PipelineShader(GLSLVersion.V460, Pipeline.INDIRECT_DRAW, Pipeline.DRAW_FRAGMENT); + public static final PipelineShader INSTANCED_ARRAYS = new PipelineShader(GLSLVersion.V420, Pipeline.INSTANCED_ARRAYS_DRAW, Pipeline.DRAW_FRAGMENT, (structType) -> structType.getLayout() + .getInstancedArraysComponent()); + public static final PipelineShader INDIRECT = new PipelineShader(GLSLVersion.V460, Pipeline.INDIRECT_DRAW, Pipeline.DRAW_FRAGMENT, (structType) -> structType.getLayout() + .getIndirectComponent()); + public static final FileResolution UTIL_TYPES = FileResolution.get(Flywheel.rl("util/types.glsl")); public static void init() { Files.init(); @@ -59,9 +62,7 @@ public class Components { public static final FileResolution BLOCK_LAYOUT = layoutVertex(ResourceUtil.subPath(Names.BLOCK, ".vert")); public static final FileResolution POS_TEX_NORMAL_LAYOUT = layoutVertex(ResourceUtil.subPath(Names.POS_TEX_NORMAL, ".vert")); public static final FileResolution TRANSFORMED = instanceVertex(ResourceUtil.subPath(Names.TRANSFORMED, ".vert")); - public static final FileResolution TRANSFORMED_INDIRECT = instanceVertex(ResourceUtil.subPath(Names.TRANSFORMED, "_indirect.glsl")); public static final FileResolution ORIENTED = instanceVertex(ResourceUtil.subPath(Names.ORIENTED, ".vert")); - public static final FileResolution ORIENTED_INDIRECT = instanceVertex(ResourceUtil.subPath(Names.ORIENTED, "_indirect.glsl")); public static final FileResolution DEFAULT_VERTEX = materialVertex(ResourceUtil.subPath(Names.DEFAULT, ".vert")); public static final FileResolution SHADED_VERTEX = materialVertex(ResourceUtil.subPath(Names.SHADED, ".vert")); public static final FileResolution DEFAULT_FRAGMENT = materialFragment(ResourceUtil.subPath(Names.DEFAULT, ".frag")); diff --git a/src/main/java/com/jozufozu/flywheel/core/FullscreenQuad.java b/src/main/java/com/jozufozu/flywheel/core/FullscreenQuad.java index 7280641fa..bcbfe95a2 100644 --- a/src/main/java/com/jozufozu/flywheel/core/FullscreenQuad.java +++ b/src/main/java/com/jozufozu/flywheel/core/FullscreenQuad.java @@ -19,7 +19,7 @@ public class FullscreenQuad { public static final Lazy INSTANCE = Lazy.of(FullscreenQuad::new); private static final BufferLayout LAYOUT = BufferLayout.builder() - .addItems(CommonItems.VEC4) + .addItem(CommonItems.VEC4, "posTex") .build(); private static final float[] vertices = { diff --git a/src/main/java/com/jozufozu/flywheel/core/SourceComponent.java b/src/main/java/com/jozufozu/flywheel/core/SourceComponent.java new file mode 100644 index 000000000..2adae92b6 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/SourceComponent.java @@ -0,0 +1,15 @@ +package com.jozufozu.flywheel.core; + +import java.util.Collection; + +import com.jozufozu.flywheel.core.source.CompilationContext; + +import net.minecraft.resources.ResourceLocation; + +public interface SourceComponent { + Collection included(); + + String source(CompilationContext ctx); + + ResourceLocation name(); +} diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/CompileUtil.java b/src/main/java/com/jozufozu/flywheel/core/compile/CompileUtil.java index d4641970e..545055281 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/CompileUtil.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/CompileUtil.java @@ -24,7 +24,9 @@ public class CompileUtil { public static int getElementCount(String type) { Matcher vec = vecType.matcher(type); - if (vec.find()) return Integer.parseInt(vec.group(1)); + if (vec.find()) { + return Integer.parseInt(vec.group(1)); + } Matcher mat = matType.matcher(type); if (mat.find()) { @@ -32,7 +34,9 @@ public class CompileUtil { String m = mat.group(2); - if (m != null) return Integer.parseInt(m) * n; + if (m != null) { + return Integer.parseInt(m) * n; + } return n; } diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/DebugCompiler.java b/src/main/java/com/jozufozu/flywheel/core/compile/DebugCompiler.java index 319d2dc11..322d2777f 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/DebugCompiler.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/DebugCompiler.java @@ -68,11 +68,17 @@ public class DebugCompiler extends Memoizer { protected GlShader _create(Context ctx) { var index = new CompilationContext(); - String source = CompileUtil.generateHeader(GLSLVersion.V420, ctx.type) + ctx.source.getFile() - .generateFinalSource(index); + StringBuilder source = new StringBuilder(CompileUtil.generateHeader(GLSLVersion.V420, ctx.type)); + + var file = ctx.source.getFile(); + for (var include : file.flattenedImports) { + source.append(include.source(index)); + } + + source.append(file.source(index)); try { - return new GlShader(source, ctx.type, ImmutableList.of(ctx.source.getFileLoc())); + return new GlShader(source.toString(), ctx.type, ImmutableList.of(ctx.source.getFileLoc())); } catch (ShaderCompilationException e) { throw e.withErrorLog(index); } diff --git a/src/main/java/com/jozufozu/flywheel/core/compile/ShaderCompilationException.java b/src/main/java/com/jozufozu/flywheel/core/compile/ShaderCompilationException.java index 7319a0e3a..caa848fc0 100644 --- a/src/main/java/com/jozufozu/flywheel/core/compile/ShaderCompilationException.java +++ b/src/main/java/com/jozufozu/flywheel/core/compile/ShaderCompilationException.java @@ -9,7 +9,7 @@ public class ShaderCompilationException extends ShaderLoadingException { private final int shaderHandle; - private String errors = ""; + public String errors = ""; public ShaderCompilationException(String message, int shaderHandle) { super(message); diff --git a/src/main/java/com/jozufozu/flywheel/core/layout/BufferLayout.java b/src/main/java/com/jozufozu/flywheel/core/layout/BufferLayout.java index 8f28d9f2d..405ac098c 100644 --- a/src/main/java/com/jozufozu/flywheel/core/layout/BufferLayout.java +++ b/src/main/java/com/jozufozu/flywheel/core/layout/BufferLayout.java @@ -1,11 +1,21 @@ package com.jozufozu.flywheel.core.layout; import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; import com.google.common.collect.ImmutableList; +import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.backend.gl.array.VertexAttribute; +import com.jozufozu.flywheel.core.Components; +import com.jozufozu.flywheel.core.SourceComponent; +import com.jozufozu.flywheel.core.source.CompilationContext; +import com.jozufozu.flywheel.core.source.generate.GlslBuilder; +import com.jozufozu.flywheel.core.source.generate.GlslExpr; + +import net.minecraft.resources.ResourceLocation; /** * Classic Vertex Format struct with a clever name. @@ -19,23 +29,25 @@ import com.jozufozu.flywheel.backend.gl.array.VertexAttribute; */ public class BufferLayout { - private final List attributes; + public final List layoutItems; + public final List attributes; private final int stride; public BufferLayout(List layoutItems, int padding) { + this.layoutItems = ImmutableList.copyOf(layoutItems); ImmutableList.Builder attributes = ImmutableList.builder(); - for (LayoutItem item : layoutItems) { - item.provideAttributes(attributes::add); + for (var item : layoutItems) { + item.type.provideAttributes(attributes::add); } this.attributes = attributes.build(); this.stride = calculateStride(this.attributes) + padding; } - public List getAttributes() { + public List attributes() { return attributes; } @@ -47,6 +59,14 @@ public class BufferLayout { return stride; } + public InstancedArraysComponent getInstancedArraysComponent() { + return new InstancedArraysComponent(); + } + + public IndirectComponent getIndirectComponent() { + return new IndirectComponent(); + } + public static Builder builder() { return new Builder(); } @@ -67,8 +87,8 @@ public class BufferLayout { allItems = ImmutableList.builder(); } - public Builder addItems(LayoutItem... attributes) { - allItems.add(attributes); + public Builder addItem(InputType type, String name) { + allItems.add(new LayoutItem(type, name)); return this; } @@ -82,4 +102,128 @@ public class BufferLayout { } } + public record LayoutItem(InputType type, String name) { + public String unpack(String argName) { + return argName + '.' + name; + } + } + + public class InstancedArraysComponent implements SourceComponent { + @Override + public Collection included() { + return Collections.emptyList(); + } + + @Override + public String source(CompilationContext ctx) { + return generateInstancedArrays(5, "Instance"); + } + + @Override + public ResourceLocation name() { + return Flywheel.rl("generated_instanced_arrays"); + } + + public String generateInstancedArrays(int baseIndex, String structName) { + var builder = new GlslBuilder(); + builder.define("FlwInstance", structName); + + int i = baseIndex; + final var attributeSuffix = "_vertex_in"; + for (var field : layoutItems) { + builder.vertexInput() + .binding(i) + .type(field.type.typeName()) + .name(field.name + attributeSuffix); + + i += field.type.attributeCount(); + } + + builder.blankLine(); + + var structBuilder = builder.struct(); + structBuilder.setName(structName); + + for (var field : layoutItems) { + structBuilder.addField(field.type.typeName(), field.name); + } + + builder.blankLine(); + + var func = builder.function() + .returnType(structName) + .name("flw_unpackInstance"); + + var args = layoutItems.stream() + .map(it -> new GlslExpr.Variable(it.name + attributeSuffix)) + .map(GlslExpr::minPrint) + .collect(Collectors.joining(", ")); + + func.statement("return " + structName + "(" + args + ");"); + + return builder.build(); + } + } + + public class IndirectComponent implements SourceComponent { + + private static final String UNPACK_ARG = "p"; + + private static GlslExpr intoGlsl(LayoutItem layoutItem) { + return GlslExpr.variable(UNPACK_ARG) + .access(layoutItem.name) + .transform(layoutItem.type::unpack); + } + + @Override + public Collection included() { + return List.of(Components.UTIL_TYPES.getFile()); + } + + @Override + public ResourceLocation name() { + return Flywheel.rl("generated_indirect"); + } + + @Override + public String source(CompilationContext ctx) { + var content = generateIndirect("IndirectStruct"); + return ctx.generatedHeader(content, name().toString()) + content; + } + + public String generateIndirect(String structName) { + var builder = new GlslBuilder(); + final var packedStructName = structName + "_packed"; + builder.define("FlwInstance", structName); + builder.define("FlwPackedInstance", packedStructName); + + var packed = builder.struct(); + builder.blankLine(); + var instance = builder.struct(); + packed.setName(packedStructName); + instance.setName(structName); + + for (var field : layoutItems) { + packed.addField(field.type.packedTypeName(), field.name); + instance.addField(field.type.typeName(), field.name); + } + + builder.blankLine(); + + var func = builder.function() + .returnType(structName) + .name("flw_unpackInstance") + .argumentIn(packedStructName, UNPACK_ARG); + + var args = layoutItems.stream() + .map(IndirectComponent::intoGlsl) + .map(GlslExpr::minPrint) + .collect(Collectors.joining(", ")); + + func.statement("return " + structName + "(" + args + ");"); + + return builder.build(); + } + } + } diff --git a/src/main/java/com/jozufozu/flywheel/core/layout/CommonItems.java b/src/main/java/com/jozufozu/flywheel/core/layout/CommonItems.java index 488d16489..ac2e5bddb 100644 --- a/src/main/java/com/jozufozu/flywheel/core/layout/CommonItems.java +++ b/src/main/java/com/jozufozu/flywheel/core/layout/CommonItems.java @@ -6,34 +6,71 @@ import com.jozufozu.flywheel.backend.gl.array.VertexAttributeI; public class CommonItems { - public static final PrimitiveItem VEC4 = primitiveF(GlNumericType.FLOAT, 4); - public static final PrimitiveItem VEC3 = primitiveF(GlNumericType.FLOAT, 3); - public static final PrimitiveItem VEC2 = primitiveF(GlNumericType.FLOAT, 2); - public static final PrimitiveItem FLOAT = primitiveF(GlNumericType.FLOAT, 1); + private static final String VEC3_TYPE = "vec3"; + private static final String VEC4_TYPE = "vec4"; + private static final String VEC2_TYPE = "vec2"; + private static final String FLOAT_TYPE = "float"; + public static final PrimitiveItem FLOAT = PrimitiveItem.builder() + .setAttribute(new VertexAttributeF(GlNumericType.FLOAT, 1, false)) + .setTypeName(FLOAT_TYPE) + .setPackedTypeName(FLOAT_TYPE) + .createPrimitiveItem(); + private static final String UINT_TYPE = "uint"; + public static final PrimitiveItem NORM_3x8 = PrimitiveItem.builder() + .setAttribute(new VertexAttributeF(GlNumericType.BYTE, 3, true)) + .setTypeName(VEC3_TYPE) + .setPackedTypeName(UINT_TYPE) + .unpack(expr -> expr.callFunction("unpackSnorm4x8") + .swizzle("xyz")) + .createPrimitiveItem(); + public static final PrimitiveItem UNORM_4x8 = PrimitiveItem.builder() + .setAttribute(new VertexAttributeF(GlNumericType.UBYTE, 4, true)) + .setTypeName(VEC4_TYPE) + .setPackedTypeName(UINT_TYPE) + .unpack(expr -> expr.callFunction("unpackUnorm4x8")) + .createPrimitiveItem(); + public static final PrimitiveItem UNORM_3x8 = PrimitiveItem.builder() + .setAttribute(new VertexAttributeF(GlNumericType.UBYTE, 3, true)) + .setTypeName(VEC3_TYPE) + .setPackedTypeName(UINT_TYPE) + .unpack(expr -> expr.callFunction("unpackUnorm4x8") + .swizzle("xyz")) + .createPrimitiveItem(); + private static final String IVEC2_TYPE = "ivec2"; + private static final String VEC4F_TYPE = "Vec4F"; + public static final PrimitiveItem VEC4 = PrimitiveItem.builder() + .setAttribute(new VertexAttributeF(GlNumericType.FLOAT, 4, false)) + .setTypeName(VEC4_TYPE) + .setPackedTypeName(VEC4F_TYPE) + .unpack(expr -> expr.callFunction("unpackVec4F")) + .createPrimitiveItem(); + private static final String VEC3F_TYPE = "Vec3F"; + public static final PrimitiveItem VEC3 = PrimitiveItem.builder() + .setAttribute(new VertexAttributeF(GlNumericType.FLOAT, 3, false)) + .setTypeName(VEC3_TYPE) + .setPackedTypeName(VEC3F_TYPE) + .unpack(expr -> expr.callFunction("unpackVec3F")) + .createPrimitiveItem(); + private static final String VEC2F_TYPE = "Vec2F"; + public static final PrimitiveItem VEC2 = PrimitiveItem.builder() + .setAttribute(new VertexAttributeF(GlNumericType.FLOAT, 2, false)) + .setTypeName(VEC2_TYPE) + .setPackedTypeName(VEC2F_TYPE) + .unpack(expr -> expr.callFunction("unpackVec2F")) + .createPrimitiveItem(); + private static final String LIGHT_COORD_TYPE = "LightCoord"; + public static final PrimitiveItem LIGHT_COORD = PrimitiveItem.builder() + .setAttribute(new VertexAttributeI(GlNumericType.USHORT, 2)) + .setTypeName(VEC2_TYPE) + .setPackedTypeName(LIGHT_COORD_TYPE) + .unpack(expr -> expr.callFunction("unpackLightCoord")) + .createPrimitiveItem(); - public static final PrimitiveItem QUATERNION = primitiveF(GlNumericType.FLOAT, 4); - public static final PrimitiveItem NORMAL = primitiveF(GlNumericType.BYTE, 3, true); - public static final PrimitiveItem UV = primitiveF(GlNumericType.FLOAT, 2); - public static final PrimitiveItem RGBA = primitiveF(GlNumericType.UBYTE, 4, true); - public static final PrimitiveItem RGB = primitiveF(GlNumericType.UBYTE, 3, true); - public static final PrimitiveItem LIGHT = primitiveI(GlNumericType.UBYTE, 2); - public static final PrimitiveItem LIGHT_SHORT = primitiveI(GlNumericType.USHORT, 2); + public static final MatrixItem MAT3 = new MatrixItem(3, 3, "mat3", "Mat3F", "unpackMat3F"); + public static final MatrixItem MAT4 = new MatrixItem(4, 4, "mat4", "Mat4F", "unpackMat4F"); - public static final PrimitiveItem NORMALIZED_BYTE = primitiveF(GlNumericType.BYTE, 1, true); + private static class Unpacking { - public static final MatrixItem MAT3 = new MatrixItem(3, 3); - public static final MatrixItem MAT4 = new MatrixItem(4, 4); - - private static PrimitiveItem primitiveF(GlNumericType type, int count, boolean normalized) { - return new PrimitiveItem(new VertexAttributeF(type, count, normalized)); - } - - private static PrimitiveItem primitiveF(GlNumericType type, int count) { - return primitiveF(type, count, false); - } - - private static PrimitiveItem primitiveI(GlNumericType type, int count) { - return new PrimitiveItem(new VertexAttributeI(type, count)); } } diff --git a/src/main/java/com/jozufozu/flywheel/core/layout/LayoutItem.java b/src/main/java/com/jozufozu/flywheel/core/layout/InputType.java similarity index 51% rename from src/main/java/com/jozufozu/flywheel/core/layout/LayoutItem.java rename to src/main/java/com/jozufozu/flywheel/core/layout/InputType.java index 6b9b22d3d..752c9edb9 100644 --- a/src/main/java/com/jozufozu/flywheel/core/layout/LayoutItem.java +++ b/src/main/java/com/jozufozu/flywheel/core/layout/InputType.java @@ -3,9 +3,17 @@ package com.jozufozu.flywheel.core.layout; import java.util.function.Consumer; import com.jozufozu.flywheel.backend.gl.array.VertexAttribute; +import com.jozufozu.flywheel.core.source.generate.GlslExpr; -public interface LayoutItem { +public interface InputType { void provideAttributes(Consumer consumer); + String typeName(); + + String packedTypeName(); + + int attributeCount(); + + GlslExpr unpack(GlslExpr packed); } diff --git a/src/main/java/com/jozufozu/flywheel/core/layout/MatrixItem.java b/src/main/java/com/jozufozu/flywheel/core/layout/MatrixItem.java index e715ff369..4bb24a5fc 100644 --- a/src/main/java/com/jozufozu/flywheel/core/layout/MatrixItem.java +++ b/src/main/java/com/jozufozu/flywheel/core/layout/MatrixItem.java @@ -5,8 +5,10 @@ import java.util.function.Consumer; import com.jozufozu.flywheel.backend.gl.GlNumericType; import com.jozufozu.flywheel.backend.gl.array.VertexAttribute; import com.jozufozu.flywheel.backend.gl.array.VertexAttributeF; +import com.jozufozu.flywheel.core.source.generate.GlslExpr; -public record MatrixItem(int rows, int cols) implements LayoutItem { +public record MatrixItem(int rows, int cols, String typeName, String packedTypeName, + String unpackingFunction) implements InputType { @Override public void provideAttributes(Consumer consumer) { @@ -15,4 +17,13 @@ public record MatrixItem(int rows, int cols) implements LayoutItem { } } + @Override + public int attributeCount() { + return rows; + } + + @Override + public GlslExpr unpack(GlslExpr packed) { + return packed.callFunction(unpackingFunction); + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/layout/PrimitiveItem.java b/src/main/java/com/jozufozu/flywheel/core/layout/PrimitiveItem.java index d26fc4a16..ca3d08d32 100644 --- a/src/main/java/com/jozufozu/flywheel/core/layout/PrimitiveItem.java +++ b/src/main/java/com/jozufozu/flywheel/core/layout/PrimitiveItem.java @@ -1,15 +1,23 @@ package com.jozufozu.flywheel.core.layout; import java.util.function.Consumer; +import java.util.function.Function; import com.jozufozu.flywheel.backend.gl.array.VertexAttribute; +import com.jozufozu.flywheel.core.source.generate.GlslExpr; -public class PrimitiveItem implements LayoutItem { +public class PrimitiveItem implements InputType { private final VertexAttribute attribute; + private final String typeName; + private final String packedTypeName; + private final Function unpackingFunction; - public PrimitiveItem(VertexAttribute attribute) { + public PrimitiveItem(VertexAttribute attribute, String typeName, String packedTypeName, Function unpackingFunction) { this.attribute = attribute; + this.typeName = typeName; + this.packedTypeName = packedTypeName; + this.unpackingFunction = unpackingFunction; } @Override @@ -17,4 +25,58 @@ public class PrimitiveItem implements LayoutItem { consumer.accept(attribute); } + @Override + public String typeName() { + return typeName; + } + + @Override + public String packedTypeName() { + return packedTypeName; + } + + @Override + public int attributeCount() { + return 1; + } + + public static PrimitiveItemBuilder builder() { + return new PrimitiveItemBuilder(); + } + + @Override + public GlslExpr unpack(GlslExpr packed) { + return unpackingFunction.apply(packed); + } + + public static class PrimitiveItemBuilder { + private VertexAttribute attribute; + private String typeName; + private String packedTypeName; + private Function unpackingFunction = Function.identity(); + + public PrimitiveItemBuilder setAttribute(VertexAttribute attribute) { + this.attribute = attribute; + return this; + } + + public PrimitiveItemBuilder setTypeName(String typeName) { + this.typeName = typeName; + return this; + } + + public PrimitiveItemBuilder setPackedTypeName(String packedTypeName) { + this.packedTypeName = packedTypeName; + return this; + } + + public PrimitiveItemBuilder unpack(Function f) { + this.unpackingFunction = f; + return this; + } + + public PrimitiveItem createPrimitiveItem() { + return new PrimitiveItem(attribute, typeName, packedTypeName, unpackingFunction); + } + } } diff --git a/src/main/java/com/jozufozu/flywheel/core/source/CompilationContext.java b/src/main/java/com/jozufozu/flywheel/core/source/CompilationContext.java index 2217b5708..016af40c7 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/CompilationContext.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/CompilationContext.java @@ -11,28 +11,58 @@ import com.jozufozu.flywheel.core.source.span.Span; public class CompilationContext { public final List files = new ArrayList<>(); - /** - * Returns an arbitrary file ID for use this compilation context, or generates one if missing. - * @param sourceFile The file to retrieve the ID for. - * @return A file ID unique to the given sourceFile. - */ - public int getFileID(SourceFile sourceFile) { - int i = files.indexOf(sourceFile); - if (i != -1) { - return i; + private String generatedSource = ""; + private int generatedLines = 0; + + String sourceHeader(SourceFile sourceFile) { + return "#line " + 0 + ' ' + getOrCreateFileID(sourceFile) + " // " + sourceFile.name + '\n'; + } + + public String generatedHeader(String generatedCode, @Nullable String comment) { + generatedSource += generatedCode; + int lines = generatedCode.split("\n").length; + + var out = "#line " + generatedLines + ' ' + 0; + + generatedLines += lines; + + if (comment != null) { + out += " // " + comment; } - int size = files.size(); - files.add(sourceFile); - return size; + return out + '\n'; } public boolean contains(SourceFile sourceFile) { return files.contains(sourceFile); } - public SourceFile getFile(int fileId) { - return files.get(fileId); + /** + * Returns an arbitrary file ID for use this compilation context, or generates one if missing. + * + * @param sourceFile The file to retrieve the ID for. + * @return A file ID unique to the given sourceFile. + */ + private int getOrCreateFileID(SourceFile sourceFile) { + int i = files.indexOf(sourceFile); + if (i != -1) { + return i + 1; + } + + files.add(sourceFile); + return files.size(); + } + + public Span getLineSpan(int fileId, int lineNo) { + if (fileId == 0) { + // TODO: Valid spans for generated code. + return null; + } + return getFile(fileId).getLineSpanNoWhitespace(lineNo); + } + + private SourceFile getFile(int fileId) { + return files.get(fileId - 1); } public String parseErrors(String log) { @@ -61,8 +91,4 @@ public class CompilationContext { return null; } - - public Span getLineSpan(int fileId, int lineNo) { - return getFile(fileId).getLineSpanNoWhitespace(lineNo); - } } diff --git a/src/main/java/com/jozufozu/flywheel/core/source/SourceChecks.java b/src/main/java/com/jozufozu/flywheel/core/source/SourceChecks.java index 1d4023705..2591d6408 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/SourceChecks.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/SourceChecks.java @@ -8,7 +8,7 @@ import org.jetbrains.annotations.Nullable; import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.core.source.error.ErrorReporter; import com.jozufozu.flywheel.core.source.parse.ShaderFunction; -import com.jozufozu.flywheel.core.source.parse.Variable; +import com.jozufozu.flywheel.core.source.parse.ShaderVariable; public class SourceChecks { @@ -46,7 +46,7 @@ public class SourceChecks { } ShaderFunction func = maybeFunc.get(); - ImmutableList params = func.getParameters(); + ImmutableList params = func.getParameters(); if (params.size() != arity) { errorReporter.generateFunctionArgumentCountError(name, arity, func.getArgs()); return null; diff --git a/src/main/java/com/jozufozu/flywheel/core/source/SourceFile.java b/src/main/java/com/jozufozu/flywheel/core/source/SourceFile.java index faeb46acb..b90528ec9 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/SourceFile.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/SourceFile.java @@ -1,8 +1,8 @@ package com.jozufozu.flywheel.core.source; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -13,6 +13,7 @@ import java.util.regex.Matcher; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.jozufozu.flywheel.core.SourceComponent; import com.jozufozu.flywheel.core.source.error.ErrorReporter; import com.jozufozu.flywheel.core.source.parse.Import; import com.jozufozu.flywheel.core.source.parse.ShaderField; @@ -21,7 +22,6 @@ import com.jozufozu.flywheel.core.source.parse.ShaderStruct; import com.jozufozu.flywheel.core.source.span.ErrorSpan; import com.jozufozu.flywheel.core.source.span.Span; import com.jozufozu.flywheel.core.source.span.StringSpan; -import com.jozufozu.flywheel.util.Pair; import net.minecraft.resources.ResourceLocation; @@ -29,10 +29,10 @@ import net.minecraft.resources.ResourceLocation; * Immutable class representing a shader file. * *

- * This class parses shader files and generates what is effectively a high level AST of the source. + * This class parses shader files and generates what is effectively a high level AST of the source. *

*/ -public class SourceFile { +public class SourceFile implements SourceComponent { public final ResourceLocation name; @@ -56,10 +56,9 @@ public class SourceFile { */ public final ImmutableList imports; public final ImmutableMap fields; - private final List elisions; // POST-RESOLUTION - private List flattenedImports; + public List flattenedImports; public SourceFile(ErrorReporter errorReporter, ShaderSources parent, ResourceLocation name, String source) { this.parent = parent; @@ -68,14 +67,27 @@ public class SourceFile { this.lines = new SourceLines(source); - this.elisions = new ArrayList<>(); - this.imports = parseImports(errorReporter); this.functions = parseFunctions(); this.structs = parseStructs(); this.fields = parseFields(); } + @Override + public Collection included() { + return flattenedImports; + } + + @Override + public String source(CompilationContext ctx) { + return ctx.sourceHeader(this) + this.elideImports(); + } + + @Override + public ResourceLocation name() { + return name; + } + public void postResolve() { this.flattenImports(); } @@ -91,7 +103,7 @@ public class SourceFile { return; } - List flat = new ArrayList<>(this.imports.size()); + ArrayList flat = new ArrayList<>(this.imports.size()); for (Import include : this.imports) { SourceFile file = include.resolution.getFile(); @@ -99,7 +111,7 @@ public class SourceFile { file.flattenImports(); flat.addAll(file.flattenedImports); - flat.add(include); + flat.add(file); } this.flattenedImports = flat.stream() @@ -135,14 +147,8 @@ public class SourceFile { if (struct != null) return Optional.of(struct); - for (Import include : flattenedImports) { - var file = include.getFile(); - - if (file == null) { - continue; - } - - var external = file.structs.get(name); + for (var include : flattenedImports) { + var external = include.structs.get(name); if (external != null) { return Optional.of(external); @@ -163,14 +169,8 @@ public class SourceFile { if (local != null) return Optional.of(local); - for (Import include : imports) { - var file = include.getFile(); - - if (file == null) { - continue; - } - - var external = file.functions.get(name); + for (var include : flattenedImports) { + var external = include.functions.get(name); if (external != null) { return Optional.of(external); @@ -184,59 +184,19 @@ public class SourceFile { return "#use " + '"' + name + '"'; } - public String generateFinalSource(CompilationContext context) { - List> replacements = Collections.emptyList(); - var out = new StringBuilder(); - for (Import include : flattenedImports) { - SourceFile file = include.getFile(); - - if (file == null || context.contains(file)) { - continue; - } - - out.append(file.generateLineHeader(context)) - .append(file.replaceAndElide(replacements)); - } - - out.append(this.generateLineHeader(context)) - .append(this.replaceAndElide(replacements)); - - return out.toString(); - } - - private String generateLineHeader(CompilationContext env) { - return "#line " + 0 + ' ' + env.getFileID(this) + " // " + name + '\n'; - } - public String printSource() { return "Source for shader '" + name + "':\n" + lines.printLinesWithNumbers(); } - private CharSequence replaceAndElide(List> replacements) { - var replacementsAndElisions = new ArrayList<>(replacements); - for (var include : imports) { - replacementsAndElisions.add(Pair.of(include.self, "")); - } - - return this.replace(replacementsAndElisions); - } - - private CharSequence replace(List> replacements) { + private CharSequence elideImports() { StringBuilder out = new StringBuilder(); int lastEnd = 0; - replacements.sort(Comparator.comparing(Pair::first)); - - for (var replacement : replacements) { - var loc = replacement.first(); - - if (loc.getSourceFile() != this) { - continue; - } + for (var include : imports) { + var loc = include.self; out.append(this.source, lastEnd, loc.getStartPos()); - out.append(replacement.second()); lastEnd = loc.getEndPos(); } diff --git a/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorBuilder.java b/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorBuilder.java index 1a4390e33..6c156df7b 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/error/ErrorBuilder.java @@ -53,6 +53,11 @@ public class ErrorBuilder { String lineNo = matcher.group(2); String msg = matcher.group(3); Span span = env.getLineSpan(Integer.parseInt(fileId), Integer.parseInt(lineNo)); + + if (span == null) { + return ErrorBuilder.compError("Error in generated code"); + } + return ErrorBuilder.compError(msg) .pointAtFile(span.getSourceFile()) .pointAt(span, 1); diff --git a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBuilder.java b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBuilder.java new file mode 100644 index 000000000..4fa9fbc33 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslBuilder.java @@ -0,0 +1,179 @@ +package com.jozufozu.flywheel.core.source.generate; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import com.jozufozu.flywheel.util.Pair; + +public class GlslBuilder { + + private final List elements = new ArrayList<>(); + + public void define(String name, String value) { + elements.add(new Define(name, value)); + } + + public StructBuilder struct() { + return add(new StructBuilder()); + } + + public FunctionBuilder function() { + return add(new FunctionBuilder()); + } + + public VertexInputBuilder vertexInput() { + return add(new VertexInputBuilder()); + } + + public T add(T element) { + elements.add(element); + return element; + } + + + public String build() { + return elements.stream() + .map(SourceElement::build) + .collect(Collectors.joining("\n")); + } + + public void blankLine() { + elements.add(Separators.BLANK_LINE); + } + + public enum Separators implements SourceElement { + BLANK_LINE(""), + ; + + private final String separator; + + Separators(String separator) { + this.separator = separator; + } + + @Override + public String build() { + return separator; + } + } + + public interface SourceElement { + String build(); + } + + public record Define(String name, String value) implements SourceElement { + @Override + public String build() { + return "#define " + name + " " + value; + } + } + + public static class VertexInputBuilder implements SourceElement { + + private int binding; + private String type; + private String name; + + public VertexInputBuilder binding(int binding) { + this.binding = binding; + return this; + } + + public VertexInputBuilder type(String type) { + this.type = type; + return this; + } + + public VertexInputBuilder name(String name) { + this.name = name; + return this; + } + + @Override + public String build() { + return "layout(location = " + binding + ") in " + type + " " + name + ";"; + } + } + + public static class StructBuilder implements SourceElement { + + private final List> fields = new ArrayList<>(); + private String name; + + public void setName(String name) { + this.name = name; + } + + public void addField(String type, String name) { + fields.add(Pair.of(type, name)); + } + + private String buildFields() { + return fields.stream() + .map(p -> '\t' + p.first() + ' ' + p.second() + ';') + .collect(Collectors.joining("\n")); + } + + public String build() { + return """ + struct %s { + %s + }; + """.formatted(name, buildFields()); + } + } + + public static class FunctionBuilder implements SourceElement { + private final List> arguments = new ArrayList<>(); + private final List body = new ArrayList<>(); + private String returnType; + private String name; + + public FunctionBuilder returnType(String returnType) { + this.returnType = returnType; + return this; + } + + public FunctionBuilder name(String name) { + this.name = name; + return this; + } + + public FunctionBuilder argument(String type, String name) { + arguments.add(Pair.of(type, name)); + return this; + } + + public FunctionBuilder argumentIn(String type, String name) { + arguments.add(Pair.of("in " + type, name)); + return this; + } + + public FunctionBuilder statement(String statement) { + this.body.add(statement); + return this; + } + + + public String build() { + return """ + %s %s(%s) { + %s + } + """.formatted(returnType, name, buildArguments(), buildBody()); + } + + private String buildBody() { + return body.stream() + .map(s -> '\t' + s) + .collect(Collectors.joining("\n")); + } + + private String buildArguments() { + return arguments.stream() + .map(p -> p.first() + ' ' + p.second()) + .collect(Collectors.joining(", ")); + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslExpr.java b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslExpr.java new file mode 100644 index 000000000..7ae03952b --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/source/generate/GlslExpr.java @@ -0,0 +1,86 @@ +package com.jozufozu.flywheel.core.source.generate; + +import java.util.function.Function; + +public sealed interface GlslExpr { + + /** + * Create a glsl variable with the given name. + * + * @param name The name of the variable. + * @return A new variable expression. + */ + static Variable variable(String name) { + return new Variable(name); + } + + String minPrint(); + + /** + * Call a one-parameter function with the given name on this expression. + * + * @param name The name of the function to call. + * @return A new glsl function call expression. + */ + default FunctionCall callFunction(String name) { + return new FunctionCall(name, this); + } + + /** + * Swizzle the components of this expression. + * + * @param selection The components to select. For example, "xyz", "zyx", or "zzzw". + * @return A new glsl swizzle expression. + */ + default Swizzle swizzle(String selection) { + return new Swizzle(this, selection); + } + + /** + * Access the given member of this expression. + * + * @param member The name of the member to access. + * @return A new glsl member access expression. + */ + default Access access(String member) { + return new Access(this, member); + } + + /** + * Catchall method for applying external transformations to this expression. + * + * @param f The transformation to apply. + * @return A new expression. + */ + default GlslExpr transform(Function f) { + return f.apply(this); + } + + record Variable(String name) implements GlslExpr { + @Override + public String minPrint() { + return name; + } + } + + record FunctionCall(String name, GlslExpr target) implements GlslExpr { + @Override + public String minPrint() { + return name + "(" + target.minPrint() + ")"; + } + } + + record Swizzle(GlslExpr target, String selection) implements GlslExpr { + @Override + public String minPrint() { + return target.minPrint() + "." + selection; + } + } + + record Access(GlslExpr target, String argName) implements GlslExpr { + @Override + public String minPrint() { + return target.minPrint() + "." + argName; + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderFunction.java b/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderFunction.java index 38dda848c..2a817e4ca 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderFunction.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderFunction.java @@ -20,7 +20,7 @@ public class ShaderFunction extends AbstractShaderElement { private final Span args; private final Span body; - private final ImmutableList parameters; + private final ImmutableList parameters; public ShaderFunction(Span self, Span type, Span name, Span args, Span body) { super(self); @@ -56,7 +56,7 @@ public class ShaderFunction extends AbstractShaderElement { return parameters.get(index).type; } - public ImmutableList getParameters() { + public ImmutableList getParameters() { return parameters; } @@ -64,12 +64,12 @@ public class ShaderFunction extends AbstractShaderElement { return type.get(); } - protected ImmutableList parseArguments() { + protected ImmutableList parseArguments() { if (args.isErr() || args.isEmpty()) return ImmutableList.of(); Matcher arguments = argument.matcher(args.get()); - ImmutableList.Builder builder = ImmutableList.builder(); + ImmutableList.Builder builder = ImmutableList.builder(); while (arguments.find()) { Span self = Span.fromMatcher(args, arguments); @@ -77,7 +77,7 @@ public class ShaderFunction extends AbstractShaderElement { Span type = Span.fromMatcher(args, arguments, 2); Span name = Span.fromMatcher(args, arguments, 3); - builder.add(new Variable(self, qualifier, type, name)); + builder.add(new ShaderVariable(self, qualifier, type, name)); } return builder.build(); diff --git a/src/main/java/com/jozufozu/flywheel/core/source/parse/Variable.java b/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderVariable.java similarity index 84% rename from src/main/java/com/jozufozu/flywheel/core/source/parse/Variable.java rename to src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderVariable.java index 0d6f9aa99..cf421e810 100644 --- a/src/main/java/com/jozufozu/flywheel/core/source/parse/Variable.java +++ b/src/main/java/com/jozufozu/flywheel/core/source/parse/ShaderVariable.java @@ -2,14 +2,14 @@ package com.jozufozu.flywheel.core.source.parse; import com.jozufozu.flywheel.core.source.span.Span; -public class Variable extends AbstractShaderElement { +public class ShaderVariable extends AbstractShaderElement { public final Span qualifierSpan; public final Span type; public final Span name; public final Qualifier qualifier; - public Variable(Span self, Span qualifier, Span type, Span name) { + public ShaderVariable(Span self, Span qualifier, Span type, Span name) { super(self); this.qualifierSpan = qualifier; this.type = type; diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedType.java b/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedType.java index 039fdd1e5..826d4f791 100644 --- a/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedType.java +++ b/src/main/java/com/jozufozu/flywheel/core/structs/oriented/OrientedType.java @@ -15,8 +15,11 @@ import com.mojang.math.Vector4f; public class OrientedType implements StructType { public static final BufferLayout FORMAT = BufferLayout.builder() - .addItems(CommonItems.LIGHT, CommonItems.RGBA) - .addItems(CommonItems.VEC3, CommonItems.VEC3, CommonItems.QUATERNION) + .addItem(CommonItems.LIGHT_COORD, "light") + .addItem(CommonItems.UNORM_4x8, "color") + .addItem(CommonItems.VEC3, "position") + .addItem(CommonItems.VEC3, "pivot") + .addItem(CommonItems.VEC4, "rotation") .build(); @Override @@ -44,11 +47,6 @@ public class OrientedType implements StructType { return Components.Files.ORIENTED; } - @Override - public FileResolution getIndirectShader() { - return Components.Files.ORIENTED_INDIRECT; - } - @Override public VertexTransformer getVertexTransformer() { return (vertexList, struct, level) -> { diff --git a/src/main/java/com/jozufozu/flywheel/core/structs/transformed/TransformedType.java b/src/main/java/com/jozufozu/flywheel/core/structs/transformed/TransformedType.java index aa6ba75d9..02451b6eb 100644 --- a/src/main/java/com/jozufozu/flywheel/core/structs/transformed/TransformedType.java +++ b/src/main/java/com/jozufozu/flywheel/core/structs/transformed/TransformedType.java @@ -13,8 +13,10 @@ import com.mojang.math.Vector4f; public class TransformedType implements StructType { public static final BufferLayout FORMAT = BufferLayout.builder() - .addItems(CommonItems.LIGHT, CommonItems.RGBA) - .addItems(CommonItems.MAT4, CommonItems.MAT3) + .addItem(CommonItems.LIGHT_COORD, "light") + .addItem(CommonItems.UNORM_4x8, "color") + .addItem(CommonItems.MAT4, "pose") + .addItem(CommonItems.MAT3, "normal") .build(); @Override @@ -42,11 +44,6 @@ public class TransformedType implements StructType { return Components.Files.TRANSFORMED; } - @Override - public FileResolution getIndirectShader() { - return Components.Files.TRANSFORMED_INDIRECT; - } - @Override public VertexTransformer getVertexTransformer() { return (vertexList, struct, level) -> { diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertex.java b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertex.java index e916d5ce3..e95692529 100644 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertex.java +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertex.java @@ -8,11 +8,11 @@ import com.jozufozu.flywheel.core.source.FileResolution; public class BlockVertex implements VertexType { public static final BufferLayout FORMAT = BufferLayout.builder() - .addItems(CommonItems.VEC3, - CommonItems.RGBA, - CommonItems.UV, - CommonItems.LIGHT_SHORT, - CommonItems.NORMAL) + .addItem(CommonItems.VEC3, "position") + .addItem(CommonItems.UNORM_4x8, "color") + .addItem(CommonItems.VEC2, "tex") + .addItem(CommonItems.LIGHT_COORD, "light") + .addItem(CommonItems.NORM_3x8, "normal") .withPadding(1) .build(); diff --git a/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertex.java b/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertex.java index 131bfc6e6..9d0ad7856 100644 --- a/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertex.java +++ b/src/main/java/com/jozufozu/flywheel/core/vertex/PosTexNormalVertex.java @@ -8,7 +8,9 @@ import com.jozufozu.flywheel.core.source.FileResolution; public class PosTexNormalVertex implements VertexType { public static final BufferLayout FORMAT = BufferLayout.builder() - .addItems(CommonItems.VEC3, CommonItems.UV, CommonItems.NORMAL) + .addItem(CommonItems.VEC3, "position") + .addItem(CommonItems.VEC2, "tex") + .addItem(CommonItems.NORM_3x8, "normal") .build(); @Override diff --git a/src/main/resources/assets/flywheel/flywheel/instance/oriented.vert b/src/main/resources/assets/flywheel/flywheel/instance/oriented.vert index 880d55de4..34c29a142 100644 --- a/src/main/resources/assets/flywheel/flywheel/instance/oriented.vert +++ b/src/main/resources/assets/flywheel/flywheel/instance/oriented.vert @@ -1,15 +1,20 @@ #use "flywheel:api/vertex.glsl" #use "flywheel:util/quaternion.glsl" +#use "flywheel:util/types.glsl" -layout(location = FLW_INSTANCE_BASE_INDEX + 0) in ivec2 oriented_light; -layout(location = FLW_INSTANCE_BASE_INDEX + 1) in vec4 oriented_color; -layout(location = FLW_INSTANCE_BASE_INDEX + 2) in vec3 oriented_pos; -layout(location = FLW_INSTANCE_BASE_INDEX + 3) in vec3 oriented_pivot; -layout(location = FLW_INSTANCE_BASE_INDEX + 4) in vec4 oriented_rotation; +void flw_transformBoundingSphere(in FlwInstance i, inout vec3 center, inout float radius) { + vec4 rotation = i.rotation; + vec3 pivot = i.pivot; + vec3 pos = i.position; -void flw_instanceVertex() { - flw_vertexPos = vec4(rotateVertexByQuat(flw_vertexPos.xyz - oriented_pivot, oriented_rotation) + oriented_pivot + oriented_pos, 1.0); - flw_vertexNormal = rotateVertexByQuat(flw_vertexNormal, oriented_rotation); - flw_vertexColor = oriented_color; - flw_vertexLight = oriented_light / 15.0; + center = rotateVertexByQuat(center - pivot, rotation) + pivot + pos; } + + #ifdef VERTEX_SHADER +void flw_instanceVertex(in FlwInstance i) { + flw_vertexPos = vec4(rotateVertexByQuat(flw_vertexPos.xyz - i.pivot, i.rotation) + i.pivot + i.position, 1.0); + flw_vertexNormal = rotateVertexByQuat(flw_vertexNormal, i.rotation); + flw_vertexColor = i.color; + flw_vertexLight = i.light; +} + #endif diff --git a/src/main/resources/assets/flywheel/flywheel/instance/oriented_indirect.glsl b/src/main/resources/assets/flywheel/flywheel/instance/oriented_indirect.glsl deleted file mode 100644 index cd0f90fb2..000000000 --- a/src/main/resources/assets/flywheel/flywheel/instance/oriented_indirect.glsl +++ /dev/null @@ -1,32 +0,0 @@ -#use "flywheel:api/vertex.glsl" -#use "flywheel:util/quaternion.glsl" -#use "flywheel:util/types.glsl" - -#define FLW_INSTANCE_STRUCT Instance -struct Instance { - Vec4F rotation; - Vec3F pos; - Vec3F pivot; - uint light; - uint color; -}; - -void flw_transformBoundingSphere(in Instance i, inout vec3 center, inout float radius) { - vec4 rotation = unpackVec4F(i.rotation); - vec3 pivot = unpackVec3F(i.pivot); - vec3 pos = unpackVec3F(i.pos); - - center = rotateVertexByQuat(center - pivot, rotation) + pivot + pos; -} - -#ifdef VERTEX_SHADER -void flw_instanceVertex(Instance i) { - vec4 rotation = unpackVec4F(i.rotation); - vec3 pivot = unpackVec3F(i.pivot); - vec3 pos = unpackVec3F(i.pos); - flw_vertexPos = vec4(rotateVertexByQuat(flw_vertexPos.xyz - pivot, rotation) + pivot + pos, 1.0); - flw_vertexNormal = rotateVertexByQuat(flw_vertexNormal, rotation); - flw_vertexColor = unpackUnorm4x8(i.color); - flw_vertexLight = vec2(float((i.light >> 16) & 0xFFFFu), float(i.light & 0xFFFFu)) / 15.0; -} - #endif diff --git a/src/main/resources/assets/flywheel/flywheel/instance/transformed.vert b/src/main/resources/assets/flywheel/flywheel/instance/transformed.vert index 2c6161d18..78fcaa831 100644 --- a/src/main/resources/assets/flywheel/flywheel/instance/transformed.vert +++ b/src/main/resources/assets/flywheel/flywheel/instance/transformed.vert @@ -1,13 +1,19 @@ #use "flywheel:api/vertex.glsl" +#use "flywheel:util/types.glsl" -layout(location = FLW_INSTANCE_BASE_INDEX + 0) in ivec2 transformed_light; -layout(location = FLW_INSTANCE_BASE_INDEX + 1) in vec4 transformed_color; -layout(location = FLW_INSTANCE_BASE_INDEX + 2) in mat4 transformed_pose; -layout(location = FLW_INSTANCE_BASE_INDEX + 6) in mat3 transformed_normal; +void flw_transformBoundingSphere(in FlwInstance i, inout vec3 center, inout float radius) { + mat4 pose = i.pose; + center = (pose * vec4(center, 1.0)).xyz; -void flw_instanceVertex() { - flw_vertexPos = transformed_pose * flw_vertexPos; - flw_vertexNormal = transformed_normal * flw_vertexNormal; - flw_vertexColor = transformed_color; - flw_vertexLight = transformed_light / 15.0; + float scale = max(length(pose[0].xyz), max(length(pose[1].xyz), length(pose[2].xyz))); + radius *= scale; } + + #ifdef VERTEX_SHADER +void flw_instanceVertex(in FlwInstance i) { + flw_vertexPos = i.pose * flw_vertexPos; + flw_vertexNormal = i.normal * flw_vertexNormal; + flw_vertexColor = i.color; + flw_vertexLight = i.light; +} + #endif diff --git a/src/main/resources/assets/flywheel/flywheel/instance/transformed_indirect.glsl b/src/main/resources/assets/flywheel/flywheel/instance/transformed_indirect.glsl deleted file mode 100644 index f0067c4b9..000000000 --- a/src/main/resources/assets/flywheel/flywheel/instance/transformed_indirect.glsl +++ /dev/null @@ -1,27 +0,0 @@ -#use "flywheel:api/vertex.glsl" -#use "flywheel:util/types.glsl" - -#define FLW_INSTANCE_STRUCT Instance -struct Instance { - Mat4F pose; - Mat3F normal; - uint color; - uint light; -}; - -void flw_transformBoundingSphere(in Instance i, inout vec3 center, inout float radius) { - mat4 pose = unpackMat4F(i.pose); - center = (pose * vec4(center, 1.0)).xyz; - - float scale = max(length(pose[0].xyz), max(length(pose[1].xyz), length(pose[2].xyz))); - radius *= scale; -} - - #ifdef VERTEX_SHADER -void flw_instanceVertex(Instance i) { - flw_vertexPos = unpackMat4F(i.pose) * flw_vertexPos; - flw_vertexNormal = unpackMat3F(i.normal) * flw_vertexNormal; - flw_vertexColor = unpackUnorm4x8(i.color); - flw_vertexLight = vec2(float((i.light >> 16) & 0xFFFFu), float(i.light & 0xFFFFu)) / 15.0; -} - #endif diff --git a/src/main/resources/assets/flywheel/flywheel/pipeline/indirect_cull.glsl b/src/main/resources/assets/flywheel/flywheel/pipeline/indirect_cull.glsl index b1706edf0..b52c12d30 100644 --- a/src/main/resources/assets/flywheel/flywheel/pipeline/indirect_cull.glsl +++ b/src/main/resources/assets/flywheel/flywheel/pipeline/indirect_cull.glsl @@ -16,7 +16,7 @@ struct MeshDrawCommand { // populated by instancers layout(std430, binding = 0) restrict readonly buffer ObjectBuffer { - FLW_INSTANCE_STRUCT objects[]; + FlwPackedInstance objects[]; }; layout(std430, binding = 1) restrict writeonly buffer TargetBuffer { @@ -45,7 +45,9 @@ bool isVisible() { vec3 center; float radius; unpackBoundingSphere(sphere, center, radius); - flw_transformBoundingSphere(objects[flw_objectID], center, radius); + + FlwInstance object = flw_unpackInstance(objects[flw_objectID]); + flw_transformBoundingSphere(object, center, radius); return testSphere(center, radius); } diff --git a/src/main/resources/assets/flywheel/flywheel/pipeline/indirect_draw.vert b/src/main/resources/assets/flywheel/flywheel/pipeline/indirect_draw.vert index 7583ebbd6..2a29b662b 100644 --- a/src/main/resources/assets/flywheel/flywheel/pipeline/indirect_draw.vert +++ b/src/main/resources/assets/flywheel/flywheel/pipeline/indirect_draw.vert @@ -1,7 +1,7 @@ #use "flywheel:api/vertex.glsl" layout(std430, binding = 0) restrict readonly buffer ObjectBuffer { - FLW_INSTANCE_STRUCT objects[]; + FlwPackedInstance objects[]; }; layout(std430, binding = 1) restrict readonly buffer TargetBuffer { @@ -10,8 +10,8 @@ layout(std430, binding = 1) restrict readonly buffer TargetBuffer { void main() { uint instanceIndex = objectIDs[gl_BaseInstance + gl_InstanceID]; + FlwInstance i = flw_unpackInstance(objects[instanceIndex]); flw_layoutVertex(); - FLW_INSTANCE_STRUCT i = objects[instanceIndex]; flw_instanceVertex(i); flw_materialVertex(); flw_contextVertex(); diff --git a/src/main/resources/assets/flywheel/flywheel/pipeline/instanced_arrays_draw.vert b/src/main/resources/assets/flywheel/flywheel/pipeline/instanced_arrays_draw.vert index 0b75edde3..47a939bf4 100644 --- a/src/main/resources/assets/flywheel/flywheel/pipeline/instanced_arrays_draw.vert +++ b/src/main/resources/assets/flywheel/flywheel/pipeline/instanced_arrays_draw.vert @@ -2,7 +2,8 @@ void main() { flw_layoutVertex(); - flw_instanceVertex(); + FlwInstance i = flw_unpackInstance(); + flw_instanceVertex(i); flw_materialVertex(); flw_contextVertex(); } diff --git a/src/main/resources/assets/flywheel/flywheel/util/types.glsl b/src/main/resources/assets/flywheel/flywheel/util/types.glsl index 3a93dbda4..731e81357 100644 --- a/src/main/resources/assets/flywheel/flywheel/util/types.glsl +++ b/src/main/resources/assets/flywheel/flywheel/util/types.glsl @@ -32,6 +32,10 @@ struct BoundingSphere { float radius; }; +struct LightCoord { + uint p; +}; + vec3 unpackVec3F(in Vec3F v) { return vec3(v.x, v.y, v.z); } @@ -61,3 +65,7 @@ void unpackBoundingSphere(in BoundingSphere sphere, out vec3 center, out float r center = unpackVec3F(sphere.center); radius = sphere.radius; } + +vec2 unpackLightCoord(in LightCoord light) { + return vec2(float((light.p >> 16) & 0xFFFFu), float(light.p & 0xFFFFu)) / 15.0; +}