mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-14 00:06:12 +01:00
Compile everything on the fly
- Simplify game state system - Need some way to re-add errors on load. - Streamline shader compilation, reduce map lookups - Move pipeline package from backend to core - Simplify interfaces and remove unnecessary classes
This commit is contained in:
parent
aca216cf9a
commit
1b09c2c1eb
40 changed files with 269 additions and 514 deletions
|
@ -1,15 +0,0 @@
|
|||
package com.jozufozu.flywheel.api.shader;
|
||||
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
|
||||
/**
|
||||
* Represents a vertex format agnostic shader.
|
||||
*/
|
||||
public interface FlexibleShader<P extends GlProgram> {
|
||||
|
||||
/**
|
||||
* Get a version of this shader that accepts the given VertexType as input.
|
||||
*/
|
||||
P get(VertexType type);
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
package com.jozufozu.flywheel.backend;
|
||||
|
||||
import com.jozufozu.flywheel.api.shader.FlexibleShader;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
|
||||
|
@ -8,12 +7,7 @@ import net.minecraft.resources.ResourceLocation;
|
|||
|
||||
public interface ShaderContext<P extends GlProgram> {
|
||||
|
||||
default P getProgram(ResourceLocation loc, VertexType inputType) {
|
||||
return this.getProgramSupplier(loc)
|
||||
.get(inputType);
|
||||
}
|
||||
|
||||
FlexibleShader<P> getProgramSupplier(ResourceLocation loc);
|
||||
P getProgram(ResourceLocation loc, VertexType vertexType);
|
||||
|
||||
/**
|
||||
* Load all programs associated with this context. This might be just one, if the context is very specialized.
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
package com.jozufozu.flywheel.backend.gl.shader;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.lwjgl.opengl.GL20;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.gl.GlObject;
|
||||
import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
|
||||
import com.jozufozu.flywheel.backend.pipeline.ShaderCompiler;
|
||||
import com.jozufozu.flywheel.backend.source.ShaderLoadingException;
|
||||
import com.jozufozu.flywheel.backend.source.error.ErrorBuilder;
|
||||
import com.jozufozu.flywheel.backend.source.error.ErrorReporter;
|
||||
import com.jozufozu.flywheel.core.pipeline.ShaderCompiler;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
|
@ -30,27 +25,7 @@ public class GlShader extends GlObject {
|
|||
String log = GL20.glGetShaderInfoLog(handle);
|
||||
|
||||
if (!log.isEmpty()) {
|
||||
List<String> lines = log.lines()
|
||||
.toList();
|
||||
|
||||
boolean needsSourceDump = false;
|
||||
|
||||
StringBuilder errors = new StringBuilder();
|
||||
for (String line : lines) {
|
||||
ErrorBuilder builder = env.parseCompilerError(line);
|
||||
|
||||
if (builder != null) {
|
||||
errors.append(builder.build());
|
||||
} else {
|
||||
errors.append(line).append('\n');
|
||||
needsSourceDump = true;
|
||||
}
|
||||
}
|
||||
Backend.LOGGER.error("Errors compiling '" + name + "': \n" + errors);
|
||||
if (needsSourceDump) {
|
||||
// TODO: generated code gets its own "file"
|
||||
ErrorReporter.printLines(source);
|
||||
}
|
||||
env.printShaderInfoLog(source, log, this.name);
|
||||
}
|
||||
|
||||
if (GL20.glGetShaderi(handle, GL20.GL_COMPILE_STATUS) != GL20.GL_TRUE) {
|
||||
|
@ -64,4 +39,5 @@ public class GlShader extends GlObject {
|
|||
protected void deleteInternal(int handle) {
|
||||
GL20.glDeleteShader(handle);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import java.util.stream.Stream;
|
|||
import javax.annotation.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.api.MaterialGroup;
|
||||
import com.jozufozu.flywheel.api.shader.FlexibleShader;
|
||||
import com.jozufozu.flywheel.backend.RenderLayer;
|
||||
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
|
||||
|
@ -24,7 +23,6 @@ import net.minecraft.client.Camera;
|
|||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Vec3i;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Mth;
|
||||
|
||||
public class InstancingEngine<P extends WorldProgram> implements Engine {
|
||||
|
@ -126,10 +124,6 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
}
|
||||
}
|
||||
|
||||
public FlexibleShader<P> getProgram(ResourceLocation name) {
|
||||
return context.getProgramSupplier(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3i getOriginCoordinate() {
|
||||
return originCoordinate;
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.pipeline;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.jozufozu.flywheel.api.shader.FlexibleShader;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.core.shader.ContextAwareProgram;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
import com.jozufozu.flywheel.core.shader.spec.ProgramSpec;
|
||||
|
||||
public class LazyCompiler<P extends WorldProgram> implements FlexibleShader<P> {
|
||||
|
||||
private final ShaderPipeline<P> pipeline;
|
||||
private final ProgramSpec spec;
|
||||
|
||||
private final Map<VertexType, ContextAwareProgram<P>> cache = new HashMap<>();
|
||||
|
||||
public LazyCompiler(ShaderPipeline<P> pipeline, ProgramSpec spec) {
|
||||
|
||||
this.pipeline = pipeline;
|
||||
this.spec = spec;
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
cache.values().forEach(ContextAwareProgram::delete);
|
||||
}
|
||||
|
||||
@Override
|
||||
public P get(VertexType type) {
|
||||
return cache.computeIfAbsent(type, t -> pipeline.compile(spec, t)).get();
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.pipeline;
|
||||
|
||||
public class Shader {
|
||||
|
||||
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.pipeline;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.jozufozu.flywheel.backend.source.parse.ShaderStruct;
|
||||
import com.jozufozu.flywheel.backend.source.parse.StructField;
|
||||
|
||||
/**
|
||||
* A single input to a shader.
|
||||
*/
|
||||
public class ShaderInput {
|
||||
public final CharSequence name;
|
||||
public final int attribCount;
|
||||
|
||||
public ShaderInput(CharSequence name, int attribCount) {
|
||||
this.name = name;
|
||||
this.attribCount = attribCount;
|
||||
}
|
||||
|
||||
public ShaderInput withPrefix(CharSequence prefix) {
|
||||
return new ShaderInput(prefix.toString() + name, attribCount);
|
||||
}
|
||||
|
||||
public static Collection<ShaderInput> fromStruct(ShaderStruct struct, String prefix) {
|
||||
return struct.getFields()
|
||||
.stream()
|
||||
.map(ShaderInput::from)
|
||||
.map(a -> a.withPrefix(prefix))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static ShaderInput from(StructField field) {
|
||||
int attributeCount = TypeHelper.getAttributeCount(field.type);
|
||||
|
||||
return new ShaderInput(field.name, attributeCount);
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.pipeline;
|
||||
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.core.shader.ContextAwareProgram;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
import com.jozufozu.flywheel.core.shader.spec.ProgramSpec;
|
||||
|
||||
/**
|
||||
* The main interface for compiling usable shaders from program specs.
|
||||
* @param <P> the type of the program that this pipeline compiles.
|
||||
*/
|
||||
public interface ShaderPipeline<P extends WorldProgram> {
|
||||
|
||||
ContextAwareProgram<P> compile(ProgramSpec spec, VertexType vertexType);
|
||||
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.pipeline;
|
||||
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.source.FileResolution;
|
||||
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||
import com.jozufozu.flywheel.core.shader.ContextAwareProgram;
|
||||
import com.jozufozu.flywheel.core.shader.ExtensibleGlProgram;
|
||||
import com.jozufozu.flywheel.core.shader.GameStateProgram;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
import com.jozufozu.flywheel.core.shader.spec.ProgramSpec;
|
||||
import com.jozufozu.flywheel.core.shader.spec.ProgramState;
|
||||
|
||||
public class WorldShaderPipeline<P extends WorldProgram> implements ShaderPipeline<P> {
|
||||
|
||||
private final ExtensibleGlProgram.Factory<P> factory;
|
||||
|
||||
private final Template<?> template;
|
||||
private final FileResolution header;
|
||||
|
||||
public WorldShaderPipeline(ExtensibleGlProgram.Factory<P> factory, Template<?> template, FileResolution header) {
|
||||
this.factory = factory;
|
||||
this.template = template;
|
||||
this.header = header;
|
||||
}
|
||||
|
||||
public ContextAwareProgram<P> compile(ProgramSpec spec, VertexType vertexType) {
|
||||
|
||||
SourceFile file = spec.getSource().getFile();
|
||||
|
||||
ShaderCompiler shader = new ShaderCompiler(spec.name, file, template, header, vertexType);
|
||||
|
||||
GameStateProgram.Builder<P> builder = GameStateProgram.builder(shader.compile(this.factory));
|
||||
for (ProgramState variant : spec.getStates()) {
|
||||
shader.setVariant(variant);
|
||||
builder.withVariant(variant.context(), shader.compile(this.factory));
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
}
|
|
@ -3,8 +3,6 @@ package com.jozufozu.flywheel.backend.source;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.source.error.ErrorBuilder;
|
||||
import com.jozufozu.flywheel.backend.source.span.Span;
|
||||
|
@ -37,7 +35,6 @@ public class FileResolution {
|
|||
return fileLoc;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SourceFile getFile() {
|
||||
return file;
|
||||
}
|
||||
|
@ -73,6 +70,7 @@ public class FileResolution {
|
|||
.pointAt(span, 1);
|
||||
}
|
||||
Backend.LOGGER.error(builder.build());
|
||||
throw new ShaderLoadingException();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,13 +10,13 @@ import java.util.regex.Pattern;
|
|||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.jozufozu.flywheel.backend.pipeline.ShaderCompiler;
|
||||
import com.jozufozu.flywheel.backend.source.parse.Import;
|
||||
import com.jozufozu.flywheel.backend.source.parse.ShaderFunction;
|
||||
import com.jozufozu.flywheel.backend.source.parse.ShaderStruct;
|
||||
import com.jozufozu.flywheel.backend.source.span.ErrorSpan;
|
||||
import com.jozufozu.flywheel.backend.source.span.Span;
|
||||
import com.jozufozu.flywheel.backend.source.span.StringSpan;
|
||||
import com.jozufozu.flywheel.core.pipeline.ShaderCompiler;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
|
@ -138,12 +138,6 @@ public class SourceFile {
|
|||
return "#use " + '"' + name + '"';
|
||||
}
|
||||
|
||||
public CharSequence generateFinalSource(ShaderCompiler env) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
generateFinalSource(env, builder);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public void generateFinalSource(ShaderCompiler env, StringBuilder source) {
|
||||
for (Import include : imports) {
|
||||
SourceFile file = include.getFile();
|
||||
|
@ -151,24 +145,16 @@ public class SourceFile {
|
|||
if (file != null) file.generateFinalSource(env, source);
|
||||
}
|
||||
|
||||
int i = env.allocateFile(this);
|
||||
source.append("#line ")
|
||||
.append(0)
|
||||
.append(' ')
|
||||
.append(i)
|
||||
.append(env.getFileID(this))
|
||||
.append('\n');
|
||||
source.append(elided);
|
||||
}
|
||||
|
||||
public String printSource() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
builder.append("Source for shader '")
|
||||
.append(name)
|
||||
.append("':\n")
|
||||
.append(lines.printLinesWithNumbers());
|
||||
|
||||
return builder.toString();
|
||||
return "Source for shader '" + name + "':\n" + lines.printLinesWithNumbers();
|
||||
}
|
||||
|
||||
private static CharSequence elideSource(String source, List<Span> elisions) {
|
||||
|
|
|
@ -7,7 +7,6 @@ import java.util.regex.Pattern;
|
|||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.backend.pipeline.ShaderCompiler;
|
||||
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||
import com.jozufozu.flywheel.backend.source.SourceLines;
|
||||
import com.jozufozu.flywheel.backend.source.error.lines.ErrorLine;
|
||||
|
@ -17,6 +16,7 @@ import com.jozufozu.flywheel.backend.source.error.lines.SourceLine;
|
|||
import com.jozufozu.flywheel.backend.source.error.lines.SpanHighlightLine;
|
||||
import com.jozufozu.flywheel.backend.source.error.lines.TextLine;
|
||||
import com.jozufozu.flywheel.backend.source.span.Span;
|
||||
import com.jozufozu.flywheel.core.pipeline.ShaderCompiler;
|
||||
import com.jozufozu.flywheel.util.FlwUtil;
|
||||
|
||||
public class ErrorBuilder {
|
||||
|
|
|
@ -3,11 +3,11 @@ package com.jozufozu.flywheel.core;
|
|||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.GameStateRegistry;
|
||||
import com.jozufozu.flywheel.backend.pipeline.ShaderPipeline;
|
||||
import com.jozufozu.flywheel.backend.pipeline.WorldShaderPipeline;
|
||||
import com.jozufozu.flywheel.backend.source.FileResolution;
|
||||
import com.jozufozu.flywheel.backend.source.Resolver;
|
||||
import com.jozufozu.flywheel.core.crumbling.CrumblingProgram;
|
||||
import com.jozufozu.flywheel.core.pipeline.PipelineCompiler;
|
||||
import com.jozufozu.flywheel.core.pipeline.WorldCompiler;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
import com.jozufozu.flywheel.core.shader.gamestate.NormalDebugStateProvider;
|
||||
import com.jozufozu.flywheel.event.GatherContextEvent;
|
||||
|
@ -31,8 +31,8 @@ public class Contexts {
|
|||
FileResolution crumblingBuiltins = Resolver.INSTANCE.findShader(ResourceUtil.subPath(Names.CRUMBLING, ".glsl"));
|
||||
FileResolution worldBuiltins = Resolver.INSTANCE.findShader(ResourceUtil.subPath(Names.WORLD, ".glsl"));
|
||||
|
||||
ShaderPipeline<CrumblingProgram> crumblingPipeline = new WorldShaderPipeline<>(CrumblingProgram::new, Templates.INSTANCING, crumblingBuiltins);
|
||||
ShaderPipeline<WorldProgram> worldPipeline = new WorldShaderPipeline<>(WorldProgram::new, Templates.INSTANCING, worldBuiltins);
|
||||
PipelineCompiler<CrumblingProgram> crumblingPipeline = new WorldCompiler<>(CrumblingProgram::new, Templates.INSTANCING, crumblingBuiltins);
|
||||
PipelineCompiler<WorldProgram> worldPipeline = new WorldCompiler<>(WorldProgram::new, Templates.INSTANCING, worldBuiltins);
|
||||
|
||||
CRUMBLING = backend.register(WorldContext.builder(backend, Names.CRUMBLING).build(crumblingPipeline));
|
||||
WORLD = backend.register(WorldContext.builder(backend, Names.WORLD).build(worldPipeline));
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package com.jozufozu.flywheel.core;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
||||
import com.jozufozu.flywheel.backend.pipeline.InstancingTemplateData;
|
||||
import com.jozufozu.flywheel.backend.pipeline.OneShotTemplateData;
|
||||
import com.jozufozu.flywheel.backend.pipeline.Template;
|
||||
import com.jozufozu.flywheel.core.pipeline.InstancingTemplateData;
|
||||
import com.jozufozu.flywheel.core.pipeline.OneShotTemplateData;
|
||||
import com.jozufozu.flywheel.core.pipeline.Template;
|
||||
|
||||
public class Templates {
|
||||
|
||||
|
|
|
@ -6,13 +6,13 @@ import java.util.Objects;
|
|||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.jozufozu.flywheel.api.shader.FlexibleShader;
|
||||
import com.jozufozu.flywheel.api.struct.Instanced;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.ShaderContext;
|
||||
import com.jozufozu.flywheel.backend.pipeline.LazyCompiler;
|
||||
import com.jozufozu.flywheel.backend.pipeline.ShaderPipeline;
|
||||
import com.jozufozu.flywheel.backend.source.ShaderLoadingException;
|
||||
import com.jozufozu.flywheel.core.pipeline.CachingCompiler;
|
||||
import com.jozufozu.flywheel.core.pipeline.PipelineCompiler;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
import com.jozufozu.flywheel.core.shader.spec.ProgramSpec;
|
||||
|
||||
|
@ -20,17 +20,16 @@ import net.minecraft.resources.ResourceLocation;
|
|||
|
||||
public class WorldContext<P extends WorldProgram> implements ShaderContext<P> {
|
||||
public final Backend backend;
|
||||
protected final Map<ResourceLocation, LazyCompiler<P>> programs = new HashMap<>();
|
||||
protected final Map<ResourceLocation, ProgramSpec> programs = new HashMap<>();
|
||||
protected final ResourceLocation name;
|
||||
protected final Supplier<Stream<ResourceLocation>> specStream;
|
||||
private final CachingCompiler<P> programCache;
|
||||
|
||||
public final ShaderPipeline<P> pipeline;
|
||||
|
||||
public WorldContext(Backend backend, ResourceLocation name, Supplier<Stream<ResourceLocation>> specStream, ShaderPipeline<P> pipeline) {
|
||||
public WorldContext(Backend backend, ResourceLocation name, Supplier<Stream<ResourceLocation>> specStream, PipelineCompiler<P> pipeline) {
|
||||
this.backend = backend;
|
||||
this.name = name;
|
||||
this.specStream = specStream;
|
||||
this.pipeline = pipeline;
|
||||
this.programCache = new CachingCompiler<>(pipeline);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -46,7 +45,7 @@ public class WorldContext<P extends WorldProgram> implements ShaderContext<P> {
|
|||
private void loadSpec(ProgramSpec spec) {
|
||||
|
||||
try {
|
||||
programs.put(spec.name, new LazyCompiler<>(pipeline, spec));
|
||||
programs.put(spec.name, spec);
|
||||
|
||||
Backend.LOGGER.debug("Loaded program {}", spec.name);
|
||||
} catch (Exception e) {
|
||||
|
@ -59,14 +58,19 @@ public class WorldContext<P extends WorldProgram> implements ShaderContext<P> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public FlexibleShader<P> getProgramSupplier(ResourceLocation spec) {
|
||||
return programs.get(spec);
|
||||
public P getProgram(ResourceLocation loc, VertexType vertexType) {
|
||||
ProgramSpec spec = programs.get(loc);
|
||||
|
||||
if (spec == null) {
|
||||
throw new NullPointerException("Cannot compile shader because '" + loc + "' is not recognized.");
|
||||
}
|
||||
|
||||
return programCache.getProgram(spec, vertexType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
programs.values()
|
||||
.forEach(LazyCompiler::delete);
|
||||
programCache.invalidate();
|
||||
programs.clear();
|
||||
}
|
||||
|
||||
|
@ -89,7 +93,7 @@ public class WorldContext<P extends WorldProgram> implements ShaderContext<P> {
|
|||
return this;
|
||||
}
|
||||
|
||||
public <P extends WorldProgram> WorldContext<P> build(ShaderPipeline<P> pipeline) {
|
||||
public <P extends WorldProgram> WorldContext<P> build(PipelineCompiler<P> pipeline) {
|
||||
if (specStream == null) {
|
||||
specStream = () -> backend.allMaterials()
|
||||
.stream()
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.jozufozu.flywheel.core.materials;
|
||||
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.util.Color;
|
||||
|
||||
import net.minecraft.client.renderer.LightTexture;
|
||||
|
||||
|
@ -33,6 +34,15 @@ public abstract class BasicData extends InstanceData implements FlatLit<BasicDat
|
|||
return LightTexture.pack(this.blockLight, this.skyLight);
|
||||
}
|
||||
|
||||
public BasicData setColor(Color color) {
|
||||
this.r = (byte) color.getRed();
|
||||
this.g = (byte) color.getGreen();
|
||||
this.b = (byte) color.getBlue();
|
||||
this.a = (byte) color.getAlpha();
|
||||
markDirty();
|
||||
return this;
|
||||
}
|
||||
|
||||
public BasicData setColor(int color) {
|
||||
return setColor(color, false);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
package com.jozufozu.flywheel.core.pipeline;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.core.shader.spec.ProgramSpec;
|
||||
|
||||
/**
|
||||
* Lazily compiles shader programs, caching the results.
|
||||
*
|
||||
* @param <P> The class that the PipelineCompiler outputs.
|
||||
*/
|
||||
public class CachingCompiler<P extends GlProgram> {
|
||||
protected final Map<CompilationContext, P> cache = new HashMap<>();
|
||||
private final PipelineCompiler<P> pipeline;
|
||||
|
||||
public CachingCompiler(PipelineCompiler<P> pipeline) {
|
||||
this.pipeline = pipeline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or compile a spec to the given vertex type, accounting for all game state conditions specified by the spec.
|
||||
*
|
||||
* @param spec The ProgramSpec to target.
|
||||
* @param vertexType The VertexType to target.
|
||||
* @return A compiled GlProgram.
|
||||
*/
|
||||
public P getProgram(ProgramSpec spec, VertexType vertexType) {
|
||||
return cache.computeIfAbsent(new CompilationContext(vertexType, spec, spec.getCurrentStateID()), this.pipeline::compile);
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
cache.values().forEach(P::delete);
|
||||
cache.clear();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package com.jozufozu.flywheel.core.pipeline;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||
import com.jozufozu.flywheel.core.shader.spec.ProgramSpec;
|
||||
|
||||
/**
|
||||
* Represents the entire context of a program's usage.
|
||||
*
|
||||
* @param vertexType The vertexType the program should be adapted for.
|
||||
* @param spec The generic program name.
|
||||
* @param ctx An ID representing the state at the time of usage.
|
||||
*/
|
||||
public record CompilationContext(VertexType vertexType, ProgramSpec spec, long ctx) {
|
||||
|
||||
public SourceFile getFile() {
|
||||
return spec().getSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
CompilationContext that = (CompilationContext) o;
|
||||
// override for instance equality on vertexType
|
||||
return ctx == that.ctx && vertexType == that.vertexType && spec.equals(that.spec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(vertexType, spec, ctx);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package com.jozufozu.flywheel.backend.pipeline;
|
||||
package com.jozufozu.flywheel.core.pipeline;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
|
@ -107,7 +107,7 @@ public class InstancingTemplateData implements TemplateData {
|
|||
.append("a_i_")
|
||||
.append(field.name)
|
||||
.append(";\n");
|
||||
attributeBinding += ShaderInput.from(field).attribCount;
|
||||
attributeBinding += TypeHelper.getAttributeCount(field.type);
|
||||
}
|
||||
Template.prefixFields(template, interpolant, "out", "v2f_");
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.jozufozu.flywheel.backend.pipeline;
|
||||
package com.jozufozu.flywheel.core.pipeline;
|
||||
|
||||
import java.util.Optional;
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.jozufozu.flywheel.core.pipeline;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
|
||||
/**
|
||||
* The main interface for compiling usable shaders from program specs.
|
||||
* @param <P> the type of the program that this pipeline compiles.
|
||||
*/
|
||||
public interface PipelineCompiler<P extends GlProgram> {
|
||||
|
||||
P compile(CompilationContext vertexType);
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package com.jozufozu.flywheel.backend.pipeline;
|
||||
package com.jozufozu.flywheel.core.pipeline;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.GL_TRUE;
|
||||
import static org.lwjgl.opengl.GL20.GL_LINK_STATUS;
|
|
@ -1,4 +1,4 @@
|
|||
package com.jozufozu.flywheel.backend.pipeline;
|
||||
package com.jozufozu.flywheel.core.pipeline;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -6,15 +6,16 @@ import java.util.List;
|
|||
import javax.annotation.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlShader;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
||||
import com.jozufozu.flywheel.backend.source.FileResolution;
|
||||
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||
import com.jozufozu.flywheel.backend.source.error.ErrorBuilder;
|
||||
import com.jozufozu.flywheel.backend.source.error.ErrorReporter;
|
||||
import com.jozufozu.flywheel.backend.source.span.Span;
|
||||
import com.jozufozu.flywheel.core.shader.ExtensibleGlProgram;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
import com.jozufozu.flywheel.core.shader.spec.ProgramState;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
|
@ -24,27 +25,22 @@ public class ShaderCompiler {
|
|||
public final Template<?> template;
|
||||
private final FileResolution header;
|
||||
|
||||
@Nullable
|
||||
private ProgramState variant;
|
||||
private final List<String> defines;
|
||||
|
||||
public final VertexType vertexType;
|
||||
|
||||
public SourceFile mainFile;
|
||||
public final SourceFile mainFile;
|
||||
|
||||
public ShaderCompiler(ResourceLocation name, SourceFile mainSource, Template<?> template, FileResolution header, VertexType vertexType) {
|
||||
this.name = name;
|
||||
private final List<SourceFile> files = new ArrayList<>();
|
||||
|
||||
public ShaderCompiler(CompilationContext usage, Template<?> template, FileResolution header) {
|
||||
this.name = usage.spec().name;
|
||||
this.template = template;
|
||||
this.header = header;
|
||||
this.mainFile = mainSource;
|
||||
this.vertexType = vertexType;
|
||||
}
|
||||
|
||||
public ShaderCompiler setMainSource(SourceFile file) {
|
||||
if (mainFile == file) return this;
|
||||
|
||||
mainFile = file;
|
||||
|
||||
return this;
|
||||
this.mainFile = usage.getFile();
|
||||
this.defines = usage.spec()
|
||||
.getDefines(usage.ctx());
|
||||
this.vertexType = usage.vertexType();
|
||||
}
|
||||
|
||||
public GlShader compile(ShaderType type) {
|
||||
|
@ -60,13 +56,10 @@ public class ShaderCompiler {
|
|||
.append(type.define) // special case shader type declaration
|
||||
.append('\n');
|
||||
|
||||
ProgramState variant = getVariant();
|
||||
if (variant != null) {
|
||||
for (String def : variant.defines()) {
|
||||
finalSource.append("#define ")
|
||||
.append(def)
|
||||
.append('\n');
|
||||
}
|
||||
for (String def : defines) {
|
||||
finalSource.append("#define ")
|
||||
.append(def)
|
||||
.append('\n');
|
||||
}
|
||||
|
||||
if (type == ShaderType.VERTEX) {
|
||||
|
@ -83,9 +76,7 @@ public class ShaderCompiler {
|
|||
}
|
||||
|
||||
files.clear();
|
||||
if (header.getFile() != null) {
|
||||
header.getFile().generateFinalSource(this, finalSource);
|
||||
}
|
||||
header.getFile().generateFinalSource(this, finalSource);
|
||||
mainFile.generateFinalSource(this, finalSource);
|
||||
|
||||
template.getMetadata(mainFile).generateFooter(finalSource, type, this);
|
||||
|
@ -93,18 +84,21 @@ public class ShaderCompiler {
|
|||
return new GlShader(this, type, finalSource.toString());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ProgramState getVariant() {
|
||||
return variant;
|
||||
public <P extends WorldProgram> P compile(ExtensibleGlProgram.Factory<P> worldShaderPipeline) {
|
||||
return new ProgramAssembler(this.name)
|
||||
.attachShader(compile(ShaderType.VERTEX))
|
||||
.attachShader(compile(ShaderType.FRAGMENT))
|
||||
.link()
|
||||
.deleteLinkedShaders()
|
||||
.build(worldShaderPipeline);
|
||||
}
|
||||
|
||||
public void setVariant(@Nullable ProgramState variant) {
|
||||
this.variant = variant;
|
||||
}
|
||||
|
||||
private final List<SourceFile> files = new ArrayList<>();
|
||||
|
||||
public int allocateFile(SourceFile sourceFile) {
|
||||
/**
|
||||
* Returns an arbitrary file ID for use this compilation context, or generates one if missing.
|
||||
* @param sourceFile The file to retrieve the ID for.
|
||||
* @return A file ID unique to the given sourceFile.
|
||||
*/
|
||||
public int getFileID(SourceFile sourceFile) {
|
||||
int i = files.indexOf(sourceFile);
|
||||
if (i != -1) {
|
||||
return i;
|
||||
|
@ -121,8 +115,32 @@ public class ShaderCompiler {
|
|||
return file.getLineSpanNoWhitespace(lineNo);
|
||||
}
|
||||
|
||||
public void printShaderInfoLog(String source, String log, ResourceLocation name) {
|
||||
List<String> lines = log.lines()
|
||||
.toList();
|
||||
|
||||
boolean needsSourceDump = false;
|
||||
|
||||
StringBuilder errors = new StringBuilder();
|
||||
for (String line : lines) {
|
||||
ErrorBuilder builder = parseCompilerError(line);
|
||||
|
||||
if (builder != null) {
|
||||
errors.append(builder.build());
|
||||
} else {
|
||||
errors.append(line).append('\n');
|
||||
needsSourceDump = true;
|
||||
}
|
||||
}
|
||||
Backend.LOGGER.error("Errors compiling '" + name + "': \n" + errors);
|
||||
if (needsSourceDump) {
|
||||
// TODO: generated code gets its own "file"
|
||||
ErrorReporter.printLines(source);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ErrorBuilder parseCompilerError(String line) {
|
||||
private ErrorBuilder parseCompilerError(String line) {
|
||||
try {
|
||||
ErrorBuilder error = ErrorBuilder.fromLogLine(this, line);
|
||||
if (error != null) {
|
||||
|
@ -133,13 +151,4 @@ public class ShaderCompiler {
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
public <P extends WorldProgram> P compile(ExtensibleGlProgram.Factory<P> worldShaderPipeline) {
|
||||
return new ProgramAssembler(this.name)
|
||||
.attachShader(compile(ShaderType.VERTEX))
|
||||
.attachShader(compile(ShaderType.FRAGMENT))
|
||||
.link()
|
||||
.deleteLinkedShaders()
|
||||
.build(worldShaderPipeline);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package com.jozufozu.flywheel.backend.pipeline;
|
||||
package com.jozufozu.flywheel.core.pipeline;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
|
@ -1,4 +1,4 @@
|
|||
package com.jozufozu.flywheel.backend.pipeline;
|
||||
package com.jozufozu.flywheel.core.pipeline;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.jozufozu.flywheel.backend.pipeline;
|
||||
package com.jozufozu.flywheel.core.pipeline;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
|
@ -0,0 +1,33 @@
|
|||
package com.jozufozu.flywheel.core.pipeline;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
||||
import com.jozufozu.flywheel.backend.source.FileResolution;
|
||||
import com.jozufozu.flywheel.core.shader.ExtensibleGlProgram;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
|
||||
public class WorldCompiler<P extends WorldProgram> implements PipelineCompiler<P> {
|
||||
|
||||
private final ExtensibleGlProgram.Factory<P> factory;
|
||||
|
||||
private final Template<?> template;
|
||||
private final FileResolution header;
|
||||
|
||||
public WorldCompiler(ExtensibleGlProgram.Factory<P> factory, Template<?> template, FileResolution header) {
|
||||
this.factory = factory;
|
||||
this.template = template;
|
||||
this.header = header;
|
||||
}
|
||||
|
||||
@Override
|
||||
public P compile(CompilationContext usage) {
|
||||
ShaderCompiler compiler = new ShaderCompiler(usage, template, header);
|
||||
|
||||
return new ProgramAssembler(compiler.name)
|
||||
.attachShader(compiler.compile(ShaderType.VERTEX))
|
||||
.attachShader(compiler.compile(ShaderType.FRAGMENT))
|
||||
.link()
|
||||
.deleteLinkedShaders()
|
||||
.build(this.factory);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault
|
||||
package com.jozufozu.flywheel.backend.pipeline;
|
||||
package com.jozufozu.flywheel.core.pipeline;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
package com.jozufozu.flywheel.core.shader;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
|
||||
/**
|
||||
* Encapsulates any number of shader programs for use in similar contexts.
|
||||
* Allows the implementor to choose which shader program to use based on arbitrary state.
|
||||
*
|
||||
* @param <P>
|
||||
*/
|
||||
public interface ContextAwareProgram<P extends GlProgram> extends Supplier<P> {
|
||||
|
||||
/**
|
||||
* Get the shader program most suited for the current game state.
|
||||
*
|
||||
* @return The one true program.
|
||||
*/
|
||||
P get();
|
||||
|
||||
/**
|
||||
* Delete all shader programs encapsulated by your implementation.
|
||||
*/
|
||||
void delete();
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
package com.jozufozu.flywheel.core.shader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.core.shader.spec.IGameStateCondition;
|
||||
import com.jozufozu.flywheel.util.Pair;
|
||||
|
||||
public class GameStateProgram<P extends GlProgram> implements ContextAwareProgram<P> {
|
||||
|
||||
private final List<Pair<IGameStateCondition, P>> variants;
|
||||
private final P fallback;
|
||||
|
||||
protected GameStateProgram(List<Pair<IGameStateCondition, P>> variants, P fallback) {
|
||||
this.variants = variants;
|
||||
this.fallback = fallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public P get() {
|
||||
for (Pair<IGameStateCondition, P> variant : variants) {
|
||||
if (variant.first()
|
||||
.isMet()) return variant.second();
|
||||
}
|
||||
|
||||
return fallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
for (Pair<IGameStateCondition, P> variant : variants) {
|
||||
variant.second()
|
||||
.delete();
|
||||
}
|
||||
|
||||
fallback.delete();
|
||||
}
|
||||
|
||||
public static <P extends GlProgram> Builder<P> builder(P fallback) {
|
||||
return new Builder<>(fallback);
|
||||
}
|
||||
|
||||
public static class Builder<P extends GlProgram> {
|
||||
private final P fallback;
|
||||
private final List<Pair<IGameStateCondition, P>> variants = new ArrayList<>();
|
||||
|
||||
public Builder(P fallback) {
|
||||
this.fallback = fallback;
|
||||
}
|
||||
|
||||
public Builder<P> withVariant(IGameStateCondition condition, P program) {
|
||||
variants.add(Pair.of(condition, program));
|
||||
return this;
|
||||
}
|
||||
|
||||
public ContextAwareProgram<P> build() {
|
||||
return new GameStateProgram<>(ImmutableList.copyOf(variants), fallback);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,5 +11,5 @@ public interface IGameStateProvider {
|
|||
|
||||
ResourceLocation getID();
|
||||
|
||||
Object getValue();
|
||||
boolean isTrue();
|
||||
}
|
||||
|
|
|
@ -2,11 +2,10 @@ package com.jozufozu.flywheel.core.shader.gamestate;
|
|||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.config.FlwConfig;
|
||||
import com.jozufozu.flywheel.core.shader.spec.IBooleanStateProvider;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class NormalDebugStateProvider implements IBooleanStateProvider {
|
||||
public class NormalDebugStateProvider implements IGameStateProvider {
|
||||
|
||||
public static final NormalDebugStateProvider INSTANCE = new NormalDebugStateProvider();
|
||||
public static final ResourceLocation NAME = Flywheel.rl("normal_debug");
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
package com.jozufozu.flywheel.core.shader.spec;
|
||||
|
||||
import com.jozufozu.flywheel.core.shader.gamestate.IGameStateProvider;
|
||||
import com.mojang.serialization.Codec;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class BooleanGameStateCondition implements IGameStateCondition {
|
||||
|
||||
public static final Codec<BooleanGameStateCondition> BOOLEAN_SUGAR = IGameStateProvider.CODEC.xmap(gameContext -> {
|
||||
if (gameContext instanceof IBooleanStateProvider) {
|
||||
return new BooleanGameStateCondition(((IBooleanStateProvider) gameContext));
|
||||
}
|
||||
|
||||
return null;
|
||||
}, IGameStateCondition::getStateProvider);
|
||||
protected final IBooleanStateProvider context;
|
||||
|
||||
public BooleanGameStateCondition(IBooleanStateProvider context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getID() {
|
||||
return context.getID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGameStateProvider getStateProvider() {
|
||||
return context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMet() {
|
||||
return context.isTrue();
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package com.jozufozu.flywheel.core.shader.spec;
|
||||
|
||||
import com.jozufozu.flywheel.core.shader.gamestate.IGameStateProvider;
|
||||
|
||||
public interface IBooleanStateProvider extends IGameStateProvider {
|
||||
|
||||
boolean isTrue();
|
||||
|
||||
@Override
|
||||
default Boolean getValue() {
|
||||
return isTrue();
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
package com.jozufozu.flywheel.core.shader.spec;
|
||||
|
||||
import com.jozufozu.flywheel.core.shader.gamestate.IGameStateProvider;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public interface IGameStateCondition {
|
||||
|
||||
ResourceLocation getID();
|
||||
|
||||
IGameStateProvider getStateProvider();
|
||||
|
||||
boolean isMet();
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
package com.jozufozu.flywheel.core.shader.spec;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.backend.source.FileResolution;
|
||||
import com.jozufozu.flywheel.backend.source.Resolver;
|
||||
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||
|
@ -38,11 +40,11 @@ public class ProgramSpec {
|
|||
public ResourceLocation name;
|
||||
public final FileResolution source;
|
||||
|
||||
public final List<ProgramState> states;
|
||||
public final ImmutableList<ProgramState> states;
|
||||
|
||||
public ProgramSpec(ResourceLocation source, List<ProgramState> states) {
|
||||
this.source = Resolver.INSTANCE.findShader(source);
|
||||
this.states = states;
|
||||
this.states = ImmutableList.copyOf(states);
|
||||
}
|
||||
|
||||
public void setName(ResourceLocation name) {
|
||||
|
@ -53,12 +55,40 @@ public class ProgramSpec {
|
|||
return source.getFileLoc();
|
||||
}
|
||||
|
||||
public FileResolution getSource() {
|
||||
return source;
|
||||
public SourceFile getSource() {
|
||||
return source.getFile();
|
||||
}
|
||||
|
||||
public List<ProgramState> getStates() {
|
||||
public ImmutableList<ProgramState> getStates() {
|
||||
return states;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a unique ID representing the current game state.
|
||||
*/
|
||||
public long getCurrentStateID() {
|
||||
long ctx = 0;
|
||||
for (ProgramState state : states) {
|
||||
if (state.context().isTrue()) {
|
||||
ctx |= 1;
|
||||
}
|
||||
ctx <<= 1;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the stateID, get a list of defines to include at the top of a compiling program.
|
||||
*/
|
||||
public List<String> getDefines(long stateID) {
|
||||
List<String> defines = new ArrayList<>();
|
||||
|
||||
for (ProgramState state : states) {
|
||||
if ((stateID & 1) == 1) {
|
||||
defines.addAll(state.defines());
|
||||
}
|
||||
stateID >>= 1;
|
||||
}
|
||||
return defines;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,29 +3,14 @@ package com.jozufozu.flywheel.core.shader.spec;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.jozufozu.flywheel.core.shader.gamestate.IGameStateProvider;
|
||||
import com.jozufozu.flywheel.util.CodecUtil;
|
||||
import com.mojang.datafixers.util.Either;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.DataResult;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
|
||||
public record ProgramState(IGameStateCondition context, List<String> defines) {
|
||||
public record ProgramState(IGameStateProvider context, List<String> defines) {
|
||||
|
||||
// TODO: Use Codec.dispatch
|
||||
private static final Codec<IGameStateCondition> WHEN = Codec.either(BooleanGameStateCondition.BOOLEAN_SUGAR, SpecificValueCondition.CODEC)
|
||||
.flatXmap(either -> either.map(DataResult::success, DataResult::success), any -> {
|
||||
if (any instanceof BooleanGameStateCondition) {
|
||||
return DataResult.success(Either.left((BooleanGameStateCondition) any));
|
||||
}
|
||||
|
||||
if (any instanceof SpecificValueCondition) {
|
||||
return DataResult.success(Either.right((SpecificValueCondition) any));
|
||||
}
|
||||
|
||||
return DataResult.error("unknown context condition");
|
||||
});
|
||||
|
||||
public static final Codec<ProgramState> CODEC = RecordCodecBuilder.create(state -> state.group(WHEN.fieldOf("when")
|
||||
public static final Codec<ProgramState> CODEC = RecordCodecBuilder.create(state -> state.group(IGameStateProvider.CODEC.fieldOf("when")
|
||||
.forGetter(ProgramState::context), CodecUtil.oneOrMore(Codec.STRING)
|
||||
.optionalFieldOf("define", Collections.emptyList())
|
||||
.forGetter(ProgramState::defines))
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
package com.jozufozu.flywheel.core.shader.spec;
|
||||
|
||||
import com.jozufozu.flywheel.core.shader.gamestate.IGameStateProvider;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class SpecificValueCondition implements IGameStateCondition {
|
||||
|
||||
public static final Codec<SpecificValueCondition> CODEC = RecordCodecBuilder.create(condition -> condition.group(IGameStateProvider.CODEC.fieldOf("provider")
|
||||
.forGetter(SpecificValueCondition::getStateProvider), Codec.STRING.fieldOf("value")
|
||||
.forGetter(SpecificValueCondition::getValue))
|
||||
.apply(condition, SpecificValueCondition::new));
|
||||
|
||||
private final String required;
|
||||
private final IGameStateProvider context;
|
||||
|
||||
public SpecificValueCondition(IGameStateProvider context, String required) {
|
||||
this.required = required;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getID() {
|
||||
return context.getID();
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return required;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGameStateProvider getStateProvider() {
|
||||
return context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMet() {
|
||||
return required.equals(context.getValue()
|
||||
.toString());
|
||||
}
|
||||
}
|
|
@ -2,10 +2,7 @@
|
|||
"source": "flywheel:model.vert",
|
||||
"states": [
|
||||
{
|
||||
"when": {
|
||||
"provider": "flywheel:normal_debug",
|
||||
"value": "true"
|
||||
},
|
||||
"when": "flywheel:normal_debug",
|
||||
"define": "DEBUG_NORMAL"
|
||||
}
|
||||
]
|
||||
|
|
|
@ -2,10 +2,7 @@
|
|||
"source": "flywheel:oriented.vert",
|
||||
"states": [
|
||||
{
|
||||
"when": {
|
||||
"provider": "flywheel:normal_debug",
|
||||
"value": "true"
|
||||
},
|
||||
"when": "flywheel:normal_debug",
|
||||
"define": "DEBUG_NORMAL"
|
||||
}
|
||||
]
|
||||
|
|
Loading…
Reference in a new issue