mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-14 00:06:12 +01:00
Almost sane shaders
- No more ShaderContext. Programs are directly retrieved through ProgramCompilers. - Templates don't need generics - Remove ExtensibleGlProgram
This commit is contained in:
parent
06e1d5a901
commit
bfe123d167
38 changed files with 339 additions and 437 deletions
|
@ -1,9 +1,7 @@
|
|||
package com.jozufozu.flywheel.backend;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
@ -40,7 +38,6 @@ public class Backend {
|
|||
public GlCompat compat;
|
||||
|
||||
public final Loader loader;
|
||||
private final List<ShaderContext<?>> contexts = new ArrayList<>();
|
||||
private final Map<ResourceLocation, StructType<?>> materialRegistry = new HashMap<>();
|
||||
private final Map<ResourceLocation, ProgramSpec> programSpecRegistry = new HashMap<>();
|
||||
|
||||
|
@ -74,14 +71,6 @@ public class Backend {
|
|||
return spec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a shader context.
|
||||
*/
|
||||
public <C extends ShaderContext<?>> C register(C spec) {
|
||||
contexts.add(spec);
|
||||
return spec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an instancing material.
|
||||
*/
|
||||
|
@ -96,6 +85,7 @@ public class Backend {
|
|||
return spec;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ProgramSpec getSpec(ResourceLocation name) {
|
||||
return programSpecRegistry.get(name);
|
||||
}
|
||||
|
@ -118,10 +108,6 @@ public class Backend {
|
|||
return programSpecRegistry.values();
|
||||
}
|
||||
|
||||
public Collection<ShaderContext<?>> allContexts() {
|
||||
return contexts;
|
||||
}
|
||||
|
||||
public static boolean isOn() {
|
||||
return getInstance().engine != FlwEngine.OFF;
|
||||
}
|
||||
|
@ -157,8 +143,6 @@ public class Backend {
|
|||
void _clearContexts() {
|
||||
GameStateRegistry.clear();
|
||||
programSpecRegistry.clear();
|
||||
contexts.forEach(ShaderContext::delete);
|
||||
contexts.clear();
|
||||
materialRegistry.clear();
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ import com.google.gson.GsonBuilder;
|
|||
import com.google.gson.JsonElement;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
|
||||
import com.jozufozu.flywheel.backend.source.Resolver;
|
||||
import com.jozufozu.flywheel.backend.source.ShaderLoadingException;
|
||||
import com.jozufozu.flywheel.backend.source.ShaderSources;
|
||||
import com.jozufozu.flywheel.core.crumbling.CrumblingRenderer;
|
||||
import com.jozufozu.flywheel.core.shader.ProgramSpec;
|
||||
|
@ -39,7 +38,6 @@ public class Loader implements ResourceManagerReloadListener {
|
|||
private static final Gson GSON = new GsonBuilder().create();
|
||||
|
||||
private final Backend backend;
|
||||
private boolean shouldCrash;
|
||||
|
||||
private boolean firstLoad = true;
|
||||
|
||||
|
@ -56,15 +54,10 @@ public class Loader implements ResourceManagerReloadListener {
|
|||
}
|
||||
}
|
||||
|
||||
public void notifyError() {
|
||||
shouldCrash = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResourceManagerReload(ResourceManager manager) {
|
||||
backend.refresh();
|
||||
|
||||
shouldCrash = false;
|
||||
backend._clearContexts();
|
||||
|
||||
Resolver.INSTANCE.invalidate();
|
||||
|
@ -75,17 +68,9 @@ public class Loader implements ResourceManagerReloadListener {
|
|||
|
||||
loadProgramSpecs(manager);
|
||||
|
||||
Resolver.INSTANCE.resolve(sources);
|
||||
Resolver.INSTANCE.run(sources);
|
||||
|
||||
for (ShaderContext<?> context : backend.allContexts()) {
|
||||
context.load();
|
||||
}
|
||||
|
||||
if (shouldCrash) {
|
||||
throw new ShaderLoadingException("Could not load all shaders, see log for details");
|
||||
}
|
||||
|
||||
Backend.LOGGER.info("Loaded all shader programs.");
|
||||
Backend.LOGGER.info("Loaded all shader sources.");
|
||||
|
||||
ClientLevel world = Minecraft.getInstance().level;
|
||||
if (Backend.canUseInstancing(world)) {
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend;
|
||||
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public interface ShaderContext<P extends GlProgram> {
|
||||
|
||||
P getProgram(ResourceLocation loc, VertexType vertexType, RenderLayer layer);
|
||||
|
||||
/**
|
||||
* Load all programs associated with this context. This might be just one, if the context is very specialized.
|
||||
*/
|
||||
void load();
|
||||
|
||||
void delete();
|
||||
}
|
|
@ -7,6 +7,8 @@ import static org.lwjgl.opengl.GL20.glUniformMatrix4fv;
|
|||
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
|
@ -87,4 +89,13 @@ public abstract class GlProgram extends GlObject {
|
|||
public String toString() {
|
||||
return "program " + name;
|
||||
}
|
||||
|
||||
/**
|
||||
* A factory interface to create a {@link GlProgram}.
|
||||
*/
|
||||
public interface Factory<P extends GlProgram> {
|
||||
|
||||
@Nonnull
|
||||
P create(ResourceLocation name, int handle);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import org.lwjgl.opengl.GL20;
|
|||
import com.jozufozu.flywheel.backend.gl.GlObject;
|
||||
import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
|
||||
import com.jozufozu.flywheel.backend.source.ShaderLoadingException;
|
||||
import com.jozufozu.flywheel.core.pipeline.ShaderCompiler;
|
||||
import com.jozufozu.flywheel.core.compile.ShaderCompiler;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
|
|
|
@ -16,4 +16,8 @@ public enum ShaderType {
|
|||
this.define = define;
|
||||
this.glEnum = glEnum;
|
||||
}
|
||||
|
||||
public String getDefineStatement() {
|
||||
return "#define " + define + "\n";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import com.jozufozu.flywheel.backend.model.FallbackAllocator;
|
|||
import com.jozufozu.flywheel.backend.model.ModelAllocator;
|
||||
import com.jozufozu.flywheel.backend.model.ModelPool;
|
||||
import com.jozufozu.flywheel.core.Formats;
|
||||
import com.jozufozu.flywheel.core.compile.ProgramContext;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
import com.jozufozu.flywheel.util.Textures;
|
||||
import com.mojang.math.Matrix4f;
|
||||
|
@ -78,8 +79,8 @@ public class InstancedMaterialGroup<P extends WorldProgram> implements MaterialG
|
|||
InstancedMaterial<?> material = entry.getValue();
|
||||
if (material.nothingToRender()) continue;
|
||||
|
||||
P program = owner.context.getProgram(entry.getKey()
|
||||
.getProgramSpec(), Formats.POS_TEX_NORMAL, layer);
|
||||
P program = owner.context.getProgram(ProgramContext.create(entry.getKey()
|
||||
.getProgramSpec(), Formats.POS_TEX_NORMAL, layer));
|
||||
|
||||
program.bind();
|
||||
program.uploadViewProjection(viewProjection);
|
||||
|
|
|
@ -13,7 +13,7 @@ import com.jozufozu.flywheel.backend.gl.GlVertexArray;
|
|||
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
|
||||
import com.jozufozu.flywheel.backend.instancing.Engine;
|
||||
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
|
||||
import com.jozufozu.flywheel.core.WorldContext;
|
||||
import com.jozufozu.flywheel.core.compile.ProgramCompiler;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
import com.jozufozu.flywheel.event.RenderLayerEvent;
|
||||
import com.jozufozu.flywheel.util.WeakHashSet;
|
||||
|
@ -31,7 +31,7 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
|
||||
protected BlockPos originCoordinate = BlockPos.ZERO;
|
||||
|
||||
protected final WorldContext<P> context;
|
||||
protected final ProgramCompiler<P> context;
|
||||
protected final GroupFactory<P> groupFactory;
|
||||
protected final boolean ignoreOriginCoordinate;
|
||||
|
||||
|
@ -39,15 +39,11 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
|
||||
private final WeakHashSet<OriginShiftListener> listeners;
|
||||
|
||||
public InstancingEngine(WorldContext<P> context, TaskEngine taskEngine) {
|
||||
this(context, InstancedMaterialGroup::new, false);
|
||||
}
|
||||
|
||||
public static <P extends WorldProgram> Builder<P> builder(WorldContext<P> context) {
|
||||
public static <P extends WorldProgram> Builder<P> builder(ProgramCompiler<P> context) {
|
||||
return new Builder<>(context);
|
||||
}
|
||||
|
||||
public InstancingEngine(WorldContext<P> context, GroupFactory<P> groupFactory, boolean ignoreOriginCoordinate) {
|
||||
public InstancingEngine(ProgramCompiler<P> context, GroupFactory<P> groupFactory, boolean ignoreOriginCoordinate) {
|
||||
this.context = context;
|
||||
this.ignoreOriginCoordinate = ignoreOriginCoordinate;
|
||||
|
||||
|
@ -180,11 +176,11 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
}
|
||||
|
||||
public static class Builder<P extends WorldProgram> {
|
||||
protected final WorldContext<P> context;
|
||||
protected final ProgramCompiler<P> context;
|
||||
protected GroupFactory<P> groupFactory = InstancedMaterialGroup::new;
|
||||
protected boolean ignoreOriginCoordinate;
|
||||
|
||||
public Builder(WorldContext<P> context) {
|
||||
public Builder(ProgramCompiler<P> context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.jozufozu.flywheel.backend.source;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.source.error.ErrorBuilder;
|
||||
|
@ -21,13 +22,13 @@ import net.minecraft.resources.ResourceLocation;
|
|||
public class FileResolution {
|
||||
|
||||
/**
|
||||
* Spans that have references that resolved to this.
|
||||
* Extra info about where this resolution is required. Includes ProgramSpecs and shader Spans.
|
||||
*/
|
||||
private final List<Span> foundSpans = new ArrayList<>();
|
||||
private final List<Consumer<ErrorBuilder>> extraCrashInfoProviders = new ArrayList<>();
|
||||
private final ResourceLocation fileLoc;
|
||||
private SourceFile file;
|
||||
|
||||
public FileResolution(ResourceLocation fileLoc) {
|
||||
FileResolution(ResourceLocation fileLoc) {
|
||||
this.fileLoc = fileLoc;
|
||||
}
|
||||
|
||||
|
@ -35,6 +36,10 @@ public class FileResolution {
|
|||
return fileLoc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Non-null if this file is resolved because there would have been a crash otherwise.
|
||||
* @return The file that this resolution resolves to.
|
||||
*/
|
||||
public SourceFile getFile() {
|
||||
return file;
|
||||
}
|
||||
|
@ -48,34 +53,44 @@ public class FileResolution {
|
|||
* @param span A span where this file is referenced.
|
||||
*/
|
||||
public FileResolution addSpan(Span span) {
|
||||
foundSpans.add(span);
|
||||
extraCrashInfoProviders.add(builder -> builder.pointAtFile(span.getSourceFile())
|
||||
.pointAt(span, 1));
|
||||
return this;
|
||||
}
|
||||
|
||||
public void addSpec(ResourceLocation name) {
|
||||
extraCrashInfoProviders.add(builder -> builder.extra("needed by spec: " + name + ".json"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if this file actually resolves to something.
|
||||
*
|
||||
* <p>
|
||||
* Called after all files are loaded. If we can't find the file here, it doesn't exist.
|
||||
* </p>
|
||||
*
|
||||
* @return True if this file is resolved.
|
||||
*/
|
||||
void resolve(SourceFinder sources) {
|
||||
boolean resolve(SourceFinder sources) {
|
||||
file = sources.findSource(fileLoc);
|
||||
|
||||
if (file == null) {
|
||||
ErrorBuilder builder = ErrorBuilder.error(String.format("could not find source for file %s", fileLoc));
|
||||
// print the location of all places where this file was referenced
|
||||
for (Span span : foundSpans) {
|
||||
builder.pointAtFile(span.getSourceFile())
|
||||
.pointAt(span, 1);
|
||||
for (Consumer<ErrorBuilder> consumer : extraCrashInfoProviders) {
|
||||
consumer.accept(builder);
|
||||
}
|
||||
Backend.LOGGER.error(builder.build());
|
||||
throw new ShaderLoadingException();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Let the GC do its thing
|
||||
extraCrashInfoProviders.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
void invalidate() {
|
||||
foundSpans.clear();
|
||||
extraCrashInfoProviders.clear();
|
||||
file = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,29 +9,51 @@ import net.minecraft.resources.ResourceLocation;
|
|||
* Manages deferred file resolution.
|
||||
*
|
||||
* <p>
|
||||
* Interns all referenced files in all sources, duplicating the final lookups and allowing for more dev-friendly
|
||||
* error reporting.
|
||||
* </p><p>
|
||||
* See {@link FileResolution} for more information.
|
||||
* Interns all file names in shader sources and program specs, deduplicating the final lookups and allowing for more
|
||||
* dev-friendly error reporting.
|
||||
* </p>
|
||||
*
|
||||
* @see FileResolution
|
||||
*/
|
||||
public class Resolver {
|
||||
|
||||
public static final Resolver INSTANCE = new Resolver();
|
||||
|
||||
private final Map<ResourceLocation, FileResolution> resolutions = new HashMap<>();
|
||||
private boolean hasRun = false;
|
||||
|
||||
public FileResolution findShader(ResourceLocation fileLoc) {
|
||||
return resolutions.computeIfAbsent(fileLoc, FileResolution::new);
|
||||
public FileResolution get(ResourceLocation file) {
|
||||
if (!hasRun) {
|
||||
return resolutions.computeIfAbsent(file, FileResolution::new);
|
||||
} else {
|
||||
// Lock the map after resolution has run.
|
||||
FileResolution fileResolution = resolutions.get(file);
|
||||
|
||||
// ...so crash immediately if the file isn't found.
|
||||
if (fileResolution == null) {
|
||||
throw new RuntimeException("could not find source for file: " + file);
|
||||
}
|
||||
|
||||
return fileResolution;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try and resolve all referenced source files, printing errors if any aren't found.
|
||||
*/
|
||||
public void resolve(SourceFinder sources) {
|
||||
public void run(SourceFinder sources) {
|
||||
boolean needsCrash = false;
|
||||
for (FileResolution resolution : resolutions.values()) {
|
||||
resolution.resolve(sources);
|
||||
if (!resolution.resolve(sources)) {
|
||||
needsCrash = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (needsCrash) {
|
||||
throw new ShaderLoadingException("Failed to resolve all source files, see log for details");
|
||||
}
|
||||
|
||||
hasRun = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -43,5 +65,6 @@ public class Resolver {
|
|||
*/
|
||||
public void invalidate() {
|
||||
resolutions.values().forEach(FileResolution::invalidate);
|
||||
hasRun = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ 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 com.jozufozu.flywheel.core.compile.FileIndex;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
|
@ -138,7 +138,7 @@ public class SourceFile {
|
|||
return "#use " + '"' + name + '"';
|
||||
}
|
||||
|
||||
public void generateFinalSource(ShaderCompiler env, StringBuilder source) {
|
||||
public void generateFinalSource(FileIndex env, StringBuilder source) {
|
||||
for (Import include : imports) {
|
||||
SourceFile file = include.getFile();
|
||||
|
||||
|
|
|
@ -16,7 +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.core.compile.ShaderCompiler;
|
||||
import com.jozufozu.flywheel.util.FlwUtil;
|
||||
|
||||
public class ErrorBuilder {
|
||||
|
@ -127,6 +127,7 @@ public class ErrorBuilder {
|
|||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append('\n');
|
||||
for (ErrorLine line : lines) {
|
||||
int length = line.neededMargin();
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ public class Import extends AbstractShaderElement {
|
|||
super(self);
|
||||
this.file = file;
|
||||
|
||||
resolution = resolver.findShader(toRL(file))
|
||||
resolution = resolver.get(toRL(file))
|
||||
.addSpan(file);
|
||||
|
||||
IMPORTS.add(this);
|
||||
|
|
|
@ -1,13 +1,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.source.FileResolution;
|
||||
import com.jozufozu.flywheel.backend.source.Resolver;
|
||||
import com.jozufozu.flywheel.core.compile.ProgramCompiler;
|
||||
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.NormalDebugStateProvider;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
import com.jozufozu.flywheel.event.GatherContextEvent;
|
||||
|
@ -20,22 +18,17 @@ import net.minecraftforge.api.distmarker.OnlyIn;
|
|||
@OnlyIn(Dist.CLIENT)
|
||||
public class Contexts {
|
||||
|
||||
public static WorldContext<WorldProgram> WORLD;
|
||||
public static WorldContext<CrumblingProgram> CRUMBLING;
|
||||
public static ProgramCompiler<WorldProgram> WORLD;
|
||||
public static ProgramCompiler<CrumblingProgram> CRUMBLING;
|
||||
|
||||
public static void flwInit(GatherContextEvent event) {
|
||||
Backend backend = event.getBackend();
|
||||
|
||||
GameStateRegistry.register(NormalDebugStateProvider.INSTANCE);
|
||||
|
||||
FileResolution crumblingBuiltins = Resolver.INSTANCE.findShader(ResourceUtil.subPath(Names.CRUMBLING, ".glsl"));
|
||||
FileResolution worldBuiltins = Resolver.INSTANCE.findShader(ResourceUtil.subPath(Names.WORLD, ".glsl"));
|
||||
FileResolution worldBuiltins = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.WORLD, ".glsl"));
|
||||
FileResolution crumblingBuiltins = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.CRUMBLING, ".glsl"));
|
||||
|
||||
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));
|
||||
WORLD = Templates.INSTANCING.programCompiler(WorldProgram::new, worldBuiltins);
|
||||
CRUMBLING = Templates.INSTANCING.programCompiler(CrumblingProgram::new, crumblingBuiltins);
|
||||
}
|
||||
|
||||
public static class Names {
|
||||
|
|
|
@ -28,5 +28,6 @@ public class Materials {
|
|||
public static class Names {
|
||||
public static final ResourceLocation MODEL = Flywheel.rl("model");
|
||||
public static final ResourceLocation ORIENTED = Flywheel.rl("oriented");
|
||||
public static final ResourceLocation PASSTHRU = Flywheel.rl("passthru");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
package com.jozufozu.flywheel.core;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
||||
import com.jozufozu.flywheel.core.pipeline.InstancingTemplateData;
|
||||
import com.jozufozu.flywheel.core.pipeline.OneShotTemplateData;
|
||||
import com.jozufozu.flywheel.core.pipeline.Template;
|
||||
import com.jozufozu.flywheel.core.compile.InstancingTemplateData;
|
||||
import com.jozufozu.flywheel.core.compile.OneShotTemplateData;
|
||||
import com.jozufozu.flywheel.core.compile.Template;
|
||||
|
||||
public class Templates {
|
||||
|
||||
public static final Template<InstancingTemplateData> INSTANCING = new Template<>(GLSLVersion.V330, InstancingTemplateData::new);
|
||||
public static final Template<OneShotTemplateData> ONE_SHOT = new Template<>(GLSLVersion.V150, OneShotTemplateData::new);
|
||||
public static final Template INSTANCING = new Template(GLSLVersion.V330, InstancingTemplateData::new);
|
||||
public static final Template ONE_SHOT = new Template(GLSLVersion.V150, OneShotTemplateData::new);
|
||||
}
|
||||
|
|
|
@ -1,109 +0,0 @@
|
|||
package com.jozufozu.flywheel.core;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
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.RenderLayer;
|
||||
import com.jozufozu.flywheel.backend.ShaderContext;
|
||||
import com.jozufozu.flywheel.backend.source.ShaderLoadingException;
|
||||
import com.jozufozu.flywheel.core.pipeline.CachingCompiler;
|
||||
import com.jozufozu.flywheel.core.pipeline.CompilationContext;
|
||||
import com.jozufozu.flywheel.core.pipeline.PipelineCompiler;
|
||||
import com.jozufozu.flywheel.core.shader.ProgramSpec;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class WorldContext<P extends WorldProgram> implements ShaderContext<P> {
|
||||
public final Backend backend;
|
||||
protected final Map<ResourceLocation, ProgramSpec> programs = new HashMap<>();
|
||||
protected final ResourceLocation name;
|
||||
protected final Supplier<Stream<ResourceLocation>> specStream;
|
||||
private final CachingCompiler<P> programCache;
|
||||
|
||||
public WorldContext(Backend backend, ResourceLocation name, Supplier<Stream<ResourceLocation>> specStream, PipelineCompiler<P> pipeline) {
|
||||
this.backend = backend;
|
||||
this.name = name;
|
||||
this.specStream = specStream;
|
||||
this.programCache = new CachingCompiler<>(pipeline);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
|
||||
Backend.LOGGER.info("Loading context '{}'", name);
|
||||
|
||||
specStream.get()
|
||||
.map(backend::getSpec)
|
||||
.forEach(this::loadSpec);
|
||||
}
|
||||
|
||||
private void loadSpec(ProgramSpec spec) {
|
||||
|
||||
try {
|
||||
programs.put(spec.name, spec);
|
||||
|
||||
Backend.LOGGER.debug("Loaded program {}", spec.name);
|
||||
} catch (Exception e) {
|
||||
Backend.LOGGER.error("Error loading program {}", spec.name);
|
||||
if (!(e instanceof ShaderLoadingException)) {
|
||||
Backend.LOGGER.error("", e);
|
||||
}
|
||||
backend.loader.notifyError();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public P getProgram(ResourceLocation loc, VertexType vertexType, RenderLayer layer) {
|
||||
ProgramSpec spec = programs.get(loc);
|
||||
|
||||
if (spec == null) {
|
||||
throw new NullPointerException("Cannot compile shader because '" + loc + "' is not recognized.");
|
||||
}
|
||||
|
||||
return programCache.getProgram(CompilationContext.create(vertexType, layer, spec));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
programCache.invalidate();
|
||||
programs.clear();
|
||||
}
|
||||
|
||||
public static Builder builder(Backend backend, ResourceLocation name) {
|
||||
return new Builder(backend, name);
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private final Backend backend;
|
||||
private final ResourceLocation name;
|
||||
private Supplier<Stream<ResourceLocation>> specStream;
|
||||
|
||||
public Builder(Backend backend, ResourceLocation name) {
|
||||
this.backend = backend;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Builder setSpecStream(Supplier<Stream<ResourceLocation>> specStream) {
|
||||
this.specStream = specStream;
|
||||
return this;
|
||||
}
|
||||
|
||||
public <P extends WorldProgram> WorldContext<P> build(PipelineCompiler<P> pipeline) {
|
||||
if (specStream == null) {
|
||||
specStream = () -> backend.allMaterials()
|
||||
.stream()
|
||||
.map(t -> t instanceof Instanced<?> i ? i : null)
|
||||
.filter(Objects::nonNull)
|
||||
.map(Instanced::getProgramSpec);
|
||||
}
|
||||
return new WorldContext<>(backend, name, specStream, pipeline);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.jozufozu.flywheel.core.compile;
|
||||
|
||||
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||
|
||||
public interface FileIndex {
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
int getFileID(SourceFile sourceFile);
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package com.jozufozu.flywheel.core.pipeline;
|
||||
package com.jozufozu.flywheel.core.compile;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
|
@ -134,7 +134,7 @@ public class InstancingTemplateData implements TemplateData {
|
|||
));
|
||||
}
|
||||
|
||||
public void fragmentFooter(StringBuilder template, ShaderCompiler shader) {
|
||||
public void fragmentFooter(StringBuilder template, FileIndex shader) {
|
||||
Template.prefixFields(template, interpolant, "in", "v2f_");
|
||||
|
||||
template.append(String.format("""
|
|
@ -1,4 +1,4 @@
|
|||
package com.jozufozu.flywheel.core.pipeline;
|
||||
package com.jozufozu.flywheel.core.compile;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
|
@ -99,7 +99,7 @@ public class OneShotTemplateData implements TemplateData {
|
|||
""");
|
||||
}
|
||||
|
||||
public void fragmentFooter(StringBuilder template, ShaderCompiler file) {
|
||||
public void fragmentFooter(StringBuilder template, FileIndex file) {
|
||||
Template.prefixFields(template, interpolant, "in", "v2f_");
|
||||
|
||||
template.append(String.format("""
|
|
@ -1,4 +1,4 @@
|
|||
package com.jozufozu.flywheel.core.pipeline;
|
||||
package com.jozufozu.flywheel.core.compile;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.GL_TRUE;
|
||||
import static org.lwjgl.opengl.GL20.GL_LINK_STATUS;
|
||||
|
@ -11,9 +11,8 @@ import static org.lwjgl.opengl.GL20.glLinkProgram;
|
|||
import java.util.List;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlShader;
|
||||
import com.jozufozu.flywheel.core.shader.ExtensibleGlProgram;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
@ -61,7 +60,7 @@ public class ProgramAssembler {
|
|||
return this;
|
||||
}
|
||||
|
||||
public <P extends WorldProgram> P build(ExtensibleGlProgram.Factory<P> factory) {
|
||||
public <P extends GlProgram> P build(GlProgram.Factory<P> factory) {
|
||||
return factory.create(name, program);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package com.jozufozu.flywheel.core.compile;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
||||
import com.jozufozu.flywheel.backend.source.FileResolution;
|
||||
|
||||
/**
|
||||
* A caching compiler.
|
||||
*
|
||||
* <p>
|
||||
* This class is responsible for compiling programs on the fly. An instance of this class will keep a cache of
|
||||
* compiled programs, and will only compile a program if it is not already in the cache.
|
||||
* </p>
|
||||
*/
|
||||
public class ProgramCompiler<P extends GlProgram> {
|
||||
|
||||
protected final Map<ProgramContext, P> cache = new HashMap<>();
|
||||
private final GlProgram.Factory<P> factory;
|
||||
|
||||
private final Template template;
|
||||
private final FileResolution header;
|
||||
|
||||
public ProgramCompiler(GlProgram.Factory<P> factory, Template template, FileResolution header) {
|
||||
this.factory = factory;
|
||||
this.template = template;
|
||||
this.header = header;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or compile a spec to the given vertex type, accounting for all game state conditions specified by the spec.
|
||||
*
|
||||
* @param ctx The context of compilation.
|
||||
* @return A compiled GlProgram.
|
||||
*/
|
||||
public P getProgram(ProgramContext ctx) {
|
||||
return cache.computeIfAbsent(ctx, this::compile);
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
cache.values().forEach(P::delete);
|
||||
cache.clear();
|
||||
}
|
||||
|
||||
private P compile(ProgramContext ctx) {
|
||||
ShaderCompiler compiler = new ShaderCompiler(ctx, template, header);
|
||||
|
||||
return new ProgramAssembler(compiler.name)
|
||||
.attachShader(compiler.compile(ShaderType.VERTEX))
|
||||
.attachShader(compiler.compile(ShaderType.FRAGMENT))
|
||||
.link()
|
||||
.deleteLinkedShaders()
|
||||
.build(this.factory);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package com.jozufozu.flywheel.core.compile;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.RenderLayer;
|
||||
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||
import com.jozufozu.flywheel.core.shader.ProgramSpec;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
/**
|
||||
* Represents the entire context of a program's usage.
|
||||
*
|
||||
* @param alphaDiscard Alpha threshold below which pixels are discarded.
|
||||
* @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 ProgramContext(float alphaDiscard, VertexType vertexType, ProgramSpec spec, long ctx) {
|
||||
|
||||
/**
|
||||
* Creates a compilation context for the given program, vertex type and render layer.
|
||||
*
|
||||
* @param programName The name of the program to use.
|
||||
* @param vertexType The vertex type to use.
|
||||
* @param layer If cutout, the alpha discard threshold is 0.1, otherwise 0.
|
||||
* @return A compilation context.
|
||||
*/
|
||||
public static ProgramContext create(ResourceLocation programName, VertexType vertexType, @Nullable RenderLayer layer) {
|
||||
ProgramSpec spec = Backend.getInstance()
|
||||
.getSpec(programName);
|
||||
|
||||
if (spec == null) {
|
||||
throw new NullPointerException("Cannot compile shader because '" + programName + "' is not recognized.");
|
||||
}
|
||||
|
||||
return new ProgramContext(getAlphaDiscard(layer), vertexType, spec, spec.getCurrentStateID());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the alpha discard threshold for the given render layer.
|
||||
*
|
||||
* @param layer The render layer to get the alpha discard threshold for.
|
||||
* @return The alpha discard threshold.
|
||||
*/
|
||||
public static float getAlphaDiscard(@Nullable RenderLayer layer) {
|
||||
return layer == RenderLayer.CUTOUT ? 0.1f : 0f;
|
||||
}
|
||||
|
||||
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;
|
||||
ProgramContext that = (ProgramContext) o;
|
||||
// override for instance equality on vertexType
|
||||
return alphaDiscard == that.alphaDiscard && ctx == that.ctx && vertexType == that.vertexType && spec.equals(that.spec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(alphaDiscard, vertexType, spec, ctx);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package com.jozufozu.flywheel.core.pipeline;
|
||||
package com.jozufozu.flywheel.core.compile;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -7,7 +7,7 @@ import javax.annotation.Nullable;
|
|||
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.RenderLayer;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlShader;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
||||
import com.jozufozu.flywheel.backend.source.FileResolution;
|
||||
|
@ -15,27 +15,50 @@ 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 net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class ShaderCompiler {
|
||||
/**
|
||||
* Compiles a shader program.
|
||||
*/
|
||||
public class ShaderCompiler implements FileIndex {
|
||||
|
||||
/**
|
||||
* The name of the file responsible for this compilation.
|
||||
*/
|
||||
public final ResourceLocation name;
|
||||
public final Template<?> template;
|
||||
|
||||
/**
|
||||
* The template we'll be using to generate the final source.
|
||||
*/
|
||||
public final Template template;
|
||||
|
||||
private final FileResolution header;
|
||||
|
||||
/**
|
||||
* Extra {@code #define}s to be added to the shader.
|
||||
*/
|
||||
private final List<String> defines;
|
||||
|
||||
private final RenderLayer layer;
|
||||
/**
|
||||
* Alpha threshold below which pixels are discarded.
|
||||
*/
|
||||
private final float alphaDiscard;
|
||||
|
||||
/**
|
||||
* The vertex type to use.
|
||||
*/
|
||||
public final VertexType vertexType;
|
||||
|
||||
/**
|
||||
* The main file to compile.
|
||||
*/
|
||||
public final SourceFile mainFile;
|
||||
|
||||
private final List<SourceFile> files = new ArrayList<>();
|
||||
|
||||
public ShaderCompiler(CompilationContext context, Template<?> template, FileResolution header) {
|
||||
public ShaderCompiler(ProgramContext context, Template template, FileResolution header) {
|
||||
this.name = context.spec().name;
|
||||
this.template = template;
|
||||
this.header = header;
|
||||
|
@ -43,7 +66,7 @@ public class ShaderCompiler {
|
|||
this.defines = context.spec()
|
||||
.getDefines(context.ctx());
|
||||
this.vertexType = context.vertexType();
|
||||
layer = context.layer();
|
||||
this.alphaDiscard = context.alphaDiscard();
|
||||
}
|
||||
|
||||
public GlShader compile(ShaderType type) {
|
||||
|
@ -55,11 +78,9 @@ public class ShaderCompiler {
|
|||
.append('\n')
|
||||
.append("#extension GL_ARB_explicit_attrib_location : enable\n")
|
||||
.append("#extension GL_ARB_conservative_depth : enable\n")
|
||||
.append("#define ")
|
||||
.append(type.define) // special case shader type declaration
|
||||
.append('\n');
|
||||
.append(type.getDefineStatement()); // special case shader type declaration
|
||||
|
||||
if (layer == RenderLayer.CUTOUT) {
|
||||
if (alphaDiscard > 0) {
|
||||
finalSource.append("#define ALPHA_DISCARD 0.1\n");
|
||||
}
|
||||
|
||||
|
@ -91,7 +112,7 @@ public class ShaderCompiler {
|
|||
return new GlShader(this, type, finalSource.toString());
|
||||
}
|
||||
|
||||
public <P extends WorldProgram> P compile(ExtensibleGlProgram.Factory<P> worldShaderPipeline) {
|
||||
public <P extends WorldProgram> P compile(GlProgram.Factory<P> worldShaderPipeline) {
|
||||
return new ProgramAssembler(this.name)
|
||||
.attachShader(compile(ShaderType.VERTEX))
|
||||
.attachShader(compile(ShaderType.FRAGMENT))
|
||||
|
@ -105,6 +126,7 @@ public class ShaderCompiler {
|
|||
* @param sourceFile The file to retrieve the ID for.
|
||||
* @return A file ID unique to the given sourceFile.
|
||||
*/
|
||||
@Override
|
||||
public int getFileID(SourceFile sourceFile) {
|
||||
int i = files.indexOf(sourceFile);
|
||||
if (i != -1) {
|
|
@ -1,4 +1,4 @@
|
|||
package com.jozufozu.flywheel.core.pipeline;
|
||||
package com.jozufozu.flywheel.core.compile;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
@ -6,6 +6,8 @@ import java.util.function.Function;
|
|||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.backend.source.FileResolution;
|
||||
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||
import com.jozufozu.flywheel.backend.source.parse.ShaderStruct;
|
||||
import com.jozufozu.flywheel.backend.source.parse.StructField;
|
||||
|
@ -17,25 +19,35 @@ import com.jozufozu.flywheel.backend.source.parse.StructField;
|
|||
* Shader files are written somewhat abstractly. Subclasses of Template handle those abstractions, using SourceFile
|
||||
* metadata to generate shader code that OpenGL can use to call into our shader programs.
|
||||
* </p>
|
||||
* @param <D> Holds metadata, generates errors.
|
||||
*/
|
||||
public class Template<D extends TemplateData> {
|
||||
public class Template {
|
||||
|
||||
private final Map<SourceFile, D> metadata = new HashMap<>();
|
||||
private final Map<SourceFile, TemplateData> metadata = new HashMap<>();
|
||||
|
||||
private final Function<SourceFile, D> reader;
|
||||
private final Function<SourceFile, TemplateData> reader;
|
||||
private final GLSLVersion glslVersion;
|
||||
|
||||
public Template(GLSLVersion glslVersion, Function<SourceFile, D> reader) {
|
||||
public Template(GLSLVersion glslVersion, Function<SourceFile, TemplateData> reader) {
|
||||
this.reader = reader;
|
||||
this.glslVersion = glslVersion;
|
||||
}
|
||||
|
||||
public D getMetadata(SourceFile file) {
|
||||
public TemplateData getMetadata(SourceFile file) {
|
||||
// lazily read files, cache results
|
||||
return metadata.computeIfAbsent(file, reader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a program compiler using this template.
|
||||
* @param factory A factory to add meaning to compiled programs.
|
||||
* @param header The header file to use for the program.
|
||||
* @param <P> The type of program to compile.
|
||||
* @return A program compiler.
|
||||
*/
|
||||
public <P extends GlProgram> ProgramCompiler<P> programCompiler(GlProgram.Factory<P> factory, FileResolution header) {
|
||||
return new ProgramCompiler<>(factory, this, header);
|
||||
}
|
||||
|
||||
public GLSLVersion getVersion() {
|
||||
return glslVersion;
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
package com.jozufozu.flywheel.core.pipeline;
|
||||
package com.jozufozu.flywheel.core.compile;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
||||
|
||||
public interface TemplateData {
|
||||
void vertexFooter(StringBuilder builder, ShaderCompiler file);
|
||||
void fragmentFooter(StringBuilder builder, ShaderCompiler file);
|
||||
void fragmentFooter(StringBuilder builder, FileIndex file);
|
||||
|
||||
/**
|
||||
* Generate the necessary glue code here.
|
|
@ -1,4 +1,4 @@
|
|||
package com.jozufozu.flywheel.core.pipeline;
|
||||
package com.jozufozu.flywheel.core.compile;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
|
@ -1,5 +1,5 @@
|
|||
@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault
|
||||
package com.jozufozu.flywheel.core.pipeline;
|
||||
package com.jozufozu.flywheel.core.compile;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
package com.jozufozu.flywheel.core.pipeline;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
|
||||
/**
|
||||
* 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 context The context of compilation.
|
||||
* @return A compiled GlProgram.
|
||||
*/
|
||||
public P getProgram(CompilationContext context) {
|
||||
return cache.computeIfAbsent(context, this.pipeline::compile);
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
cache.values().forEach(P::delete);
|
||||
cache.clear();
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
package com.jozufozu.flywheel.core.pipeline;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.RenderLayer;
|
||||
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||
import com.jozufozu.flywheel.core.shader.ProgramSpec;
|
||||
|
||||
/**
|
||||
* Represents the entire context of a program's usage.
|
||||
*
|
||||
* @param layer
|
||||
* @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(RenderLayer layer, VertexType vertexType, ProgramSpec spec, long ctx) {
|
||||
|
||||
public static CompilationContext create(VertexType vertexType, RenderLayer layer, ProgramSpec spec) {
|
||||
return new CompilationContext(layer, vertexType, spec, spec.getCurrentStateID());
|
||||
}
|
||||
|
||||
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 layer == that.layer && ctx == that.ctx && vertexType == that.vertexType && spec.equals(that.spec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(layer, vertexType, spec, ctx);
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
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,33 +0,0 @@
|
|||
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,63 +0,0 @@
|
|||
package com.jozufozu.flywheel.core.shader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import com.jozufozu.flywheel.backend.ShaderContext;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
/**
|
||||
* A shader program that be arbitrarily "extended". This class can take in any number of program extensions, and
|
||||
* will initialize them and then call their {@link ExtensionInstance#bind() bind} function every subsequent time this
|
||||
* program is bound. An "extension" is something that interacts with the shader program in a way that is invisible to
|
||||
* the caller using the program. This is used by some programs to implement the different fog modes. Other uses might
|
||||
* include binding extra textures to allow for blocks to have normal maps, for example. As the extensions are
|
||||
* per-program, this also allows for same extra specialization within a
|
||||
* {@link ShaderContext ShaderContext}.
|
||||
*/
|
||||
public class ExtensibleGlProgram extends GlProgram {
|
||||
|
||||
protected final List<ExtensionInstance> extensions = new ArrayList<>();
|
||||
|
||||
public ExtensibleGlProgram(ResourceLocation name, int handle) {
|
||||
super(name, handle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind() {
|
||||
super.bind();
|
||||
|
||||
extensions.forEach(ExtensionInstance::bind);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("program ")
|
||||
.append(name)
|
||||
.append('[');
|
||||
|
||||
for (ExtensionInstance extension : extensions) {
|
||||
builder.append(extension)
|
||||
.append('+');
|
||||
}
|
||||
|
||||
builder.append(']');
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* A factory interface to create {@link GlProgram}s parameterized by a list of extensions. This doesn't necessarily
|
||||
* have to return an {@link ExtensibleGlProgram} if implementors want more flexibility for whatever reason.
|
||||
*/
|
||||
public interface Factory<P extends GlProgram> {
|
||||
|
||||
@Nonnull
|
||||
P create(ResourceLocation name, int handle);
|
||||
}
|
||||
}
|
|
@ -43,12 +43,13 @@ public class ProgramSpec {
|
|||
public final ImmutableList<ProgramState> states;
|
||||
|
||||
public ProgramSpec(ResourceLocation source, List<ProgramState> states) {
|
||||
this.source = Resolver.INSTANCE.findShader(source);
|
||||
this.source = Resolver.INSTANCE.get(source);
|
||||
this.states = ImmutableList.copyOf(states);
|
||||
}
|
||||
|
||||
public void setName(ResourceLocation name) {
|
||||
this.name = name;
|
||||
this.source.addSpec(name);
|
||||
}
|
||||
|
||||
public ResourceLocation getSourceLoc() {
|
||||
|
|
|
@ -4,6 +4,7 @@ import static org.lwjgl.opengl.GL20.glUniform1f;
|
|||
import static org.lwjgl.opengl.GL20.glUniform2f;
|
||||
import static org.lwjgl.opengl.GL20.glUniform3f;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.util.AnimationTickHolder;
|
||||
import com.mojang.blaze3d.platform.Window;
|
||||
import com.mojang.math.Matrix4f;
|
||||
|
@ -11,11 +12,12 @@ import com.mojang.math.Matrix4f;
|
|||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class WorldProgram extends ExtensibleGlProgram {
|
||||
public class WorldProgram extends GlProgram {
|
||||
protected final int uTime = getUniformLocation("uTime");
|
||||
protected final int uViewProjection = getUniformLocation("uViewProjection");
|
||||
protected final int uCameraPos = getUniformLocation("uCameraPos");
|
||||
protected final int uWindowSize = getUniformLocation("uWindowSize");
|
||||
private final WorldFog fog;
|
||||
|
||||
protected int uBlockAtlas;
|
||||
protected int uLightMap;
|
||||
|
@ -23,7 +25,7 @@ public class WorldProgram extends ExtensibleGlProgram {
|
|||
public WorldProgram(ResourceLocation name, int handle) {
|
||||
super(name, handle);
|
||||
|
||||
this.extensions.add(new WorldFog(this));
|
||||
fog = new WorldFog(this);
|
||||
|
||||
super.bind();
|
||||
registerSamplers();
|
||||
|
@ -66,7 +68,7 @@ public class WorldProgram extends ExtensibleGlProgram {
|
|||
@Override
|
||||
public void bind() {
|
||||
super.bind();
|
||||
|
||||
fog.bind();
|
||||
uploadWindowSize();
|
||||
uploadTime(AnimationTickHolder.getRenderTime());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault
|
||||
package com.jozufozu.flywheel.core.shader;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"source": "flywheel:passthru.vert",
|
||||
"states": [
|
||||
{
|
||||
"when": "flywheel:normal_debug",
|
||||
"define": "DEBUG_NORMAL"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#use "flywheel:block.frag"
|
||||
|
||||
#if defined(VERTEX_SHADER)
|
||||
void vertex(inout Vertex v) {
|
||||
|
||||
}
|
||||
#endif
|
Loading…
Reference in a new issue