mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-12-27 07:26:48 +01:00
Separate vertex and fragment shaders and templates
This commit is contained in:
parent
12cab85f69
commit
2d63d8c7db
28 changed files with 379 additions and 400 deletions
|
@ -32,6 +32,8 @@ public interface VertexType {
|
|||
*/
|
||||
VertexList createReader(ByteBuffer buffer, int vertexCount);
|
||||
|
||||
String getShaderHeader();
|
||||
|
||||
default int getStride() {
|
||||
return getLayout().getStride();
|
||||
}
|
||||
|
@ -39,6 +41,4 @@ public interface VertexType {
|
|||
default int byteOffset(int vertexIndex) {
|
||||
return getStride() * vertexIndex;
|
||||
}
|
||||
|
||||
String writeShaderHeader();
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ 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.compile.ShaderCompiler;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
|
@ -14,8 +13,8 @@ public class GlShader extends GlObject {
|
|||
public final ResourceLocation name;
|
||||
public final ShaderType type;
|
||||
|
||||
public GlShader(ShaderCompiler env, ShaderType type, String source) {
|
||||
name = env.name;
|
||||
public GlShader(ResourceLocation name, ShaderType type, String source) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
int handle = GL20.glCreateShader(type.glEnum);
|
||||
|
||||
|
@ -24,9 +23,9 @@ public class GlShader extends GlObject {
|
|||
|
||||
String log = GL20.glGetShaderInfoLog(handle);
|
||||
|
||||
if (!log.isEmpty()) {
|
||||
env.printShaderInfoLog(source, log, this.name);
|
||||
}
|
||||
// if (!log.isEmpty()) {
|
||||
// env.printShaderInfoLog(source, log, this.name);
|
||||
// }
|
||||
|
||||
if (GL20.glGetShaderi(handle, GL20.GL_COMPILE_STATUS) != GL20.GL_TRUE) {
|
||||
throw new ShaderLoadingException("Could not compile " + name + ". See log for details.");
|
||||
|
|
|
@ -3,15 +3,12 @@ package com.jozufozu.flywheel.backend.instancing.instancing;
|
|||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.api.MaterialGroup;
|
||||
import com.jozufozu.flywheel.backend.RenderLayer;
|
||||
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.compile.ProgramCompiler;
|
||||
|
@ -24,7 +21,6 @@ import net.minecraft.client.Camera;
|
|||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Vec3i;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Mth;
|
||||
|
||||
public class InstancingEngine<P extends WorldProgram> implements Engine {
|
||||
|
|
|
@ -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.compile.ShaderCompiler;
|
||||
import com.jozufozu.flywheel.core.compile.FileIndex;
|
||||
import com.jozufozu.flywheel.util.FlwUtil;
|
||||
|
||||
public class ErrorBuilder {
|
||||
|
@ -45,7 +45,7 @@ public class ErrorBuilder {
|
|||
}
|
||||
|
||||
@Nullable
|
||||
public static ErrorBuilder fromLogLine(ShaderCompiler env, String s) {
|
||||
public static ErrorBuilder fromLogLine(FileIndex env, String s) {
|
||||
Matcher matcher = ERROR_LINE.matcher(s);
|
||||
|
||||
if (matcher.find()) {
|
||||
|
|
|
@ -27,8 +27,8 @@ public class Contexts {
|
|||
FileResolution worldBuiltins = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.WORLD, ".glsl"));
|
||||
FileResolution crumblingBuiltins = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.CRUMBLING, ".glsl"));
|
||||
|
||||
WORLD = Templates.INSTANCING.programCompiler(WorldProgram::new, worldBuiltins);
|
||||
CRUMBLING = Templates.INSTANCING.programCompiler(CrumblingProgram::new, crumblingBuiltins);
|
||||
WORLD = ProgramCompiler.create(Templates.INSTANCING, WorldProgram::new, worldBuiltins);
|
||||
CRUMBLING = ProgramCompiler.create(Templates.INSTANCING, CrumblingProgram::new, crumblingBuiltins);
|
||||
}
|
||||
|
||||
public static class Names {
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
package com.jozufozu.flywheel.core;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
||||
import com.jozufozu.flywheel.core.compile.FragmentTemplateData;
|
||||
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 INSTANCING = new Template(GLSLVersion.V330, InstancingTemplateData::new);
|
||||
public static final Template ONE_SHOT = new Template(GLSLVersion.V150, OneShotTemplateData::new);
|
||||
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<FragmentTemplateData> FRAGMENT = new Template<>(GLSLVersion.V150, FragmentTemplateData::new);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.jozufozu.flywheel.core.compile;
|
||||
|
||||
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||
import com.jozufozu.flywheel.backend.source.span.Span;
|
||||
|
||||
public interface FileIndex {
|
||||
/**
|
||||
|
@ -10,4 +11,10 @@ public interface FileIndex {
|
|||
* @return A file ID unique to the given sourceFile.
|
||||
*/
|
||||
int getFileID(SourceFile sourceFile);
|
||||
|
||||
SourceFile getFile(int fileID);
|
||||
|
||||
default Span getLineSpan(int fileId, int lineNo) {
|
||||
return getFile(fileId).getLineSpanNoWhitespace(lineNo);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
package com.jozufozu.flywheel.core.compile;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||
import com.jozufozu.flywheel.backend.source.error.ErrorBuilder;
|
||||
import com.jozufozu.flywheel.backend.source.error.ErrorReporter;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class FileIndexImpl implements FileIndex {
|
||||
public final List<SourceFile> files = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@Override
|
||||
public int getFileID(SourceFile sourceFile) {
|
||||
int i = files.indexOf(sourceFile);
|
||||
if (i != -1) {
|
||||
return i;
|
||||
}
|
||||
|
||||
int size = files.size();
|
||||
files.add(sourceFile);
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceFile getFile(int fileId) {
|
||||
return files.get(fileId);
|
||||
}
|
||||
|
||||
|
||||
public void printShaderInfoLog(String source, String log, ResourceLocation name) {
|
||||
List<String> lines = log.lines()
|
||||
.toList();
|
||||
|
||||
boolean needsSourceDump = false;
|
||||
|
||||
StringBuilder errors = new StringBuilder();
|
||||
for (String line : lines) {
|
||||
ErrorBuilder builder = parseCompilerError(line);
|
||||
|
||||
if (builder != null) {
|
||||
errors.append(builder.build());
|
||||
} else {
|
||||
errors.append(line).append('\n');
|
||||
needsSourceDump = true;
|
||||
}
|
||||
}
|
||||
Backend.LOGGER.error("Errors compiling '" + name + "': \n" + errors);
|
||||
if (needsSourceDump) {
|
||||
// TODO: generated code gets its own "file"
|
||||
ErrorReporter.printLines(source);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ErrorBuilder parseCompilerError(String line) {
|
||||
try {
|
||||
ErrorBuilder error = ErrorBuilder.fromLogLine(this, line);
|
||||
if (error != null) {
|
||||
return error;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package com.jozufozu.flywheel.core.compile;
|
||||
|
||||
public interface FragmentData {
|
||||
/**
|
||||
* Generate the necessary glue code here.
|
||||
*/
|
||||
String generateFooter();
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
package com.jozufozu.flywheel.core.compile;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||
import com.jozufozu.flywheel.backend.source.error.ErrorReporter;
|
||||
import com.jozufozu.flywheel.backend.source.parse.ShaderFunction;
|
||||
import com.jozufozu.flywheel.backend.source.parse.ShaderStruct;
|
||||
import com.jozufozu.flywheel.backend.source.parse.StructField;
|
||||
import com.jozufozu.flywheel.backend.source.parse.Variable;
|
||||
import com.jozufozu.flywheel.backend.source.span.Span;
|
||||
|
||||
public class FragmentTemplateData implements FragmentData {
|
||||
public final SourceFile file;
|
||||
public final Span interpolantName;
|
||||
public final ShaderStruct interpolant;
|
||||
public final ShaderFunction fragmentMain;
|
||||
|
||||
public FragmentTemplateData(SourceFile file) {
|
||||
this.file = file;
|
||||
|
||||
Optional<ShaderFunction> maybeFragmentMain = file.findFunction("fragment");
|
||||
|
||||
if (maybeFragmentMain.isEmpty()) {
|
||||
ErrorReporter.generateMissingFunction(file, "fragment", "\"fragment\" function not defined");
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
fragmentMain = maybeFragmentMain.get();
|
||||
ImmutableList<Variable> fragmentParameters = fragmentMain.getParameters();
|
||||
|
||||
|
||||
if (fragmentParameters.size() != 1) {
|
||||
ErrorReporter.generateSpanError(fragmentMain.getArgs(), "fragment function must have exactly one argument");
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
interpolantName = fragmentMain.getParameters().get(0).type;
|
||||
|
||||
Optional<ShaderStruct> maybeInterpolant = file.findStruct(interpolantName);
|
||||
|
||||
if (maybeInterpolant.isEmpty()) {
|
||||
ErrorReporter.generateMissingStruct(file, interpolantName, "struct not defined");
|
||||
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
interpolant = maybeInterpolant.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateFooter() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
prefixFields(builder, interpolant, "in", "v2f_");
|
||||
|
||||
builder.append(String.format("""
|
||||
void main() {
|
||||
Fragment o;
|
||||
o.color = v2f_color;
|
||||
o.texCoords = v2f_texCoords;
|
||||
o.light = v2f_light;
|
||||
o.diffuse = v2f_diffuse;
|
||||
|
||||
vec4 color = %s;
|
||||
FLWFinalizeColor(color);
|
||||
}
|
||||
""",
|
||||
fragmentMain.call("o")
|
||||
));
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static void prefixFields(StringBuilder builder, ShaderStruct struct, String qualifier, String prefix) {
|
||||
ImmutableList<StructField> fields = struct.getFields();
|
||||
|
||||
for (StructField field : fields) {
|
||||
builder.append(qualifier)
|
||||
.append(' ')
|
||||
.append(field.type)
|
||||
.append(' ')
|
||||
.append(prefix)
|
||||
.append(field.name)
|
||||
.append(";\n");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,43 +13,27 @@ import com.jozufozu.flywheel.backend.source.parse.StructField;
|
|||
import com.jozufozu.flywheel.backend.source.parse.Variable;
|
||||
import com.jozufozu.flywheel.backend.source.span.Span;
|
||||
|
||||
public class InstancingTemplateData implements TemplateData {
|
||||
public class InstancingTemplateData implements VertexData {
|
||||
|
||||
public final SourceFile file;
|
||||
public final ShaderFunction vertexMain;
|
||||
public final ShaderFunction fragmentMain;
|
||||
public final Span interpolantName;
|
||||
public final Span vertexName;
|
||||
public final Span instanceName;
|
||||
public final ShaderStruct interpolant;
|
||||
public final ShaderStruct instance;
|
||||
|
||||
public InstancingTemplateData(SourceFile file) {
|
||||
this.file = file;
|
||||
|
||||
Optional<ShaderFunction> vertexFunc = file.findFunction("vertex");
|
||||
Optional<ShaderFunction> fragmentFunc = file.findFunction("fragment");
|
||||
|
||||
if (fragmentFunc.isEmpty()) {
|
||||
ErrorReporter.generateMissingFunction(file, "fragment", "\"fragment\" function not defined");
|
||||
}
|
||||
if (vertexFunc.isEmpty()) {
|
||||
ErrorReporter.generateFileError(file, "could not find \"vertex\" function");
|
||||
}
|
||||
|
||||
if (fragmentFunc.isEmpty() || vertexFunc.isEmpty()) {
|
||||
throw new ShaderLoadingException();
|
||||
}
|
||||
|
||||
fragmentMain = fragmentFunc.get();
|
||||
vertexMain = vertexFunc.get();
|
||||
ImmutableList<Variable> parameters = fragmentMain.getParameters();
|
||||
ImmutableList<Variable> vertexParams = vertexMain.getParameters();
|
||||
|
||||
if (parameters.size() != 1) {
|
||||
ErrorReporter.generateSpanError(fragmentMain.getArgs(), "instancing requires fragment function to have 1 argument");
|
||||
}
|
||||
|
||||
if (vertexParams.size() != 2) {
|
||||
ErrorReporter.generateSpanError(vertexMain.getArgs(), "instancing requires vertex function to have 2 arguments");
|
||||
throw new ShaderLoadingException();
|
||||
|
@ -68,35 +52,27 @@ public class InstancingTemplateData implements TemplateData {
|
|||
throw new ShaderLoadingException();
|
||||
}
|
||||
|
||||
interpolantName = parameters.get(0).type;
|
||||
instanceName = vertexParams.get(1).type;
|
||||
|
||||
Optional<ShaderStruct> maybeInterpolant = file.findStruct(interpolantName);
|
||||
Optional<ShaderStruct> maybeInstance = file.findStruct(instanceName);
|
||||
|
||||
if (maybeInterpolant.isEmpty()) {
|
||||
ErrorReporter.generateMissingStruct(file, interpolantName, "struct not defined");
|
||||
}
|
||||
|
||||
if (maybeInstance.isEmpty()) {
|
||||
ErrorReporter.generateMissingStruct(file, instanceName, "struct not defined");
|
||||
}
|
||||
|
||||
if (maybeInterpolant.isEmpty() || maybeInstance.isEmpty()) {
|
||||
throw new ShaderLoadingException();
|
||||
}
|
||||
|
||||
interpolant = maybeInterpolant.get();
|
||||
instance = maybeInstance.get();
|
||||
}
|
||||
|
||||
public void vertexFooter(StringBuilder template, ShaderCompiler shader) {
|
||||
@Override
|
||||
public String generateFooter(FileIndex shader, VertexType vertexType) {
|
||||
ImmutableList<StructField> fields = instance.getFields();
|
||||
VertexType vertexType = shader.vertexType;
|
||||
|
||||
int attributeBinding = vertexType.getLayout()
|
||||
.getAttributeCount();
|
||||
|
||||
StringBuilder template = new StringBuilder();
|
||||
|
||||
for (StructField field : fields) {
|
||||
template.append("layout(location = ")
|
||||
.append(attributeBinding)
|
||||
|
@ -109,9 +85,12 @@ public class InstancingTemplateData implements TemplateData {
|
|||
.append(";\n");
|
||||
attributeBinding += TypeHelper.getAttributeCount(field.type);
|
||||
}
|
||||
Template.prefixFields(template, interpolant, "out", "v2f_");
|
||||
|
||||
template.append(String.format("""
|
||||
out vec4 v2f_color;
|
||||
out vec2 v2f_texCoords;
|
||||
out vec2 v2f_light;
|
||||
out float v2f_diffuse;
|
||||
|
||||
void main() {
|
||||
Vertex v = FLWCreateVertex();
|
||||
%s i;
|
||||
|
@ -130,26 +109,26 @@ public class InstancingTemplateData implements TemplateData {
|
|||
}
|
||||
""",
|
||||
instanceName,
|
||||
Template.assignFields(instance, "i.", "a_i_")
|
||||
assignFields(instance, "i.", "a_i_")
|
||||
));
|
||||
|
||||
return template.toString();
|
||||
}
|
||||
|
||||
public void fragmentFooter(StringBuilder template, FileIndex shader) {
|
||||
Template.prefixFields(template, interpolant, "in", "v2f_");
|
||||
public static StringBuilder assignFields(ShaderStruct struct, String prefix1, String prefix2) {
|
||||
ImmutableList<StructField> fields = struct.getFields();
|
||||
|
||||
template.append(String.format("""
|
||||
void main() {
|
||||
Fragment o;
|
||||
o.color = v2f_color;
|
||||
o.texCoords = v2f_texCoords;
|
||||
o.light = v2f_light;
|
||||
o.diffuse = v2f_diffuse;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
vec4 color = %s;
|
||||
FLWFinalizeColor(color);
|
||||
for (StructField field : fields) {
|
||||
builder.append(prefix1)
|
||||
.append(field.name)
|
||||
.append(" = ")
|
||||
.append(prefix2)
|
||||
.append(field.name)
|
||||
.append(";\n");
|
||||
}
|
||||
""",
|
||||
fragmentMain.call("o")
|
||||
));
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,54 +3,33 @@ package com.jozufozu.flywheel.core.compile;
|
|||
import java.util.Optional;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.source.ShaderLoadingException;
|
||||
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||
import com.jozufozu.flywheel.backend.source.error.ErrorReporter;
|
||||
import com.jozufozu.flywheel.backend.source.parse.ShaderFunction;
|
||||
import com.jozufozu.flywheel.backend.source.parse.ShaderStruct;
|
||||
import com.jozufozu.flywheel.backend.source.parse.Variable;
|
||||
import com.jozufozu.flywheel.backend.source.span.Span;
|
||||
|
||||
public class OneShotTemplateData implements TemplateData {
|
||||
public class OneShotTemplateData implements VertexData {
|
||||
|
||||
public final SourceFile file;
|
||||
public final ShaderFunction vertexMain;
|
||||
public final Span interpolantName;
|
||||
public final ShaderStruct interpolant;
|
||||
public final ShaderFunction fragmentMain;
|
||||
|
||||
public OneShotTemplateData(SourceFile file) {
|
||||
this.file = file;
|
||||
|
||||
Optional<ShaderFunction> maybeVertexMain = file.findFunction("vertex");
|
||||
Optional<ShaderFunction> maybeFragmentMain = file.findFunction("fragment");
|
||||
|
||||
if (maybeVertexMain.isEmpty()) {
|
||||
ErrorReporter.generateFileError(file, "could not find \"vertex\" function");
|
||||
}
|
||||
|
||||
if (maybeFragmentMain.isEmpty()) {
|
||||
ErrorReporter.generateMissingFunction(file, "fragment", "\"fragment\" function not defined");
|
||||
}
|
||||
|
||||
if (maybeVertexMain.isEmpty() || maybeFragmentMain.isEmpty()) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
vertexMain = maybeVertexMain.get();
|
||||
fragmentMain = maybeFragmentMain.get();
|
||||
ImmutableList<Variable> fragmentParameters = fragmentMain.getParameters();
|
||||
ImmutableList<Variable> vertexParameters = vertexMain.getParameters();
|
||||
|
||||
if (vertexParameters.size() != 1) {
|
||||
ErrorReporter.generateSpanError(vertexMain.getArgs(), "a basic model requires vertex function to have one argument");
|
||||
}
|
||||
|
||||
if (fragmentParameters.size() != 1) {
|
||||
ErrorReporter.generateSpanError(fragmentMain.getArgs(), "fragment function must have exactly one argument");
|
||||
}
|
||||
|
||||
if (vertexParameters.size() != 1 || fragmentParameters.size() != 1) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
|
@ -64,24 +43,16 @@ public class OneShotTemplateData implements TemplateData {
|
|||
ErrorReporter.generateSpanError(vertexParam.qualifierSpan, "first parameter must be inout Vertex");
|
||||
throw new ShaderLoadingException();
|
||||
}
|
||||
|
||||
interpolantName = fragmentMain.getParameters().get(0).type;
|
||||
|
||||
Optional<ShaderStruct> maybeInterpolant = file.findStruct(interpolantName);
|
||||
|
||||
if (maybeInterpolant.isEmpty()) {
|
||||
ErrorReporter.generateMissingStruct(file, interpolantName, "struct not defined");
|
||||
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
interpolant = maybeInterpolant.get();
|
||||
}
|
||||
@Override
|
||||
public String generateFooter(FileIndex file, VertexType vertexType) {
|
||||
return """
|
||||
out vec4 v2f_color;
|
||||
out vec2 v2f_texCoords;
|
||||
out vec2 v2f_light;
|
||||
out float v2f_diffuse;
|
||||
|
||||
public void vertexFooter(StringBuilder template, ShaderCompiler file) {
|
||||
Template.prefixFields(template, interpolant, "out", "v2f_");
|
||||
|
||||
template.append("""
|
||||
void main() {
|
||||
Vertex v = FLWCreateVertex();
|
||||
vertex(v);
|
||||
|
@ -96,25 +67,6 @@ public class OneShotTemplateData implements TemplateData {
|
|||
v2f_color = vec4(v.normal, 1.);
|
||||
#endif
|
||||
}
|
||||
""");
|
||||
}
|
||||
|
||||
public void fragmentFooter(StringBuilder template, FileIndex file) {
|
||||
Template.prefixFields(template, interpolant, "in", "v2f_");
|
||||
|
||||
template.append(String.format("""
|
||||
void main() {
|
||||
Fragment o;
|
||||
o.color = v2f_color;
|
||||
o.texCoords = v2f_texCoords;
|
||||
o.light = v2f_light;
|
||||
o.diffuse = v2f_diffuse;
|
||||
|
||||
vec4 color = %s;
|
||||
FLWFinalizeColor(color);
|
||||
}
|
||||
""",
|
||||
fragmentMain.call("o")
|
||||
));
|
||||
""";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,12 @@ package com.jozufozu.flywheel.core.compile;
|
|||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlShader;
|
||||
import com.jozufozu.flywheel.backend.source.FileResolution;
|
||||
import com.jozufozu.flywheel.core.Templates;
|
||||
|
||||
/**
|
||||
* A caching compiler.
|
||||
|
@ -18,15 +20,27 @@ import com.jozufozu.flywheel.backend.source.FileResolution;
|
|||
public class ProgramCompiler<P extends GlProgram> {
|
||||
|
||||
protected final Map<ProgramContext, P> cache = new HashMap<>();
|
||||
|
||||
private final GlProgram.Factory<P> factory;
|
||||
private final Function<ProgramContext, GlShader> vertexCompiler;
|
||||
private final Function<ProgramContext, GlShader> fragmentCompiler;
|
||||
|
||||
private final Template template;
|
||||
private final FileResolution header;
|
||||
|
||||
public ProgramCompiler(GlProgram.Factory<P> factory, Template template, FileResolution header) {
|
||||
public ProgramCompiler(GlProgram.Factory<P> factory, Function<ProgramContext, GlShader> vertexCompiler, Function<ProgramContext, GlShader> fragmentCompiler) {
|
||||
this.factory = factory;
|
||||
this.template = template;
|
||||
this.header = header;
|
||||
this.vertexCompiler = vertexCompiler;
|
||||
this.fragmentCompiler = fragmentCompiler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a program compiler using this template.
|
||||
* @param template The vertex template to use.
|
||||
* @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 static <T extends VertexData, P extends GlProgram> ProgramCompiler<P> create(Template<T> template, GlProgram.Factory<P> factory, FileResolution header) {
|
||||
return new ProgramCompiler<>(factory, ctx -> ShaderCompiler.compileVertex(ctx, template, header), ctx -> ShaderCompiler.compileFragment(ctx, Templates.FRAGMENT, header));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -45,11 +59,10 @@ public class ProgramCompiler<P extends GlProgram> {
|
|||
}
|
||||
|
||||
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))
|
||||
return new ProgramAssembler(ctx.spec().name)
|
||||
.attachShader(vertexCompiler.apply(ctx))
|
||||
.attachShader(fragmentCompiler.apply(ctx))
|
||||
.link()
|
||||
.deleteLinkedShaders()
|
||||
.build(this.factory);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.jozufozu.flywheel.core.compile;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
@ -7,7 +8,6 @@ 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;
|
||||
|
@ -51,8 +51,8 @@ public record ProgramContext(float alphaDiscard, VertexType vertexType, ProgramS
|
|||
return layer == RenderLayer.CUTOUT ? 0.1f : 0f;
|
||||
}
|
||||
|
||||
public SourceFile getFile() {
|
||||
return spec().getSource();
|
||||
public List<String> createDefines() {
|
||||
return spec().getDefines(ctx());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,96 +1,27 @@
|
|||
package com.jozufozu.flywheel.core.compile;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlShader;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
||||
import com.jozufozu.flywheel.backend.source.FileResolution;
|
||||
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||
import com.jozufozu.flywheel.backend.source.error.ErrorBuilder;
|
||||
import com.jozufozu.flywheel.backend.source.error.ErrorReporter;
|
||||
import com.jozufozu.flywheel.backend.source.span.Span;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import com.jozufozu.flywheel.core.shader.ProgramSpec;
|
||||
|
||||
/**
|
||||
* Compiles a shader program.
|
||||
*/
|
||||
public class ShaderCompiler implements FileIndex {
|
||||
|
||||
/**
|
||||
* The name of the file responsible for this compilation.
|
||||
*/
|
||||
public final ResourceLocation name;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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(ProgramContext context, Template template, FileResolution header) {
|
||||
this.name = context.spec().name;
|
||||
this.template = template;
|
||||
this.header = header;
|
||||
this.mainFile = context.getFile();
|
||||
this.defines = context.spec()
|
||||
.getDefines(context.ctx());
|
||||
this.vertexType = context.vertexType();
|
||||
this.alphaDiscard = context.alphaDiscard();
|
||||
}
|
||||
|
||||
public GlShader compile(ShaderType type) {
|
||||
public class ShaderCompiler {
|
||||
|
||||
public static <T extends VertexData> GlShader compileVertex(ProgramContext context, Template<T> template, FileResolution header) {
|
||||
StringBuilder finalSource = new StringBuilder();
|
||||
|
||||
finalSource.append("#version ")
|
||||
.append(template.getVersion())
|
||||
.append('\n')
|
||||
.append("#extension GL_ARB_explicit_attrib_location : enable\n")
|
||||
.append("#extension GL_ARB_conservative_depth : enable\n")
|
||||
.append(type.getDefineStatement()); // special case shader type declaration
|
||||
finalSource.append(generateHeader(template.getVersion(), ShaderType.VERTEX));
|
||||
|
||||
if (alphaDiscard > 0) {
|
||||
finalSource.append("#define ALPHA_DISCARD 0.1\n");
|
||||
}
|
||||
|
||||
for (String def : defines) {
|
||||
for (String def : context.createDefines()) {
|
||||
finalSource.append("#define ")
|
||||
.append(def)
|
||||
.append('\n');
|
||||
}
|
||||
|
||||
if (type == ShaderType.VERTEX) {
|
||||
finalSource.append("""
|
||||
struct Vertex {
|
||||
vec3 pos;
|
||||
|
@ -100,84 +31,58 @@ public class ShaderCompiler implements FileIndex {
|
|||
vec3 normal;
|
||||
};
|
||||
""");
|
||||
finalSource.append(vertexType.writeShaderHeader());
|
||||
finalSource.append(context.vertexType()
|
||||
.getShaderHeader());
|
||||
|
||||
FileIndexImpl index = new FileIndexImpl();
|
||||
|
||||
header.getFile()
|
||||
.generateFinalSource(index, finalSource);
|
||||
ProgramSpec spec = context.spec();
|
||||
spec.getVertexFile()
|
||||
.generateFinalSource(index, finalSource);
|
||||
|
||||
T appliedTemplate = template.apply(spec.getVertexFile());
|
||||
finalSource.append(appliedTemplate.generateFooter(index, context.vertexType()));
|
||||
|
||||
return new GlShader(spec.name, ShaderType.VERTEX, finalSource.toString());
|
||||
}
|
||||
|
||||
files.clear();
|
||||
header.getFile().generateFinalSource(this, finalSource);
|
||||
mainFile.generateFinalSource(this, finalSource);
|
||||
public static <T extends FragmentData> GlShader compileFragment(ProgramContext context, Template<T> template, FileResolution header) {
|
||||
|
||||
template.getMetadata(mainFile).generateFooter(finalSource, type, this);
|
||||
StringBuilder finalSource = new StringBuilder();
|
||||
|
||||
return new GlShader(this, type, finalSource.toString());
|
||||
finalSource.append(generateHeader(template.getVersion(), ShaderType.FRAGMENT));
|
||||
for (String def : context.createDefines()) {
|
||||
finalSource.append("#define ")
|
||||
.append(def)
|
||||
.append('\n');
|
||||
}
|
||||
|
||||
public <P extends WorldProgram> P compile(GlProgram.Factory<P> worldShaderPipeline) {
|
||||
return new ProgramAssembler(this.name)
|
||||
.attachShader(compile(ShaderType.VERTEX))
|
||||
.attachShader(compile(ShaderType.FRAGMENT))
|
||||
.link()
|
||||
.deleteLinkedShaders()
|
||||
.build(worldShaderPipeline);
|
||||
if (context.alphaDiscard() > 0) {
|
||||
finalSource.append("#define ALPHA_DISCARD 0.1\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@Override
|
||||
public int getFileID(SourceFile sourceFile) {
|
||||
int i = files.indexOf(sourceFile);
|
||||
if (i != -1) {
|
||||
return i;
|
||||
|
||||
FileIndexImpl index = new FileIndexImpl();
|
||||
|
||||
ProgramSpec spec = context.spec();
|
||||
header.getFile().generateFinalSource(index, finalSource);
|
||||
spec.getFragmentFile()
|
||||
.generateFinalSource(index, finalSource);
|
||||
|
||||
T appliedTemplate = template.apply(spec.getFragmentFile());
|
||||
finalSource.append(appliedTemplate.generateFooter());
|
||||
|
||||
return new GlShader(spec.name, ShaderType.FRAGMENT, finalSource.toString());
|
||||
}
|
||||
|
||||
int size = files.size();
|
||||
files.add(sourceFile);
|
||||
return size;
|
||||
}
|
||||
|
||||
public Span getLineSpan(int fileId, int lineNo) {
|
||||
SourceFile file = files.get(fileId);
|
||||
|
||||
return file.getLineSpanNoWhitespace(lineNo);
|
||||
}
|
||||
|
||||
public void printShaderInfoLog(String source, String log, ResourceLocation name) {
|
||||
List<String> lines = log.lines()
|
||||
.toList();
|
||||
|
||||
boolean needsSourceDump = false;
|
||||
|
||||
StringBuilder errors = new StringBuilder();
|
||||
for (String line : lines) {
|
||||
ErrorBuilder builder = parseCompilerError(line);
|
||||
|
||||
if (builder != null) {
|
||||
errors.append(builder.build());
|
||||
} else {
|
||||
errors.append(line).append('\n');
|
||||
needsSourceDump = true;
|
||||
}
|
||||
}
|
||||
Backend.LOGGER.error("Errors compiling '" + name + "': \n" + errors);
|
||||
if (needsSourceDump) {
|
||||
// TODO: generated code gets its own "file"
|
||||
ErrorReporter.printLines(source);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ErrorBuilder parseCompilerError(String line) {
|
||||
try {
|
||||
ErrorBuilder error = ErrorBuilder.fromLogLine(this, line);
|
||||
if (error != null) {
|
||||
return error;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
return null;
|
||||
protected static String generateHeader(GLSLVersion version, ShaderType type) {
|
||||
return "#version "
|
||||
+ version
|
||||
+ '\n'
|
||||
+ "#extension GL_ARB_explicit_attrib_location : enable\n"
|
||||
+ "#extension GL_ARB_conservative_depth : enable\n"
|
||||
+ type.getDefineStatement();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,8 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
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;
|
||||
|
||||
/**
|
||||
* A class that generates glsl glue code given a SourceFile.
|
||||
|
@ -20,66 +15,33 @@ import com.jozufozu.flywheel.backend.source.parse.StructField;
|
|||
* metadata to generate shader code that OpenGL can use to call into our shader programs.
|
||||
* </p>
|
||||
*/
|
||||
public class Template {
|
||||
public class Template<T> {
|
||||
|
||||
private final Map<SourceFile, TemplateData> metadata = new HashMap<>();
|
||||
private final Map<SourceFile, T> metadata = new HashMap<>();
|
||||
|
||||
private final Function<SourceFile, TemplateData> reader;
|
||||
private final Function<SourceFile, T> reader;
|
||||
private final GLSLVersion glslVersion;
|
||||
|
||||
public Template(GLSLVersion glslVersion, Function<SourceFile, TemplateData> reader) {
|
||||
public Template(GLSLVersion glslVersion, Function<SourceFile, T> reader) {
|
||||
this.reader = reader;
|
||||
this.glslVersion = glslVersion;
|
||||
}
|
||||
|
||||
public TemplateData getMetadata(SourceFile file) {
|
||||
/**
|
||||
* Verify that the given SourceFile is valid for this Template and return the metadata.
|
||||
* @param file The SourceFile to apply this Template to.
|
||||
* @return The applied template metadata.
|
||||
*/
|
||||
public T apply(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.
|
||||
* @return The GLSL version this template requires.
|
||||
*/
|
||||
public <P extends GlProgram> ProgramCompiler<P> programCompiler(GlProgram.Factory<P> factory, FileResolution header) {
|
||||
return new ProgramCompiler<>(factory, this, header);
|
||||
}
|
||||
|
||||
public GLSLVersion getVersion() {
|
||||
return glslVersion;
|
||||
}
|
||||
|
||||
public static void prefixFields(StringBuilder builder, ShaderStruct struct, String qualifier, String prefix) {
|
||||
ImmutableList<StructField> fields = struct.getFields();
|
||||
|
||||
for (StructField field : fields) {
|
||||
builder.append(qualifier)
|
||||
.append(' ')
|
||||
.append(field.type)
|
||||
.append(' ')
|
||||
.append(prefix)
|
||||
.append(field.name)
|
||||
.append(";\n");
|
||||
}
|
||||
}
|
||||
|
||||
public static StringBuilder assignFields(ShaderStruct struct, String prefix1, String prefix2) {
|
||||
ImmutableList<StructField> fields = struct.getFields();
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
for (StructField field : fields) {
|
||||
builder.append(prefix1)
|
||||
.append(field.name)
|
||||
.append(" = ")
|
||||
.append(prefix2)
|
||||
.append(field.name)
|
||||
.append(";\n");
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
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, FileIndex file);
|
||||
|
||||
/**
|
||||
* Generate the necessary glue code here.
|
||||
*
|
||||
* @param builder The builder to generate the source into.
|
||||
* @param type The shader stage glue code is needed for.
|
||||
* @param file The SourceFile with user written code.
|
||||
*/
|
||||
default void generateFooter(StringBuilder builder, ShaderType type, ShaderCompiler file) {
|
||||
if (type == ShaderType.VERTEX) {
|
||||
vertexFooter(builder, file);
|
||||
} else if (type == ShaderType.FRAGMENT) {
|
||||
fragmentFooter(builder, file);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package com.jozufozu.flywheel.core.compile;
|
||||
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
|
||||
public interface VertexData {
|
||||
/**
|
||||
* Generate the necessary glue code here.
|
||||
* @param file The SourceFile with user written code.
|
||||
*/
|
||||
String generateFooter(FileIndex file, VertexType vertexType);
|
||||
}
|
|
@ -30,34 +30,47 @@ public class ProgramSpec {
|
|||
|
||||
// TODO: Block model style inheritance?
|
||||
public static final Codec<ProgramSpec> CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
ResourceLocation.CODEC.fieldOf("source")
|
||||
ResourceLocation.CODEC.fieldOf("vertex")
|
||||
.forGetter(ProgramSpec::getSourceLoc),
|
||||
ResourceLocation.CODEC.fieldOf("fragment")
|
||||
.forGetter(ProgramSpec::getFragmentLoc),
|
||||
ProgramState.CODEC.listOf()
|
||||
.optionalFieldOf("states", Collections.emptyList())
|
||||
.forGetter(ProgramSpec::getStates))
|
||||
.apply(instance, ProgramSpec::new));
|
||||
|
||||
public ResourceLocation name;
|
||||
public final FileResolution source;
|
||||
public final FileResolution vertex;
|
||||
public final FileResolution fragment;
|
||||
|
||||
public final ImmutableList<ProgramState> states;
|
||||
|
||||
public ProgramSpec(ResourceLocation source, List<ProgramState> states) {
|
||||
this.source = Resolver.INSTANCE.get(source);
|
||||
public ProgramSpec(ResourceLocation vertex, ResourceLocation fragment, List<ProgramState> states) {
|
||||
this.vertex = Resolver.INSTANCE.get(vertex);
|
||||
this.fragment = Resolver.INSTANCE.get(fragment);
|
||||
this.states = ImmutableList.copyOf(states);
|
||||
}
|
||||
|
||||
public void setName(ResourceLocation name) {
|
||||
this.name = name;
|
||||
this.source.addSpec(name);
|
||||
this.vertex.addSpec(name);
|
||||
this.fragment.addSpec(name);
|
||||
}
|
||||
|
||||
public ResourceLocation getSourceLoc() {
|
||||
return source.getFileLoc();
|
||||
return vertex.getFileLoc();
|
||||
}
|
||||
|
||||
public SourceFile getSource() {
|
||||
return source.getFile();
|
||||
public ResourceLocation getFragmentLoc() {
|
||||
return fragment.getFileLoc();
|
||||
}
|
||||
|
||||
public SourceFile getVertexFile() {
|
||||
return vertex.getFile();
|
||||
}
|
||||
|
||||
public SourceFile getFragmentFile() {
|
||||
return fragment.getFile();
|
||||
}
|
||||
|
||||
public ImmutableList<ProgramState> getStates() {
|
||||
|
|
|
@ -37,7 +37,7 @@ public class BlockVertex implements VertexType {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String writeShaderHeader() {
|
||||
public String getShaderHeader() {
|
||||
return """
|
||||
layout (location = 0) in vec3 _flw_v_pos;
|
||||
layout (location = 1) in vec4 _flw_v_color;
|
||||
|
|
|
@ -28,7 +28,7 @@ public class PosTexNormalVertex implements VertexType {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String writeShaderHeader() {
|
||||
public String getShaderHeader() {
|
||||
return """
|
||||
layout (location = 0) in vec3 _flw_v_pos;
|
||||
layout (location = 1) in vec2 _flw_v_texCoords;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"source": "flywheel:model.vert",
|
||||
"vertex": "flywheel:model.vert",
|
||||
"fragment": "flywheel:block.frag",
|
||||
"states": [
|
||||
{
|
||||
"when": "flywheel:normal_debug",
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"source": "flywheel:oriented.vert",
|
||||
"vertex": "flywheel:oriented.vert",
|
||||
"fragment": "flywheel:block.frag",
|
||||
"states": [
|
||||
{
|
||||
"when": "flywheel:normal_debug",
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"source": "flywheel:passthru.vert",
|
||||
"vertex": "flywheel:passthru.vert",
|
||||
"fragment": "flywheel:block.frag",
|
||||
"states": [
|
||||
{
|
||||
"when": "flywheel:normal_debug",
|
||||
|
|
|
@ -6,10 +6,8 @@ struct Fragment {
|
|||
vec2 light;
|
||||
};
|
||||
|
||||
#if defined(FRAGMENT_SHADER)
|
||||
vec4 fragment(Fragment r) {
|
||||
vec4 tex = FLWBlockTexture(r.texCoords);
|
||||
|
||||
return vec4(tex.rgb * FLWLight(r.light).rgb * r.diffuse, tex.a) * r.color;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
#use "flywheel:block.frag"
|
||||
|
||||
#if defined(VERTEX_SHADER)
|
||||
|
||||
struct Instance {
|
||||
vec2 light;
|
||||
|
@ -15,4 +12,3 @@ void vertex(inout Vertex v, Instance i) {
|
|||
v.color = i.color;
|
||||
v.light = i.light;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
#use "flywheel:block.frag"
|
||||
|
||||
#if defined(VERTEX_SHADER)
|
||||
#use "flywheel:core/quaternion.glsl"
|
||||
|
||||
struct Oriented {
|
||||
|
@ -17,4 +14,3 @@ void vertex(inout Vertex v, Oriented o) {
|
|||
v.color = o.color;
|
||||
v.light = o.light;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
#use "flywheel:block.frag"
|
||||
|
||||
#if defined(VERTEX_SHADER)
|
||||
void vertex(inout Vertex v) {
|
||||
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue