mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-02-06 18:24:59 +01:00
Inderinstanced
This commit is contained in:
parent
61c2c76b47
commit
bf03f084c3
42 changed files with 895 additions and 302 deletions
|
@ -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<StructType<?>, SourceComponent> {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,8 +31,6 @@ public interface StructType<S extends InstancedPart> {
|
|||
|
||||
StorageBufferWriter<S> getStorageBufferWriter();
|
||||
|
||||
FileResolution getIndirectShader();
|
||||
|
||||
interface VertexTransformer<S extends InstancedPart> {
|
||||
void transform(MutableVertexList vertexList, S struct, ClientLevel level);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<PipelineCompiler.Context, GlProgr
|
|||
var vertex = new ShaderCompiler.Context(glslVersion, ShaderType.VERTEX, ctx.getVertexComponents());
|
||||
var fragment = new ShaderCompiler.Context(glslVersion, ShaderType.FRAGMENT, ctx.getFragmentComponents());
|
||||
|
||||
return new ProgramAssembler(ctx.instanceShader.getFileLoc())
|
||||
.attachShader(shaderCompiler.get(vertex))
|
||||
return new ProgramAssembler(ctx.structType.getInstanceShader()
|
||||
.getFileLoc()).attachShader(shaderCompiler.get(vertex))
|
||||
.attachShader(shaderCompiler.get(fragment))
|
||||
.link()
|
||||
.build(ctx.contextShader.factory());
|
||||
|
@ -87,22 +88,35 @@ public class PipelineCompiler extends Memoizer<PipelineCompiler.Context, GlProgr
|
|||
/**
|
||||
* Represents the entire context of a program's usage.
|
||||
*
|
||||
* @param vertexType The vertexType the program should be adapted for.
|
||||
* @param material The material shader to use. TODO: Flatten materials
|
||||
* @param instanceShader The instance shader to use.
|
||||
* @param contextShader The context shader to use.
|
||||
* @param vertexType The vertexType the program should be adapted for.
|
||||
* @param material The material shader to use. TODO: Flatten materials
|
||||
* @param structType The instance shader to use.
|
||||
* @param contextShader The context shader to use.
|
||||
*/
|
||||
public record Context(VertexType vertexType, Material material, FileResolution instanceShader,
|
||||
public record Context(VertexType vertexType, Material material, StructType<?> structType,
|
||||
ContextShader contextShader, PipelineShader pipelineShader) {
|
||||
|
||||
ImmutableList<SourceFile> getVertexComponents() {
|
||||
return ImmutableList.of(vertexType.getLayoutShader().getFile(), instanceShader.getFile(), material.getVertexShader().getFile(),
|
||||
contextShader.getVertexShader(), pipelineShader.vertex().getFile());
|
||||
ImmutableList<SourceComponent> 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<SourceFile> getFragmentComponents() {
|
||||
return ImmutableList.of(material.getFragmentShader().getFile(), contextShader.getFragmentShader(),
|
||||
pipelineShader.fragment().getFile());
|
||||
ImmutableList<SourceComponent> 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 Memoizer<PipelineCompiler.Context, GlProgr
|
|||
|
||||
@Override
|
||||
protected GlShader _create(Context key) {
|
||||
StringBuilder finalSource = new StringBuilder();
|
||||
|
||||
finalSource.append(key.generateHeader());
|
||||
StringBuilder finalSource = new StringBuilder(key.generateHeader());
|
||||
finalSource.append("#extension GL_ARB_explicit_attrib_location : enable\n");
|
||||
finalSource.append("#extension GL_ARB_conservative_depth : enable\n");
|
||||
finalSource.append("#extension GL_ARB_enhanced_layouts : enable\n");
|
||||
|
@ -126,9 +138,18 @@ public class PipelineCompiler extends Memoizer<PipelineCompiler.Context, GlProgr
|
|||
var ctx = new CompilationContext();
|
||||
|
||||
var names = ImmutableList.<ResourceLocation>builder();
|
||||
for (var file : key.components) {
|
||||
finalSource.append(file.generateFinalSource(ctx));
|
||||
names.add(file.name);
|
||||
var included = new LinkedHashSet<SourceComponent>(); // 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<PipelineCompiler.Context, GlProgr
|
|||
}
|
||||
|
||||
/**
|
||||
* @param glslVersion The GLSL version to use.
|
||||
* @param components A list of shader components to stitch together, in order.
|
||||
* @param glslVersion The GLSL version to use.
|
||||
* @param sourceComponents A list of shader components to stitch together, in order.
|
||||
*/
|
||||
public record Context(GLSLVersion glslVersion, ShaderType shaderType, List<SourceFile> components) {
|
||||
public record Context(GLSLVersion glslVersion, ShaderType shaderType, List<SourceComponent> sourceComponents) {
|
||||
|
||||
public String generateHeader() {
|
||||
return CompileUtil.generateHeader(glslVersion, shaderType);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<FileResolution, GlProgram> {
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class ComputeCullerCompiler extends Memoizer<StructType<?>, GlProgram> {
|
||||
|
||||
public static final ComputeCullerCompiler INSTANCE = new ComputeCullerCompiler();
|
||||
|
||||
|
@ -22,22 +28,35 @@ public class ComputeCullerCompiler extends Memoizer<FileResolution, GlProgram> {
|
|||
}
|
||||
|
||||
@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.<ResourceLocation>builder();
|
||||
var included = new LinkedHashSet<SourceComponent>(); // 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) {
|
||||
|
|
|
@ -64,9 +64,8 @@ public class IndirectCullingGroup<T extends InstancedPart> {
|
|||
.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<T extends InstancedPart> {
|
|||
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++) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -19,7 +19,7 @@ public class FullscreenQuad {
|
|||
|
||||
public static final Lazy<FullscreenQuad> 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 = {
|
||||
|
|
|
@ -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<? extends SourceComponent> included();
|
||||
|
||||
String source(CompilationContext ctx);
|
||||
|
||||
ResourceLocation name();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -68,11 +68,17 @@ public class DebugCompiler extends Memoizer<DebugCompiler.Context, GlProgram> {
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<VertexAttribute> attributes;
|
||||
public final List<LayoutItem> layoutItems;
|
||||
public final List<VertexAttribute> attributes;
|
||||
|
||||
private final int stride;
|
||||
|
||||
public BufferLayout(List<LayoutItem> layoutItems, int padding) {
|
||||
this.layoutItems = ImmutableList.copyOf(layoutItems);
|
||||
|
||||
ImmutableList.Builder<VertexAttribute> 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<VertexAttribute> getAttributes() {
|
||||
public List<VertexAttribute> 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<? extends SourceComponent> 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<? extends SourceComponent> 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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<VertexAttribute> consumer);
|
||||
|
||||
String typeName();
|
||||
|
||||
String packedTypeName();
|
||||
|
||||
int attributeCount();
|
||||
|
||||
GlslExpr unpack(GlslExpr packed);
|
||||
}
|
|
@ -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<VertexAttribute> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<GlslExpr, GlslExpr> unpackingFunction;
|
||||
|
||||
public PrimitiveItem(VertexAttribute attribute) {
|
||||
public PrimitiveItem(VertexAttribute attribute, String typeName, String packedTypeName, Function<GlslExpr, GlslExpr> 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<GlslExpr, GlslExpr> 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<GlslExpr, GlslExpr> f) {
|
||||
this.unpackingFunction = f;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PrimitiveItem createPrimitiveItem() {
|
||||
return new PrimitiveItem(attribute, typeName, packedTypeName, unpackingFunction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,28 +11,58 @@ import com.jozufozu.flywheel.core.source.span.Span;
|
|||
public class CompilationContext {
|
||||
public final List<SourceFile> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Variable> params = func.getParameters();
|
||||
ImmutableList<ShaderVariable> params = func.getParameters();
|
||||
if (params.size() != arity) {
|
||||
errorReporter.generateFunctionArgumentCountError(name, arity, func.getArgs());
|
||||
return null;
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*/
|
||||
public class SourceFile {
|
||||
public class SourceFile implements SourceComponent {
|
||||
|
||||
public final ResourceLocation name;
|
||||
|
||||
|
@ -56,10 +56,9 @@ public class SourceFile {
|
|||
*/
|
||||
public final ImmutableList<Import> imports;
|
||||
public final ImmutableMap<String, ShaderField> fields;
|
||||
private final List<Span> elisions;
|
||||
|
||||
// POST-RESOLUTION
|
||||
private List<Import> flattenedImports;
|
||||
public List<SourceFile> 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<? extends SourceComponent> 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<Import> flat = new ArrayList<>(this.imports.size());
|
||||
ArrayList<SourceFile> 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<Pair<Span, String>> 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<Pair<Span, String>> replacements) {
|
||||
var replacementsAndElisions = new ArrayList<>(replacements);
|
||||
for (var include : imports) {
|
||||
replacementsAndElisions.add(Pair.of(include.self, ""));
|
||||
}
|
||||
|
||||
return this.replace(replacementsAndElisions);
|
||||
}
|
||||
|
||||
private CharSequence replace(List<Pair<Span, String>> 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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<SourceElement> 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 extends SourceElement> 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<Pair<String, String>> 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<Pair<String, String>> arguments = new ArrayList<>();
|
||||
private final List<String> 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(", "));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<GlslExpr, GlslExpr> 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -20,7 +20,7 @@ public class ShaderFunction extends AbstractShaderElement {
|
|||
private final Span args;
|
||||
private final Span body;
|
||||
|
||||
private final ImmutableList<Variable> parameters;
|
||||
private final ImmutableList<ShaderVariable> 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<Variable> getParameters() {
|
||||
public ImmutableList<ShaderVariable> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
|
@ -64,12 +64,12 @@ public class ShaderFunction extends AbstractShaderElement {
|
|||
return type.get();
|
||||
}
|
||||
|
||||
protected ImmutableList<Variable> parseArguments() {
|
||||
protected ImmutableList<ShaderVariable> parseArguments() {
|
||||
if (args.isErr() || args.isEmpty()) return ImmutableList.of();
|
||||
|
||||
Matcher arguments = argument.matcher(args.get());
|
||||
|
||||
ImmutableList.Builder<Variable> builder = ImmutableList.builder();
|
||||
ImmutableList.Builder<ShaderVariable> 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();
|
||||
|
|
|
@ -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;
|
|
@ -15,8 +15,11 @@ import com.mojang.math.Vector4f;
|
|||
public class OrientedType implements StructType<OrientedPart> {
|
||||
|
||||
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<OrientedPart> {
|
|||
return Components.Files.ORIENTED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileResolution getIndirectShader() {
|
||||
return Components.Files.ORIENTED_INDIRECT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexTransformer<OrientedPart> getVertexTransformer() {
|
||||
return (vertexList, struct, level) -> {
|
||||
|
|
|
@ -13,8 +13,10 @@ import com.mojang.math.Vector4f;
|
|||
public class TransformedType implements StructType<TransformedPart> {
|
||||
|
||||
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<TransformedPart> {
|
|||
return Components.Files.TRANSFORMED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileResolution getIndirectShader() {
|
||||
return Components.Files.TRANSFORMED_INDIRECT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexTransformer<TransformedPart> getVertexTransformer() {
|
||||
return (vertexList, struct, level) -> {
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
void main() {
|
||||
flw_layoutVertex();
|
||||
flw_instanceVertex();
|
||||
FlwInstance i = flw_unpackInstance();
|
||||
flw_instanceVertex(i);
|
||||
flw_materialVertex();
|
||||
flw_contextVertex();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue