Fog so thick you could cut it

- Add generic ResourceLocation Index in ShaderIndices.
- Add FogShader and CutoutShader API.
- Implement existing fog/cutout configurations as separate shaders.
- Simplify pipeline shaders to accommodate for new api.
- Separate fog and cutout ubershader components.
  - This was much easier than I anticipated, seems we finally have a
    usable compiler/shader stitcher.
- Pass fog and cutout IDs to ubershader via a 2x16 packed uint.
- Remove discardPredicate and fogFilter from default material shader.
This commit is contained in:
Jozufozu 2023-12-02 01:49:25 -08:00
parent 23ddf350ea
commit 570e00978a
39 changed files with 403 additions and 287 deletions

View file

@ -8,7 +8,7 @@ import org.slf4j.Logger;
import com.jozufozu.flywheel.api.event.EndClientResourceReloadEvent;
import com.jozufozu.flywheel.api.visualization.VisualizationManager;
import com.jozufozu.flywheel.backend.Backends;
import com.jozufozu.flywheel.backend.MaterialShaderIndices;
import com.jozufozu.flywheel.backend.ShaderIndices;
import com.jozufozu.flywheel.backend.compile.FlwPrograms;
import com.jozufozu.flywheel.backend.engine.UniformBuffer;
import com.jozufozu.flywheel.backend.engine.batching.DrawBuffer;
@ -132,7 +132,7 @@ public class Flywheel {
StandardMaterialShaders.init();
Contexts.init();
MaterialShaderIndices.init();
ShaderIndices.init();
VanillaVisuals.init();

View file

@ -1,16 +0,0 @@
package com.jozufozu.flywheel.api.material;
public enum Cutout {
/**
* Do not discard any fragments based on alpha.
*/
OFF,
/**
* Discard fragments with alpha close to or equal to zero.
*/
EPSILON,
/**
* Discard fragments with alpha less than to 0.5.
*/
HALF,
}

View file

@ -0,0 +1,12 @@
package com.jozufozu.flywheel.api.material;
import com.jozufozu.flywheel.api.registry.Registry;
import com.jozufozu.flywheel.impl.RegistryImpl;
import net.minecraft.resources.ResourceLocation;
public interface CutoutShader {
static Registry<CutoutShader> REGISTRY = RegistryImpl.create();
ResourceLocation source();
}

View file

@ -0,0 +1,12 @@
package com.jozufozu.flywheel.api.material;
import com.jozufozu.flywheel.api.registry.Registry;
import com.jozufozu.flywheel.impl.RegistryImpl;
import net.minecraft.resources.ResourceLocation;
public interface FogShader {
static Registry<FogShader> REGISTRY = RegistryImpl.create();
ResourceLocation source();
}

View file

@ -44,11 +44,11 @@ public interface Material {
boolean mip();
Fog fog();
FogShader fog();
CutoutShader cutout();
Transparency transparency();
Cutout cutout();
WriteMask writeMask();
}

View file

@ -1,122 +0,0 @@
package com.jozufozu.flywheel.backend;
import java.util.List;
import org.jetbrains.annotations.Unmodifiable;
import com.jozufozu.flywheel.api.material.MaterialShaders;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntMaps;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectList;
import it.unimi.dsi.fastutil.objects.ObjectLists;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import it.unimi.dsi.fastutil.objects.ObjectSet;
import net.minecraft.resources.ResourceLocation;
public final class MaterialShaderIndices {
private static Object2IntMap<ResourceLocation> vertexShaderIndices;
private static Object2IntMap<ResourceLocation> fragmentShaderIndices;
private static ObjectList<ResourceLocation> vertexShadersByIndex;
private static ObjectList<ResourceLocation> fragmentShadersByIndex;
private static boolean initialized;
private MaterialShaderIndices() {
}
public static int getVertexShaderIndex(ResourceLocation vertexShader) {
if (!initialized) {
throw new IllegalStateException("Not initialized!");
}
return vertexShaderIndices.getInt(vertexShader);
}
public static int getFragmentShaderIndex(ResourceLocation fragmentShader) {
if (!initialized) {
throw new IllegalStateException("Not initialized!");
}
return fragmentShaderIndices.getInt(fragmentShader);
}
public static int getVertexShaderIndex(MaterialShaders shaders) {
return getVertexShaderIndex(shaders.vertexShader());
}
public static int getFragmentShaderIndex(MaterialShaders shaders) {
return getFragmentShaderIndex(shaders.fragmentShader());
}
public static ResourceLocation getVertexShader(int index) {
if (!initialized) {
throw new IllegalStateException("Not initialized!");
}
return vertexShadersByIndex.get(index);
}
public static ResourceLocation getFragmentShader(int index) {
if (!initialized) {
throw new IllegalStateException("Not initialized!");
}
return fragmentShadersByIndex.get(index);
}
@Unmodifiable
public static List<ResourceLocation> getAllVertexShaders() {
if (!initialized) {
throw new IllegalStateException("Not initialized!");
}
return vertexShadersByIndex;
}
@Unmodifiable
public static List<ResourceLocation> getAllFragmentShaders() {
if (!initialized) {
throw new IllegalStateException("Not initialized!");
}
return fragmentShadersByIndex;
}
private static void initInner() {
int amount = MaterialShaders.REGISTRY.getAll().size();
Object2IntMap<ResourceLocation> vertexShaderIndices = new Object2IntOpenHashMap<>();
vertexShaderIndices.defaultReturnValue(-1);
Object2IntMap<ResourceLocation> fragmentShaderIndices = new Object2IntOpenHashMap<>();
fragmentShaderIndices.defaultReturnValue(-1);
ObjectList<ResourceLocation> vertexShadersByIndex = new ObjectArrayList<>(amount);
ObjectList<ResourceLocation> fragmentShadersByIndex = new ObjectArrayList<>(amount);
ObjectSet<ResourceLocation> allVertexShaders = new ObjectOpenHashSet<>();
ObjectSet<ResourceLocation> allFragmentShaders = new ObjectOpenHashSet<>();
int vertexShaderIndex = 0;
int fragmentShaderIndex = 0;
for (MaterialShaders shaders : MaterialShaders.REGISTRY) {
ResourceLocation vertexShader = shaders.vertexShader();
if (allVertexShaders.add(vertexShader)) {
vertexShaderIndices.put(vertexShader, vertexShaderIndex);
vertexShadersByIndex.add(vertexShader);
vertexShaderIndex++;
}
ResourceLocation fragmentShader = shaders.fragmentShader();
if (allFragmentShaders.add(fragmentShader)) {
fragmentShaderIndices.put(fragmentShader, fragmentShaderIndex);
fragmentShadersByIndex.add(fragmentShader);
fragmentShaderIndex++;
}
}
MaterialShaderIndices.vertexShaderIndices = Object2IntMaps.unmodifiable(vertexShaderIndices);
MaterialShaderIndices.fragmentShaderIndices = Object2IntMaps.unmodifiable(fragmentShaderIndices);
MaterialShaderIndices.vertexShadersByIndex = ObjectLists.unmodifiable(vertexShadersByIndex);
MaterialShaderIndices.fragmentShadersByIndex = ObjectLists.unmodifiable(fragmentShadersByIndex);
initialized = true;
}
public static void init() {
MaterialShaders.REGISTRY.addFreezeCallback(MaterialShaderIndices::initInner);
}
}

View file

@ -114,10 +114,6 @@ public class MaterialUtil {
public static final int BACKFACE_CULL_MASK = 1 << 3;
public static final int POLYGON_OFFSET_MASK = 1 << 4;
public static final int MIP_MASK = 1 << 5;
public static final int FOG_MASK = 0b11000000;
public static final int TRANSPARENCY_MASK = 0b11100000000;
public static final int CUTOUT_MASK = 0b1100000000000;
public static final int WRITE_MASK_MASK = 0b110000000000000;
public static int packProperties(Material material) {
int out = 0;
@ -129,15 +125,23 @@ public class MaterialUtil {
if (material.polygonOffset()) out |= POLYGON_OFFSET_MASK;
if (material.mip()) out |= MIP_MASK;
out |= (material.fog()
out |= (material.writeMask()
.ordinal() & 0x3) << 6;
out |= (material.transparency()
.ordinal() & 0x7) << 8;
out |= (material.cutout()
.ordinal() & 0x3) << 11;
out |= (material.writeMask()
.ordinal() & 0x3) << 13;
return out;
}
public static int packFogAndCutout(Material material) {
var fog = ShaderIndices.fog()
.index(material.fog()
.source());
var cutout = ShaderIndices.cutout()
.index(material.cutout()
.source());
return fog & 0xFFFF | (cutout & 0xFFFF) << 16;
}
}

View file

@ -0,0 +1,183 @@
package com.jozufozu.flywheel.backend;
import java.util.List;
import org.jetbrains.annotations.Unmodifiable;
import com.jozufozu.flywheel.api.material.CutoutShader;
import com.jozufozu.flywheel.api.material.FogShader;
import com.jozufozu.flywheel.api.material.MaterialShaders;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntMaps;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectList;
import it.unimi.dsi.fastutil.objects.ObjectLists;
import net.minecraft.resources.ResourceLocation;
public final class ShaderIndices {
private static Index vertexShaders;
private static Index fragmentShaders;
private static Index cutoutShaders;
private static Index fogShaders;
private ShaderIndices() {
}
public static Index materialVertex() {
if (vertexShaders == null) {
throw new IllegalStateException("Not initialized!");
}
return vertexShaders;
}
public static Index materialFragment() {
if (fragmentShaders == null) {
throw new IllegalStateException("Not initialized!");
}
return fragmentShaders;
}
public static Index cutout() {
if (cutoutShaders == null) {
throw new IllegalStateException("Not initialized!");
}
return cutoutShaders;
}
public static Index fog() {
if (fogShaders == null) {
throw new IllegalStateException("Not initialized!");
}
return fogShaders;
}
public static int getCutoutShaderIndex(CutoutShader cutoutShader) {
return cutout().index(cutoutShader.source());
}
public static int getFogShaderIndex(FogShader fogShader) {
return fog().index(fogShader.source());
}
public static int getVertexShaderIndex(MaterialShaders shaders) {
return materialVertex().index(shaders.vertexShader());
}
public static int getFragmentShaderIndex(MaterialShaders shaders) {
return materialFragment().index(shaders.fragmentShader());
}
private static void initMaterialShaders() {
int amount = MaterialShaders.REGISTRY.getAll()
.size();
var vertexShaders = new IndexBuilder(amount);
var fragmentShaders = new IndexBuilder(amount);
for (MaterialShaders shaders : MaterialShaders.REGISTRY) {
vertexShaders.add(shaders.vertexShader());
fragmentShaders.add(shaders.fragmentShader());
}
ShaderIndices.vertexShaders = vertexShaders.build();
ShaderIndices.fragmentShaders = fragmentShaders.build();
}
private static void initCutoutShaders() {
int amount = CutoutShader.REGISTRY.getAll()
.size();
var cutout = new IndexBuilder(amount);
for (CutoutShader shaders : CutoutShader.REGISTRY) {
cutout.add(shaders.source());
}
ShaderIndices.cutoutShaders = cutout.build();
}
private static void initFogShaders() {
int amount = FogShader.REGISTRY.getAll()
.size();
var fog = new IndexBuilder(amount);
for (FogShader shaders : FogShader.REGISTRY) {
fog.add(shaders.source());
}
ShaderIndices.fogShaders = fog.build();
}
public static void init() {
MaterialShaders.REGISTRY.addFreezeCallback(ShaderIndices::initMaterialShaders);
CutoutShader.REGISTRY.addFreezeCallback(ShaderIndices::initCutoutShaders);
FogShader.REGISTRY.addFreezeCallback(ShaderIndices::initFogShaders);
}
public static class Index {
private final Object2IntMap<ResourceLocation> shaders2Index;
private final ObjectList<ResourceLocation> shaders;
private Index(IndexBuilder builder) {
this.shaders2Index = Object2IntMaps.unmodifiable(builder.shaders2Index);
this.shaders = ObjectLists.unmodifiable(builder.shaders);
}
public int index(ResourceLocation shader) {
return shaders2Index.getInt(shader);
}
@Unmodifiable
public List<ResourceLocation> all() {
return shaders;
}
public ResourceLocation get(int index) {
return shaders.get(index);
}
}
private static class IndexBuilder {
private int index;
private final Object2IntMap<ResourceLocation> shaders2Index;
private final ObjectList<ResourceLocation> shaders;
public IndexBuilder(int amount) {
shaders2Index = new Object2IntOpenHashMap<>();
shaders2Index.defaultReturnValue(-1);
shaders = new ObjectArrayList<>(amount);
}
public void add(ResourceLocation shader) {
if (shaders2Index.putIfAbsent(shader, index) == -1) {
shaders.add(shader);
index++;
}
}
public Index build() {
return new Index(this);
}
}
}

View file

@ -1,6 +1,7 @@
package com.jozufozu.flywheel.backend.compile;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
@ -114,6 +115,11 @@ public class Compile<K> {
return this;
}
public ShaderCompilerBuilder<K> withComponents(Collection<SourceComponent> components) {
components.forEach(this::withComponent);
return this;
}
public ShaderCompilerBuilder<K> withComponent(SourceComponent component) {
return withComponent($ -> component);
}

View file

@ -8,11 +8,12 @@ import com.jozufozu.flywheel.api.context.Context;
import com.jozufozu.flywheel.api.instance.InstanceType;
import com.jozufozu.flywheel.api.uniform.ShaderUniforms;
import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.backend.MaterialShaderIndices;
import com.jozufozu.flywheel.backend.compile.component.MaterialAdapterComponent;
import com.jozufozu.flywheel.backend.ShaderIndices;
import com.jozufozu.flywheel.backend.compile.component.UberShaderComponent;
import com.jozufozu.flywheel.backend.compile.component.UniformComponent;
import com.jozufozu.flywheel.backend.compile.core.CompilerStats;
import com.jozufozu.flywheel.glsl.ShaderSources;
import com.jozufozu.flywheel.glsl.SourceComponent;
import com.jozufozu.flywheel.glsl.generate.FnSignature;
import com.jozufozu.flywheel.glsl.generate.GlslExpr;
@ -32,38 +33,56 @@ public class FlwPrograms {
var pipelineKeys = createPipelineKeys();
var uniformComponent = createUniformComponent(loadChecker);
var vertexMaterialComponent = createVertexMaterialComponent(loadChecker);
var fragmentMaterialComponent = createFragmentMaterialComponent(loadChecker);
List<SourceComponent> vertexComponents = List.of(createVertexMaterialComponent(loadChecker));
List<SourceComponent> fragmentComponents = List.of(createFragmentMaterialComponent(loadChecker), createFogComponent(loadChecker), createCutoutComponent(loadChecker));
InstancingPrograms.reload(sources, pipelineKeys, uniformComponent, vertexMaterialComponent, fragmentMaterialComponent);
IndirectPrograms.reload(sources, pipelineKeys, uniformComponent, vertexMaterialComponent, fragmentMaterialComponent);
InstancingPrograms.reload(sources, pipelineKeys, uniformComponent, vertexComponents, fragmentComponents);
IndirectPrograms.reload(sources, pipelineKeys, uniformComponent, vertexComponents, fragmentComponents);
if (preLoadStats.errored()) {
Flywheel.LOGGER.error(preLoadStats.generateErrorLog());
}
}
private static MaterialAdapterComponent createFragmentMaterialComponent(SourceLoader loadChecker) {
return MaterialAdapterComponent.builder(Flywheel.rl("fragment_material_adapter"))
.materialSources(MaterialShaderIndices.getAllFragmentShaders())
private static UberShaderComponent createFragmentMaterialComponent(SourceLoader loadChecker) {
return UberShaderComponent.builder(Flywheel.rl("uber_fragment_material"))
.materialSources(ShaderIndices.materialFragment()
.all())
.adapt(FnSignature.ofVoid("flw_materialFragment"))
.adapt(FnSignature.create()
.returnType("bool")
.name("flw_discardPredicate")
.arg("vec4", "color")
.build(), GlslExpr.boolLiteral(false))
.switchOn(GlslExpr.variable("_flw_materialFragmentID"))
.build(loadChecker);
}
private static UberShaderComponent createFogComponent(SourceLoader loadChecker) {
return UberShaderComponent.builder(Flywheel.rl("uber_fog"))
.materialSources(ShaderIndices.fog()
.all())
.adapt(FnSignature.create()
.returnType("vec4")
.name("flw_fogFilter")
.arg("vec4", "color")
.build(), GlslExpr.variable("color"))
.switchOn(GlslExpr.variable("_flw_materialFragmentID"))
.switchOn(GlslExpr.variable("_flw_fogID"))
.build(loadChecker);
}
private static MaterialAdapterComponent createVertexMaterialComponent(SourceLoader loadChecker) {
return MaterialAdapterComponent.builder(Flywheel.rl("vertex_material_adapter"))
.materialSources(MaterialShaderIndices.getAllVertexShaders())
private static UberShaderComponent createCutoutComponent(SourceLoader loadChecker) {
return UberShaderComponent.builder(Flywheel.rl("uber_cutout"))
.materialSources(ShaderIndices.cutout()
.all())
.adapt(FnSignature.create()
.returnType("bool")
.name("flw_discardPredicate")
.arg("vec4", "color")
.build(), GlslExpr.boolLiteral(false))
.switchOn(GlslExpr.variable("_flw_cutoutID"))
.build(loadChecker);
}
private static UberShaderComponent createVertexMaterialComponent(SourceLoader loadChecker) {
return UberShaderComponent.builder(Flywheel.rl("vertex_material_adapter"))
.materialSources(ShaderIndices.materialVertex()
.all())
.adapt(FnSignature.ofVoid("flw_materialVertex"))
.switchOn(GlslExpr.variable("_flw_materialVertexID"))
.build(loadChecker);

View file

@ -1,5 +1,6 @@
package com.jozufozu.flywheel.backend.compile;
import java.util.List;
import java.util.Map;
import org.jetbrains.annotations.Nullable;
@ -10,13 +11,13 @@ import com.jozufozu.flywheel.api.context.Context;
import com.jozufozu.flywheel.api.instance.InstanceType;
import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.backend.compile.component.IndirectComponent;
import com.jozufozu.flywheel.backend.compile.component.MaterialAdapterComponent;
import com.jozufozu.flywheel.backend.compile.component.UniformComponent;
import com.jozufozu.flywheel.gl.GlCompat;
import com.jozufozu.flywheel.gl.shader.GlProgram;
import com.jozufozu.flywheel.gl.shader.ShaderType;
import com.jozufozu.flywheel.glsl.GLSLVersion;
import com.jozufozu.flywheel.glsl.ShaderSources;
import com.jozufozu.flywheel.glsl.SourceComponent;
import net.minecraft.resources.ResourceLocation;
@ -31,9 +32,9 @@ public class IndirectPrograms {
this.culling = culling;
}
static void reload(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent, MaterialAdapterComponent vertexMaterialComponent, MaterialAdapterComponent fragmentMaterialComponent) {
static void reload(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent, List<SourceComponent> vertexComponents, List<SourceComponent> fragmentComponents) {
_delete();
var pipelineCompiler = PipelineCompiler.create(sources, Pipelines.INDIRECT, pipelineKeys, uniformComponent, vertexMaterialComponent, fragmentMaterialComponent);
var pipelineCompiler = PipelineCompiler.create(sources, Pipelines.INDIRECT, pipelineKeys, uniformComponent, vertexComponents, fragmentComponents);
var cullingCompiler = createCullingCompiler(uniformComponent, sources);
try {

View file

@ -1,5 +1,6 @@
package com.jozufozu.flywheel.backend.compile;
import java.util.List;
import java.util.Map;
import org.jetbrains.annotations.Nullable;
@ -9,10 +10,10 @@ import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.api.context.Context;
import com.jozufozu.flywheel.api.instance.InstanceType;
import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.backend.compile.component.MaterialAdapterComponent;
import com.jozufozu.flywheel.backend.compile.component.UniformComponent;
import com.jozufozu.flywheel.gl.shader.GlProgram;
import com.jozufozu.flywheel.glsl.ShaderSources;
import com.jozufozu.flywheel.glsl.SourceComponent;
public class InstancingPrograms {
static InstancingPrograms instance;
@ -22,9 +23,9 @@ public class InstancingPrograms {
this.pipeline = pipeline;
}
static void reload(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent, MaterialAdapterComponent vertexMaterialComponent, MaterialAdapterComponent fragmentMaterialComponent) {
static void reload(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent, List<SourceComponent> vertexComponents, List<SourceComponent> fragmentComponents) {
_delete();
var instancingCompiler = PipelineCompiler.create(sources, Pipelines.INSTANCED_ARRAYS, pipelineKeys, uniformComponent, vertexMaterialComponent, fragmentMaterialComponent);
var instancingCompiler = PipelineCompiler.create(sources, Pipelines.INSTANCED_ARRAYS, pipelineKeys, uniformComponent, vertexComponents, fragmentComponents);
try {
var result = instancingCompiler.compileAndReportErrors();

View file

@ -1,15 +1,17 @@
package com.jozufozu.flywheel.backend.compile;
import java.util.List;
import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.backend.compile.component.MaterialAdapterComponent;
import com.jozufozu.flywheel.backend.compile.component.UniformComponent;
import com.jozufozu.flywheel.gl.shader.ShaderType;
import com.jozufozu.flywheel.glsl.ShaderSources;
import com.jozufozu.flywheel.glsl.SourceComponent;
public class PipelineCompiler {
private static final Compile<PipelineProgramKey> PIPELINE = new Compile<>();
static CompilationHarness<PipelineProgramKey> create(ShaderSources sources, Pipeline pipeline, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent, MaterialAdapterComponent vertexMaterialComponent, MaterialAdapterComponent fragmentMaterialComponent) {
static CompilationHarness<PipelineProgramKey> create(ShaderSources sources, Pipeline pipeline, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent, List<SourceComponent> vertexComponents, List<SourceComponent> fragmentComponents) {
return PIPELINE.harness(sources)
.keys(pipelineKeys)
.compiler(PIPELINE.program()
@ -18,7 +20,7 @@ public class PipelineCompiler {
.withComponent(key -> pipeline.assembler()
.assemble(new Pipeline.InstanceAssemblerContext(key.vertexType(), key.instanceType())))
.withResource(pipeline.vertexAPI())
.withComponent(vertexMaterialComponent)
.withComponents(vertexComponents)
.withResource(key -> key.vertexType()
.layoutShader())
.withResource(key -> key.instanceType()
@ -30,7 +32,7 @@ public class PipelineCompiler {
.enableExtension("GL_ARB_conservative_depth")
.withComponent(uniformComponent)
.withResource(pipeline.fragmentAPI())
.withComponent(fragmentMaterialComponent)
.withComponents(fragmentComponents)
.withResource(key -> key.contextShader()
.fragmentShader())
.withResource(pipeline.fragmentShader()))

View file

@ -20,13 +20,13 @@ import com.jozufozu.flywheel.glsl.generate.GlslSwitch;
import net.minecraft.resources.ResourceLocation;
public class MaterialAdapterComponent implements SourceComponent {
public class UberShaderComponent implements SourceComponent {
private final ResourceLocation name;
private final GlslExpr switchArg;
private final List<AdaptedFn> functionsToAdapt;
private final List<StringSubstitutionSourceComponent> adaptedComponents;
private MaterialAdapterComponent(ResourceLocation name, GlslExpr switchArg, List<AdaptedFn> functionsToAdapt, List<StringSubstitutionSourceComponent> adaptedComponents) {
private UberShaderComponent(ResourceLocation name, GlslExpr switchArg, List<AdaptedFn> functionsToAdapt, List<StringSubstitutionSourceComponent> adaptedComponents) {
this.name = name;
this.switchArg = switchArg;
this.functionsToAdapt = functionsToAdapt;
@ -134,7 +134,7 @@ public class MaterialAdapterComponent implements SourceComponent {
return this;
}
public MaterialAdapterComponent build(SourceLoader sources) {
public UberShaderComponent build(SourceLoader sources) {
if (switchArg == null) {
throw new NullPointerException("Switch argument must be set");
}
@ -159,7 +159,7 @@ public class MaterialAdapterComponent implements SourceComponent {
return null;
}
return new MaterialAdapterComponent(name, switchArg, adaptedFunctions, transformed.build());
return new UberShaderComponent(name, switchArg, adaptedFunctions, transformed.build());
}
}

View file

@ -5,8 +5,8 @@ import org.lwjgl.system.MemoryUtil;
import com.jozufozu.flywheel.api.event.RenderStage;
import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.backend.MaterialShaderIndices;
import com.jozufozu.flywheel.backend.MaterialUtil;
import com.jozufozu.flywheel.backend.ShaderIndices;
public class IndirectDraw<I extends Instance> {
private final IndirectInstancer<I> instancer;
@ -16,6 +16,7 @@ public class IndirectDraw<I extends Instance> {
private final int vertexMaterialID;
private final int fragmentMaterialID;
private final int packedFogAndCutout;
private final int packedMaterialProperties;
private int baseInstance = -1;
@ -27,8 +28,9 @@ public class IndirectDraw<I extends Instance> {
this.mesh = mesh;
this.stage = stage;
this.vertexMaterialID = MaterialShaderIndices.getVertexShaderIndex(material.shaders());
this.fragmentMaterialID = MaterialShaderIndices.getFragmentShaderIndex(material.shaders());
this.vertexMaterialID = ShaderIndices.getVertexShaderIndex(material.shaders());
this.fragmentMaterialID = ShaderIndices.getFragmentShaderIndex(material.shaders());
this.packedFogAndCutout = MaterialUtil.packFogAndCutout(material);
this.packedMaterialProperties = MaterialUtil.packProperties(material);
}
@ -78,6 +80,7 @@ public class IndirectDraw<I extends Instance> {
boundingSphere.getToAddress(ptr + 20); // boundingSphere
MemoryUtil.memPutInt(ptr + 36, vertexMaterialID); // vertexMaterialID
MemoryUtil.memPutInt(ptr + 40, fragmentMaterialID); // fragmentMaterialID
MemoryUtil.memPutInt(ptr + 44, packedMaterialProperties); // packedMaterialProperties
MemoryUtil.memPutInt(ptr + 44, packedFogAndCutout); // packedFogAndCutout
MemoryUtil.memPutInt(ptr + 48, packedMaterialProperties); // packedMaterialProperties
}
}

View file

@ -9,8 +9,8 @@ import com.jozufozu.flywheel.api.event.RenderStage;
import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.task.Plan;
import com.jozufozu.flywheel.api.task.TaskExecutor;
import com.jozufozu.flywheel.backend.MaterialShaderIndices;
import com.jozufozu.flywheel.backend.MaterialUtil;
import com.jozufozu.flywheel.backend.ShaderIndices;
import com.jozufozu.flywheel.backend.compile.InstancingPrograms;
import com.jozufozu.flywheel.backend.engine.AbstractEngine;
import com.jozufozu.flywheel.backend.engine.AbstractInstancer;
@ -126,9 +126,10 @@ public class InstancingEngine extends AbstractEngine {
public static void uploadMaterialIDUniform(GlProgram program, Material material) {
int materialIDUniform = program.getUniformLocation("_flw_material_instancing");
int vertexID = MaterialShaderIndices.getVertexShaderIndex(material.shaders());
int fragmentID = MaterialShaderIndices.getFragmentShaderIndex(material.shaders());
int vertexID = ShaderIndices.getVertexShaderIndex(material.shaders());
int fragmentID = ShaderIndices.getFragmentShaderIndex(material.shaders());
int packedFogAndCutout = MaterialUtil.packFogAndCutout(material);
int packedMaterialProperties = MaterialUtil.packProperties(material);
GL32.glUniform3ui(materialIDUniform, vertexID, fragmentID, packedMaterialProperties);
GL32.glUniform4ui(materialIDUniform, vertexID, fragmentID, packedFogAndCutout, packedMaterialProperties);
}
}

View file

@ -1,6 +1,5 @@
package com.jozufozu.flywheel.lib.material;
import com.jozufozu.flywheel.api.material.Cutout;
import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.material.MaterialVertexTransformer;
import com.jozufozu.flywheel.api.material.Transparency;
@ -38,26 +37,26 @@ public final class Materials {
.build();
public static final Material CHUNK_CUTOUT_MIPPED_SHADED = SimpleMaterial.builder()
.cutout(Cutout.EPSILON)
.cutout(StandardMaterialShaders.EPSILON)
.fallbackRenderType(RenderType.cutoutMipped())
.vertexTransformer(SHADING_TRANSFORMER)
.build();
public static final Material CHUNK_CUTOUT_MIPPED_UNSHADED = SimpleMaterial.builder()
.diffuse(false)
.cutout(Cutout.EPSILON)
.cutout(StandardMaterialShaders.EPSILON)
.fallbackRenderType(RenderType.cutoutMipped())
.build();
public static final Material CHUNK_CUTOUT_SHADED = SimpleMaterial.builder()
.mip(false)
.cutout(Cutout.EPSILON)
.cutout(StandardMaterialShaders.EPSILON)
.fallbackRenderType(RenderType.cutout())
.vertexTransformer(SHADING_TRANSFORMER)
.build();
public static final Material CHUNK_CUTOUT_UNSHADED = SimpleMaterial.builder()
.diffuse(false)
.mip(false)
.cutout(Cutout.EPSILON)
.cutout(StandardMaterialShaders.EPSILON)
.fallbackRenderType(RenderType.cutout())
.build();
@ -74,14 +73,14 @@ public final class Materials {
public static final Material CHUNK_TRIPWIRE_SHADED = SimpleMaterial.builder()
.transparency(Transparency.TRANSLUCENT)
.cutout(Cutout.EPSILON)
.cutout(StandardMaterialShaders.EPSILON)
.fallbackRenderType(RenderType.tripwire())
.vertexTransformer(SHADING_TRANSFORMER)
.build();
public static final Material CHUNK_TRIPWIRE_UNSHADED = SimpleMaterial.builder()
.diffuse(false)
.transparency(Transparency.TRANSLUCENT)
.cutout(Cutout.EPSILON)
.cutout(StandardMaterialShaders.EPSILON)
.fallbackRenderType(RenderType.tripwire())
.build();
@ -94,7 +93,7 @@ public final class Materials {
.baseTexture(Sheets.SHULKER_SHEET)
.mip(false)
.backfaceCull(false)
.cutout(Cutout.EPSILON)
.cutout(StandardMaterialShaders.EPSILON)
.fallbackRenderType(Sheets.shulkerBoxSheet())
.build();
public static final Material BELL = SimpleMaterial.builder()

View file

@ -0,0 +1,8 @@
package com.jozufozu.flywheel.lib.material;
import com.jozufozu.flywheel.api.material.CutoutShader;
import net.minecraft.resources.ResourceLocation;
public record SimpleCutoutShader(@Override ResourceLocation source) implements CutoutShader {
}

View file

@ -0,0 +1,8 @@
package com.jozufozu.flywheel.lib.material;
import com.jozufozu.flywheel.api.material.FogShader;
import net.minecraft.resources.ResourceLocation;
public record SimpleFogShader(@Override ResourceLocation source) implements FogShader {
}

View file

@ -1,7 +1,7 @@
package com.jozufozu.flywheel.lib.material;
import com.jozufozu.flywheel.api.material.Cutout;
import com.jozufozu.flywheel.api.material.Fog;
import com.jozufozu.flywheel.api.material.CutoutShader;
import com.jozufozu.flywheel.api.material.FogShader;
import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.material.MaterialShaders;
import com.jozufozu.flywheel.api.material.MaterialVertexTransformer;
@ -24,9 +24,9 @@ public class SimpleMaterial implements Material {
protected final boolean backfaceCull;
protected final boolean polygonOffset;
protected final boolean mip;
protected final Fog fog;
protected final FogShader fog;
protected final Transparency transparency;
protected final Cutout cutout;
protected final CutoutShader cutout;
protected final WriteMask writeMask;
protected SimpleMaterial(Builder builder) {
@ -101,7 +101,7 @@ public class SimpleMaterial implements Material {
}
@Override
public Fog fog() {
public FogShader fog() {
return fog;
}
@ -111,7 +111,7 @@ public class SimpleMaterial implements Material {
}
@Override
public Cutout cutout() {
public CutoutShader cutout() {
return cutout;
}
@ -131,9 +131,9 @@ public class SimpleMaterial implements Material {
protected boolean backfaceCull = true;
protected boolean polygonOffset = false;
protected boolean mip = true;
protected Fog fog = Fog.LINEAR;
protected FogShader fog = StandardMaterialShaders.LINEAR;
protected Transparency transparency = Transparency.OPAQUE;
protected Cutout cutout = Cutout.OFF;
protected CutoutShader cutout = StandardMaterialShaders.OFF;
protected WriteMask writeMask = WriteMask.BOTH;
public Builder() {
@ -189,7 +189,7 @@ public class SimpleMaterial implements Material {
return this;
}
public Builder fog(Fog value) {
public Builder fog(FogShader value) {
this.fog = value;
return this;
}
@ -199,7 +199,7 @@ public class SimpleMaterial implements Material {
return this;
}
public Builder cutout(Cutout value) {
public Builder cutout(CutoutShader value) {
this.cutout = value;
return this;
}

View file

@ -3,11 +3,30 @@ package com.jozufozu.flywheel.lib.material;
import org.jetbrains.annotations.ApiStatus;
import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.api.material.CutoutShader;
import com.jozufozu.flywheel.api.material.FogShader;
import com.jozufozu.flywheel.api.material.MaterialShaders;
import net.minecraft.resources.ResourceLocation;
public final class StandardMaterialShaders {
/**
* Do not discard any fragments based on alpha.
*/
public static final CutoutShader OFF = CutoutShader.REGISTRY.registerAndGet(new SimpleCutoutShader(Flywheel.rl("cutout/off.glsl")));
/**
* Discard fragments with alpha close to or equal to zero.
*/
public static final CutoutShader EPSILON = CutoutShader.REGISTRY.registerAndGet(new SimpleCutoutShader(Flywheel.rl("cutout/epsilon.glsl")));
/**
* Discard fragments with alpha less than to 0.5.
*/
public static final CutoutShader HALF = CutoutShader.REGISTRY.registerAndGet(new SimpleCutoutShader(Flywheel.rl("cutout/half.glsl")));
public static final FogShader NONE = FogShader.REGISTRY.registerAndGet(new SimpleFogShader(Flywheel.rl("fog/none.glsl")));
public static final FogShader LINEAR = FogShader.REGISTRY.registerAndGet(new SimpleFogShader(Flywheel.rl("fog/linear.glsl")));
public static final FogShader LINEAR_FADE = FogShader.REGISTRY.registerAndGet(new SimpleFogShader(Flywheel.rl("fog/linear_fade.glsl")));
public static final MaterialShaders DEFAULT = MaterialShaders.REGISTRY.registerAndGet(new SimpleMaterialShaders(Files.DEFAULT_VERTEX, Files.DEFAULT_FRAGMENT));
private StandardMaterialShaders() {

View file

@ -1,8 +1,3 @@
const uint FLW_FOG_LINEAR = 0u;
const uint FLW_FOG_LINEAR_FADE = 1u;
const uint FLW_FOG_NONE = 2u;
const uint FLW_FOG_CUSTOM = 3u;
const uint FLW_TRANSPARENCY_OPAQUE = 0u;
const uint FLW_TRANSPARENCY_ADDITIVE = 1u;
const uint FLW_TRANSPARENCY_LIGHTING = 2u;
@ -10,11 +5,6 @@ const uint FLW_TRANSPARENCY_GLINT = 3u;
const uint FLW_TRANSPARENCY_CRUMBLING = 4u;
const uint FLW_TRANSPARENCY_TRANSLUCENT = 5u;
const uint FLW_CUTOUT_OFF = 0u;
const uint FLW_CUTOUT_EPSILON = 1u;
const uint FLW_CUTOUT_HALF = 2u;
const uint FLW_CUTOUT_CUSTOM = 3u;
const uint FLW_WRITE_MASK_BOTH = 0u;
const uint FLW_WRITE_MASK_COLOR = 1u;
const uint FLW_WRITE_MASK_DEPTH = 2u;
@ -27,8 +17,6 @@ struct FlwMaterial {
bool polygonOffset;
bool mip;
uint fog;
uint transparency;
uint cutout;
uint writeMask;
uint transparency;
};

View file

@ -0,0 +1,3 @@
bool flw_discardPredicate(vec4 finalColor) {
return finalColor.a < 0.01;
}

View file

@ -0,0 +1,3 @@
bool flw_discardPredicate(vec4 finalColor) {
return finalColor.a < 0.5;
}

View file

@ -0,0 +1,3 @@
bool flw_discardPredicate(vec4 finalColor) {
return false;
}

View file

@ -0,0 +1,5 @@
#include "flywheel:util/fog.glsl"
vec4 flw_fogFilter(vec4 color) {
return linear_fog(color, flw_distance, flywheel.fogRange.x, flywheel.fogRange.y, flywheel.fogColor);
}

View file

@ -0,0 +1,5 @@
#include "flywheel:util/fog.glsl"
vec4 flw_fogFilter(vec4 color) {
return linear_fog_fade(color, flw_distance, flywheel.fogRange.x, flywheel.fogRange.y);
}

View file

@ -0,0 +1,3 @@
vec4 flw_fogFilter(vec4 color) {
return color;
}

View file

@ -38,5 +38,7 @@ void flw_endFragment();
// ------------------------------------------
uint _flw_materialFragmentID;
uint _flw_fogID;
uint _flw_cutoutID;
// ------------------------------------------

View file

@ -30,7 +30,6 @@ void flw_endVertex();
// ------------------------------------------
uint _flw_materialVertexID;
uint _flw_materialFragmentID;
FlwInstance _flw_unpackInstance(FlwPackedInstance i);

View file

@ -12,14 +12,16 @@ uniform sampler2D flw_diffuseTex;
uniform sampler2D flw_overlayTex;
uniform sampler2D flw_lightTex;
flat in uvec2 _flw_material;
flat in uvec3 _flw_material;
out vec4 fragColor;
void main() {
_flw_materialFragmentID = _flw_material.x;
_flw_fogID = _flw_material.y & 0xFFFFu;
_flw_cutoutID = _flw_material.y >> 16u;
_flw_unpackMaterial(_flw_material.y, flw_material);
_flw_unpackMaterial(_flw_material.z, flw_material);
flw_sampleColor = texture(flw_diffuseTex, flw_vertexTexCoord);
flw_fragColor = flw_vertexColor * flw_sampleColor;
@ -40,23 +42,13 @@ void main() {
color *= lightColor;
}
if (flw_material.cutout == FLW_CUTOUT_EPSILON && color.a < 0.01) {
discard;
} else if (flw_material.cutout == FLW_CUTOUT_HALF && color.a < 0.5) {
discard;
} else if (flw_material.cutout == FLW_CUTOUT_CUSTOM) {
if (flw_discardPredicate(color)) {
discard;
}
if (flw_material.lighting) {
color *= lightColor;
}
if (flw_material.fog == FLW_FOG_LINEAR) {
color = linear_fog(color, flw_distance, flywheel.fogRange.x, flywheel.fogRange.y, flywheel.fogColor);
} else if (flw_material.fog == FLW_FOG_LINEAR_FADE) {
color = linear_fog_fade(color, flw_distance, flywheel.fogRange.x, flywheel.fogRange.y);
} else if (flw_material.fog == FLW_FOG_CUSTOM) {
color = flw_fogFilter(color);
if (flw_discardPredicate(color)) {
discard;
}
fragColor = color;
fragColor = flw_fogFilter(color);
}

View file

@ -3,7 +3,7 @@
#include "flywheel:internal/material.glsl"
#include "flywheel:util/diffuse.glsl"
flat out uvec2 _flw_material;
flat out uvec3 _flw_material;
struct Object {
uint batchID;
@ -28,11 +28,10 @@ void main() {
FlwInstance i = _flw_unpackInstance(objects[instanceIndex].instance);
_flw_materialVertexID = drawCommands[batchID].vertexMaterialID;
_flw_materialFragmentID = drawCommands[batchID].fragmentMaterialID;
uint p = drawCommands[batchID].packedMaterialProperties;
_flw_unpackMaterial(p, flw_material);
_flw_material = uvec2(_flw_materialFragmentID, p);
_flw_material = uvec3(drawCommands[batchID].fragmentMaterialID, drawCommands[batchID].packedFogAndCutout, p);
flw_layoutVertex();
flw_beginVertex();

View file

@ -20,5 +20,6 @@ struct MeshDrawCommand {
BoundingSphere boundingSphere;
uint vertexMaterialID;
uint fragmentMaterialID;
uint packedFogAndCutout;
uint packedMaterialProperties;
};

View file

@ -36,9 +36,8 @@ void flw_endFragment();
// INTERNAL
// -----------------------------------------
uint _flw_materialVertexID;
uint _flw_materialFragmentID;
uniform uvec3 _flw_material_instancing;
uint _flw_fogID;
uint _flw_cutoutID;
// -----------------------------------------

View file

@ -29,10 +29,7 @@ void flw_endVertex();
// ------------------------------------
uint _flw_materialVertexID;
uint _flw_materialFragmentID;
FlwInstance _flw_unpackInstance();
uniform uvec3 _flw_material_instancing;
// ------------------------------------

View file

@ -1,6 +1,5 @@
#include "flywheel:internal/instancing/api/fragment.glsl"
#include "flywheel:internal/material.glsl"
#include "flywheel:util/fog.glsl"
// optimize discard usage
#ifdef ALPHA_DISCARD
@ -13,13 +12,16 @@ uniform sampler2D flw_diffuseTex;
uniform sampler2D flw_overlayTex;
uniform sampler2D flw_lightTex;
uniform uvec4 _flw_material_instancing;
out vec4 fragColor;
void main() {
_flw_materialVertexID = _flw_material_instancing.x;
_flw_materialFragmentID = _flw_material_instancing.y;
_flw_fogID = _flw_material_instancing.z & 0xFFFFu;
_flw_cutoutID = _flw_material_instancing.z >> 16u;
_flw_unpackMaterial(_flw_material_instancing.z, flw_material);
_flw_unpackMaterial(_flw_material_instancing.w, flw_material);
flw_sampleColor = texture(flw_diffuseTex, flw_vertexTexCoord);
flw_fragColor = flw_vertexColor * flw_sampleColor;
@ -40,23 +42,9 @@ void main() {
color *= lightColor;
}
if (flw_material.cutout == FLW_CUTOUT_EPSILON && color.a < 0.01) {
if (flw_discardPredicate(color)) {
discard;
} else if (flw_material.cutout == FLW_CUTOUT_HALF && color.a < 0.5) {
discard;
} else if (flw_material.cutout == FLW_CUTOUT_CUSTOM) {
if (flw_discardPredicate(color)) {
discard;
}
}
if (flw_material.fog == FLW_FOG_LINEAR) {
color = linear_fog(color, flw_distance, flywheel.fogRange.x, flywheel.fogRange.y, flywheel.fogColor);
} else if (flw_material.fog == FLW_FOG_LINEAR_FADE) {
color = linear_fog_fade(color, flw_distance, flywheel.fogRange.x, flywheel.fogRange.y);
} else if (flw_material.fog == FLW_FOG_CUSTOM) {
color = flw_fogFilter(color);
}
fragColor = color;
fragColor = flw_fogFilter(color);
}

View file

@ -2,11 +2,12 @@
#include "flywheel:internal/material.glsl"
#include "flywheel:util/diffuse.glsl"
uniform uvec4 _flw_material_instancing;
void main() {
_flw_materialVertexID = _flw_material_instancing.x;
_flw_materialFragmentID = _flw_material_instancing.y;
_flw_unpackMaterial(_flw_material_instancing.z, flw_material);
_flw_unpackMaterial(_flw_material_instancing.w, flw_material);
FlwInstance i = _flw_unpackInstance();

View file

@ -1,7 +1,7 @@
#include "flywheel:api/material.glsl"
// Packed format:
// writeMask[2] | cutout[2] | transparency[3] | fog[2] | mip[1] | polygonOffset[1] | backfaceCull[1] | blur[1] | lighting[1] | diffuse[1]
// transparency[3] | writeMask[2] | mip[1] | polygonOffset[1] | backfaceCull[1] | blur[1] | lighting[1] | diffuse[1]
const uint DIFFUSE_MASK = 1u;
const uint LIGHTING_MASK = 1u << 1u;
@ -9,10 +9,9 @@ const uint BLUR_MASK = 1u << 2u;
const uint BACKFACE_CULL_MASK = 1u << 3u;
const uint POLYGON_OFFSET_MASK = 1u << 4u;
const uint MIP_MASK = 1u << 5u;
const uint FOG_MASK = 3u << 6u;
const uint WRITE_MASK_MASK = 3u << 6u;
const uint TRANSPARENCY_MASK = 7u << 8u;
const uint CUTOUT_MASK = 3u << 11u;
const uint WRITE_MASK_MASK = 3u << 13u;
void _flw_unpackMaterial(uint m, out FlwMaterial o) {
o.diffuse = (m & DIFFUSE_MASK) != 0u;
@ -21,8 +20,6 @@ void _flw_unpackMaterial(uint m, out FlwMaterial o) {
o.backfaceCull = (m & BACKFACE_CULL_MASK) != 0u;
o.polygonOffset = (m & POLYGON_OFFSET_MASK) != 0u;
o.mip = (m & MIP_MASK) != 0u;
o.fog = (m & FOG_MASK) >> 6;
o.writeMask = (m & WRITE_MASK_MASK) >> 6;
o.transparency = (m & TRANSPARENCY_MASK) >> 8;
o.cutout = (m & CUTOUT_MASK) >> 11;
o.writeMask = (m & WRITE_MASK_MASK) >> 13;
}

View file

@ -1,13 +1,4 @@
#include "flywheel:api/fragment.glsl"
#include "flywheel:util/fog.glsl"
void flw_materialFragment() {
}
bool flw_discardPredicate(vec4 finalColor) {
return false;
}
vec4 flw_fogFilter(vec4 color) {
return linear_fog(color, flw_distance, flywheel.fogRange.x, flywheel.fogRange.y, flywheel.fogColor);
}