mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-11-14 22:43:56 +01:00
Merge branch '1.20/dev' into feat/multi-loader-1.21
# Conflicts: # forge/src/main/java/dev/engine_room/flywheel/impl/ForgeFlwConfig.java
This commit is contained in:
commit
08866edf09
@ -1,8 +1,6 @@
|
||||
package dev.engine_room.flywheel.api.instance;
|
||||
|
||||
import dev.engine_room.flywheel.api.internal.FlwApiLink;
|
||||
import dev.engine_room.flywheel.api.layout.Layout;
|
||||
import dev.engine_room.flywheel.api.registry.Registry;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
/**
|
||||
@ -11,8 +9,6 @@ import net.minecraft.resources.ResourceLocation;
|
||||
* @param <I> The java representation of the instance.
|
||||
*/
|
||||
public interface InstanceType<I extends Instance> {
|
||||
Registry<InstanceType<?>> REGISTRY = FlwApiLink.INSTANCE.createRegistry();
|
||||
|
||||
/**
|
||||
* @param handle A handle that allows you to mark the instance as dirty or deleted.
|
||||
* @return A new, zeroed instance of I.
|
||||
|
@ -5,7 +5,6 @@ import org.jetbrains.annotations.Nullable;
|
||||
import dev.engine_room.flywheel.api.backend.Backend;
|
||||
import dev.engine_room.flywheel.api.layout.LayoutBuilder;
|
||||
import dev.engine_room.flywheel.api.registry.IdRegistry;
|
||||
import dev.engine_room.flywheel.api.registry.Registry;
|
||||
import dev.engine_room.flywheel.api.visualization.BlockEntityVisualizer;
|
||||
import dev.engine_room.flywheel.api.visualization.EntityVisualizer;
|
||||
import dev.engine_room.flywheel.api.visualization.VisualizationManager;
|
||||
@ -18,8 +17,6 @@ import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
public interface FlwApiLink {
|
||||
FlwApiLink INSTANCE = DependencyInjection.load(FlwApiLink.class, "dev.engine_room.flywheel.impl.FlwApiLinkImpl");
|
||||
|
||||
<T> Registry<T> createRegistry();
|
||||
|
||||
<T> IdRegistry<T> createIdRegistry();
|
||||
|
||||
Backend getCurrentBackend();
|
||||
|
@ -1,11 +1,7 @@
|
||||
package dev.engine_room.flywheel.api.material;
|
||||
|
||||
import dev.engine_room.flywheel.api.internal.FlwApiLink;
|
||||
import dev.engine_room.flywheel.api.registry.Registry;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public interface CutoutShader {
|
||||
Registry<CutoutShader> REGISTRY = FlwApiLink.INSTANCE.createRegistry();
|
||||
|
||||
ResourceLocation source();
|
||||
}
|
||||
|
@ -1,11 +1,7 @@
|
||||
package dev.engine_room.flywheel.api.material;
|
||||
|
||||
import dev.engine_room.flywheel.api.internal.FlwApiLink;
|
||||
import dev.engine_room.flywheel.api.registry.Registry;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public interface FogShader {
|
||||
Registry<FogShader> REGISTRY = FlwApiLink.INSTANCE.createRegistry();
|
||||
|
||||
ResourceLocation source();
|
||||
}
|
||||
|
@ -1,11 +1,7 @@
|
||||
package dev.engine_room.flywheel.api.material;
|
||||
|
||||
import dev.engine_room.flywheel.api.internal.FlwApiLink;
|
||||
import dev.engine_room.flywheel.api.registry.Registry;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public interface LightShader {
|
||||
Registry<LightShader> REGISTRY = FlwApiLink.INSTANCE.createRegistry();
|
||||
|
||||
ResourceLocation source();
|
||||
}
|
||||
|
@ -1,12 +1,8 @@
|
||||
package dev.engine_room.flywheel.api.material;
|
||||
|
||||
import dev.engine_room.flywheel.api.internal.FlwApiLink;
|
||||
import dev.engine_room.flywheel.api.registry.Registry;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public interface MaterialShaders {
|
||||
Registry<MaterialShaders> REGISTRY = FlwApiLink.INSTANCE.createRegistry();
|
||||
|
||||
ResourceLocation vertexSource();
|
||||
|
||||
ResourceLocation fragmentSource();
|
||||
|
@ -1,18 +0,0 @@
|
||||
package dev.engine_room.flywheel.api.registry;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.UnmodifiableView;
|
||||
|
||||
@ApiStatus.NonExtendable
|
||||
public interface Registry<T> extends Iterable<T> {
|
||||
void register(T object);
|
||||
|
||||
<S extends T> S registerAndGet(S object);
|
||||
|
||||
@UnmodifiableView
|
||||
Set<T> getAll();
|
||||
|
||||
boolean isFrozen();
|
||||
}
|
@ -11,4 +11,6 @@ public interface BackendConfig {
|
||||
* @return The current light smoothness setting.
|
||||
*/
|
||||
LightSmoothness lightSmoothness();
|
||||
|
||||
boolean useLightDirections();
|
||||
}
|
||||
|
@ -1,15 +1,12 @@
|
||||
package dev.engine_room.flywheel.backend;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.Unmodifiable;
|
||||
|
||||
import dev.engine_room.flywheel.api.material.CutoutShader;
|
||||
import dev.engine_room.flywheel.api.material.FogShader;
|
||||
import dev.engine_room.flywheel.api.material.MaterialShaders;
|
||||
import dev.engine_room.flywheel.api.registry.Registry;
|
||||
import dev.engine_room.flywheel.backend.compile.PipelineCompiler;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
@ -17,54 +14,20 @@ import it.unimi.dsi.fastutil.objects.ObjectList;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public final class MaterialShaderIndices {
|
||||
@Nullable
|
||||
private static Index vertexSources;
|
||||
@Nullable
|
||||
private static Index fragmentSources;
|
||||
@Nullable
|
||||
private static Index fogSources;
|
||||
@Nullable
|
||||
private static Index cutoutSources;
|
||||
private static final Index fogSources = new Index();
|
||||
private static final Index cutoutSources = new Index();
|
||||
|
||||
private MaterialShaderIndices() {
|
||||
}
|
||||
|
||||
public static Index vertexSources() {
|
||||
if (vertexSources == null) {
|
||||
vertexSources = indexFromRegistry(MaterialShaders.REGISTRY, MaterialShaders::vertexSource);
|
||||
}
|
||||
return vertexSources;
|
||||
}
|
||||
|
||||
public static Index fragmentSources() {
|
||||
if (fragmentSources == null) {
|
||||
fragmentSources = indexFromRegistry(MaterialShaders.REGISTRY, MaterialShaders::fragmentSource);
|
||||
}
|
||||
return fragmentSources;
|
||||
}
|
||||
|
||||
public static Index fogSources() {
|
||||
if (fogSources == null) {
|
||||
fogSources = indexFromRegistry(FogShader.REGISTRY, FogShader::source);
|
||||
}
|
||||
return fogSources;
|
||||
}
|
||||
|
||||
public static Index cutoutSources() {
|
||||
if (cutoutSources == null) {
|
||||
cutoutSources = indexFromRegistry(CutoutShader.REGISTRY, CutoutShader::source);
|
||||
}
|
||||
return cutoutSources;
|
||||
}
|
||||
|
||||
public static int vertexIndex(MaterialShaders shaders) {
|
||||
return vertexSources().index(shaders.vertexSource());
|
||||
}
|
||||
|
||||
public static int fragmentIndex(MaterialShaders shaders) {
|
||||
return fragmentSources().index(shaders.fragmentSource());
|
||||
}
|
||||
|
||||
public static int fogIndex(FogShader fogShader) {
|
||||
return fogSources().index(fogShader.source());
|
||||
}
|
||||
@ -73,63 +36,41 @@ public final class MaterialShaderIndices {
|
||||
return cutoutSources().index(cutoutShader.source());
|
||||
}
|
||||
|
||||
private static <T> Index indexFromRegistry(Registry<T> registry, Function<T, ResourceLocation> sourceFunc) {
|
||||
if (!registry.isFrozen()) {
|
||||
throw new IllegalStateException("Cannot create index from registry that is not frozen!");
|
||||
}
|
||||
|
||||
var builder = new IndexBuilder();
|
||||
|
||||
for (T object : registry) {
|
||||
builder.add(sourceFunc.apply(object));
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public static class Index {
|
||||
private final Object2IntMap<ResourceLocation> sources2Index;
|
||||
private final ObjectList<ResourceLocation> sources;
|
||||
|
||||
private Index(IndexBuilder builder) {
|
||||
this.sources2Index = new Object2IntOpenHashMap<>(builder.sources2Index);
|
||||
this.sources = new ObjectArrayList<>(builder.sources);
|
||||
}
|
||||
|
||||
public int index(ResourceLocation source) {
|
||||
return sources2Index.getInt(source);
|
||||
private Index() {
|
||||
this.sources2Index = new Object2IntOpenHashMap<>();
|
||||
sources2Index.defaultReturnValue(-1);
|
||||
this.sources = new ObjectArrayList<>();
|
||||
}
|
||||
|
||||
public ResourceLocation get(int index) {
|
||||
return sources.get(index);
|
||||
}
|
||||
|
||||
public int index(ResourceLocation source) {
|
||||
var out = sources2Index.getInt(source);
|
||||
|
||||
if (out == -1) {
|
||||
add(source);
|
||||
PipelineCompiler.deleteAll();
|
||||
return sources2Index.getInt(source);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@Unmodifiable
|
||||
public List<ResourceLocation> all() {
|
||||
return sources;
|
||||
}
|
||||
}
|
||||
|
||||
private static class IndexBuilder {
|
||||
private final Object2IntMap<ResourceLocation> sources2Index;
|
||||
private final ObjectList<ResourceLocation> sources;
|
||||
private int index = 0;
|
||||
|
||||
public IndexBuilder() {
|
||||
sources2Index = new Object2IntOpenHashMap<>();
|
||||
sources2Index.defaultReturnValue(-1);
|
||||
sources = new ObjectArrayList<>();
|
||||
}
|
||||
|
||||
public void add(ResourceLocation source) {
|
||||
if (sources2Index.putIfAbsent(source, index) == -1) {
|
||||
private void add(ResourceLocation source) {
|
||||
if (sources2Index.putIfAbsent(source, sources.size()) == -1) {
|
||||
sources.add(source);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
public Index build() {
|
||||
return new Index(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,28 +2,22 @@ package dev.engine_room.flywheel.backend.compile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import dev.engine_room.flywheel.api.Flywheel;
|
||||
import dev.engine_room.flywheel.backend.MaterialShaderIndices;
|
||||
import dev.engine_room.flywheel.backend.compile.component.UberShaderComponent;
|
||||
import dev.engine_room.flywheel.backend.compile.core.CompilerStats;
|
||||
import dev.engine_room.flywheel.backend.compile.core.SourceLoader;
|
||||
import dev.engine_room.flywheel.backend.glsl.ShaderSources;
|
||||
import dev.engine_room.flywheel.backend.glsl.SourceComponent;
|
||||
import dev.engine_room.flywheel.backend.glsl.generate.FnSignature;
|
||||
import dev.engine_room.flywheel.backend.glsl.generate.GlslExpr;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.packs.resources.ResourceManager;
|
||||
|
||||
public final class FlwPrograms {
|
||||
public static final Logger LOGGER = LoggerFactory.getLogger(Flywheel.ID + "/backend/shaders");
|
||||
|
||||
private static final ResourceLocation COMPONENTS_HEADER_VERT = Flywheel.rl("internal/components_header.vert");
|
||||
private static final ResourceLocation COMPONENTS_HEADER_FRAG = Flywheel.rl("internal/components_header.frag");
|
||||
|
||||
public static ShaderSources SOURCES;
|
||||
|
||||
private FlwPrograms() {
|
||||
}
|
||||
|
||||
@ -33,53 +27,14 @@ public final class FlwPrograms {
|
||||
IndirectPrograms.setInstance(null);
|
||||
|
||||
var sources = new ShaderSources(resourceManager);
|
||||
var stats = new CompilerStats("ubershaders");
|
||||
var loader = new SourceLoader(sources, stats);
|
||||
SOURCES = sources;
|
||||
|
||||
var vertexComponentsHeader = loader.find(COMPONENTS_HEADER_VERT);
|
||||
var fragmentComponentsHeader = loader.find(COMPONENTS_HEADER_FRAG);
|
||||
var fragmentComponentsHeader = sources.get(COMPONENTS_HEADER_FRAG);
|
||||
|
||||
var fogComponent = createFogComponent(loader);
|
||||
|
||||
// TODO: separate compilation for cutout OFF, but keep the rest uber'd?
|
||||
if (stats.errored() || vertexComponentsHeader == null || fragmentComponentsHeader == null || fogComponent == null) {
|
||||
// Probably means the shader sources are missing.
|
||||
stats.emitErrorLog();
|
||||
return;
|
||||
}
|
||||
|
||||
List<SourceComponent> vertexComponents = List.of(vertexComponentsHeader);
|
||||
List<SourceComponent> fragmentComponents = List.of(fragmentComponentsHeader, fogComponent);
|
||||
List<SourceComponent> vertexComponents = List.of();
|
||||
List<SourceComponent> fragmentComponents = List.of(fragmentComponentsHeader);
|
||||
|
||||
InstancingPrograms.reload(sources, vertexComponents, fragmentComponents);
|
||||
IndirectPrograms.reload(sources, vertexComponents, fragmentComponents);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static UberShaderComponent createFogComponent(SourceLoader loader) {
|
||||
return UberShaderComponent.builder(Flywheel.rl("fog"))
|
||||
.materialSources(MaterialShaderIndices.fogSources()
|
||||
.all())
|
||||
.adapt(FnSignature.create()
|
||||
.returnType("vec4")
|
||||
.name("flw_fogFilter")
|
||||
.arg("vec4", "color")
|
||||
.build(), GlslExpr.variable("color"))
|
||||
.switchOn(GlslExpr.variable("_flw_uberFogIndex"))
|
||||
.build(loader);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static UberShaderComponent createCutoutComponent(SourceLoader loader) {
|
||||
return UberShaderComponent.builder(Flywheel.rl("cutout"))
|
||||
.materialSources(MaterialShaderIndices.cutoutSources()
|
||||
.all())
|
||||
.adapt(FnSignature.create()
|
||||
.returnType("bool")
|
||||
.name("flw_discardPredicate")
|
||||
.arg("vec4", "color")
|
||||
.build(), GlslExpr.boolLiteral(false))
|
||||
.switchOn(GlslExpr.variable("_flw_uberCutoutIndex"))
|
||||
.build(loader);
|
||||
}
|
||||
}
|
||||
|
@ -8,9 +8,7 @@ import com.google.common.collect.ImmutableList;
|
||||
|
||||
import dev.engine_room.flywheel.api.Flywheel;
|
||||
import dev.engine_room.flywheel.api.instance.InstanceType;
|
||||
import dev.engine_room.flywheel.api.material.CutoutShader;
|
||||
import dev.engine_room.flywheel.api.material.LightShader;
|
||||
import dev.engine_room.flywheel.api.material.MaterialShaders;
|
||||
import dev.engine_room.flywheel.api.material.Material;
|
||||
import dev.engine_room.flywheel.backend.compile.component.InstanceStructComponent;
|
||||
import dev.engine_room.flywheel.backend.compile.component.SsboInstanceComponent;
|
||||
import dev.engine_room.flywheel.backend.compile.core.CompilationHarness;
|
||||
@ -44,11 +42,11 @@ public class IndirectPrograms extends AtomicReferenceCounted {
|
||||
@Nullable
|
||||
private static IndirectPrograms instance;
|
||||
|
||||
private final CompilationHarness<PipelineProgramKey> pipeline;
|
||||
private final PipelineCompiler pipeline;
|
||||
private final CompilationHarness<InstanceType<?>> culling;
|
||||
private final CompilationHarness<ResourceLocation> utils;
|
||||
|
||||
private IndirectPrograms(CompilationHarness<PipelineProgramKey> pipeline, CompilationHarness<InstanceType<?>> culling, CompilationHarness<ResourceLocation> utils) {
|
||||
private IndirectPrograms(PipelineCompiler pipeline, CompilationHarness<InstanceType<?>> culling, CompilationHarness<ResourceLocation> utils) {
|
||||
this.pipeline = pipeline;
|
||||
this.culling = culling;
|
||||
this.utils = utils;
|
||||
@ -150,8 +148,8 @@ public class IndirectPrograms extends AtomicReferenceCounted {
|
||||
setInstance(null);
|
||||
}
|
||||
|
||||
public GlProgram getIndirectProgram(InstanceType<?> instanceType, ContextShader contextShader, LightShader light, CutoutShader cutout, MaterialShaders shaders) {
|
||||
return pipeline.get(new PipelineProgramKey(instanceType, contextShader, light, cutout, shaders));
|
||||
public GlProgram getIndirectProgram(InstanceType<?> instanceType, ContextShader contextShader, Material material) {
|
||||
return pipeline.get(instanceType, contextShader, material);
|
||||
}
|
||||
|
||||
public GlProgram getCullingProgram(InstanceType<?> instanceType) {
|
||||
|
@ -7,10 +7,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import dev.engine_room.flywheel.api.instance.InstanceType;
|
||||
import dev.engine_room.flywheel.api.material.CutoutShader;
|
||||
import dev.engine_room.flywheel.api.material.LightShader;
|
||||
import dev.engine_room.flywheel.api.material.MaterialShaders;
|
||||
import dev.engine_room.flywheel.backend.compile.core.CompilationHarness;
|
||||
import dev.engine_room.flywheel.api.material.Material;
|
||||
import dev.engine_room.flywheel.backend.gl.GlCompat;
|
||||
import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
|
||||
import dev.engine_room.flywheel.backend.glsl.GlslVersion;
|
||||
@ -24,9 +21,9 @@ public class InstancingPrograms extends AtomicReferenceCounted {
|
||||
@Nullable
|
||||
private static InstancingPrograms instance;
|
||||
|
||||
private final CompilationHarness<PipelineProgramKey> pipeline;
|
||||
private final PipelineCompiler pipeline;
|
||||
|
||||
private InstancingPrograms(CompilationHarness<PipelineProgramKey> pipeline) {
|
||||
private InstancingPrograms(PipelineCompiler pipeline) {
|
||||
this.pipeline = pipeline;
|
||||
}
|
||||
|
||||
@ -43,7 +40,6 @@ public class InstancingPrograms extends AtomicReferenceCounted {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var pipelineCompiler = PipelineCompiler.create(sources, Pipelines.INSTANCING, vertexComponents, fragmentComponents, EXTENSIONS);
|
||||
InstancingPrograms newInstance = new InstancingPrograms(pipelineCompiler);
|
||||
|
||||
@ -73,8 +69,8 @@ public class InstancingPrograms extends AtomicReferenceCounted {
|
||||
setInstance(null);
|
||||
}
|
||||
|
||||
public GlProgram get(InstanceType<?> instanceType, ContextShader contextShader, LightShader light, CutoutShader cutout, MaterialShaders materialShaders) {
|
||||
return pipeline.get(new PipelineProgramKey(instanceType, contextShader, light, cutout, materialShaders));
|
||||
public GlProgram get(InstanceType<?> instanceType, ContextShader contextShader, Material material) {
|
||||
return pipeline.get(instanceType, contextShader, material);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -4,32 +4,84 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import dev.engine_room.flywheel.api.Flywheel;
|
||||
import dev.engine_room.flywheel.api.instance.InstanceType;
|
||||
import dev.engine_room.flywheel.api.material.LightShader;
|
||||
import dev.engine_room.flywheel.api.material.Material;
|
||||
import dev.engine_room.flywheel.api.material.MaterialShaders;
|
||||
import dev.engine_room.flywheel.backend.BackendConfig;
|
||||
import dev.engine_room.flywheel.backend.InternalVertex;
|
||||
import dev.engine_room.flywheel.backend.MaterialShaderIndices;
|
||||
import dev.engine_room.flywheel.backend.Samplers;
|
||||
import dev.engine_room.flywheel.backend.compile.component.InstanceStructComponent;
|
||||
import dev.engine_room.flywheel.backend.compile.component.UberShaderComponent;
|
||||
import dev.engine_room.flywheel.backend.compile.core.CompilationHarness;
|
||||
import dev.engine_room.flywheel.backend.compile.core.Compile;
|
||||
import dev.engine_room.flywheel.backend.engine.uniform.FrameUniforms;
|
||||
import dev.engine_room.flywheel.backend.engine.uniform.Uniforms;
|
||||
import dev.engine_room.flywheel.backend.gl.GlCompat;
|
||||
import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
|
||||
import dev.engine_room.flywheel.backend.gl.shader.ShaderType;
|
||||
import dev.engine_room.flywheel.backend.glsl.ShaderSources;
|
||||
import dev.engine_room.flywheel.backend.glsl.SourceComponent;
|
||||
import dev.engine_room.flywheel.backend.glsl.generate.FnSignature;
|
||||
import dev.engine_room.flywheel.backend.glsl.generate.GlslExpr;
|
||||
import dev.engine_room.flywheel.lib.material.CutoutShaders;
|
||||
import dev.engine_room.flywheel.lib.util.ResourceUtil;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public final class PipelineCompiler {
|
||||
private static final List<PipelineCompiler> ALL = List.of();
|
||||
|
||||
private static final Compile<PipelineProgramKey> PIPELINE = new Compile<>();
|
||||
|
||||
private static UberShaderComponent FOG;
|
||||
private static UberShaderComponent CUTOUT;
|
||||
|
||||
private static final ResourceLocation API_IMPL_VERT = Flywheel.rl("internal/api_impl.vert");
|
||||
private static final ResourceLocation API_IMPL_FRAG = Flywheel.rl("internal/api_impl.frag");
|
||||
|
||||
static CompilationHarness<PipelineProgramKey> create(ShaderSources sources, Pipeline pipeline, List<SourceComponent> vertexComponents, List<SourceComponent> fragmentComponents, Collection<String> extensions) {
|
||||
private final CompilationHarness<PipelineProgramKey> harness;
|
||||
|
||||
public PipelineCompiler(CompilationHarness<PipelineProgramKey> harness) {
|
||||
this.harness = harness;
|
||||
}
|
||||
|
||||
public GlProgram get(InstanceType<?> instanceType, ContextShader contextShader, Material material) {
|
||||
var light = material.light();
|
||||
var cutout = material.cutout();
|
||||
var shaders = material.shaders();
|
||||
var fog = material.fog();
|
||||
|
||||
// Tell fogSources to index the fog shader if we haven't seen it before.
|
||||
// If it is new, this will trigger a deletion of all programs.
|
||||
MaterialShaderIndices.fogSources()
|
||||
.index(fog.source());
|
||||
|
||||
boolean useCutout = cutout != CutoutShaders.OFF;
|
||||
|
||||
if (useCutout) {
|
||||
// Same thing for cutout.
|
||||
MaterialShaderIndices.cutoutSources()
|
||||
.index(cutout.source());
|
||||
}
|
||||
|
||||
return harness.get(new PipelineProgramKey(instanceType, contextShader, light, shaders, useCutout, FrameUniforms.debugOn()));
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
harness.delete();
|
||||
}
|
||||
|
||||
public static void deleteAll() {
|
||||
createFogComponent();
|
||||
createCutoutComponent();
|
||||
ALL.forEach(PipelineCompiler::delete);
|
||||
}
|
||||
|
||||
static PipelineCompiler create(ShaderSources sources, Pipeline pipeline, List<SourceComponent> vertexComponents, List<SourceComponent> fragmentComponents, Collection<String> extensions) {
|
||||
// We could technically compile every version of light smoothness ahead of time,
|
||||
// but that seems unnecessary as I doubt most folks will be changing this option often.
|
||||
var lightSmoothness = BackendConfig.INSTANCE.lightSmoothness();
|
||||
return PIPELINE.program()
|
||||
var harness = PIPELINE.program()
|
||||
.link(PIPELINE.shader(GlCompat.MAX_GLSL_VERSION, ShaderType.VERTEX)
|
||||
.nameMapper(key -> {
|
||||
var instance = ResourceUtil.toDebugFileNameNoExtension(key.instanceType()
|
||||
@ -39,12 +91,19 @@ public final class PipelineCompiler {
|
||||
.vertexSource());
|
||||
var context = key.contextShader()
|
||||
.nameLowerCase();
|
||||
return "pipeline/" + pipeline.compilerMarker() + "/" + instance + "/" + material + "_" + context;
|
||||
var debug = key.debugEnabled() ? "_debug" : "";
|
||||
return "pipeline/" + pipeline.compilerMarker() + "/" + instance + "/" + material + "_" + context + debug;
|
||||
})
|
||||
.requireExtensions(extensions)
|
||||
.onCompile((key, comp) -> key.contextShader()
|
||||
.onCompile(comp))
|
||||
.onCompile((key, comp) -> lightSmoothness.onCompile(comp))
|
||||
.onCompile((key, comp) -> BackendConfig.INSTANCE.lightSmoothness()
|
||||
.onCompile(comp))
|
||||
.onCompile((key, comp) -> {
|
||||
if (key.debugEnabled()) {
|
||||
comp.define("_FLW_DEBUG");
|
||||
}
|
||||
})
|
||||
.withResource(API_IMPL_VERT)
|
||||
.withComponent(key -> new InstanceStructComponent(key.instanceType()))
|
||||
.withResource(key -> key.instanceType()
|
||||
@ -64,26 +123,36 @@ public final class PipelineCompiler {
|
||||
var material = ResourceUtil.toDebugFileNameNoExtension(key.materialShaders()
|
||||
.fragmentSource());
|
||||
|
||||
var cutout = ResourceUtil.toDebugFileNameNoExtension(key.cutout()
|
||||
.source());
|
||||
|
||||
var light = ResourceUtil.toDebugFileNameNoExtension(key.light()
|
||||
.source());
|
||||
return "pipeline/" + pipeline.compilerMarker() + "/frag/" + material + "/" + light + "_" + cutout + "_" + context;
|
||||
var debug = key.debugEnabled() ? "_debug" : "";
|
||||
var cutout = key.useCutout() ? "_cutout" : "";
|
||||
return "pipeline/" + pipeline.compilerMarker() + "/frag/" + material + "/" + light + "_" + context + cutout + debug;
|
||||
})
|
||||
.requireExtensions(extensions)
|
||||
.enableExtension("GL_ARB_conservative_depth")
|
||||
.onCompile((key, comp) -> key.contextShader()
|
||||
.onCompile(comp))
|
||||
.onCompile((key, comp) -> lightSmoothness.onCompile(comp))
|
||||
.onCompile((key, comp) -> BackendConfig.INSTANCE.lightSmoothness()
|
||||
.onCompile(comp))
|
||||
.onCompile((key, comp) -> {
|
||||
if (key.debugEnabled()) {
|
||||
comp.define("_FLW_DEBUG");
|
||||
}
|
||||
})
|
||||
.onCompile((key, comp) -> {
|
||||
if (key.useCutout()) {
|
||||
comp.define("_FLW_USE_DISCARD");
|
||||
}
|
||||
})
|
||||
.withResource(API_IMPL_FRAG)
|
||||
.withResource(key -> key.materialShaders()
|
||||
.fragmentSource())
|
||||
.withComponents(fragmentComponents)
|
||||
.withComponent(key -> FOG)
|
||||
.withResource(key -> key.light()
|
||||
.source())
|
||||
.withResource(key -> key.cutout()
|
||||
.source())
|
||||
.with((key, fetcher) -> (key.useCutout() ? CUTOUT : fetcher.get(CutoutShaders.OFF.source())))
|
||||
.withResource(pipeline.fragmentMain()))
|
||||
.preLink((key, program) -> {
|
||||
program.bindAttribLocation("_flw_aPos", 0);
|
||||
@ -109,5 +178,44 @@ public final class PipelineCompiler {
|
||||
GlProgram.unbind();
|
||||
})
|
||||
.harness(pipeline.compilerMarker(), sources);
|
||||
|
||||
return new PipelineCompiler(harness);
|
||||
}
|
||||
|
||||
public static void createFogComponent() {
|
||||
FOG = UberShaderComponent.builder(Flywheel.rl("fog"))
|
||||
.materialSources(MaterialShaderIndices.fogSources()
|
||||
.all())
|
||||
.adapt(FnSignature.create()
|
||||
.returnType("vec4")
|
||||
.name("flw_fogFilter")
|
||||
.arg("vec4", "color")
|
||||
.build(), GlslExpr.variable("color"))
|
||||
.switchOn(GlslExpr.variable("_flw_uberFogIndex"))
|
||||
.build(FlwPrograms.SOURCES);
|
||||
}
|
||||
|
||||
private static void createCutoutComponent() {
|
||||
CUTOUT = UberShaderComponent.builder(Flywheel.rl("cutout"))
|
||||
.materialSources(MaterialShaderIndices.cutoutSources()
|
||||
.all())
|
||||
.adapt(FnSignature.create()
|
||||
.returnType("bool")
|
||||
.name("flw_discardPredicate")
|
||||
.arg("vec4", "color")
|
||||
.build(), GlslExpr.boolLiteral(false))
|
||||
.switchOn(GlslExpr.variable("_flw_uberCutoutIndex"))
|
||||
.build(FlwPrograms.SOURCES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the entire context of a program's usage.
|
||||
*
|
||||
* @param instanceType The instance shader to use.
|
||||
* @param contextShader The context shader to use.
|
||||
* @param light The light shader to use.
|
||||
*/
|
||||
public record PipelineProgramKey(InstanceType<?> instanceType, ContextShader contextShader, LightShader light,
|
||||
MaterialShaders materialShaders, boolean useCutout, boolean debugEnabled) {
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
package dev.engine_room.flywheel.backend.compile;
|
||||
|
||||
import dev.engine_room.flywheel.api.instance.InstanceType;
|
||||
import dev.engine_room.flywheel.api.material.CutoutShader;
|
||||
import dev.engine_room.flywheel.api.material.LightShader;
|
||||
import dev.engine_room.flywheel.api.material.MaterialShaders;
|
||||
|
||||
/**
|
||||
* Represents the entire context of a program's usage.
|
||||
*
|
||||
* @param instanceType The instance shader to use.
|
||||
* @param contextShader The context shader to use.
|
||||
* @param light The light shader to use.
|
||||
*/
|
||||
public record PipelineProgramKey(InstanceType<?> instanceType, ContextShader contextShader, LightShader light,
|
||||
CutoutShader cutout, MaterialShaders materialShaders) {
|
||||
}
|
@ -11,7 +11,7 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import dev.engine_room.flywheel.api.Flywheel;
|
||||
import dev.engine_room.flywheel.backend.compile.core.SourceLoader;
|
||||
import dev.engine_room.flywheel.backend.glsl.ShaderSources;
|
||||
import dev.engine_room.flywheel.backend.glsl.SourceComponent;
|
||||
import dev.engine_room.flywheel.backend.glsl.SourceFile;
|
||||
import dev.engine_room.flywheel.backend.glsl.generate.FnSignature;
|
||||
@ -136,32 +136,22 @@ public class UberShaderComponent implements SourceComponent {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public UberShaderComponent build(SourceLoader sources) {
|
||||
public UberShaderComponent build(ShaderSources sources) {
|
||||
if (switchArg == null) {
|
||||
throw new NullPointerException("Switch argument must be set");
|
||||
}
|
||||
|
||||
var transformed = ImmutableList.<StringSubstitutionComponent>builder();
|
||||
|
||||
boolean errored = false;
|
||||
int index = 0;
|
||||
for (var rl : materialSources) {
|
||||
SourceFile sourceFile = sources.find(rl);
|
||||
if (sourceFile != null) {
|
||||
final int finalIndex = index;
|
||||
var adapterMap = createAdapterMap(adaptedFunctions, fnName -> "_" + fnName + "_" + finalIndex);
|
||||
transformed.add(new StringSubstitutionComponent(sourceFile, adapterMap));
|
||||
} else {
|
||||
errored = true;
|
||||
}
|
||||
SourceFile sourceFile = sources.get(rl);
|
||||
final int finalIndex = index;
|
||||
var adapterMap = createAdapterMap(adaptedFunctions, fnName -> "_" + fnName + "_" + finalIndex);
|
||||
transformed.add(new StringSubstitutionComponent(sourceFile, adapterMap));
|
||||
index++;
|
||||
}
|
||||
|
||||
if (errored) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new UberShaderComponent(name, switchArg, adaptedFunctions, transformed.build());
|
||||
}
|
||||
|
||||
|
@ -3,26 +3,23 @@ package dev.engine_room.flywheel.backend.compile.core;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import dev.engine_room.flywheel.backend.gl.GlObject;
|
||||
import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
|
||||
import dev.engine_room.flywheel.backend.glsl.ShaderSources;
|
||||
|
||||
public class CompilationHarness<K> {
|
||||
private final ShaderSources sources;
|
||||
private final KeyCompiler<K> compiler;
|
||||
private final SourceLoader sourceLoader;
|
||||
private final ShaderCache shaderCache;
|
||||
private final ProgramLinker programLinker;
|
||||
private final CompilerStats stats;
|
||||
|
||||
private final Map<K, GlProgram> programs = new HashMap<>();
|
||||
|
||||
public CompilationHarness(String marker, ShaderSources sources, KeyCompiler<K> compiler) {
|
||||
this.sources = sources;
|
||||
this.compiler = compiler;
|
||||
stats = new CompilerStats(marker);
|
||||
sourceLoader = new SourceLoader(sources, stats);
|
||||
shaderCache = new ShaderCache(stats);
|
||||
programLinker = new ProgramLinker(stats);
|
||||
shaderCache = new ShaderCache();
|
||||
programLinker = new ProgramLinker();
|
||||
}
|
||||
|
||||
public GlProgram get(K key) {
|
||||
@ -30,25 +27,19 @@ public class CompilationHarness<K> {
|
||||
}
|
||||
|
||||
private GlProgram compile(K key) {
|
||||
var out = compiler.compile(key, sourceLoader, shaderCache, programLinker);
|
||||
|
||||
if (out == null) {
|
||||
// TODO: populate exception with error details
|
||||
throw new ShaderException();
|
||||
}
|
||||
|
||||
return out;
|
||||
return compiler.compile(key, sources, shaderCache, programLinker);
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
shaderCache.delete();
|
||||
|
||||
for (var program : programs.values()) {
|
||||
program.delete();
|
||||
}
|
||||
programs.values()
|
||||
.forEach(GlObject::delete);
|
||||
|
||||
programs.clear();
|
||||
}
|
||||
|
||||
public interface KeyCompiler<K> {
|
||||
@Nullable GlProgram compile(K key, SourceLoader loader, ShaderCache shaderCache, ProgramLinker programLinker);
|
||||
GlProgram compile(K key, ShaderSources loader, ShaderCache shaderCache, ProgramLinker programLinker);
|
||||
}
|
||||
}
|
||||
|
@ -10,8 +10,6 @@ import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import dev.engine_room.flywheel.backend.compile.FlwPrograms;
|
||||
import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
|
||||
import dev.engine_room.flywheel.backend.gl.shader.GlShader;
|
||||
@ -44,7 +42,7 @@ public class Compile<K> {
|
||||
public static class ShaderCompiler<K> {
|
||||
private final GlslVersion glslVersion;
|
||||
private final ShaderType shaderType;
|
||||
private final List<BiFunction<K, SourceLoader, @Nullable SourceComponent>> fetchers = new ArrayList<>();
|
||||
private final List<BiFunction<K, ShaderSources, SourceComponent>> fetchers = new ArrayList<>();
|
||||
private BiConsumer<K, Compilation> compilationCallbacks = ($, $$) -> {
|
||||
};
|
||||
private Function<K, String> nameMapper = Object::toString;
|
||||
@ -59,26 +57,26 @@ public class Compile<K> {
|
||||
return this;
|
||||
}
|
||||
|
||||
public ShaderCompiler<K> with(BiFunction<K, SourceLoader, @Nullable SourceComponent> fetch) {
|
||||
public ShaderCompiler<K> with(BiFunction<K, ShaderSources, SourceComponent> fetch) {
|
||||
fetchers.add(fetch);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ShaderCompiler<K> withComponents(Collection<@Nullable SourceComponent> components) {
|
||||
public ShaderCompiler<K> withComponents(Collection<SourceComponent> components) {
|
||||
components.forEach(this::withComponent);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ShaderCompiler<K> withComponent(@Nullable SourceComponent component) {
|
||||
public ShaderCompiler<K> withComponent(SourceComponent component) {
|
||||
return withComponent($ -> component);
|
||||
}
|
||||
|
||||
public ShaderCompiler<K> withComponent(Function<K, @Nullable SourceComponent> sourceFetcher) {
|
||||
public ShaderCompiler<K> withComponent(Function<K, SourceComponent> sourceFetcher) {
|
||||
return with((key, $) -> sourceFetcher.apply(key));
|
||||
}
|
||||
|
||||
public ShaderCompiler<K> withResource(Function<K, ResourceLocation> sourceFetcher) {
|
||||
return with((key, loader) -> loader.find(sourceFetcher.apply(key)));
|
||||
return with((key, loader) -> loader.get(sourceFetcher.apply(key)));
|
||||
}
|
||||
|
||||
public ShaderCompiler<K> withResource(ResourceLocation resourceLocation) {
|
||||
@ -122,22 +120,12 @@ public class Compile<K> {
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private GlShader compile(K key, ShaderCache compiler, SourceLoader loader) {
|
||||
private GlShader compile(K key, ShaderCache compiler, ShaderSources loader) {
|
||||
long start = System.nanoTime();
|
||||
|
||||
var components = new ArrayList<SourceComponent>();
|
||||
boolean ok = true;
|
||||
for (var fetcher : fetchers) {
|
||||
SourceComponent apply = fetcher.apply(key, loader);
|
||||
if (apply == null) {
|
||||
ok = false;
|
||||
}
|
||||
components.add(apply);
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
return null;
|
||||
components.add(fetcher.apply(key, loader));
|
||||
}
|
||||
|
||||
Consumer<Compilation> cb = ctx -> compilationCallbacks.accept(key, ctx);
|
||||
@ -182,8 +170,7 @@ public class Compile<K> {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public GlProgram compile(K key, SourceLoader loader, ShaderCache shaderCache, ProgramLinker programLinker) {
|
||||
public GlProgram compile(K key, ShaderSources loader, ShaderCache shaderCache, ProgramLinker programLinker) {
|
||||
if (compilers.isEmpty()) {
|
||||
throw new IllegalStateException("No shader compilers were added!");
|
||||
}
|
||||
@ -192,24 +179,13 @@ public class Compile<K> {
|
||||
|
||||
List<GlShader> shaders = new ArrayList<>();
|
||||
|
||||
boolean ok = true;
|
||||
for (ShaderCompiler<K> compiler : compilers.values()) {
|
||||
var shader = compiler.compile(key, shaderCache, loader);
|
||||
if (shader == null) {
|
||||
ok = false;
|
||||
}
|
||||
shaders.add(shader);
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
return null;
|
||||
shaders.add(compiler.compile(key, shaderCache, loader));
|
||||
}
|
||||
|
||||
var out = programLinker.link(shaders, p -> preLink.accept(key, p));
|
||||
|
||||
if (out != null) {
|
||||
postLink.accept(key, out);
|
||||
}
|
||||
postLink.accept(key, out);
|
||||
|
||||
long end = System.nanoTime();
|
||||
|
||||
|
@ -1,106 +0,0 @@
|
||||
package dev.engine_room.flywheel.backend.compile.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Marker;
|
||||
import org.slf4j.MarkerFactory;
|
||||
|
||||
import dev.engine_room.flywheel.backend.compile.FlwPrograms;
|
||||
import dev.engine_room.flywheel.backend.glsl.LoadError;
|
||||
import dev.engine_room.flywheel.backend.glsl.LoadResult;
|
||||
import dev.engine_room.flywheel.backend.glsl.error.ErrorBuilder;
|
||||
import dev.engine_room.flywheel.lib.util.StringUtil;
|
||||
|
||||
public class CompilerStats {
|
||||
private final Marker marker;
|
||||
private long compileStart;
|
||||
|
||||
private final Set<LoadError> loadErrors = new HashSet<>();
|
||||
private final List<FailedCompilation> shaderErrors = new ArrayList<>();
|
||||
private final List<String> programErrors = new ArrayList<>();
|
||||
|
||||
private boolean errored = false;
|
||||
private int shaderCount = 0;
|
||||
private int programCount = 0;
|
||||
|
||||
public CompilerStats(String marker) {
|
||||
this.marker = MarkerFactory.getMarker(marker);
|
||||
}
|
||||
|
||||
public void start() {
|
||||
compileStart = System.nanoTime();
|
||||
}
|
||||
|
||||
public void finish() {
|
||||
long compileEnd = System.nanoTime();
|
||||
var elapsed = StringUtil.formatTime(compileEnd - compileStart);
|
||||
|
||||
FlwPrograms.LOGGER.info(marker, "Compiled %d programs (with %d link errors) and %d shaders (with %d compile errors) in %s".formatted(programCount, programErrors.size(), shaderCount, shaderErrors.size(), elapsed));
|
||||
}
|
||||
|
||||
public boolean errored() {
|
||||
return errored;
|
||||
}
|
||||
|
||||
public void emitErrorLog() {
|
||||
String out = "";
|
||||
|
||||
if (!loadErrors.isEmpty()) {
|
||||
out += "\nErrors loading sources:\n" + loadErrors();
|
||||
}
|
||||
|
||||
if (!shaderErrors.isEmpty()) {
|
||||
out += "\nShader compilation errors:\n" + compileErrors();
|
||||
}
|
||||
|
||||
if (!programErrors.isEmpty()) {
|
||||
out += "\nProgram link errors:\n" + linkErrors();
|
||||
}
|
||||
|
||||
FlwPrograms.LOGGER.error(marker, out);
|
||||
}
|
||||
|
||||
private String compileErrors() {
|
||||
return shaderErrors.stream()
|
||||
.map(FailedCompilation::generateMessage)
|
||||
.collect(Collectors.joining("\n"));
|
||||
}
|
||||
|
||||
private String linkErrors() {
|
||||
return String.join("\n", programErrors);
|
||||
}
|
||||
|
||||
private String loadErrors() {
|
||||
return loadErrors.stream()
|
||||
.map(LoadError::generateMessage)
|
||||
.map(ErrorBuilder::build)
|
||||
.collect(Collectors.joining("\n"));
|
||||
}
|
||||
|
||||
public void shaderResult(ShaderResult result) {
|
||||
if (result instanceof ShaderResult.Failure f) {
|
||||
shaderErrors.add(f.failure());
|
||||
errored = true;
|
||||
}
|
||||
shaderCount++;
|
||||
}
|
||||
|
||||
public void linkResult(LinkResult linkResult) {
|
||||
if (linkResult instanceof LinkResult.Failure f) {
|
||||
programErrors.add(f.failure());
|
||||
errored = true;
|
||||
}
|
||||
programCount++;
|
||||
}
|
||||
|
||||
public void loadResult(LoadResult loadResult) {
|
||||
if (loadResult instanceof LoadResult.Failure f) {
|
||||
loadErrors.add(f.error());
|
||||
errored = true;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +1,11 @@
|
||||
package dev.engine_room.flywheel.backend.compile.core;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
|
||||
|
||||
public sealed interface LinkResult {
|
||||
@Nullable
|
||||
default GlProgram unwrap() {
|
||||
return null;
|
||||
}
|
||||
GlProgram unwrap();
|
||||
|
||||
record Success(GlProgram program, String log) implements LinkResult {
|
||||
@Override
|
||||
@ -20,6 +16,10 @@ public sealed interface LinkResult {
|
||||
}
|
||||
|
||||
record Failure(String failure) implements LinkResult {
|
||||
@Override
|
||||
public GlProgram unwrap() {
|
||||
throw new ShaderException.Link(failure);
|
||||
}
|
||||
}
|
||||
|
||||
static LinkResult success(GlProgram program, String log) {
|
||||
|
@ -11,24 +11,17 @@ import static org.lwjgl.opengl.GL20.glLinkProgram;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
|
||||
import dev.engine_room.flywheel.backend.gl.shader.GlShader;
|
||||
|
||||
public class ProgramLinker {
|
||||
private final CompilerStats stats;
|
||||
|
||||
public ProgramLinker(CompilerStats stats) {
|
||||
this.stats = stats;
|
||||
public ProgramLinker() {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public GlProgram link(List<GlShader> shaders, Consumer<GlProgram> preLink) {
|
||||
// this probably doesn't need caching
|
||||
var linkResult = linkInternal(shaders, preLink);
|
||||
stats.linkResult(linkResult);
|
||||
return linkResult.unwrap();
|
||||
return linkInternal(shaders, preLink).unwrap();
|
||||
}
|
||||
|
||||
private LinkResult linkInternal(List<GlShader> shaders, Consumer<GlProgram> preLink) {
|
||||
|
@ -4,12 +4,9 @@ import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import dev.engine_room.flywheel.backend.gl.shader.GlShader;
|
||||
import dev.engine_room.flywheel.backend.gl.shader.ShaderType;
|
||||
import dev.engine_room.flywheel.backend.glsl.GlslVersion;
|
||||
@ -17,13 +14,10 @@ import dev.engine_room.flywheel.backend.glsl.SourceComponent;
|
||||
|
||||
public class ShaderCache {
|
||||
private final Map<ShaderKey, ShaderResult> inner = new HashMap<>();
|
||||
private final CompilerStats stats;
|
||||
|
||||
public ShaderCache(CompilerStats stats) {
|
||||
this.stats = stats;
|
||||
public ShaderCache() {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public GlShader compile(GlslVersion glslVersion, ShaderType shaderType, String name, Consumer<Compilation> callback, List<SourceComponent> sourceComponents) {
|
||||
var key = new ShaderKey(glslVersion, shaderType, name);
|
||||
var cached = inner.get(key);
|
||||
@ -41,16 +35,16 @@ public class ShaderCache {
|
||||
|
||||
ShaderResult out = ctx.compile(shaderType, name);
|
||||
inner.put(key, out);
|
||||
stats.shaderResult(out);
|
||||
return out.unwrap();
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
inner.values()
|
||||
.stream()
|
||||
.filter(r -> r instanceof ShaderResult.Success)
|
||||
.map(ShaderResult::unwrap)
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(GlShader::delete);
|
||||
inner.clear();
|
||||
}
|
||||
|
||||
private static void expand(List<SourceComponent> rootSources, Consumer<SourceComponent> out) {
|
||||
|
@ -1,4 +1,57 @@
|
||||
package dev.engine_room.flywheel.backend.compile.core;
|
||||
|
||||
public class ShaderException extends RuntimeException {
|
||||
public ShaderException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ShaderException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public ShaderException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public static class Link extends ShaderException {
|
||||
public Link(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public Link(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public Link(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Compile extends ShaderException {
|
||||
public Compile(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public Compile(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public Compile(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Load extends ShaderException {
|
||||
public Load(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public Load(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public Load(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,22 @@
|
||||
package dev.engine_room.flywheel.backend.compile.core;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import dev.engine_room.flywheel.backend.gl.shader.GlShader;
|
||||
|
||||
public sealed interface ShaderResult {
|
||||
@Nullable
|
||||
default GlShader unwrap() {
|
||||
return null;
|
||||
}
|
||||
GlShader unwrap();
|
||||
|
||||
record Success(GlShader shader, String infoLog) implements ShaderResult {
|
||||
@Override
|
||||
@NotNull
|
||||
public GlShader unwrap() {
|
||||
return shader;
|
||||
}
|
||||
}
|
||||
|
||||
record Failure(FailedCompilation failure) implements ShaderResult {
|
||||
@Override
|
||||
public GlShader unwrap() {
|
||||
throw new ShaderException.Compile(failure.generateMessage());
|
||||
}
|
||||
}
|
||||
|
||||
static ShaderResult success(GlShader program, String infoLog) {
|
||||
|
@ -1,24 +0,0 @@
|
||||
package dev.engine_room.flywheel.backend.compile.core;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import dev.engine_room.flywheel.backend.glsl.ShaderSources;
|
||||
import dev.engine_room.flywheel.backend.glsl.SourceFile;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class SourceLoader {
|
||||
private final ShaderSources sources;
|
||||
private final CompilerStats stats;
|
||||
|
||||
public SourceLoader(ShaderSources sources, CompilerStats stats) {
|
||||
this.sources = sources;
|
||||
this.stats = stats;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SourceFile find(ResourceLocation location) {
|
||||
var out = sources.find(location);
|
||||
stats.loadResult(out);
|
||||
return out.unwrap();
|
||||
}
|
||||
}
|
@ -160,7 +160,7 @@ public abstract class AbstractInstancer<I extends Instance> implements Instancer
|
||||
deleted.set(index);
|
||||
}
|
||||
|
||||
protected void removeDeletedInstances() {
|
||||
public void removeDeletedInstances() {
|
||||
if (deleted.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
@ -10,14 +10,17 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
|
||||
import dev.engine_room.flywheel.api.RenderContext;
|
||||
import dev.engine_room.flywheel.api.backend.Engine;
|
||||
import dev.engine_room.flywheel.api.instance.Instance;
|
||||
import dev.engine_room.flywheel.api.instance.InstanceType;
|
||||
import dev.engine_room.flywheel.api.model.Model;
|
||||
import dev.engine_room.flywheel.api.task.Plan;
|
||||
import dev.engine_room.flywheel.api.visualization.VisualType;
|
||||
import dev.engine_room.flywheel.backend.FlwBackend;
|
||||
import dev.engine_room.flywheel.backend.engine.embed.Environment;
|
||||
import dev.engine_room.flywheel.backend.engine.embed.EnvironmentStorage;
|
||||
import dev.engine_room.flywheel.lib.task.ForEachPlan;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import net.minecraft.client.resources.model.ModelBakery;
|
||||
@ -45,6 +48,11 @@ public abstract class DrawManager<N extends AbstractInstancer<?>> {
|
||||
return (AbstractInstancer<I>) instancers.computeIfAbsent(key, this::createAndDeferInit);
|
||||
}
|
||||
|
||||
public Plan<RenderContext> createFramePlan() {
|
||||
// Go wide on instancers to process deletions in parallel.
|
||||
return ForEachPlan.of(() -> new ArrayList<>(instancers.values()), AbstractInstancer::removeDeletedInstances);
|
||||
}
|
||||
|
||||
public void flush(LightStorage lightStorage, EnvironmentStorage environmentStorage) {
|
||||
// Thread safety: flush is called from the render thread after all visual updates have been made,
|
||||
// so there are no:tm: threads we could be racing with.
|
||||
|
@ -13,6 +13,7 @@ import dev.engine_room.flywheel.api.task.Plan;
|
||||
import dev.engine_room.flywheel.api.visualization.VisualEmbedding;
|
||||
import dev.engine_room.flywheel.api.visualization.VisualType;
|
||||
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
|
||||
import dev.engine_room.flywheel.backend.FlwBackend;
|
||||
import dev.engine_room.flywheel.backend.compile.core.ShaderException;
|
||||
import dev.engine_room.flywheel.backend.engine.embed.EmbeddedEnvironment;
|
||||
import dev.engine_room.flywheel.backend.engine.embed.Environment;
|
||||
@ -50,7 +51,8 @@ public class EngineImpl implements Engine {
|
||||
|
||||
@Override
|
||||
public Plan<RenderContext> createFramePlan() {
|
||||
return lightStorage.createFramePlan();
|
||||
return drawManager.createFramePlan()
|
||||
.and(lightStorage.createFramePlan());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -92,6 +94,7 @@ public class EngineImpl implements Engine {
|
||||
environmentStorage.flush();
|
||||
drawManager.flush(lightStorage, environmentStorage);
|
||||
} catch (ShaderException e) {
|
||||
FlwBackend.LOGGER.error("Falling back", e);
|
||||
triggerFallback();
|
||||
}
|
||||
}
|
||||
@ -101,6 +104,7 @@ public class EngineImpl implements Engine {
|
||||
try (var state = GlStateTracker.getRestoreState()) {
|
||||
drawManager.render(visualType);
|
||||
} catch (ShaderException e) {
|
||||
FlwBackend.LOGGER.error("Falling back", e);
|
||||
triggerFallback();
|
||||
}
|
||||
}
|
||||
@ -110,6 +114,7 @@ public class EngineImpl implements Engine {
|
||||
try (var state = GlStateTracker.getRestoreState()) {
|
||||
drawManager.renderCrumbling(crumblingBlocks);
|
||||
} catch (ShaderException e) {
|
||||
FlwBackend.LOGGER.error("Falling back", e);
|
||||
triggerFallback();
|
||||
}
|
||||
}
|
||||
|
@ -5,23 +5,21 @@ import org.lwjgl.opengl.GL46;
|
||||
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
|
||||
import dev.engine_room.flywheel.backend.compile.IndirectPrograms;
|
||||
import dev.engine_room.flywheel.backend.gl.GlTextureUnit;
|
||||
import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
|
||||
import dev.engine_room.flywheel.lib.math.MoreMath;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
public class DepthPyramid {
|
||||
private final GlProgram downsampleFirstProgram;
|
||||
private final GlProgram downsampleSecondProgram;
|
||||
private final IndirectPrograms programs;
|
||||
|
||||
public int pyramidTextureId = -1;
|
||||
|
||||
private int lastWidth = -1;
|
||||
private int lastHeight = -1;
|
||||
|
||||
public DepthPyramid(GlProgram downsampleFirstProgram, GlProgram downsampleSecondProgram) {
|
||||
this.downsampleFirstProgram = downsampleFirstProgram;
|
||||
this.downsampleSecondProgram = downsampleSecondProgram;
|
||||
public DepthPyramid(IndirectPrograms programs) {
|
||||
this.programs = programs;
|
||||
}
|
||||
|
||||
public void generate() {
|
||||
@ -42,6 +40,7 @@ public class DepthPyramid {
|
||||
GlTextureUnit.T0.makeActive();
|
||||
GlStateManager._bindTexture(depthBufferId);
|
||||
|
||||
var downsampleFirstProgram = programs.getDownsampleFirstProgram();
|
||||
downsampleFirstProgram.bind();
|
||||
downsampleFirstProgram.setUInt("max_mip_level", mipLevels);
|
||||
|
||||
@ -59,6 +58,7 @@ public class DepthPyramid {
|
||||
|
||||
GL46.glMemoryBarrier(GL46.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
|
||||
|
||||
var downsampleSecondProgram = programs.getDownsampleSecondProgram();
|
||||
downsampleSecondProgram.bind();
|
||||
downsampleSecondProgram.setUInt("max_mip_level", mipLevels);
|
||||
|
||||
|
@ -19,7 +19,7 @@ public class IndirectBuffers {
|
||||
public static final long MODEL_STRIDE = 28;
|
||||
|
||||
// Byte size of a draw command, plus our added mesh data.
|
||||
public static final long DRAW_COMMAND_STRIDE = 44;
|
||||
public static final long DRAW_COMMAND_STRIDE = 36;
|
||||
public static final long DRAW_COMMAND_OFFSET = 0;
|
||||
|
||||
// Offsets to the 3 segments
|
||||
|
@ -64,7 +64,6 @@ public class IndirectCullingGroup<I extends Instance> {
|
||||
int modelIndex = 0;
|
||||
for (var iterator = instancers.iterator(); iterator.hasNext(); ) {
|
||||
var instancer = iterator.next();
|
||||
instancer.update();
|
||||
var instanceCount = instancer.instanceCount();
|
||||
|
||||
if (instanceCount == 0) {
|
||||
@ -73,7 +72,7 @@ public class IndirectCullingGroup<I extends Instance> {
|
||||
continue;
|
||||
}
|
||||
|
||||
instancer.postUpdate(modelIndex, instanceCountThisFrame);
|
||||
instancer.update(modelIndex, instanceCountThisFrame);
|
||||
instanceCountThisFrame += instanceCount;
|
||||
|
||||
modelIndex++;
|
||||
@ -172,7 +171,7 @@ public class IndirectCullingGroup<I extends Instance> {
|
||||
|
||||
public void add(IndirectInstancer<I> instancer, InstancerKey<I> key, MeshPool meshPool) {
|
||||
instancer.mapping = buffers.objectStorage.createMapping();
|
||||
instancer.postUpdate(instancers.size(), -1);
|
||||
instancer.update(instancers.size(), -1);
|
||||
|
||||
instancers.add(instancer);
|
||||
|
||||
@ -203,7 +202,7 @@ public class IndirectCullingGroup<I extends Instance> {
|
||||
int baseDrawUniformLoc = -1;
|
||||
|
||||
for (var multiDraw : multiDraws.get(visualType)) {
|
||||
var drawProgram = programs.getIndirectProgram(instanceType, multiDraw.embedded ? ContextShader.EMBEDDED : ContextShader.DEFAULT, multiDraw.material.light(), multiDraw.material.cutout(), multiDraw.material.shaders());
|
||||
var drawProgram = programs.getIndirectProgram(instanceType, multiDraw.embedded ? ContextShader.EMBEDDED : ContextShader.DEFAULT, multiDraw.material);
|
||||
if (drawProgram != lastProgram) {
|
||||
lastProgram = drawProgram;
|
||||
|
||||
@ -221,7 +220,7 @@ public class IndirectCullingGroup<I extends Instance> {
|
||||
}
|
||||
|
||||
public void bindWithContextShader(ContextShader override, Material material) {
|
||||
var program = programs.getIndirectProgram(instanceType, override, material.light(), material.cutout(), material.shaders());
|
||||
var program = programs.getIndirectProgram(instanceType, override, material);
|
||||
|
||||
program.bind();
|
||||
|
||||
|
@ -4,7 +4,6 @@ import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import dev.engine_room.flywheel.api.material.Material;
|
||||
import dev.engine_room.flywheel.api.visualization.VisualType;
|
||||
import dev.engine_room.flywheel.backend.MaterialShaderIndices;
|
||||
import dev.engine_room.flywheel.backend.engine.MaterialEncoder;
|
||||
import dev.engine_room.flywheel.backend.engine.MeshPool;
|
||||
import dev.engine_room.flywheel.backend.engine.embed.EmbeddedEnvironment;
|
||||
@ -17,8 +16,6 @@ public class IndirectDraw {
|
||||
private final int bias;
|
||||
private final int indexOfMeshInModel;
|
||||
|
||||
private final int materialVertexIndex;
|
||||
private final int materialFragmentIndex;
|
||||
private final int packedFogAndCutout;
|
||||
private final int packedMaterialProperties;
|
||||
private boolean deleted;
|
||||
@ -33,8 +30,6 @@ public class IndirectDraw {
|
||||
|
||||
mesh.acquire();
|
||||
|
||||
this.materialVertexIndex = MaterialShaderIndices.vertexIndex(material.shaders());
|
||||
this.materialFragmentIndex = MaterialShaderIndices.fragmentIndex(material.shaders());
|
||||
this.packedFogAndCutout = MaterialEncoder.packUberShader(material);
|
||||
this.packedMaterialProperties = MaterialEncoder.packProperties(material);
|
||||
}
|
||||
@ -78,10 +73,8 @@ public class IndirectDraw {
|
||||
|
||||
MemoryUtil.memPutInt(ptr + 24, instancer.environment.matrixIndex()); // matrixIndex
|
||||
|
||||
MemoryUtil.memPutInt(ptr + 28, materialVertexIndex); // materialVertexIndex
|
||||
MemoryUtil.memPutInt(ptr + 32, materialFragmentIndex); // materialFragmentIndex
|
||||
MemoryUtil.memPutInt(ptr + 36, packedFogAndCutout); // packedFogAndCutout
|
||||
MemoryUtil.memPutInt(ptr + 40, packedMaterialProperties); // packedMaterialProperties
|
||||
MemoryUtil.memPutInt(ptr + 28, packedFogAndCutout); // packedFogAndCutout
|
||||
MemoryUtil.memPutInt(ptr + 32, packedMaterialProperties); // packedMaterialProperties
|
||||
}
|
||||
|
||||
public void writeWithOverrides(long ptr, int instanceIndex, Material materialOverride) {
|
||||
@ -95,10 +88,8 @@ public class IndirectDraw {
|
||||
|
||||
MemoryUtil.memPutInt(ptr + 24, instancer.environment.matrixIndex()); // matrixIndex
|
||||
|
||||
MemoryUtil.memPutInt(ptr + 28, MaterialShaderIndices.vertexIndex(materialOverride.shaders())); // materialVertexIndex
|
||||
MemoryUtil.memPutInt(ptr + 32, MaterialShaderIndices.fragmentIndex(materialOverride.shaders())); // materialFragmentIndex
|
||||
MemoryUtil.memPutInt(ptr + 36, MaterialEncoder.packUberShader(materialOverride)); // packedFogAndCutout
|
||||
MemoryUtil.memPutInt(ptr + 40, MaterialEncoder.packProperties(materialOverride)); // packedMaterialProperties
|
||||
MemoryUtil.memPutInt(ptr + 28, MaterialEncoder.packUberShader(materialOverride)); // packedFogAndCutout
|
||||
MemoryUtil.memPutInt(ptr + 32, MaterialEncoder.packProperties(materialOverride)); // packedMaterialProperties
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
|
@ -56,6 +56,8 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
|
||||
this.programs = programs;
|
||||
programs.acquire();
|
||||
|
||||
// WARN: We should avoid eagerly grabbing GlPrograms here as catching compile
|
||||
// errors and falling back during construction is a bit more complicated.
|
||||
stagingBuffer = new StagingBuffer(this.programs);
|
||||
meshPool = new MeshPool();
|
||||
vertexArray = GlVertexArray.create();
|
||||
@ -63,7 +65,7 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
|
||||
lightBuffers = new LightBuffers();
|
||||
matrixBuffer = new MatrixBuffer();
|
||||
|
||||
depthPyramid = new DepthPyramid(programs.getDownsampleFirstProgram(), programs.getDownsampleSecondProgram());
|
||||
depthPyramid = new DepthPyramid(programs);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -55,11 +55,7 @@ public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I>
|
||||
return associatedDraws;
|
||||
}
|
||||
|
||||
public void update() {
|
||||
removeDeletedInstances();
|
||||
}
|
||||
|
||||
public void postUpdate(int modelIndex, int baseInstance) {
|
||||
public void update(int modelIndex, int baseInstance) {
|
||||
this.modelIndex = modelIndex;
|
||||
this.baseInstance = baseInstance;
|
||||
mapping.update(modelIndex, instanceCount());
|
||||
|
@ -10,7 +10,6 @@ import org.lwjgl.system.MemoryUtil;
|
||||
import dev.engine_room.flywheel.backend.compile.IndirectPrograms;
|
||||
import dev.engine_room.flywheel.backend.gl.GlFence;
|
||||
import dev.engine_room.flywheel.backend.gl.buffer.GlBuffer;
|
||||
import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
|
||||
import dev.engine_room.flywheel.lib.memory.FlwMemoryTracker;
|
||||
import dev.engine_room.flywheel.lib.memory.MemoryBlock;
|
||||
import it.unimi.dsi.fastutil.PriorityQueue;
|
||||
@ -26,6 +25,7 @@ public class StagingBuffer {
|
||||
private final int vbo;
|
||||
private final long map;
|
||||
private final long capacity;
|
||||
private final IndirectPrograms programs;
|
||||
|
||||
private final OverflowStagingBuffer overflow = new OverflowStagingBuffer();
|
||||
private final TransferList transfers = new TransferList();
|
||||
@ -33,8 +33,6 @@ public class StagingBuffer {
|
||||
private final GlBuffer scatterBuffer = new GlBuffer();
|
||||
private final ScatterList scatterList = new ScatterList();
|
||||
|
||||
private final GlProgram scatterProgram;
|
||||
|
||||
/**
|
||||
* The position in the buffer at the time of the last flush.
|
||||
*/
|
||||
@ -70,6 +68,7 @@ public class StagingBuffer {
|
||||
|
||||
public StagingBuffer(long capacity, IndirectPrograms programs) {
|
||||
this.capacity = capacity;
|
||||
this.programs = programs;
|
||||
vbo = GL45C.glCreateBuffers();
|
||||
|
||||
GL45C.glNamedBufferStorage(vbo, capacity, STORAGE_FLAGS);
|
||||
@ -78,8 +77,6 @@ public class StagingBuffer {
|
||||
totalAvailable = capacity;
|
||||
|
||||
FlwMemoryTracker._allocCpuMemory(capacity);
|
||||
|
||||
scatterProgram = programs.getScatterProgram();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -251,7 +248,8 @@ public class StagingBuffer {
|
||||
* <a href=https://on-demand.gputechconf.com/gtc/2016/presentation/s6138-christoph-kubisch-pierre-boudier-gpu-driven-rendering.pdf>this presentation</a>
|
||||
*/
|
||||
private void dispatchComputeCopies() {
|
||||
scatterProgram.bind();
|
||||
programs.getScatterProgram()
|
||||
.bind();
|
||||
|
||||
// These bindings don't change between dstVbos.
|
||||
GL45.glBindBufferBase(GL45C.GL_SHADER_STORAGE_BUFFER, 0, scatterBuffer.handle());
|
||||
|
@ -4,13 +4,10 @@ import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
import dev.engine_room.flywheel.api.backend.Engine;
|
||||
import dev.engine_room.flywheel.api.instance.Instance;
|
||||
import dev.engine_room.flywheel.api.material.Material;
|
||||
import dev.engine_room.flywheel.api.visualization.VisualType;
|
||||
import dev.engine_room.flywheel.backend.MaterialShaderIndices;
|
||||
import dev.engine_room.flywheel.backend.Samplers;
|
||||
import dev.engine_room.flywheel.backend.compile.ContextShader;
|
||||
import dev.engine_room.flywheel.backend.compile.InstancingPrograms;
|
||||
@ -65,13 +62,11 @@ public class InstancedDrawManager extends DrawManager<InstancedInstancer<?>> {
|
||||
|
||||
this.instancers.values()
|
||||
.removeIf(instancer -> {
|
||||
// Update the instancers and remove any that are empty.
|
||||
instancer.update();
|
||||
|
||||
if (instancer.instanceCount() == 0) {
|
||||
instancer.delete();
|
||||
return true;
|
||||
} else {
|
||||
instancer.updateBuffer();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
@ -179,7 +174,7 @@ public class InstancedDrawManager extends DrawManager<InstancedInstancer<?>> {
|
||||
|
||||
for (InstancedDraw draw : instancer.draws()) {
|
||||
CommonCrumbling.applyCrumblingProperties(crumblingMaterial, draw.material());
|
||||
var program = programs.get(shader.instanceType(), ContextShader.CRUMBLING, crumblingMaterial.light(), crumblingMaterial.cutout(), crumblingMaterial.shaders());
|
||||
var program = programs.get(shader.instanceType(), ContextShader.CRUMBLING, crumblingMaterial);
|
||||
program.bind();
|
||||
program.setInt("_flw_baseInstance", index);
|
||||
uploadMaterialUniform(program, crumblingMaterial);
|
||||
@ -205,11 +200,8 @@ public class InstancedDrawManager extends DrawManager<InstancedInstancer<?>> {
|
||||
}
|
||||
|
||||
public static void uploadMaterialUniform(GlProgram program, Material material) {
|
||||
int uniformLocation = program.getUniformLocation("_flw_packedMaterial");
|
||||
int vertexIndex = MaterialShaderIndices.vertexIndex(material.shaders());
|
||||
int fragmentIndex = MaterialShaderIndices.fragmentIndex(material.shaders());
|
||||
int packedFogAndCutout = MaterialEncoder.packUberShader(material);
|
||||
int packedMaterialProperties = MaterialEncoder.packProperties(material);
|
||||
GL32.glUniform4ui(uniformLocation, vertexIndex, fragmentIndex, packedFogAndCutout, packedMaterialProperties);
|
||||
program.setUVec2("_flw_packedMaterial", packedFogAndCutout, packedMaterialProperties);
|
||||
}
|
||||
}
|
||||
|
@ -44,12 +44,7 @@ public class InstancedInstancer<I extends Instance> extends AbstractInstancer<I>
|
||||
vbo = new GlBuffer(GlBufferUsage.DYNAMIC_DRAW);
|
||||
}
|
||||
|
||||
public void update() {
|
||||
removeDeletedInstances();
|
||||
updateBuffer();
|
||||
}
|
||||
|
||||
private void updateBuffer() {
|
||||
public void updateBuffer() {
|
||||
if (changed.isEmpty() || vbo == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ public class InstancedRenderStage {
|
||||
for (var drawCall : drawCalls.draws) {
|
||||
var material = drawCall.material();
|
||||
|
||||
var program = programs.get(shader.instanceType(), environment.contextShader(), material.light(), material.cutout(), material.shaders());
|
||||
var program = programs.get(shader.instanceType(), environment.contextShader(), material);
|
||||
program.bind();
|
||||
|
||||
environment.setupDraw(program);
|
||||
|
@ -10,6 +10,7 @@ import dev.engine_room.flywheel.api.RenderContext;
|
||||
import dev.engine_room.flywheel.api.visualization.VisualizationManager;
|
||||
import dev.engine_room.flywheel.backend.engine.indirect.DepthPyramid;
|
||||
import dev.engine_room.flywheel.backend.mixin.LevelRendererAccessor;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.BlockPos;
|
||||
@ -18,7 +19,7 @@ import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public final class FrameUniforms extends UniformWriter {
|
||||
private static final int SIZE = 96 + 64 * 9 + 16 * 5 + 8 * 2 + 8 + 4 * 17;
|
||||
private static final int SIZE = 96 + 64 * 9 + 16 * 5 + 8 * 2 + 8 + 4 * 19;
|
||||
static final UniformBuffer BUFFER = new UniformBuffer(Uniforms.FRAME_INDEX, SIZE);
|
||||
|
||||
private static final Matrix4f VIEW = new Matrix4f();
|
||||
@ -93,6 +94,8 @@ public final class FrameUniforms extends UniformWriter {
|
||||
|
||||
ptr += 96;
|
||||
|
||||
ptr = writeCullData(ptr);
|
||||
|
||||
ptr = writeMatrices(ptr);
|
||||
|
||||
ptr = writeRenderOrigin(ptr, renderOrigin);
|
||||
@ -113,8 +116,6 @@ public final class FrameUniforms extends UniformWriter {
|
||||
|
||||
ptr = writeInt(ptr, debugMode);
|
||||
|
||||
ptr = writeCullData(ptr);
|
||||
|
||||
firstWrite = false;
|
||||
BUFFER.markDirty();
|
||||
}
|
||||
@ -161,11 +162,15 @@ public final class FrameUniforms extends UniformWriter {
|
||||
float partialTick = context.partialTick();
|
||||
float renderTicks = ticks + partialTick;
|
||||
float renderSeconds = renderTicks / 20f;
|
||||
float systemSeconds = Util.getMillis() / 1000f;
|
||||
int systemMillis = (int) (Util.getMillis() % Integer.MAX_VALUE);
|
||||
|
||||
ptr = writeInt(ptr, ticks);
|
||||
ptr = writeFloat(ptr, partialTick);
|
||||
ptr = writeFloat(ptr, renderTicks);
|
||||
ptr = writeFloat(ptr, renderSeconds);
|
||||
ptr = writeFloat(ptr, systemSeconds);
|
||||
ptr = writeInt(ptr, systemMillis);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@ -315,4 +320,8 @@ public final class FrameUniforms extends UniformWriter {
|
||||
MemoryUtil.memPutFloat(ptr + 88, nzW);
|
||||
MemoryUtil.memPutFloat(ptr + 92, pzW);
|
||||
}
|
||||
|
||||
public static boolean debugOn() {
|
||||
return debugMode != DebugMode.OFF.ordinal();
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,21 @@
|
||||
package dev.engine_room.flywheel.backend.engine.uniform;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import dev.engine_room.flywheel.api.RenderContext;
|
||||
import dev.engine_room.flywheel.backend.BackendConfig;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public final class LevelUniforms extends UniformWriter {
|
||||
private static final int SIZE = 16 * 2 + 4 * 13;
|
||||
private static final int SIZE = 16 * 4 + 4 * 13;
|
||||
static final UniformBuffer BUFFER = new UniformBuffer(Uniforms.LEVEL_INDEX, SIZE);
|
||||
|
||||
public static final Vector3f LIGHT0_DIRECTION = new Vector3f();
|
||||
public static final Vector3f LIGHT1_DIRECTION = new Vector3f();
|
||||
|
||||
private LevelUniforms() {
|
||||
}
|
||||
|
||||
@ -24,6 +30,9 @@ public final class LevelUniforms extends UniformWriter {
|
||||
ptr = writeVec4(ptr, (float) skyColor.x, (float) skyColor.y, (float) skyColor.z, 1f);
|
||||
ptr = writeVec4(ptr, (float) cloudColor.x, (float) cloudColor.y, (float) cloudColor.z, 1f);
|
||||
|
||||
ptr = writeVec3(ptr, LIGHT0_DIRECTION);
|
||||
ptr = writeVec3(ptr, LIGHT1_DIRECTION);
|
||||
|
||||
long dayTime = level.getDayTime();
|
||||
long levelDay = dayTime / 24000L;
|
||||
float timeOfDay = (float) (dayTime - levelDay * 24000L) / 24000f;
|
||||
@ -46,6 +55,8 @@ public final class LevelUniforms extends UniformWriter {
|
||||
|
||||
ptr = writeInt(ptr, level.effects().constantAmbientLight() ? 1 : 0);
|
||||
|
||||
ptr = writeInt(ptr, BackendConfig.INSTANCE.useLightDirections() ? 1 : 0);
|
||||
|
||||
// TODO: use defines for custom dimension ids
|
||||
int dimensionId;
|
||||
ResourceKey<Level> dimension = level.dimension();
|
||||
|
@ -40,7 +40,7 @@ public final class PlayerUniforms extends UniformWriter {
|
||||
Vec3 eyePos = player.getEyePosition(context.partialTick());
|
||||
ptr = writeVec3(ptr, (float) eyePos.x, (float) eyePos.y, (float) eyePos.z);
|
||||
|
||||
ptr = writeTeamColor(ptr, info.getTeam());
|
||||
ptr = writeTeamColor(ptr, info == null ? null : info.getTeam());
|
||||
|
||||
ptr = writeEyeBrightness(ptr, player);
|
||||
|
||||
@ -54,7 +54,8 @@ public final class PlayerUniforms extends UniformWriter {
|
||||
|
||||
ptr = writeInt(ptr, player.isShiftKeyDown() ? 1 : 0);
|
||||
|
||||
ptr = writeInt(ptr, info.getGameMode().getId());
|
||||
ptr = writeInt(ptr, info == null ? 0 : info.getGameMode()
|
||||
.getId());
|
||||
|
||||
BUFFER.markDirty();
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package dev.engine_room.flywheel.backend.engine.uniform;
|
||||
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector3fc;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import dev.engine_room.flywheel.lib.util.ExtraMemoryOps;
|
||||
@ -37,6 +38,10 @@ class UniformWriter {
|
||||
return ptr + 16;
|
||||
}
|
||||
|
||||
static long writeVec3(long ptr, Vector3fc vec) {
|
||||
return writeVec3(ptr, vec.x(), vec.y(), vec.z());
|
||||
}
|
||||
|
||||
static long writeVec4(long ptr, float x, float y, float z, float w) {
|
||||
MemoryUtil.memPutFloat(ptr, x);
|
||||
MemoryUtil.memPutFloat(ptr + 4, y);
|
||||
|
@ -1,22 +1,22 @@
|
||||
package dev.engine_room.flywheel.backend.glsl;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import dev.engine_room.flywheel.backend.compile.core.ShaderException;
|
||||
|
||||
public sealed interface LoadResult {
|
||||
@Nullable
|
||||
default SourceFile unwrap() {
|
||||
return null;
|
||||
}
|
||||
SourceFile unwrap();
|
||||
|
||||
record Success(SourceFile source) implements LoadResult {
|
||||
@Override
|
||||
@NotNull
|
||||
public SourceFile unwrap() {
|
||||
return source;
|
||||
}
|
||||
}
|
||||
|
||||
record Failure(LoadError error) implements LoadResult {
|
||||
@Override
|
||||
public SourceFile unwrap() {
|
||||
throw new ShaderException.Load(error.generateMessage()
|
||||
.build());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,6 +49,10 @@ public class ShaderSources {
|
||||
return cache.computeIfAbsent(location, loc -> new LoadResult.Failure(new LoadError.ResourceError(loc)));
|
||||
}
|
||||
|
||||
public SourceFile get(ResourceLocation location) {
|
||||
return find(location).unwrap();
|
||||
}
|
||||
|
||||
private static boolean isShader(ResourceLocation loc) {
|
||||
var path = loc.getPath();
|
||||
return path.endsWith(".glsl") || path.endsWith(".vert") || path.endsWith(".frag") || path.endsWith(".comp");
|
||||
|
@ -1,5 +1,6 @@
|
||||
package dev.engine_room.flywheel.backend.mixin;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
@ -9,5 +10,6 @@ import net.minecraft.client.player.AbstractClientPlayer;
|
||||
@Mixin(AbstractClientPlayer.class)
|
||||
public interface AbstractClientPlayerAccessor {
|
||||
@Invoker("getPlayerInfo")
|
||||
@Nullable
|
||||
PlayerInfo flywheel$getPlayerInfo();
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package dev.engine_room.flywheel.backend.mixin;
|
||||
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector3f;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
@ -7,6 +9,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
|
||||
import dev.engine_room.flywheel.backend.engine.uniform.LevelUniforms;
|
||||
import dev.engine_room.flywheel.backend.gl.GlStateTracker;
|
||||
import dev.engine_room.flywheel.backend.gl.buffer.GlBufferType;
|
||||
|
||||
@ -26,4 +29,12 @@ abstract class GlStateManagerMixin {
|
||||
private static void flywheel$onUseProgram(int program, CallbackInfo ci) {
|
||||
GlStateTracker._setProgram(program);
|
||||
}
|
||||
|
||||
@Inject(method = "setupLevelDiffuseLighting", at = @At("HEAD"))
|
||||
private static void flywheel$onSetupLevelDiffuseLighting(Vector3f vector3f, Vector3f vector3f2, Matrix4f matrix4f, CallbackInfo ci) {
|
||||
// Capture the light directions before they're transformed into screen space
|
||||
// Basically all usages of assigning light direction go through here so I think this is safe
|
||||
LevelUniforms.LIGHT0_DIRECTION.set(vector3f);
|
||||
LevelUniforms.LIGHT1_DIRECTION.set(vector3f2);
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include "flywheel:internal/colorizer.glsl"
|
||||
|
||||
// optimize discard usage
|
||||
#ifdef GL_ARB_conservative_depth
|
||||
#if defined(GL_ARB_conservative_depth) && defined(_FLW_USE_DISCARD)
|
||||
layout (depth_greater) out float gl_FragDepth;
|
||||
#endif
|
||||
|
||||
@ -13,16 +13,22 @@ uniform sampler2D _flw_crumblingTex;
|
||||
in vec2 _flw_crumblingTexCoord;
|
||||
#endif
|
||||
|
||||
#ifdef _FLW_DEBUG
|
||||
flat in uint _flw_instanceID;
|
||||
#endif
|
||||
|
||||
out vec4 _flw_outputColor;
|
||||
|
||||
float _flw_diffuseFactor() {
|
||||
if (flw_material.diffuse) {
|
||||
if (flw_constantAmbientLight == 1u) {
|
||||
return diffuseNether(flw_vertexNormal);
|
||||
if (flw_useLightDirections == 1u) {
|
||||
return diffuseFromLightDirections(flw_vertexNormal);
|
||||
} else {
|
||||
return diffuse(flw_vertexNormal);
|
||||
if (flw_constantAmbientLight == 1u) {
|
||||
return diffuseNether(flw_vertexNormal);
|
||||
} else {
|
||||
return diffuse(flw_vertexNormal);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return 1.;
|
||||
@ -49,9 +55,11 @@ void _flw_main() {
|
||||
|
||||
vec4 color = flw_fragColor;
|
||||
|
||||
#ifdef _FLW_USE_DISCARD
|
||||
if (flw_discardPredicate(color)) {
|
||||
discard;
|
||||
}
|
||||
#endif
|
||||
|
||||
float diffuseFactor = _flw_diffuseFactor();
|
||||
color.rgb *= diffuseFactor;
|
||||
@ -67,6 +75,7 @@ void _flw_main() {
|
||||
color *= lightColor;
|
||||
}
|
||||
|
||||
#ifdef _FLW_DEBUG
|
||||
switch (_flw_debugMode) {
|
||||
case 1u:
|
||||
color = vec4(flw_vertexNormal * .5 + .5, 1.);
|
||||
@ -87,6 +96,7 @@ void _flw_main() {
|
||||
color = vec4(vec3(diffuseFactor), 1.);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
_flw_outputColor = flw_fogFilter(color);
|
||||
}
|
||||
|
@ -71,7 +71,9 @@ mat4 _flw_modelMatrix;
|
||||
mat3 _flw_normalMatrix;
|
||||
#endif
|
||||
|
||||
#ifdef _FLW_DEBUG
|
||||
flat out uint _flw_instanceID;
|
||||
#endif
|
||||
|
||||
void _flw_main(in FlwInstance instance, in uint stableInstanceID) {
|
||||
_flw_layoutVertex();
|
||||
@ -93,5 +95,7 @@ void _flw_main(in FlwInstance instance, in uint stableInstanceID) {
|
||||
|
||||
gl_Position = flw_viewProjection * flw_vertexPos;
|
||||
|
||||
#ifdef _FLW_DEBUG
|
||||
_flw_instanceID = stableInstanceID;
|
||||
#endif
|
||||
}
|
||||
|
@ -1,3 +1,2 @@
|
||||
uint _flw_uberMaterialFragmentIndex;
|
||||
uint _flw_uberFogIndex;
|
||||
uint _flw_uberCutoutIndex;
|
||||
|
@ -1 +0,0 @@
|
||||
uint _flw_uberMaterialVertexIndex;
|
@ -7,3 +7,11 @@ float diffuseNether(vec3 normal) {
|
||||
vec3 n2 = normal * normal * vec3(.6, .9, .8);
|
||||
return min(n2.x + n2.y + n2.z, 1.);
|
||||
}
|
||||
|
||||
float diffuseFromLightDirections(vec3 normal) {
|
||||
// We assume the directions are normalized before upload.
|
||||
float light0 = max(0.0, dot(flw_light0Direction, normal));
|
||||
float light1 = max(0.0, dot(flw_light1Direction, normal));
|
||||
return min(1.0, (light0 + light1) * 0.6 + 0.4);
|
||||
}
|
||||
|
||||
|
@ -8,8 +8,6 @@ struct MeshDrawCommand {
|
||||
uint modelIndex;
|
||||
uint matrixIndex;
|
||||
|
||||
uint materialVertexIndex;
|
||||
uint materialFragmentIndex;
|
||||
uint packedFogAndCutout;
|
||||
uint packedMaterialProperties;
|
||||
};
|
||||
|
@ -2,12 +2,11 @@
|
||||
#include "flywheel:internal/indirect/buffer_bindings.glsl"
|
||||
#include "flywheel:internal/indirect/light.glsl"
|
||||
|
||||
flat in uvec3 _flw_packedMaterial;
|
||||
flat in uvec2 _flw_packedMaterial;
|
||||
|
||||
void main() {
|
||||
_flw_uberMaterialFragmentIndex = _flw_packedMaterial.x;
|
||||
_flw_unpackUint2x16(_flw_packedMaterial.y, _flw_uberFogIndex, _flw_uberCutoutIndex);
|
||||
_flw_unpackMaterialProperties(_flw_packedMaterial.z, flw_material);
|
||||
_flw_unpackUint2x16(_flw_packedMaterial.x, _flw_uberFogIndex, _flw_uberCutoutIndex);
|
||||
_flw_unpackMaterialProperties(_flw_packedMaterial.y, flw_material);
|
||||
|
||||
_flw_main();
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ layout(std430, binding = _FLW_MATRIX_BUFFER_BINDING) restrict buffer MatrixBuffe
|
||||
|
||||
uniform uint _flw_baseDraw;
|
||||
|
||||
flat out uvec3 _flw_packedMaterial;
|
||||
flat out uvec2 _flw_packedMaterial;
|
||||
|
||||
#if __VERSION__ < 460
|
||||
#define flw_baseInstance gl_BaseInstanceARB
|
||||
@ -35,15 +35,12 @@ void main() {
|
||||
uint drawIndex = flw_drawId + _flw_baseDraw;
|
||||
MeshDrawCommand draw = _flw_drawCommands[drawIndex];
|
||||
|
||||
_flw_uberMaterialVertexIndex = draw.materialVertexIndex;
|
||||
uint packedMaterialProperties = draw.packedMaterialProperties;
|
||||
_flw_unpackMaterialProperties(packedMaterialProperties, flw_material);
|
||||
_flw_packedMaterial = uvec3(draw.materialFragmentIndex, draw.packedFogAndCutout, packedMaterialProperties);
|
||||
_flw_packedMaterial = uvec2(draw.packedFogAndCutout, packedMaterialProperties);
|
||||
|
||||
#ifdef FLW_EMBEDDED
|
||||
_flw_unpackMatrices(_flw_matrices[draw.matrixIndex], _flw_modelMatrix, _flw_normalMatrix);
|
||||
// _flw_modelMatrix = mat4(1.);
|
||||
// _flw_normalMatrix = mat3(1.);
|
||||
#endif
|
||||
|
||||
#ifdef _FLW_CRUMBLING
|
||||
|
@ -1,12 +1,11 @@
|
||||
#include "flywheel:internal/common.frag"
|
||||
#include "flywheel:internal/instancing/light.glsl"
|
||||
|
||||
uniform uvec4 _flw_packedMaterial;
|
||||
uniform uvec2 _flw_packedMaterial;
|
||||
|
||||
void main() {
|
||||
_flw_uberMaterialFragmentIndex = _flw_packedMaterial.y;
|
||||
_flw_unpackUint2x16(_flw_packedMaterial.z, _flw_uberFogIndex, _flw_uberCutoutIndex);
|
||||
_flw_unpackMaterialProperties(_flw_packedMaterial.w, flw_material);
|
||||
_flw_unpackUint2x16(_flw_packedMaterial.x, _flw_uberFogIndex, _flw_uberCutoutIndex);
|
||||
_flw_unpackMaterialProperties(_flw_packedMaterial.y, flw_material);
|
||||
|
||||
_flw_main();
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include "flywheel:internal/packed_material.glsl"
|
||||
#include "flywheel:internal/instancing/light.glsl"
|
||||
|
||||
uniform uvec4 _flw_packedMaterial;
|
||||
uniform uvec2 _flw_packedMaterial;
|
||||
uniform int _flw_baseInstance = 0;
|
||||
|
||||
#ifdef FLW_EMBEDDED
|
||||
@ -11,8 +11,7 @@ uniform mat3 _flw_normalMatrixUniform;
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
_flw_uberMaterialVertexIndex = _flw_packedMaterial.x;
|
||||
_flw_unpackMaterialProperties(_flw_packedMaterial.w, flw_material);
|
||||
_flw_unpackMaterialProperties(_flw_packedMaterial.y, flw_material);
|
||||
|
||||
FlwInstance instance = _flw_unpackInstance(_flw_baseInstance + gl_InstanceID);
|
||||
|
||||
|
@ -23,6 +23,8 @@ struct _FlwCullData {
|
||||
layout(std140) uniform _FlwFrameUniforms {
|
||||
FrustumPlanes flw_frustumPlanes;
|
||||
|
||||
_FlwCullData _flw_cullData;
|
||||
|
||||
mat4 flw_view;
|
||||
mat4 flw_viewInverse;
|
||||
mat4 flw_viewPrev;
|
||||
@ -51,6 +53,8 @@ layout(std140) uniform _FlwFrameUniforms {
|
||||
float flw_partialTick;
|
||||
float flw_renderTicks;
|
||||
float flw_renderSeconds;
|
||||
float flw_systemSeconds;
|
||||
uint flw_systemMillis;
|
||||
|
||||
/** 0 means no fluid. Use FLW_CAMERA_IN_FLUID_* defines to detect fluid type. */
|
||||
uint flw_cameraInFluid;
|
||||
@ -58,8 +62,6 @@ layout(std140) uniform _FlwFrameUniforms {
|
||||
uint flw_cameraInBlock;
|
||||
|
||||
uint _flw_debugMode;
|
||||
|
||||
_FlwCullData _flw_cullData;
|
||||
};
|
||||
|
||||
#define flw_renderOrigin (_flw_renderOrigin.xyz)
|
||||
|
@ -2,6 +2,9 @@ layout(std140) uniform _FlwLevelUniforms {
|
||||
vec4 flw_skyColor;
|
||||
vec4 flw_cloudColor;
|
||||
|
||||
vec4 _flw_light0Direction;
|
||||
vec4 _flw_light1Direction;
|
||||
|
||||
/** The current day number of the level. */
|
||||
uint flw_levelDay;
|
||||
/** The current fraction of the current day that has elapsed. */
|
||||
@ -23,11 +26,15 @@ layout(std140) uniform _FlwLevelUniforms {
|
||||
float flw_skyDarken;
|
||||
|
||||
uint flw_constantAmbientLight;
|
||||
uint flw_useLightDirections;
|
||||
|
||||
/** Use FLW_DIMENSION_* ids to determine the dimension. May eventually be implemented for custom dimensions. */
|
||||
uint flw_dimension;
|
||||
};
|
||||
|
||||
#define flw_light0Direction (_flw_light0Direction.xyz)
|
||||
#define flw_light1Direction (_flw_light1Direction.xyz)
|
||||
|
||||
#define FLW_DIMENSION_OVERWORLD 0
|
||||
#define FLW_DIMENSION_NETHER 1
|
||||
#define FLW_DIMENSION_END 2
|
||||
|
@ -1,6 +1,5 @@
|
||||
package dev.engine_room.flywheel.lib.instance;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import dev.engine_room.flywheel.api.Flywheel;
|
||||
@ -29,7 +28,7 @@ public final class InstanceTypes {
|
||||
})
|
||||
.vertexShader(Flywheel.rl("instance/transformed.vert"))
|
||||
.cullShader(Flywheel.rl("instance/cull/transformed.glsl"))
|
||||
.register();
|
||||
.build();
|
||||
|
||||
public static final InstanceType<PosedInstance> POSED = SimpleInstanceType.builder(PosedInstance::new)
|
||||
.layout(LayoutBuilder.create()
|
||||
@ -51,7 +50,7 @@ public final class InstanceTypes {
|
||||
})
|
||||
.vertexShader(Flywheel.rl("instance/posed.vert"))
|
||||
.cullShader(Flywheel.rl("instance/cull/posed.glsl"))
|
||||
.register();
|
||||
.build();
|
||||
|
||||
public static final InstanceType<OrientedInstance> ORIENTED = SimpleInstanceType.builder(OrientedInstance::new)
|
||||
.layout(LayoutBuilder.create()
|
||||
@ -79,7 +78,7 @@ public final class InstanceTypes {
|
||||
})
|
||||
.vertexShader(Flywheel.rl("instance/oriented.vert"))
|
||||
.cullShader(Flywheel.rl("instance/cull/oriented.glsl"))
|
||||
.register();
|
||||
.build();
|
||||
|
||||
public static final InstanceType<ShadowInstance> SHADOW = SimpleInstanceType.builder(ShadowInstance::new)
|
||||
.layout(LayoutBuilder.create()
|
||||
@ -102,12 +101,8 @@ public final class InstanceTypes {
|
||||
})
|
||||
.vertexShader(Flywheel.rl("instance/shadow.vert"))
|
||||
.cullShader(Flywheel.rl("instance/cull/shadow.glsl"))
|
||||
.register();
|
||||
.build();
|
||||
|
||||
private InstanceTypes() {
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static void init() {
|
||||
}
|
||||
}
|
||||
|
@ -89,14 +89,13 @@ public final class SimpleInstanceType<I extends Instance> implements InstanceTyp
|
||||
return this;
|
||||
}
|
||||
|
||||
public SimpleInstanceType<I> register() {
|
||||
public SimpleInstanceType<I> build() {
|
||||
Objects.requireNonNull(layout);
|
||||
Objects.requireNonNull(writer);
|
||||
Objects.requireNonNull(vertexShader);
|
||||
Objects.requireNonNull(cullShader);
|
||||
|
||||
var out = new SimpleInstanceType<>(factory, layout, writer, vertexShader, cullShader);
|
||||
return InstanceType.REGISTRY.registerAndGet(out);
|
||||
return new SimpleInstanceType<>(factory, layout, writer, vertexShader, cullShader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
package dev.engine_room.flywheel.lib.material;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import dev.engine_room.flywheel.api.Flywheel;
|
||||
import dev.engine_room.flywheel.api.material.CutoutShader;
|
||||
|
||||
@ -9,24 +7,20 @@ public final class CutoutShaders {
|
||||
/**
|
||||
* Do not discard any fragments based on alpha.
|
||||
*/
|
||||
public static final CutoutShader OFF = CutoutShader.REGISTRY.registerAndGet(new SimpleCutoutShader(Flywheel.rl("cutout/off.glsl")));
|
||||
public static final CutoutShader OFF = 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")));
|
||||
public static final CutoutShader EPSILON = new SimpleCutoutShader(Flywheel.rl("cutout/epsilon.glsl"));
|
||||
/**
|
||||
* Discard fragments with alpha less than to 0.1.
|
||||
*/
|
||||
public static final CutoutShader ONE_TENTH = CutoutShader.REGISTRY.registerAndGet(new SimpleCutoutShader(Flywheel.rl("cutout/one_tenth.glsl")));
|
||||
public static final CutoutShader ONE_TENTH = new SimpleCutoutShader(Flywheel.rl("cutout/one_tenth.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 CutoutShader HALF = new SimpleCutoutShader(Flywheel.rl("cutout/half.glsl"));
|
||||
|
||||
private CutoutShaders() {
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static void init() {
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,13 @@
|
||||
package dev.engine_room.flywheel.lib.material;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import dev.engine_room.flywheel.api.Flywheel;
|
||||
import dev.engine_room.flywheel.api.material.FogShader;
|
||||
|
||||
public final class FogShaders {
|
||||
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 FogShader NONE = new SimpleFogShader(Flywheel.rl("fog/none.glsl"));
|
||||
public static final FogShader LINEAR = new SimpleFogShader(Flywheel.rl("fog/linear.glsl"));
|
||||
public static final FogShader LINEAR_FADE = new SimpleFogShader(Flywheel.rl("fog/linear_fade.glsl"));
|
||||
|
||||
private FogShaders() {
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static void init() {
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,13 @@
|
||||
package dev.engine_room.flywheel.lib.material;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import dev.engine_room.flywheel.api.Flywheel;
|
||||
import dev.engine_room.flywheel.api.material.LightShader;
|
||||
|
||||
public class LightShaders {
|
||||
public static final LightShader SMOOTH_WHEN_EMBEDDED = LightShader.REGISTRY.registerAndGet(new SimpleLightShader(Flywheel.rl("light/smooth_when_embedded.glsl")));
|
||||
public static final LightShader SMOOTH = LightShader.REGISTRY.registerAndGet(new SimpleLightShader(Flywheel.rl("light/smooth.glsl")));
|
||||
public static final LightShader FLAT = LightShader.REGISTRY.registerAndGet(new SimpleLightShader(Flywheel.rl("light/flat.glsl")));
|
||||
public static final LightShader SMOOTH_WHEN_EMBEDDED = new SimpleLightShader(Flywheel.rl("light/smooth_when_embedded.glsl"));
|
||||
public static final LightShader SMOOTH = new SimpleLightShader(Flywheel.rl("light/smooth.glsl"));
|
||||
public static final LightShader FLAT = new SimpleLightShader(Flywheel.rl("light/flat.glsl"));
|
||||
|
||||
private LightShaders() {
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static void init() {
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
package dev.engine_room.flywheel.lib.material;
|
||||
|
||||
import dev.engine_room.flywheel.api.material.DepthTest;
|
||||
import dev.engine_room.flywheel.api.material.Material;
|
||||
import dev.engine_room.flywheel.api.material.Transparency;
|
||||
import dev.engine_room.flywheel.api.material.WriteMask;
|
||||
import net.minecraft.client.renderer.entity.ItemRenderer;
|
||||
|
||||
public final class Materials {
|
||||
public static final Material SOLID_BLOCK = SimpleMaterial.builder()
|
||||
@ -46,6 +49,21 @@ public final class Materials {
|
||||
.diffuse(false)
|
||||
.build();
|
||||
|
||||
public static final Material GLINT = SimpleMaterial.builder()
|
||||
.texture(ItemRenderer.ENCHANTED_GLINT_ITEM)
|
||||
.shaders(StandardMaterialShaders.GLINT)
|
||||
.transparency(Transparency.GLINT)
|
||||
.writeMask(WriteMask.COLOR)
|
||||
.depthTest(DepthTest.EQUAL)
|
||||
.backfaceCulling(false)
|
||||
.blur(true)
|
||||
.mipmap(false)
|
||||
.build();
|
||||
|
||||
public static final Material GLINT_ENTITY = SimpleMaterial.builderOf(GLINT)
|
||||
.texture(ItemRenderer.ENCHANTED_GLINT_ENTITY)
|
||||
.build();
|
||||
|
||||
private Materials() {
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,18 @@
|
||||
package dev.engine_room.flywheel.lib.material;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import dev.engine_room.flywheel.api.Flywheel;
|
||||
import dev.engine_room.flywheel.api.material.MaterialShaders;
|
||||
|
||||
public final class StandardMaterialShaders {
|
||||
public static final MaterialShaders DEFAULT = MaterialShaders.REGISTRY.registerAndGet(new SimpleMaterialShaders(
|
||||
Flywheel.rl("material/default.vert"),
|
||||
Flywheel.rl("material/default.frag")));
|
||||
public static final MaterialShaders DEFAULT = new SimpleMaterialShaders(
|
||||
Flywheel.rl("material/default.vert"), Flywheel.rl("material/default.frag"));
|
||||
|
||||
public static final MaterialShaders WIREFRAME = MaterialShaders.REGISTRY.registerAndGet(new SimpleMaterialShaders(Flywheel.rl("material/wireframe.vert"), Flywheel.rl("material/wireframe.frag")));
|
||||
public static final MaterialShaders WIREFRAME = new SimpleMaterialShaders(Flywheel.rl("material/wireframe.vert"), Flywheel.rl("material/wireframe.frag"));
|
||||
|
||||
public static final MaterialShaders LINE = MaterialShaders.REGISTRY.registerAndGet(new SimpleMaterialShaders(Flywheel.rl("material/lines.vert"), Flywheel.rl("material/lines.frag")));
|
||||
public static final MaterialShaders LINE = new SimpleMaterialShaders(Flywheel.rl("material/lines.vert"), Flywheel.rl("material/lines.frag"));
|
||||
|
||||
public static final MaterialShaders GLINT = new SimpleMaterialShaders(Flywheel.rl("material/glint.vert"), Flywheel.rl("material/default.frag"));
|
||||
|
||||
private StandardMaterialShaders() {
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static void init() {
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import dev.engine_room.flywheel.lib.material.Materials;
|
||||
import dev.engine_room.flywheel.lib.memory.MemoryBlock;
|
||||
import dev.engine_room.flywheel.lib.vertex.PosVertexView;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.Sheets;
|
||||
import net.minecraft.client.renderer.block.BlockRenderDispatcher;
|
||||
|
||||
public final class ModelUtil {
|
||||
@ -48,6 +49,26 @@ public final class ModelUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Material getItemMaterial(RenderType renderType) {
|
||||
var chunkMaterial = getMaterial(renderType, true);
|
||||
|
||||
if (chunkMaterial != null) {
|
||||
return chunkMaterial;
|
||||
}
|
||||
|
||||
if (renderType == Sheets.translucentCullBlockSheet() || renderType == Sheets.translucentItemSheet()) {
|
||||
return Materials.CUTOUT_BLOCK;
|
||||
}
|
||||
if (renderType == RenderType.glint() || renderType == RenderType.glintDirect()) {
|
||||
return Materials.GLINT;
|
||||
}
|
||||
if (renderType == RenderType.entityGlint() || renderType == RenderType.entityGlintDirect()) {
|
||||
return Materials.GLINT_ENTITY;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int computeTotalVertexCount(Iterable<Mesh> meshes) {
|
||||
int vertexCount = 0;
|
||||
for (Mesh mesh : meshes) {
|
||||
|
@ -0,0 +1,8 @@
|
||||
void flw_materialVertex() {
|
||||
float p = flw_glintSpeedOption * flw_systemSeconds * 8.;
|
||||
|
||||
flw_vertexTexCoord *= 8.;
|
||||
// Rotate by 0.17453292 radians
|
||||
flw_vertexTexCoord *= mat2(0.98480775, 0.17364817, -0.17364817, 0.98480775);
|
||||
flw_vertexTexCoord += vec2(-p / 110., p / 30.);
|
||||
}
|
@ -6,13 +6,11 @@ import dev.engine_room.flywheel.api.backend.Backend;
|
||||
import dev.engine_room.flywheel.api.internal.FlwApiLink;
|
||||
import dev.engine_room.flywheel.api.layout.LayoutBuilder;
|
||||
import dev.engine_room.flywheel.api.registry.IdRegistry;
|
||||
import dev.engine_room.flywheel.api.registry.Registry;
|
||||
import dev.engine_room.flywheel.api.visualization.BlockEntityVisualizer;
|
||||
import dev.engine_room.flywheel.api.visualization.EntityVisualizer;
|
||||
import dev.engine_room.flywheel.api.visualization.VisualizationManager;
|
||||
import dev.engine_room.flywheel.impl.layout.LayoutBuilderImpl;
|
||||
import dev.engine_room.flywheel.impl.registry.IdRegistryImpl;
|
||||
import dev.engine_room.flywheel.impl.registry.RegistryImpl;
|
||||
import dev.engine_room.flywheel.impl.visualization.VisualizationManagerImpl;
|
||||
import dev.engine_room.flywheel.impl.visualization.VisualizerRegistryImpl;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
@ -22,11 +20,6 @@ import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
|
||||
public class FlwApiLinkImpl implements FlwApiLink {
|
||||
@Override
|
||||
public <T> Registry<T> createRegistry() {
|
||||
return new RegistryImpl<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> IdRegistry<T> createIdRegistry() {
|
||||
return new IdRegistryImpl<>();
|
||||
|
@ -6,12 +6,6 @@ import org.slf4j.LoggerFactory;
|
||||
import dev.engine_room.flywheel.api.Flywheel;
|
||||
import dev.engine_room.flywheel.backend.FlwBackend;
|
||||
import dev.engine_room.flywheel.impl.registry.IdRegistryImpl;
|
||||
import dev.engine_room.flywheel.impl.registry.RegistryImpl;
|
||||
import dev.engine_room.flywheel.lib.instance.InstanceTypes;
|
||||
import dev.engine_room.flywheel.lib.material.CutoutShaders;
|
||||
import dev.engine_room.flywheel.lib.material.FogShaders;
|
||||
import dev.engine_room.flywheel.lib.material.LightShaders;
|
||||
import dev.engine_room.flywheel.lib.material.StandardMaterialShaders;
|
||||
import dev.engine_room.flywheel.lib.util.ShadersModHandler;
|
||||
import dev.engine_room.flywheel.vanilla.VanillaVisuals;
|
||||
|
||||
@ -28,11 +22,6 @@ public final class FlwImpl {
|
||||
|
||||
// lib
|
||||
ShadersModHandler.init();
|
||||
InstanceTypes.init();
|
||||
CutoutShaders.init();
|
||||
FogShaders.init();
|
||||
LightShaders.init();
|
||||
StandardMaterialShaders.init();
|
||||
|
||||
// backend
|
||||
FlwBackend.init(FlwConfig.INSTANCE.backendConfig());
|
||||
@ -42,7 +31,6 @@ public final class FlwImpl {
|
||||
}
|
||||
|
||||
public static void freezeRegistries() {
|
||||
RegistryImpl.freezeAll();
|
||||
IdRegistryImpl.freezeAll();
|
||||
}
|
||||
}
|
||||
|
@ -1,32 +0,0 @@
|
||||
package dev.engine_room.flywheel.impl.mixin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import dev.engine_room.flywheel.api.visualization.VisualizationManager;
|
||||
import dev.engine_room.flywheel.lib.visualization.VisualizationHelper;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
|
||||
@Mixin(ClientLevel.class)
|
||||
abstract class ClientLevelMixin {
|
||||
@Inject(method = "entitiesForRendering()Ljava/lang/Iterable;", at = @At("RETURN"), cancellable = true)
|
||||
private void flywheel$filterEntities(CallbackInfoReturnable<Iterable<Entity>> cir) {
|
||||
if (!VisualizationManager.supportsVisualization((ClientLevel) (Object) this)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Iterable<Entity> entities = cir.getReturnValue();
|
||||
ArrayList<Entity> filtered = Lists.newArrayList(entities);
|
||||
|
||||
filtered.removeIf(VisualizationHelper::skipVanillaRender);
|
||||
|
||||
cir.setReturnValue(filtered);
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import dev.engine_room.flywheel.api.visualization.VisualizationManager;
|
||||
import dev.engine_room.flywheel.impl.FlwImplXplat;
|
||||
import dev.engine_room.flywheel.impl.event.RenderContextImpl;
|
||||
import dev.engine_room.flywheel.lib.visualization.VisualizationHelper;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.DeltaTracker;
|
||||
@ -24,8 +25,10 @@ import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
import net.minecraft.client.renderer.LevelRenderer;
|
||||
import net.minecraft.client.renderer.LightTexture;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.RenderBuffers;
|
||||
import net.minecraft.server.level.BlockDestructionProgress;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
|
||||
@Mixin(value = LevelRenderer.class, priority = 1001) // Higher priority to go after Sodium
|
||||
abstract class LevelRendererMixin {
|
||||
@ -119,4 +122,11 @@ abstract class LevelRendererMixin {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "renderEntity", at = @At("HEAD"), cancellable = true)
|
||||
private void flywheel$decideNotToRenderEntity(Entity pEntity, double pCamX, double pCamY, double pCamZ, float pPartialTick, PoseStack pPoseStack, MultiBufferSource pBufferSource, CallbackInfo ci) {
|
||||
if (VisualizationManager.supportsVisualization(pEntity.level()) && VisualizationHelper.skipVanillaRender(pEntity)) {
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,68 +0,0 @@
|
||||
package dev.engine_room.flywheel.impl.registry;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jetbrains.annotations.UnmodifiableView;
|
||||
|
||||
import dev.engine_room.flywheel.api.registry.Registry;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectList;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectSet;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectSets;
|
||||
|
||||
public class RegistryImpl<T> implements Registry<T> {
|
||||
private static final ObjectList<RegistryImpl<?>> ALL = new ObjectArrayList<>();
|
||||
|
||||
private final ObjectSet<T> set = ObjectSets.synchronize(new ObjectOpenHashSet<>());
|
||||
private final ObjectSet<T> setView = ObjectSets.unmodifiable(set);
|
||||
private boolean frozen;
|
||||
|
||||
public RegistryImpl() {
|
||||
ALL.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(T object) {
|
||||
if (frozen) {
|
||||
throw new IllegalStateException("Cannot register to frozen registry!");
|
||||
}
|
||||
boolean added = set.add(object);
|
||||
if (!added) {
|
||||
throw new IllegalArgumentException("Cannot override registration!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S extends T> S registerAndGet(S object) {
|
||||
register(object);
|
||||
return object;
|
||||
}
|
||||
|
||||
@Override
|
||||
@UnmodifiableView
|
||||
public Set<T> getAll() {
|
||||
return setView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFrozen() {
|
||||
return frozen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return getAll().iterator();
|
||||
}
|
||||
|
||||
private void freeze() {
|
||||
frozen = true;
|
||||
}
|
||||
|
||||
public static void freezeAll() {
|
||||
for (RegistryImpl<?> registry : ALL) {
|
||||
registry.freeze();
|
||||
}
|
||||
}
|
||||
}
|
@ -6,5 +6,9 @@
|
||||
"command.flywheel.limit_updates.get.off": "Update limiting is currently disabled",
|
||||
"command.flywheel.limit_updates.get.on": "Update limiting is currently enabled",
|
||||
"command.flywheel.limit_updates.set.off": "Update limiting is now disabled",
|
||||
"command.flywheel.limit_updates.set.on": "Update limiting is now enabled"
|
||||
"command.flywheel.limit_updates.set.on" : "Update limiting is now enabled",
|
||||
"command.flywheel.use_light_directions.get.off" : "Not using light directions",
|
||||
"command.flywheel.use_light_directions.get.on" : "Using light directions",
|
||||
"command.flywheel.use_light_directions.set.off" : "Set light directions to off",
|
||||
"command.flywheel.use_light_directions.set.on" : "Set light directions to on"
|
||||
}
|
||||
|
@ -8,7 +8,6 @@
|
||||
"BlockEntityTypeMixin",
|
||||
"BufferBuilderAccessor",
|
||||
"ClientChunkCacheMixin",
|
||||
"ClientLevelMixin",
|
||||
"EntityTypeMixin",
|
||||
"LevelMixin",
|
||||
"LevelRendererMixin",
|
||||
|
@ -185,16 +185,24 @@ public class FabricFlwConfig implements FlwConfig {
|
||||
|
||||
public static class FabricBackendConfig implements BackendConfig {
|
||||
public static final LightSmoothness LIGHT_SMOOTHNESS_DEFAULT = LightSmoothness.SMOOTH;
|
||||
public static final boolean USE_LIGHT_DIRECTIONS_DEFAULT = true;
|
||||
|
||||
public LightSmoothness lightSmoothness = LIGHT_SMOOTHNESS_DEFAULT;
|
||||
public boolean useLightDirections = USE_LIGHT_DIRECTIONS_DEFAULT;
|
||||
|
||||
@Override
|
||||
public LightSmoothness lightSmoothness() {
|
||||
return lightSmoothness;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useLightDirections() {
|
||||
return useLightDirections;
|
||||
}
|
||||
|
||||
public void fromJson(JsonObject object) {
|
||||
readLightSmoothness(object);
|
||||
readUseLightDirections(object);
|
||||
}
|
||||
|
||||
private void readLightSmoothness(JsonObject object) {
|
||||
@ -224,9 +232,23 @@ public class FabricFlwConfig implements FlwConfig {
|
||||
lightSmoothness = LIGHT_SMOOTHNESS_DEFAULT;
|
||||
}
|
||||
|
||||
private void readUseLightDirections(JsonObject object) {
|
||||
var useLightDirectionsJson = object.get("useLightDirections");
|
||||
|
||||
if (useLightDirectionsJson instanceof JsonPrimitive primitive && primitive.isBoolean()) {
|
||||
useLightDirections = primitive.getAsBoolean();
|
||||
return;
|
||||
} else if (useLightDirectionsJson != null) {
|
||||
FlwBackend.LOGGER.warn("'useLightDirections' value must be a boolean");
|
||||
}
|
||||
|
||||
useLightDirections = USE_LIGHT_DIRECTIONS_DEFAULT;
|
||||
}
|
||||
|
||||
public JsonObject toJson() {
|
||||
JsonObject object = new JsonObject();
|
||||
object.addProperty("lightSmoothness", lightSmoothness.getSerializedName());
|
||||
object.addProperty("useLightDirections", useLightDirections);
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import com.mojang.brigadier.context.CommandContext;
|
||||
import dev.engine_room.flywheel.api.backend.Backend;
|
||||
import dev.engine_room.flywheel.api.backend.BackendManager;
|
||||
import dev.engine_room.flywheel.backend.compile.LightSmoothness;
|
||||
import dev.engine_room.flywheel.backend.compile.PipelineCompiler;
|
||||
import dev.engine_room.flywheel.backend.engine.uniform.DebugMode;
|
||||
import dev.engine_room.flywheel.backend.engine.uniform.FrameUniforms;
|
||||
import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager;
|
||||
@ -133,12 +134,39 @@ public final class FlwCommands {
|
||||
if (oldValue != newValue) {
|
||||
FabricFlwConfig.INSTANCE.backendConfig.lightSmoothness = newValue;
|
||||
FabricFlwConfig.INSTANCE.save();
|
||||
Minecraft.getInstance()
|
||||
.reloadResourcePacks();
|
||||
PipelineCompiler.deleteAll();
|
||||
}
|
||||
return Command.SINGLE_SUCCESS;
|
||||
})));
|
||||
|
||||
command.then(ClientCommandManager.literal("useLightDirections")
|
||||
.executes(context -> {
|
||||
if (FabricFlwConfig.INSTANCE.backendConfig.useLightDirections) {
|
||||
context.getSource()
|
||||
.sendFeedback(Component.translatable("command.flywheel.use_light_directions.get.on"));
|
||||
} else {
|
||||
context.getSource()
|
||||
.sendFeedback(Component.translatable("command.flywheel.use_light_directions.get.off"));
|
||||
}
|
||||
return Command.SINGLE_SUCCESS;
|
||||
})
|
||||
.then(ClientCommandManager.literal("on")
|
||||
.executes(context -> {
|
||||
FabricFlwConfig.INSTANCE.backendConfig.useLightDirections = true;
|
||||
FabricFlwConfig.INSTANCE.save();
|
||||
context.getSource()
|
||||
.sendFeedback(Component.translatable("command.flywheel.use_light_directions.set.on"));
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}))
|
||||
.then(ClientCommandManager.literal("off")
|
||||
.executes(context -> {
|
||||
FabricFlwConfig.INSTANCE.backendConfig.useLightDirections = false;
|
||||
FabricFlwConfig.INSTANCE.save();
|
||||
context.getSource()
|
||||
.sendFeedback(Component.translatable("command.flywheel.use_light_directions.set.off"));
|
||||
return Command.SINGLE_SUCCESS;
|
||||
})));
|
||||
|
||||
dispatcher.register(command);
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import dev.engine_room.flywheel.api.backend.Backend;
|
||||
import dev.engine_room.flywheel.api.backend.BackendManager;
|
||||
import dev.engine_room.flywheel.backend.compile.LightSmoothness;
|
||||
import dev.engine_room.flywheel.backend.compile.PipelineCompiler;
|
||||
import dev.engine_room.flywheel.backend.engine.uniform.DebugMode;
|
||||
import dev.engine_room.flywheel.backend.engine.uniform.FrameUniforms;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@ -131,12 +132,34 @@ public final class FlwCommands {
|
||||
|
||||
if (oldValue != newValue) {
|
||||
lightSmoothnessValue.set(newValue);
|
||||
Minecraft.getInstance()
|
||||
.reloadResourcePacks();
|
||||
PipelineCompiler.deleteAll();
|
||||
}
|
||||
return Command.SINGLE_SUCCESS;
|
||||
})));
|
||||
|
||||
var useLightDirectionsValue = ForgeFlwConfig.INSTANCE.client.backendConfig.useLightDirections;
|
||||
command.then(Commands.literal("useLightDirections")
|
||||
.executes(context -> {
|
||||
if (useLightDirectionsValue.get()) {
|
||||
sendMessage(context.getSource(), Component.translatable("command.flywheel.use_light_directions.get.on"));
|
||||
} else {
|
||||
sendMessage(context.getSource(), Component.translatable("command.flywheel.use_light_directions.get.off"));
|
||||
}
|
||||
return Command.SINGLE_SUCCESS;
|
||||
})
|
||||
.then(Commands.literal("on")
|
||||
.executes(context -> {
|
||||
useLightDirectionsValue.set(true);
|
||||
sendMessage(context.getSource(), Component.translatable("command.flywheel.use_light_directions.set.on"));
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}))
|
||||
.then(Commands.literal("off")
|
||||
.executes(context -> {
|
||||
useLightDirectionsValue.set(false);
|
||||
sendMessage(context.getSource(), Component.translatable("command.flywheel.use_light_directions.set.off"));
|
||||
return Command.SINGLE_SUCCESS;
|
||||
})));
|
||||
|
||||
event.getDispatcher().register(command);
|
||||
}
|
||||
|
||||
|
@ -101,15 +101,24 @@ public class ForgeFlwConfig implements FlwConfig {
|
||||
|
||||
public static class ForgeBackendConfig implements BackendConfig {
|
||||
public final ModConfigSpec.EnumValue<LightSmoothness> lightSmoothness;
|
||||
public final ForgeConfigSpec.BooleanValue useLightDirections;
|
||||
|
||||
public ForgeBackendConfig(ModConfigSpec.Builder builder) {
|
||||
lightSmoothness = builder.comment("How smooth flywheel's shader-based lighting should be. May have a large performance impact.")
|
||||
.defineEnum("lightSmoothness", LightSmoothness.SMOOTH);
|
||||
|
||||
useLightDirections = builder.comment("If true, diffuse lighting is accurate to vanilla entities and block entities. If false, diffuse lighting is accurate to vanilla chunks. Zero performance impact, just a matter of visual preference.")
|
||||
.define("useLightDirections", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LightSmoothness lightSmoothness() {
|
||||
return lightSmoothness.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useLightDirections() {
|
||||
return useLightDirections.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user