Extremely fancy shader templating
- Nothing is properly hooked up yet. - A single shader file will be able to be compiled with different opengl targets. - I plan on using this to implement meshlet rendering as an alternate backend-backend that will be used when available. - It could also be used to enable compatibility with opengl 3.0 or potentially even 2.0.
This commit is contained in:
parent
2c4d650639
commit
c1b7a1c19d
8 changed files with 282 additions and 10 deletions
|
@ -58,6 +58,16 @@ public class ShaderLoader {
|
|||
shaderSource.clear();
|
||||
loadShaderSources(manager);
|
||||
|
||||
// ResourceLocation test = new ResourceLocation("create", "model_new.vert");
|
||||
// ResourceLocation vert = new ResourceLocation("create", "skeleton/instanced/instanced.vert");
|
||||
//
|
||||
// InstancedArraysShaderTemplate template = new InstancedArraysShaderTemplate(getShaderSource(vert));
|
||||
// ParsedShader parsedShader = new ParsedShader(getShaderSource(test));
|
||||
//
|
||||
// String apply = template.apply(parsedShader);
|
||||
//
|
||||
// printSource(test, apply);
|
||||
|
||||
for (ShaderContext<?> context : Backend.contexts.values()) {
|
||||
context.load(this);
|
||||
}
|
||||
|
@ -134,16 +144,20 @@ public class ShaderLoader {
|
|||
source = defines.process(source);
|
||||
|
||||
if (debugDumpFile) {
|
||||
Backend.log.debug("Finished processing '" + name + "':");
|
||||
int i = 1;
|
||||
for (String s : source.split("\n")) {
|
||||
Backend.log.debug(String.format("%1$4s: ", i++) + s);
|
||||
}
|
||||
printSource(name, source);
|
||||
}
|
||||
|
||||
return new GlShader(type, name, source);
|
||||
}
|
||||
|
||||
private void printSource(ResourceLocation name, String source) {
|
||||
Backend.log.debug("Finished processing '" + name + "':");
|
||||
int i = 1;
|
||||
for (String s : source.split("\n")) {
|
||||
Backend.log.debug(String.format("%1$4s: ", i++) + s);
|
||||
}
|
||||
}
|
||||
|
||||
private String processIncludes(String source, ResourceLocation baseName) {
|
||||
HashSet<ResourceLocation> seen = new HashSet<>();
|
||||
seen.add(baseName);
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
package com.jozufozu.flywheel.backend.loading;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class InstancedArraysShaderTemplate {
|
||||
|
||||
private static final String delimiter = "#flwbeginbody";
|
||||
private static final Pattern headerFinder = Pattern.compile(delimiter);
|
||||
|
||||
private static final Pattern prefixer = Pattern.compile("#FLWPrefixFields\\((\\S+),\\s*([^\\n]+)\\)");
|
||||
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 header;
|
||||
final String body;
|
||||
|
||||
public InstancedArraysShaderTemplate(String templateSrc) {
|
||||
Matcher matcher = headerFinder.matcher(templateSrc);
|
||||
|
||||
if (!matcher.find()) {
|
||||
throw new RuntimeException("Shader template must have a header and footer delimited by '" + delimiter + "'");
|
||||
}
|
||||
|
||||
this.header = templateSrc.substring(0, matcher.start());
|
||||
this.body = templateSrc.substring(matcher.end());
|
||||
|
||||
}
|
||||
|
||||
public String apply(ParsedShader shader) {
|
||||
|
||||
return header +
|
||||
shader.src +
|
||||
processBody(shader);
|
||||
}
|
||||
|
||||
public String processBody(ParsedShader shader) {
|
||||
String s = body;
|
||||
|
||||
for (String name : required) {
|
||||
TaggedStruct struct = shader.getTag(name);
|
||||
|
||||
s = s.replace(name, struct.name);
|
||||
}
|
||||
|
||||
s = fillPrefixes(shader, s);
|
||||
s = fillAssigns(shader, s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private String fillPrefixes(ParsedShader shader, String s) {
|
||||
Matcher prefixMatches = prefixer.matcher(s);
|
||||
|
||||
StringBuffer out = new StringBuffer();
|
||||
while (prefixMatches.find()) {
|
||||
String structName = prefixMatches.group(1);
|
||||
String prefix = prefixMatches.group(2);
|
||||
|
||||
TaggedStruct struct = shader.getStruct(structName);
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (String field : struct.fields.keySet()) {
|
||||
builder.append(prefix);
|
||||
builder.append(field);
|
||||
builder.append(";\n");
|
||||
}
|
||||
|
||||
prefixMatches.appendReplacement(out, builder.toString());
|
||||
}
|
||||
prefixMatches.appendTail(out);
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
private String fillAssigns(ParsedShader shader, String s) {
|
||||
Matcher assignMatches = assigner.matcher(s);
|
||||
|
||||
StringBuffer out = new StringBuffer();
|
||||
while (assignMatches.find()) {
|
||||
String structName = assignMatches.group(1);
|
||||
String lhs = assignMatches.group(2);
|
||||
String rhs = assignMatches.group(3);
|
||||
|
||||
TaggedStruct struct = shader.getStruct(structName);
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (String field : struct.fields.keySet()) {
|
||||
builder.append(lhs);
|
||||
builder.append(field);
|
||||
builder.append(" = ");
|
||||
builder.append(rhs);
|
||||
builder.append(field);
|
||||
builder.append(";\n");
|
||||
}
|
||||
|
||||
assignMatches.appendReplacement(out, builder.toString());
|
||||
}
|
||||
assignMatches.appendTail(out);
|
||||
return out.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package com.jozufozu.flywheel.backend.loading;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ParsedShader {
|
||||
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*;");
|
||||
|
||||
final String src;
|
||||
|
||||
final Map<String, TaggedStruct> tag2Struct = new HashMap<>();
|
||||
final Map<String, TaggedStruct> name2Struct = new HashMap<>();
|
||||
|
||||
public ParsedShader(String src) {
|
||||
|
||||
Matcher structs = taggedStruct.matcher(src);
|
||||
|
||||
StringBuffer strippedSrc = new StringBuffer();
|
||||
while (structs.find()) {
|
||||
TaggedStruct struct = new TaggedStruct(structs);
|
||||
|
||||
structs.appendReplacement(strippedSrc, decorator.matcher(struct.source).replaceFirst(""));
|
||||
|
||||
tag2Struct.put(struct.tag, struct);
|
||||
name2Struct.put(struct.name, struct);
|
||||
}
|
||||
structs.appendTail(strippedSrc);
|
||||
|
||||
this.src = strippedSrc.toString();
|
||||
}
|
||||
|
||||
public TaggedStruct getTag(String tag) {
|
||||
return tag2Struct.get(tag);
|
||||
}
|
||||
|
||||
public TaggedStruct getStruct(String name) {
|
||||
return name2Struct.get(name);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package com.jozufozu.flywheel.backend.loading;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class TaggedStruct {
|
||||
|
||||
public static final Pattern fieldPattern = Pattern.compile("(\\S+)\\s*(\\S+);");
|
||||
|
||||
int srcStart, srcEnd;
|
||||
String source;
|
||||
String tag;
|
||||
String name;
|
||||
String body;
|
||||
|
||||
Map<String, String> fields = new HashMap<>();
|
||||
|
||||
public TaggedStruct(Matcher foundMatcher) {
|
||||
this.source = foundMatcher.group();
|
||||
|
||||
srcStart = foundMatcher.start();
|
||||
srcEnd = foundMatcher.end();
|
||||
|
||||
tag = foundMatcher.group(1);
|
||||
name = foundMatcher.group(2);
|
||||
body = foundMatcher.group(3);
|
||||
|
||||
Matcher fielder = fieldPattern.matcher(body);
|
||||
|
||||
while (fielder.find()) {
|
||||
fields.put(fielder.group(2), fielder.group(1));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#version 110
|
||||
|
||||
#flwbuiltins
|
||||
|
||||
#[FLWFragment]
|
||||
struct Raster {
|
||||
vec2 texCoords;
|
||||
vec4 color;
|
||||
float diffuse;
|
||||
vec2 light;
|
||||
};
|
||||
|
||||
void FLWMain(Raster r) {
|
||||
vec4 tex = FLWBlockTexture(r.texCoords);
|
||||
|
||||
vec4 color = vec4(tex.rgb * FLWLight(r.light).rgb * r.diffuse, tex.a) * r.color;
|
||||
|
||||
FLWFinalizeColor(color);
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
#flwbuiltins
|
||||
#flwinclude <"create:core/matutils.glsl">
|
||||
#flwinclude <"create:core/diffuse.glsl">
|
||||
|
||||
#[FLWVertexData]
|
||||
struct Vertex {
|
||||
vec3 pos;
|
||||
vec3 normal;
|
||||
vec2 texCoords;
|
||||
};
|
||||
|
||||
#[FLWInstanceData]
|
||||
struct Instance {
|
||||
vec2 light;
|
||||
vec4 color;
|
||||
mat4 transform;
|
||||
mat3 normalMat;
|
||||
};
|
||||
|
||||
#[FLWFragment]
|
||||
struct Raster {
|
||||
vec2 texCoords;
|
||||
vec4 color;
|
||||
float diffuse;
|
||||
vec2 light;
|
||||
};
|
||||
|
||||
Raster FLWMain(Vertex v, Instance i) {
|
||||
vec4 worldPos = i.transform * vec4(v.pos, 1.);
|
||||
|
||||
vec3 norm = i.normalMat * v.normal;
|
||||
|
||||
FLWFinalizeWorldPos(worldPos);
|
||||
FLWFinalizeNormal(norm);
|
||||
|
||||
norm = normalize(norm);
|
||||
|
||||
Raster r;
|
||||
r.diffuse = diffuse(norm);
|
||||
r.texCoords = v.texCoords;
|
||||
r.light = i.light;
|
||||
r.color = i.color;
|
||||
|
||||
return r;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#version 110
|
||||
|
||||
#flwbeginbody
|
||||
|
||||
#FLWPrefixFields(FLWFragment, varying __v2f_)
|
||||
|
||||
void main() {
|
||||
FLWFragment f;
|
||||
#FLWAssignFields(FLWFragment, f., __v2f_)
|
||||
|
||||
FLWMain(f);
|
||||
}
|
|
@ -1,17 +1,19 @@
|
|||
#version 110
|
||||
|
||||
#flwbeginbody
|
||||
#FLWPrefixFields(FLWVertexData, attribute __a_)
|
||||
#FLWPrefixFields(FLWInstanceData, attribute __a_)
|
||||
|
||||
#FLWPrefixFields(FLWOut, varying __v2f_)
|
||||
#FLWPrefixFields(FLWFragment, varying __v2f_)
|
||||
|
||||
void main() {
|
||||
FLWVertexData v;
|
||||
#FLWAssignToFields(FLWVertexData, v, a_)
|
||||
#FLWAssignFields(FLWVertexData, v., __a_)
|
||||
|
||||
FLWInstanceData i;
|
||||
#FLWAssignToFields(FLWInstanceData, i, a_)
|
||||
#FLWAssignFields(FLWInstanceData, i., __a_)
|
||||
|
||||
FLWOut o = FLWMain(v, i);
|
||||
FLWFragment o = FLWMain(v, i);
|
||||
|
||||
#FLWAssignFromFields(FLWOut, o, v2f_)
|
||||
#FLWAssignFields(FLWFragment, __v2f_, o.)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue