mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-12-29 08:26:37 +01:00
It can actually load and link something
- Lots of refactoring in the shader loading code. - Abstract all the different shader source transformations into ProcessingStage. - An ordered list of ProcessingStages is called a ShaderTransformer. - When you acquire sources, a Shader now keeps track of the source location, shader type, and source code all together.
This commit is contained in:
parent
c1b7a1c19d
commit
56b2046957
23 changed files with 290 additions and 114 deletions
|
@ -7,7 +7,8 @@ import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.IMultiProgram;
|
import com.jozufozu.flywheel.backend.gl.shader.IMultiProgram;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.ProgramSpec;
|
import com.jozufozu.flywheel.backend.gl.shader.ProgramSpec;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderSpecLoader;
|
import com.jozufozu.flywheel.backend.gl.shader.ShaderSpecLoader;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
import com.jozufozu.flywheel.backend.loading.ProcessingStage;
|
||||||
|
import com.jozufozu.flywheel.backend.loading.Shader;
|
||||||
|
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
|
||||||
|
@ -32,8 +33,11 @@ public abstract class ShaderContext<P extends GlProgram> {
|
||||||
Backend.log.debug("Loaded program {}", programSpec.name);
|
Backend.log.debug("Loaded program {}", programSpec.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String preProcess(ShaderLoader loader, ShaderType type, ResourceLocation shader, String shaderSrc) {
|
public void preProcess(ShaderLoader loader, Shader shader) {
|
||||||
return shaderSrc;
|
}
|
||||||
|
|
||||||
|
public ProcessingStage loadingStage(ShaderLoader loader) {
|
||||||
|
return shader -> this.preProcess(loader, shader);
|
||||||
}
|
}
|
||||||
|
|
||||||
public P getProgram(ProgramSpec spec) {
|
public P getProgram(ProgramSpec spec) {
|
||||||
|
|
|
@ -14,6 +14,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
@ -25,12 +26,12 @@ import java.util.stream.Stream;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.jozufozu.flywheel.backend.gl.attrib.IVertexAttrib;
|
import com.jozufozu.flywheel.backend.gl.GlObject;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.GlShader;
|
import com.jozufozu.flywheel.backend.gl.shader.GlShader;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.ProgramSpec;
|
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderConstants;
|
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
||||||
|
import com.jozufozu.flywheel.backend.loading.Shader;
|
||||||
|
import com.jozufozu.flywheel.backend.loading.ShaderTransformer;
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
|
||||||
import net.minecraft.resources.IResource;
|
import net.minecraft.resources.IResource;
|
||||||
|
@ -58,15 +59,24 @@ public class ShaderLoader {
|
||||||
shaderSource.clear();
|
shaderSource.clear();
|
||||||
loadShaderSources(manager);
|
loadShaderSources(manager);
|
||||||
|
|
||||||
// ResourceLocation test = new ResourceLocation("create", "model_new.vert");
|
// InstancedArraysTemplate template = new InstancedArraysTemplate(this);
|
||||||
// ResourceLocation vert = new ResourceLocation("create", "skeleton/instanced/instanced.vert");
|
|
||||||
//
|
//
|
||||||
// InstancedArraysShaderTemplate template = new InstancedArraysShaderTemplate(getShaderSource(vert));
|
// ResourceLocation name = new ResourceLocation("create", "test");
|
||||||
// ParsedShader parsedShader = new ParsedShader(getShaderSource(test));
|
// ResourceLocation vert = new ResourceLocation("create", "model_new.vert");
|
||||||
|
// ResourceLocation frag = new ResourceLocation("create", "block_new.frag");
|
||||||
//
|
//
|
||||||
// String apply = template.apply(parsedShader);
|
// ShaderTransformer transformer = new ShaderTransformer()
|
||||||
|
// .pushStage(WorldContext.INSTANCE.loadingStage(this))
|
||||||
|
// .pushStage(this::processIncludes)
|
||||||
|
// .pushStage(template)
|
||||||
|
// .pushStage(this::processIncludes);
|
||||||
//
|
//
|
||||||
// printSource(test, apply);
|
// Shader vertexFile = this.source(vert, ShaderType.VERTEX);
|
||||||
|
// Shader fragmentFile = this.source(frag, ShaderType.FRAGMENT);
|
||||||
|
//
|
||||||
|
// GlProgram.Builder builder = loadProgram(name, transformer, vertexFile, fragmentFile);
|
||||||
|
//
|
||||||
|
// BasicProgram program = new BasicProgram(builder, GlFogMode.NONE.getFogFactory());
|
||||||
|
|
||||||
for (ShaderContext<?> context : Backend.contexts.values()) {
|
for (ShaderContext<?> context : Backend.contexts.values()) {
|
||||||
context.load(this);
|
context.load(this);
|
||||||
|
@ -108,48 +118,41 @@ public class ShaderLoader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlProgram.Builder loadProgram(ShaderContext<?> ctx, ProgramSpec programSpec) {
|
public Shader source(ResourceLocation name, ShaderType type) {
|
||||||
return loadProgram(ctx, programSpec, programSpec.defines);
|
return new Shader(type, name, getShaderSource(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlProgram.Builder loadProgram(ShaderContext<?> ctx, ProgramSpec programSpec, ShaderConstants defines) {
|
public GlProgram.Builder loadProgram(ResourceLocation name, ShaderTransformer transformer, Shader... shaders) {
|
||||||
return loadProgram(ctx, programSpec.name, programSpec.vert, programSpec.frag, programSpec.attributes, defines);
|
return loadProgram(name, transformer, Lists.newArrayList(shaders));
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlProgram.Builder loadProgram(ShaderContext<?> ctx, ResourceLocation name, ResourceLocation vert, ResourceLocation frag, Collection<IVertexAttrib> attribs, ShaderConstants defines) {
|
/**
|
||||||
GlShader vsh = null;
|
* Ingests the given shaders, compiling them and linking them together after applying the transformer to the source.
|
||||||
GlShader fsh = null;
|
*
|
||||||
|
* @param name What should we call this program if something goes wrong?
|
||||||
|
* @param transformer What should we do to the sources before compilation?
|
||||||
|
* @param shaders What are the different shader stages that should be linked together?
|
||||||
|
* @return A linked program builder.
|
||||||
|
*/
|
||||||
|
public GlProgram.Builder loadProgram(ResourceLocation name, ShaderTransformer transformer, Collection<Shader> shaders) {
|
||||||
|
List<GlShader> compiled = new ArrayList<>(shaders.size());
|
||||||
try {
|
try {
|
||||||
vsh = loadShader(ctx, vert, ShaderType.VERTEX, defines);
|
GlProgram.Builder builder = GlProgram.builder(name);
|
||||||
fsh = loadShader(ctx, frag, ShaderType.FRAGMENT, defines);
|
|
||||||
|
|
||||||
return GlProgram.builder(name)
|
for (Shader shader : shaders) {
|
||||||
.attachShader(vsh)
|
transformer.transformSource(shader);
|
||||||
.attachShader(fsh)
|
GlShader sh = new GlShader(shader);
|
||||||
.addAttributes(attribs)
|
compiled.add(sh);
|
||||||
.link();
|
|
||||||
|
builder.attachShader(sh);
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.link();
|
||||||
} finally {
|
} finally {
|
||||||
if (vsh != null) vsh.delete();
|
compiled.forEach(GlObject::delete);
|
||||||
if (fsh != null) fsh.delete();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlShader loadShader(ShaderContext<?> ctx, ResourceLocation name, ShaderType type, ShaderConstants defines) {
|
|
||||||
String source = shaderSource.get(name);
|
|
||||||
|
|
||||||
source = ctx.preProcess(this, type, name, source);
|
|
||||||
source = processIncludes(source, name);
|
|
||||||
|
|
||||||
if (defines != null)
|
|
||||||
source = defines.process(source);
|
|
||||||
|
|
||||||
if (debugDumpFile) {
|
|
||||||
printSource(name, source);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new GlShader(type, name, source);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void printSource(ResourceLocation name, String source) {
|
private void printSource(ResourceLocation name, String source) {
|
||||||
Backend.log.debug("Finished processing '" + name + "':");
|
Backend.log.debug("Finished processing '" + name + "':");
|
||||||
int i = 1;
|
int i = 1;
|
||||||
|
@ -158,11 +161,12 @@ public class ShaderLoader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String processIncludes(String source, ResourceLocation baseName) {
|
public void processIncludes(Shader shader) {
|
||||||
HashSet<ResourceLocation> seen = new HashSet<>();
|
HashSet<ResourceLocation> seen = new HashSet<>();
|
||||||
seen.add(baseName);
|
seen.add(shader.name);
|
||||||
|
|
||||||
return includeRecursive(source, seen).collect(Collectors.joining("\n"));
|
String includesInjected = includeRecursive(shader.getSource(), seen).collect(Collectors.joining("\n"));
|
||||||
|
shader.setSource(includesInjected);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Stream<String> includeRecursive(String source, Set<ResourceLocation> seen) {
|
private Stream<String> includeRecursive(String source, Set<ResourceLocation> seen) {
|
||||||
|
|
|
@ -22,6 +22,10 @@ public class BasicProgram extends GlProgram {
|
||||||
protected int uBlockAtlas;
|
protected int uBlockAtlas;
|
||||||
protected int uLightMap;
|
protected int uLightMap;
|
||||||
|
|
||||||
|
public BasicProgram(GlProgram.Builder builder, ProgramFogMode.Factory fogFactory) {
|
||||||
|
this(builder.name, builder.program, fogFactory);
|
||||||
|
}
|
||||||
|
|
||||||
public BasicProgram(ResourceLocation name, int handle, ProgramFogMode.Factory fogFactory) {
|
public BasicProgram(ResourceLocation name, int handle, ProgramFogMode.Factory fogFactory) {
|
||||||
super(name, handle);
|
super(name, handle);
|
||||||
uTime = getUniformLocation("uTime");
|
uTime = getUniformLocation("uTime");
|
||||||
|
|
|
@ -14,6 +14,7 @@ import com.jozufozu.flywheel.backend.gl.shader.IMultiProgram;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderSpecLoader;
|
import com.jozufozu.flywheel.backend.gl.shader.ShaderSpecLoader;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
||||||
import com.jozufozu.flywheel.backend.instancing.MaterialSpec;
|
import com.jozufozu.flywheel.backend.instancing.MaterialSpec;
|
||||||
|
import com.jozufozu.flywheel.backend.loading.Shader;
|
||||||
|
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
|
||||||
|
@ -50,15 +51,15 @@ public class WorldContext<P extends BasicProgram> extends ShaderContext<P> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String preProcess(ShaderLoader loader, ShaderType type, ResourceLocation shader, String shaderSrc) {
|
public void preProcess(ShaderLoader loader, Shader shader) {
|
||||||
String builtinSrc = loader.getShaderSource(builtins.get(type));
|
String builtinSrc = loader.getShaderSource(builtins.get(shader.type));
|
||||||
|
|
||||||
Matcher matcher = builtinPattern.matcher(shaderSrc);
|
Matcher matcher = builtinPattern.matcher(shader.getSource());
|
||||||
|
|
||||||
if (matcher.find())
|
if (matcher.find())
|
||||||
return matcher.replaceFirst(builtinSrc);
|
shader.setSource(matcher.replaceFirst(builtinSrc));
|
||||||
|
else
|
||||||
throw new RuntimeException(String.format("%s shader '%s' is missing %s, cannot use in World Context", type.name, shader, declaration));
|
throw new RuntimeException(String.format("%s shader '%s' is missing %s, cannot use in World Context", shader.type.name, shader.name, declaration));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -45,7 +45,7 @@ public class FogSensitiveProgram<P extends GlProgram> implements IMultiProgram<P
|
||||||
|
|
||||||
defines.defineAll(fogMode.getDefines());
|
defines.defineAll(fogMode.getDefines());
|
||||||
|
|
||||||
GlProgram.Builder builder = loader.loadProgram(ctx, spec, defines);
|
GlProgram.Builder builder = spec.loadProgram(ctx, defines, loader);
|
||||||
|
|
||||||
programs.put(fogMode, fogProgramLoader.create(builder.name, builder.program, fogMode.getFogFactory()));
|
programs.put(fogMode, fogProgramLoader.create(builder.name, builder.program, fogMode.getFogFactory()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import org.lwjgl.opengl.GL20;
|
||||||
import com.jozufozu.flywheel.backend.Backend;
|
import com.jozufozu.flywheel.backend.Backend;
|
||||||
import com.jozufozu.flywheel.backend.gl.GlObject;
|
import com.jozufozu.flywheel.backend.gl.GlObject;
|
||||||
import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
|
import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
|
||||||
|
import com.jozufozu.flywheel.backend.loading.Shader;
|
||||||
|
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
|
||||||
|
@ -13,6 +14,10 @@ public class GlShader extends GlObject {
|
||||||
public final ResourceLocation name;
|
public final ResourceLocation name;
|
||||||
public final ShaderType type;
|
public final ShaderType type;
|
||||||
|
|
||||||
|
public GlShader(Shader shader) {
|
||||||
|
this(shader.type, shader.name, shader.getSource());
|
||||||
|
}
|
||||||
|
|
||||||
public GlShader(ShaderType type, ResourceLocation name, String source) {
|
public GlShader(ShaderType type, ResourceLocation name, String source) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
@ -38,13 +43,4 @@ public class GlShader extends GlObject {
|
||||||
protected void deleteInternal(int handle) {
|
protected void deleteInternal(int handle) {
|
||||||
GL20.glDeleteShader(handle);
|
GL20.glDeleteShader(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
public interface PreProcessor {
|
|
||||||
String process(String source);
|
|
||||||
|
|
||||||
default PreProcessor andThen(PreProcessor that) {
|
|
||||||
return source -> that.process(this.process(source));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,12 @@ package com.jozufozu.flywheel.backend.gl.shader;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.backend.ShaderContext;
|
||||||
|
import com.jozufozu.flywheel.backend.ShaderLoader;
|
||||||
import com.jozufozu.flywheel.backend.gl.attrib.IVertexAttrib;
|
import com.jozufozu.flywheel.backend.gl.attrib.IVertexAttrib;
|
||||||
|
import com.jozufozu.flywheel.backend.loading.InstancedArraysTemplate;
|
||||||
|
import com.jozufozu.flywheel.backend.loading.Shader;
|
||||||
|
import com.jozufozu.flywheel.backend.loading.ShaderTransformer;
|
||||||
|
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
|
||||||
|
@ -30,6 +35,24 @@ public class ProgramSpec {
|
||||||
this.attributes = attributes;
|
this.attributes = attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GlProgram.Builder loadProgram(ShaderContext<?> ctx, ShaderConstants defines, ShaderLoader loader) {
|
||||||
|
InstancedArraysTemplate template = new InstancedArraysTemplate(loader);
|
||||||
|
|
||||||
|
ShaderTransformer transformer = new ShaderTransformer()
|
||||||
|
.pushStage(ctx.loadingStage(loader))
|
||||||
|
// .pushStage(loader::processIncludes)
|
||||||
|
// .pushStage(template)
|
||||||
|
.pushStage(loader::processIncludes);
|
||||||
|
|
||||||
|
if (defines != null)
|
||||||
|
transformer.pushStage(defines);
|
||||||
|
|
||||||
|
Shader vertexFile = loader.source(vert, ShaderType.VERTEX);
|
||||||
|
Shader fragmentFile = loader.source(frag, ShaderType.FRAGMENT);
|
||||||
|
return loader.loadProgram(name, transformer, vertexFile, fragmentFile)
|
||||||
|
.addAttributes(attributes);
|
||||||
|
}
|
||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
private ResourceLocation vert;
|
private ResourceLocation vert;
|
||||||
private ResourceLocation frag;
|
private ResourceLocation frag;
|
||||||
|
|
|
@ -8,8 +8,10 @@ import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
import com.jozufozu.flywheel.backend.loading.ProcessingStage;
|
||||||
|
import com.jozufozu.flywheel.backend.loading.Shader;
|
||||||
|
|
||||||
public class ShaderConstants implements GlShader.PreProcessor {
|
public class ShaderConstants implements ProcessingStage {
|
||||||
public static final ShaderConstants EMPTY = new ShaderConstants();
|
public static final ShaderConstants EMPTY = new ShaderConstants();
|
||||||
|
|
||||||
private final ArrayList<String> defines;
|
private final ArrayList<String> defines;
|
||||||
|
@ -45,8 +47,8 @@ public class ShaderConstants implements GlShader.PreProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String process(String source) {
|
public void process(Shader shader) {
|
||||||
return new BufferedReader(new StringReader(source)).lines().flatMap(line -> {
|
shader.setSource(new BufferedReader(new StringReader(shader.getSource())).lines().flatMap(line -> {
|
||||||
Stream<String> map = Stream.of(line);
|
Stream<String> map = Stream.of(line);
|
||||||
|
|
||||||
if (line.startsWith("#version")) {
|
if (line.startsWith("#version")) {
|
||||||
|
@ -54,6 +56,6 @@ public class ShaderConstants implements GlShader.PreProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
}).collect(Collectors.joining("\n"));
|
}).collect(Collectors.joining("\n")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ public class SingleProgram<P extends GlProgram> implements IMultiProgram<P> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IMultiProgram<P> create(ShaderLoader loader, ShaderContext<P> ctx, ProgramSpec spec) {
|
public IMultiProgram<P> create(ShaderLoader loader, ShaderContext<P> ctx, ProgramSpec spec) {
|
||||||
GlProgram.Builder builder = loader.loadProgram(ctx, spec);
|
GlProgram.Builder builder = spec.loadProgram(ctx, spec.defines, loader);
|
||||||
|
|
||||||
return new SingleProgram<>(factory.create(builder.name, builder.program));
|
return new SingleProgram<>(factory.create(builder.name, builder.program));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package com.jozufozu.flywheel.backend.loading;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.backend.ShaderLoader;
|
||||||
|
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
||||||
|
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
|
||||||
|
public class InstancedArraysTemplate extends ProgramTemplate {
|
||||||
|
public static final String[] requiredVert = {"FLWInstanceData", "FLWVertexData", "FLWFragment"};
|
||||||
|
public static final String[] requiredFrag = {"FLWFragment"};
|
||||||
|
|
||||||
|
public static final ResourceLocation vert = new ResourceLocation("create", "template/instanced/instanced.vert");
|
||||||
|
public static final ResourceLocation frag = new ResourceLocation("create", "template/instanced/instanced.frag");
|
||||||
|
|
||||||
|
public InstancedArraysTemplate(ShaderLoader loader) {
|
||||||
|
super(loader);
|
||||||
|
|
||||||
|
templates.put(ShaderType.VERTEX, new ShaderTemplate(requiredVert, loader.getShaderSource(vert)));
|
||||||
|
templates.put(ShaderType.FRAGMENT, new ShaderTemplate(requiredFrag, loader.getShaderSource(frag)));
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,17 +5,20 @@ import java.util.Map;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
|
||||||
public class ParsedShader {
|
public class ParsedShader {
|
||||||
private static final Pattern decorator = Pattern.compile("#\\[([\\w_]*)]");
|
private static final Pattern decorator = Pattern.compile("#\\[([\\w_]*)]");
|
||||||
private static final Pattern taggedStruct = Pattern.compile("#\\[([\\w_]*)]\\s*struct\\s+([\\w\\d_]*)\\s*\\{(\\s*(?:.*;\\s*\\n)+\\s*)}\\s*;");
|
private static final Pattern taggedStruct = Pattern.compile("#\\[([\\w_]*)]\\s*struct\\s+([\\w\\d_]*)\\s*\\{(\\s*(?:.*;\\s*\\n)+\\s*)}\\s*;");
|
||||||
|
|
||||||
|
final ResourceLocation loc;
|
||||||
final String src;
|
final String src;
|
||||||
|
|
||||||
final Map<String, TaggedStruct> tag2Struct = new HashMap<>();
|
final Map<String, TaggedStruct> tag2Struct = new HashMap<>();
|
||||||
final Map<String, TaggedStruct> name2Struct = new HashMap<>();
|
final Map<String, TaggedStruct> name2Struct = new HashMap<>();
|
||||||
|
|
||||||
public ParsedShader(String src) {
|
public ParsedShader(ResourceLocation loc, String src) {
|
||||||
|
this.loc = loc;
|
||||||
Matcher structs = taggedStruct.matcher(src);
|
Matcher structs = taggedStruct.matcher(src);
|
||||||
|
|
||||||
StringBuffer strippedSrc = new StringBuffer();
|
StringBuffer strippedSrc = new StringBuffer();
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.jozufozu.flywheel.backend.loading;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface ProcessingStage {
|
||||||
|
|
||||||
|
void process(Shader shader);
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package com.jozufozu.flywheel.backend.loading;
|
||||||
|
|
||||||
|
import java.util.EnumMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.backend.ShaderLoader;
|
||||||
|
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
||||||
|
|
||||||
|
public class ProgramTemplate implements ProcessingStage {
|
||||||
|
|
||||||
|
protected final ShaderLoader loader;
|
||||||
|
protected Map<ShaderType, ShaderTemplate> templates = new EnumMap<>(ShaderType.class);
|
||||||
|
|
||||||
|
public ProgramTemplate(ShaderLoader loader) {
|
||||||
|
this.loader = loader;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(Shader shader) {
|
||||||
|
ShaderTemplate template = templates.get(shader.type);
|
||||||
|
|
||||||
|
if (template == null) return;
|
||||||
|
|
||||||
|
ParsedShader parsedShader = new ParsedShader(shader.name, shader.getSource());
|
||||||
|
|
||||||
|
shader.setSource(template.apply(parsedShader));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.jozufozu.flywheel.backend.loading;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
||||||
|
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
|
||||||
|
public class Shader {
|
||||||
|
public ShaderType type;
|
||||||
|
public ResourceLocation name;
|
||||||
|
private String source;
|
||||||
|
|
||||||
|
public Shader(ShaderType type, ResourceLocation name, String source) {
|
||||||
|
this.type = type;
|
||||||
|
this.name = name;
|
||||||
|
this.setSource(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Shader vert(ResourceLocation fileLoc, String source) {
|
||||||
|
return new Shader(ShaderType.VERTEX, fileLoc, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Shader frag(ResourceLocation fileLoc, String source) {
|
||||||
|
return new Shader(ShaderType.FRAGMENT, fileLoc, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSource() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSource(String source) {
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,22 +1,26 @@
|
||||||
package com.jozufozu.flywheel.backend.loading;
|
package com.jozufozu.flywheel.backend.loading;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class InstancedArraysShaderTemplate {
|
public class ShaderTemplate {
|
||||||
|
|
||||||
private static final String delimiter = "#flwbeginbody";
|
private static final String delimiter = "#flwbeginbody";
|
||||||
private static final Pattern headerFinder = Pattern.compile(delimiter);
|
private static final Pattern headerFinder = Pattern.compile(delimiter);
|
||||||
|
|
||||||
private static final Pattern prefixer = Pattern.compile("#FLWPrefixFields\\((\\S+),\\s*([^\\n]+)\\)");
|
private static final Pattern prefixer = Pattern.compile("#FLWPrefixFields\\((\\w+),\\s*(\\w+),\\s*([\\w\\d]+)\\)");
|
||||||
private static final Pattern assigner = Pattern.compile("#FLWAssignFields\\(([\\w\\d_]+),\\s*([\\w\\d_.]+),\\s*([\\w\\d_.]+)\\)");
|
private static final Pattern assigner = Pattern.compile("#FLWAssignFields\\(([\\w\\d_]+),\\s*([\\w\\d_.]+),\\s*([\\w\\d_.]+)\\)");
|
||||||
|
|
||||||
public static final String[] required = {"FLWInstanceData", "FLWVertexData", "FLWFragment"};
|
final String[] requiredStructs;
|
||||||
|
|
||||||
final String header;
|
final String header;
|
||||||
final String body;
|
final String body;
|
||||||
|
|
||||||
public InstancedArraysShaderTemplate(String templateSrc) {
|
public ShaderTemplate(String[] requiredStructs, String templateSrc) {
|
||||||
|
this.requiredStructs = requiredStructs;
|
||||||
Matcher matcher = headerFinder.matcher(templateSrc);
|
Matcher matcher = headerFinder.matcher(templateSrc);
|
||||||
|
|
||||||
if (!matcher.find()) {
|
if (!matcher.find()) {
|
||||||
|
@ -38,10 +42,21 @@ public class InstancedArraysShaderTemplate {
|
||||||
public String processBody(ParsedShader shader) {
|
public String processBody(ParsedShader shader) {
|
||||||
String s = body;
|
String s = body;
|
||||||
|
|
||||||
for (String name : required) {
|
List<String> missing = new ArrayList<>();
|
||||||
|
|
||||||
|
for (String name : requiredStructs) {
|
||||||
TaggedStruct struct = shader.getTag(name);
|
TaggedStruct struct = shader.getTag(name);
|
||||||
|
|
||||||
s = s.replace(name, struct.name);
|
if (struct != null) {
|
||||||
|
s = s.replace(name, struct.name);
|
||||||
|
} else {
|
||||||
|
missing.add(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!missing.isEmpty()) {
|
||||||
|
String err = shader.loc + " is missing: " + String.join(", ", missing);
|
||||||
|
throw new RuntimeException(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
s = fillPrefixes(shader, s);
|
s = fillPrefixes(shader, s);
|
||||||
|
@ -56,14 +71,19 @@ public class InstancedArraysShaderTemplate {
|
||||||
StringBuffer out = new StringBuffer();
|
StringBuffer out = new StringBuffer();
|
||||||
while (prefixMatches.find()) {
|
while (prefixMatches.find()) {
|
||||||
String structName = prefixMatches.group(1);
|
String structName = prefixMatches.group(1);
|
||||||
String prefix = prefixMatches.group(2);
|
String modifier = prefixMatches.group(2);
|
||||||
|
String prefix = prefixMatches.group(3);
|
||||||
|
|
||||||
TaggedStruct struct = shader.getStruct(structName);
|
TaggedStruct struct = shader.getStruct(structName);
|
||||||
|
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
for (String field : struct.fields.keySet()) {
|
for (Map.Entry<String, String> field : struct.fields.entrySet()) {
|
||||||
|
builder.append(modifier);
|
||||||
|
builder.append(' ');
|
||||||
|
builder.append(field.getValue());
|
||||||
|
builder.append(' ');
|
||||||
builder.append(prefix);
|
builder.append(prefix);
|
||||||
builder.append(field);
|
builder.append(field.getKey());
|
||||||
builder.append(";\n");
|
builder.append(";\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.jozufozu.flywheel.backend.loading;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
public class ShaderTransformer {
|
||||||
|
|
||||||
|
private final LinkedList<ProcessingStage> stages = new LinkedList<>();
|
||||||
|
|
||||||
|
public ShaderTransformer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShaderTransformer pushStage(ProcessingStage stage) {
|
||||||
|
if (stage != null) {
|
||||||
|
stages.addLast(stage);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShaderTransformer prependStage(ProcessingStage stage) {
|
||||||
|
if (stage != null) {
|
||||||
|
stages.addFirst(stage);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void transformSource(Shader shader) {
|
||||||
|
|
||||||
|
for (ProcessingStage stage : this.stages) {
|
||||||
|
stage.process(shader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,3 @@
|
||||||
#version 110
|
|
||||||
|
|
||||||
#flwbuiltins
|
#flwbuiltins
|
||||||
|
|
||||||
#[FLWFragment]
|
#[FLWFragment]
|
||||||
|
|
|
@ -29,12 +29,11 @@ Raster FLWMain(Vertex v, Instance i) {
|
||||||
vec4 worldPos = i.transform * vec4(v.pos, 1.);
|
vec4 worldPos = i.transform * vec4(v.pos, 1.);
|
||||||
|
|
||||||
vec3 norm = i.normalMat * v.normal;
|
vec3 norm = i.normalMat * v.normal;
|
||||||
|
norm = normalize(norm);
|
||||||
|
|
||||||
FLWFinalizeWorldPos(worldPos);
|
FLWFinalizeWorldPos(worldPos);
|
||||||
FLWFinalizeNormal(norm);
|
FLWFinalizeNormal(norm);
|
||||||
|
|
||||||
norm = normalize(norm);
|
|
||||||
|
|
||||||
Raster r;
|
Raster r;
|
||||||
r.diffuse = diffuse(norm);
|
r.diffuse = diffuse(norm);
|
||||||
r.texCoords = v.texCoords;
|
r.texCoords = v.texCoords;
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
#version 110
|
|
||||||
|
|
||||||
#flwbeginbody
|
|
||||||
|
|
||||||
#FLWPrefixFields(FLWFragment, varying __v2f_)
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
FLWFragment f;
|
|
||||||
#FLWAssignFields(FLWFragment, f., __v2f_)
|
|
||||||
|
|
||||||
FLWMain(f);
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
#version 110
|
|
||||||
|
|
||||||
#flwbeginbody
|
|
||||||
#FLWPrefixFields(FLWVertexData, attribute __a_)
|
|
||||||
#FLWPrefixFields(FLWInstanceData, attribute __a_)
|
|
||||||
|
|
||||||
#FLWPrefixFields(FLWFragment, varying __v2f_)
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
FLWVertexData v;
|
|
||||||
#FLWAssignFields(FLWVertexData, v., __a_)
|
|
||||||
|
|
||||||
FLWInstanceData i;
|
|
||||||
#FLWAssignFields(FLWInstanceData, i., __a_)
|
|
||||||
|
|
||||||
FLWFragment o = FLWMain(v, i);
|
|
||||||
|
|
||||||
#FLWAssignFields(FLWFragment, __v2f_, o.)
|
|
||||||
}
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
#version 110
|
||||||
|
|
||||||
|
#flwbeginbody
|
||||||
|
|
||||||
|
#FLWPrefixFields(FLWFragment, varying, v2f_)
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
FLWFragment f;
|
||||||
|
#FLWAssignFields(FLWFragment, f., v2f_)
|
||||||
|
|
||||||
|
FLWMain(f);
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
#version 110
|
||||||
|
|
||||||
|
#flwbeginbody
|
||||||
|
#FLWPrefixFields(FLWVertexData, attribute, a_v_)
|
||||||
|
#FLWPrefixFields(FLWInstanceData, attribute, a_i_)
|
||||||
|
|
||||||
|
#FLWPrefixFields(FLWFragment, varying, v2f_)
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
FLWVertexData v;
|
||||||
|
#FLWAssignFields(FLWVertexData, v., a_v_)
|
||||||
|
|
||||||
|
FLWInstanceData i;
|
||||||
|
#FLWAssignFields(FLWInstanceData, i., a_i_)
|
||||||
|
|
||||||
|
FLWFragment o = FLWMain(v, i);
|
||||||
|
|
||||||
|
#FLWAssignFields(FLWFragment, v2f_, o.)
|
||||||
|
}
|
Loading…
Reference in a new issue