mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-01 01:46:39 +01:00
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();
|
shaderSource.clear();
|
||||||
loadShaderSources(manager);
|
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()) {
|
for (ShaderContext<?> context : Backend.contexts.values()) {
|
||||||
context.load(this);
|
context.load(this);
|
||||||
}
|
}
|
||||||
|
@ -134,16 +144,20 @@ public class ShaderLoader {
|
||||||
source = defines.process(source);
|
source = defines.process(source);
|
||||||
|
|
||||||
if (debugDumpFile) {
|
if (debugDumpFile) {
|
||||||
Backend.log.debug("Finished processing '" + name + "':");
|
printSource(name, source);
|
||||||
int i = 1;
|
|
||||||
for (String s : source.split("\n")) {
|
|
||||||
Backend.log.debug(String.format("%1$4s: ", i++) + s);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new GlShader(type, 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) {
|
private String processIncludes(String source, ResourceLocation baseName) {
|
||||||
HashSet<ResourceLocation> seen = new HashSet<>();
|
HashSet<ResourceLocation> seen = new HashSet<>();
|
||||||
seen.add(baseName);
|
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
|
#version 110
|
||||||
|
|
||||||
|
#flwbeginbody
|
||||||
#FLWPrefixFields(FLWVertexData, attribute __a_)
|
#FLWPrefixFields(FLWVertexData, attribute __a_)
|
||||||
#FLWPrefixFields(FLWInstanceData, attribute __a_)
|
#FLWPrefixFields(FLWInstanceData, attribute __a_)
|
||||||
|
|
||||||
#FLWPrefixFields(FLWOut, varying __v2f_)
|
#FLWPrefixFields(FLWFragment, varying __v2f_)
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
FLWVertexData v;
|
FLWVertexData v;
|
||||||
#FLWAssignToFields(FLWVertexData, v, a_)
|
#FLWAssignFields(FLWVertexData, v., __a_)
|
||||||
|
|
||||||
FLWInstanceData i;
|
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