mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-12-28 16:06:28 +01:00
A heck of a lot
- Reorganize everything - Isolate SourceFile related things - Should consider decoupling ShaderLoader from resource loading - Document a lot of newer things - Index functions - Awkward WorldContext builder - Template responsible for providing shader inputs - Template is now an abstract class - Template provides GLSL version - ProgramSpecs now only accept one file
This commit is contained in:
parent
3c24abe837
commit
82ea5b1720
48 changed files with 668 additions and 559 deletions
|
@ -16,6 +16,7 @@ import org.lwjgl.opengl.GLCapabilities;
|
||||||
import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
|
import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
|
||||||
import com.jozufozu.flywheel.backend.instancing.InstanceData;
|
import com.jozufozu.flywheel.backend.instancing.InstanceData;
|
||||||
import com.jozufozu.flywheel.backend.material.MaterialSpec;
|
import com.jozufozu.flywheel.backend.material.MaterialSpec;
|
||||||
|
import com.jozufozu.flywheel.backend.source.ShaderSources;
|
||||||
import com.jozufozu.flywheel.config.FlwConfig;
|
import com.jozufozu.flywheel.config.FlwConfig;
|
||||||
import com.jozufozu.flywheel.core.shader.spec.ProgramSpec;
|
import com.jozufozu.flywheel.core.shader.spec.ProgramSpec;
|
||||||
|
|
||||||
|
@ -59,14 +60,6 @@ public class Backend {
|
||||||
OptifineHandler.init();
|
OptifineHandler.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearContexts() {
|
|
||||||
SpecMetaRegistry.clear();
|
|
||||||
programSpecRegistry.clear();
|
|
||||||
contexts.forEach(IShaderContext::delete);
|
|
||||||
contexts.clear();
|
|
||||||
materialRegistry.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a string describing the Flywheel backend. When there are eventually multiple backends
|
* Get a string describing the Flywheel backend. When there are eventually multiple backends
|
||||||
* (Meshlet, MDI, GL31 Draw Instanced are planned), this will name which one is in use.
|
* (Meshlet, MDI, GL31 Draw Instanced are planned), this will name which one is in use.
|
||||||
|
@ -98,7 +91,7 @@ public class Backend {
|
||||||
/**
|
/**
|
||||||
* Register a shader context.
|
* Register a shader context.
|
||||||
*/
|
*/
|
||||||
public <C extends ShaderContext<?>> C register(C spec) {
|
public <C extends IShaderContext<?>> C register(C spec) {
|
||||||
contexts.add(spec);
|
contexts.add(spec);
|
||||||
return spec;
|
return spec;
|
||||||
}
|
}
|
||||||
|
@ -201,6 +194,17 @@ public class Backend {
|
||||||
RenderWork.enqueue(Minecraft.getInstance().levelRenderer::allChanged);
|
RenderWork.enqueue(Minecraft.getInstance().levelRenderer::allChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* INTERNAL USE ONLY
|
||||||
|
*/
|
||||||
|
public void _clearContexts() {
|
||||||
|
SpecMetaRegistry.clear();
|
||||||
|
programSpecRegistry.clear();
|
||||||
|
contexts.forEach(IShaderContext::delete);
|
||||||
|
contexts.clear();
|
||||||
|
materialRegistry.clear();
|
||||||
|
}
|
||||||
|
|
||||||
public static void init() {
|
public static void init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
package com.jozufozu.flywheel.backend;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.pipeline.SourceFile;
|
|
||||||
import com.jozufozu.flywheel.backend.pipeline.error.ErrorBuilder;
|
|
||||||
import com.jozufozu.flywheel.backend.pipeline.span.Span;
|
|
||||||
|
|
||||||
import net.minecraft.util.ResourceLocation;
|
|
||||||
|
|
||||||
public class FileResolution {
|
|
||||||
|
|
||||||
private final List<Span> foundSpans = new ArrayList<>();
|
|
||||||
private final ResourceLocation fileLoc;
|
|
||||||
private SourceFile file;
|
|
||||||
|
|
||||||
|
|
||||||
public FileResolution(ResourceLocation fileLoc) {
|
|
||||||
this.fileLoc = fileLoc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResourceLocation getFileLoc() {
|
|
||||||
return fileLoc;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public SourceFile getFile() {
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addSpan(Span span) {
|
|
||||||
foundSpans.add(span);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void resolve(ShaderSources sources) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
file = sources.source(fileLoc);
|
|
||||||
} catch (RuntimeException error) {
|
|
||||||
ErrorBuilder builder = new ErrorBuilder();
|
|
||||||
builder.error(String.format("could not find source for file %s", fileLoc));
|
|
||||||
for (Span span : foundSpans) {
|
|
||||||
builder.in(span.getSourceFile())
|
|
||||||
.pointAt(span, 2);
|
|
||||||
}
|
|
||||||
Backend.log.error(builder.build());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void invalidate() {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
package com.jozufozu.flywheel.backend;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import com.google.common.collect.Multimap;
|
|
||||||
import com.google.common.collect.MultimapBuilder;
|
|
||||||
import com.jozufozu.flywheel.backend.pipeline.SourceFile;
|
|
||||||
import com.jozufozu.flywheel.backend.pipeline.parse.ShaderStruct;
|
|
||||||
|
|
||||||
import net.minecraft.util.ResourceLocation;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indexes many shader source definitions to allow for error fix suggestions.
|
|
||||||
*/
|
|
||||||
public class Index {
|
|
||||||
|
|
||||||
private final Multimap<String, ShaderStruct> knownNames = MultimapBuilder.hashKeys().hashSetValues().build();
|
|
||||||
|
|
||||||
public Index(Map<ResourceLocation, SourceFile> sources) {
|
|
||||||
Collection<SourceFile> files = sources.values();
|
|
||||||
|
|
||||||
for (SourceFile file : files) {
|
|
||||||
file.getStructs().forEach(knownNames::put);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<ShaderStruct> getStructDefinitionsMatching(CharSequence name) {
|
|
||||||
return knownNames.get(name.toString());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
package com.jozufozu.flywheel.backend;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
|
||||||
import com.jozufozu.flywheel.core.shader.IMultiProgram;
|
|
||||||
|
|
||||||
import net.minecraft.util.ResourceLocation;
|
|
||||||
|
|
||||||
public abstract class ShaderContext<P extends GlProgram> implements IShaderContext<P> {
|
|
||||||
|
|
||||||
protected final Map<ResourceLocation, IMultiProgram<P>> programs = new HashMap<>();
|
|
||||||
|
|
||||||
public final Backend backend;
|
|
||||||
|
|
||||||
public ShaderContext(Backend backend) {
|
|
||||||
this.backend = backend;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Supplier<P> getProgramSupplier(ResourceLocation spec) {
|
|
||||||
return programs.get(spec);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void delete() {
|
|
||||||
programs.values()
|
|
||||||
.forEach(IMultiProgram::delete);
|
|
||||||
programs.clear();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
package com.jozufozu.flywheel.backend.pipeline;
|
package com.jozufozu.flywheel.backend.gl;
|
||||||
|
|
||||||
public enum GLSLVersion {
|
public enum GLSLVersion {
|
||||||
V110(110),
|
V110(110),
|
|
@ -152,6 +152,14 @@ public abstract class InstanceManager<T> implements MaterialManager.OriginShiftL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void queueUpdate(T obj) {
|
||||||
|
if (!Backend.getInstance()
|
||||||
|
.canUseInstancing()) return;
|
||||||
|
synchronized (queuedUpdates) {
|
||||||
|
queuedUpdates.add(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the instance associated with an object.
|
* Update the instance associated with an object.
|
||||||
*
|
*
|
||||||
|
@ -185,14 +193,6 @@ public abstract class InstanceManager<T> implements MaterialManager.OriginShiftL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void queueUpdate(T obj) {
|
|
||||||
if (!Backend.getInstance()
|
|
||||||
.canUseInstancing()) return;
|
|
||||||
synchronized (queuedUpdates) {
|
|
||||||
queuedUpdates.add(obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onLightUpdate(T obj) {
|
public void onLightUpdate(T obj) {
|
||||||
if (!Backend.getInstance()
|
if (!Backend.getInstance()
|
||||||
.canUseInstancing()) return;
|
.canUseInstancing()) return;
|
||||||
|
|
|
@ -27,6 +27,18 @@ public class InstancedRenderDispatcher {
|
||||||
|
|
||||||
private static final WorldAttached<InstanceWorld> instanceWorlds = new WorldAttached<>($ -> new InstanceWorld());
|
private static final WorldAttached<InstanceWorld> instanceWorlds = new WorldAttached<>($ -> new InstanceWorld());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this when you want to invoke
|
||||||
|
* @param te
|
||||||
|
*/
|
||||||
|
public static void enqueueUpdate(TileEntity te) {
|
||||||
|
getTiles(te.getLevel()).queueUpdate(te);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void enqueueUpdate(Entity entity) {
|
||||||
|
getEntities(entity.level).queueUpdate(entity);
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public static InstanceManager<TileEntity> getTiles(IWorld world) {
|
public static InstanceManager<TileEntity> getTiles(IWorld world) {
|
||||||
return instanceWorlds.get(world)
|
return instanceWorlds.get(world)
|
||||||
|
@ -52,14 +64,6 @@ public class InstancedRenderDispatcher {
|
||||||
instanceWorlds.get(world).tick();
|
instanceWorlds.get(world).tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void enqueueUpdate(TileEntity te) {
|
|
||||||
getTiles(te.getLevel()).queueUpdate(te);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void enqueueUpdate(Entity entity) {
|
|
||||||
getEntities(entity.level).queueUpdate(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public static void onBeginFrame(BeginFrameEvent event) {
|
public static void onBeginFrame(BeginFrameEvent event) {
|
||||||
instanceWorlds.get(event.getWorld()).beginFrame(event);
|
instanceWorlds.get(event.getWorld()).beginFrame(event);
|
||||||
|
|
|
@ -4,6 +4,10 @@ import com.jozufozu.flywheel.core.shader.IMultiProgram;
|
||||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||||
import com.jozufozu.flywheel.core.shader.spec.ProgramSpec;
|
import com.jozufozu.flywheel.core.shader.spec.ProgramSpec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main interface for compiling usable shaders from program specs.
|
||||||
|
* @param <P> the type of the program that this pipeline compiles.
|
||||||
|
*/
|
||||||
public interface IShaderPipeline<P extends WorldProgram> {
|
public interface IShaderPipeline<P extends WorldProgram> {
|
||||||
|
|
||||||
IMultiProgram<P> compile(ProgramSpec spec);
|
IMultiProgram<P> compile(ProgramSpec spec);
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
package com.jozufozu.flywheel.backend.pipeline;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
|
||||||
import com.jozufozu.flywheel.backend.loading.ProtoProgram;
|
|
||||||
import com.jozufozu.flywheel.backend.pipeline.parse.ShaderStruct;
|
|
||||||
import com.jozufozu.flywheel.backend.pipeline.parse.StructField;
|
|
||||||
|
|
||||||
public interface ITemplate {
|
|
||||||
void generateTemplateSource(StringBuilder builder, ShaderType type, SourceFile file);
|
|
||||||
|
|
||||||
void attachAttributes(ProtoProgram program, SourceFile file);
|
|
||||||
|
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void assignFields(StringBuilder builder, ShaderStruct struct, String prefix1, String prefix2) {
|
|
||||||
ImmutableList<StructField> fields = struct.getFields();
|
|
||||||
|
|
||||||
for (StructField field : fields) {
|
|
||||||
builder.append(prefix1)
|
|
||||||
.append(field.name)
|
|
||||||
.append(" = ")
|
|
||||||
.append(prefix2)
|
|
||||||
.append(field.name)
|
|
||||||
.append(";\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
package com.jozufozu.flywheel.backend.pipeline;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.jozufozu.flywheel.backend.pipeline.parse.Import;
|
|
||||||
|
|
||||||
import net.minecraft.util.ResourceLocation;
|
|
||||||
|
|
||||||
public class Includer {
|
|
||||||
|
|
||||||
public static List<SourceFile> recurseIncludes(SourceFile from) {
|
|
||||||
Set<ResourceLocation> seen = new HashSet<>();
|
|
||||||
|
|
||||||
seen.add(from.name);
|
|
||||||
|
|
||||||
List<SourceFile> out = new ArrayList<>();
|
|
||||||
|
|
||||||
process(seen, out, from);
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void process(Set<ResourceLocation> seen, List<SourceFile> out, SourceFile source) {
|
|
||||||
ImmutableList<Import> imports = source.getIncludes();
|
|
||||||
|
|
||||||
for (Import use : imports) {
|
|
||||||
|
|
||||||
SourceFile file = use.getFile();
|
|
||||||
if (file != null && seen.add(file.name)) {
|
|
||||||
process(seen, out, file);
|
|
||||||
|
|
||||||
out.add(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,13 +3,14 @@ package com.jozufozu.flywheel.backend.pipeline;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.jozufozu.flywheel.backend.pipeline.error.ErrorReporter;
|
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||||
import com.jozufozu.flywheel.backend.pipeline.parse.ShaderFunction;
|
import com.jozufozu.flywheel.backend.source.error.ErrorReporter;
|
||||||
import com.jozufozu.flywheel.backend.pipeline.parse.ShaderStruct;
|
import com.jozufozu.flywheel.backend.source.parse.ShaderFunction;
|
||||||
import com.jozufozu.flywheel.backend.pipeline.parse.Variable;
|
import com.jozufozu.flywheel.backend.source.parse.ShaderStruct;
|
||||||
import com.jozufozu.flywheel.backend.pipeline.span.Span;
|
import com.jozufozu.flywheel.backend.source.parse.Variable;
|
||||||
|
import com.jozufozu.flywheel.backend.source.span.Span;
|
||||||
|
|
||||||
public class InstanceTemplateData {
|
public class InstancingProgramMetaData {
|
||||||
|
|
||||||
public final SourceFile file;
|
public final SourceFile file;
|
||||||
public final ShaderFunction vertexMain;
|
public final ShaderFunction vertexMain;
|
||||||
|
@ -21,15 +22,14 @@ public class InstanceTemplateData {
|
||||||
public final ShaderStruct vertex;
|
public final ShaderStruct vertex;
|
||||||
public final ShaderStruct instance;
|
public final ShaderStruct instance;
|
||||||
|
|
||||||
public InstanceTemplateData(SourceFile file) {
|
public InstancingProgramMetaData(SourceFile file) {
|
||||||
this.file = file;
|
this.file = file;
|
||||||
|
|
||||||
Optional<ShaderFunction> vertexFunc = file.findFunction("vertex");
|
Optional<ShaderFunction> vertexFunc = file.findFunction("vertex");
|
||||||
Optional<ShaderFunction> fragmentFunc = file.findFunction("fragment");
|
Optional<ShaderFunction> fragmentFunc = file.findFunction("fragment");
|
||||||
|
|
||||||
|
|
||||||
if (!fragmentFunc.isPresent()) {
|
if (!fragmentFunc.isPresent()) {
|
||||||
ErrorReporter.generateFileError(file, "could not find \"fragment\" function");
|
ErrorReporter.generateMissingFunction(file, "fragment", "\"fragment\" function not defined");
|
||||||
}
|
}
|
||||||
if (!vertexFunc.isPresent()) {
|
if (!vertexFunc.isPresent()) {
|
||||||
ErrorReporter.generateFileError(file, "could not find \"vertex\" function");
|
ErrorReporter.generateFileError(file, "could not find \"vertex\" function");
|
||||||
|
@ -64,15 +64,15 @@ public class InstanceTemplateData {
|
||||||
Optional<ShaderStruct> maybeInstance = file.findStruct(instanceName);
|
Optional<ShaderStruct> maybeInstance = file.findStruct(instanceName);
|
||||||
|
|
||||||
if (!maybeVertex.isPresent()) {
|
if (!maybeVertex.isPresent()) {
|
||||||
ErrorReporter.generateMissingStruct(file, vertexName);
|
ErrorReporter.generateMissingStruct(file, vertexName, "struct not defined");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!maybeInterpolant.isPresent()) {
|
if (!maybeInterpolant.isPresent()) {
|
||||||
ErrorReporter.generateMissingStruct(file, interpolantName);
|
ErrorReporter.generateMissingStruct(file, interpolantName, "struct not defined");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!maybeInstance.isPresent()) {
|
if (!maybeInstance.isPresent()) {
|
||||||
ErrorReporter.generateMissingStruct(file, instanceName);
|
ErrorReporter.generateMissingStruct(file, instanceName, "struct not defined");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!maybeVertex.isPresent() || !maybeInterpolant.isPresent() || !maybeInstance.isPresent()) {
|
if (!maybeVertex.isPresent() || !maybeInterpolant.isPresent() || !maybeInstance.isPresent()) {
|
|
@ -1,16 +1,19 @@
|
||||||
package com.jozufozu.flywheel.backend.pipeline;
|
package com.jozufozu.flywheel.backend.pipeline;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.ArrayList;
|
||||||
import java.util.Map;
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
||||||
import com.jozufozu.flywheel.backend.loading.ProtoProgram;
|
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||||
|
|
||||||
public class InstancingTemplate implements ITemplate {
|
public class InstancingTemplate extends Template<InstancingProgramMetaData> {
|
||||||
|
|
||||||
public static final InstancingTemplate INSTANCE = new InstancingTemplate();
|
public static final InstancingTemplate INSTANCE = new InstancingTemplate();
|
||||||
|
|
||||||
private final Map<SourceFile, InstanceTemplateData> datas = new HashMap<>();
|
public InstancingTemplate() {
|
||||||
|
super(InstancingProgramMetaData::new);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void generateTemplateSource(StringBuilder builder, ShaderType type, SourceFile file) {
|
public void generateTemplateSource(StringBuilder builder, ShaderType type, SourceFile file) {
|
||||||
|
@ -22,51 +25,50 @@ public class InstancingTemplate implements ITemplate {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void attachAttributes(ProtoProgram program, SourceFile file) {
|
public Collection<ShaderInput> getShaderInputs(SourceFile file) {
|
||||||
InstanceTemplateData data = getData(file);
|
InstancingProgramMetaData data = getMetadata(file);
|
||||||
data.vertex.addPrefixedAttributes(program, "a_v_");
|
|
||||||
data.instance.addPrefixedAttributes(program, "a_i_");
|
|
||||||
}
|
|
||||||
|
|
||||||
public InstanceTemplateData getData(SourceFile file) {
|
List<ShaderInput> inputs = new ArrayList<>(ShaderInput.fromStruct(data.vertex, "a_v_"));
|
||||||
return datas.computeIfAbsent(file, InstanceTemplateData::new);
|
inputs.addAll(ShaderInput.fromStruct(data.instance, "a_i_"));
|
||||||
|
|
||||||
|
return inputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void vertexFooter(StringBuilder template, SourceFile file) {
|
public void vertexFooter(StringBuilder template, SourceFile file) {
|
||||||
InstanceTemplateData data = getData(file);
|
InstancingProgramMetaData data = getMetadata(file);
|
||||||
|
|
||||||
ITemplate.prefixFields(template, data.vertex, "attribute", "a_v_");
|
Template.prefixFields(template, data.vertex, "attribute", "a_v_");
|
||||||
ITemplate.prefixFields(template, data.instance, "attribute", "a_i_");
|
Template.prefixFields(template, data.instance, "attribute", "a_i_");
|
||||||
ITemplate.prefixFields(template, data.interpolant, "varying", "v2f_");
|
Template.prefixFields(template, data.interpolant, "varying", "v2f_");
|
||||||
|
|
||||||
template.append("void main() {\n");
|
template.append("void main() {\n");
|
||||||
template.append(data.vertexName)
|
template.append(data.vertexName)
|
||||||
.append(" v;\n");
|
.append(" v;\n");
|
||||||
ITemplate.assignFields(template, data.vertex, "v.", "a_v_");
|
Template.assignFields(template, data.vertex, "v.", "a_v_");
|
||||||
|
|
||||||
template.append(data.instanceName)
|
template.append(data.instanceName)
|
||||||
.append(" i;\n");
|
.append(" i;\n");
|
||||||
ITemplate.assignFields(template, data.instance, "i.", "a_i_");
|
Template.assignFields(template, data.instance, "i.", "a_i_");
|
||||||
|
|
||||||
template.append(data.interpolantName)
|
template.append(data.interpolantName)
|
||||||
.append(" o = ")
|
.append(" o = ")
|
||||||
.append(data.vertexMain.call("v", "i"))
|
.append(data.vertexMain.call("v", "i"))
|
||||||
.append(";\n");
|
.append(";\n");
|
||||||
|
|
||||||
ITemplate.assignFields(template, data.interpolant, "v2f_", "o.");
|
Template.assignFields(template, data.interpolant, "v2f_", "o.");
|
||||||
|
|
||||||
template.append('}');
|
template.append('}');
|
||||||
}
|
}
|
||||||
|
|
||||||
public void fragmentFooter(StringBuilder template, SourceFile file) {
|
public void fragmentFooter(StringBuilder template, SourceFile file) {
|
||||||
InstanceTemplateData data = getData(file);
|
InstancingProgramMetaData data = getMetadata(file);
|
||||||
|
|
||||||
ITemplate.prefixFields(template, data.interpolant, "varying", "v2f_");
|
Template.prefixFields(template, data.interpolant, "varying", "v2f_");
|
||||||
|
|
||||||
template.append("void main() {\n");
|
template.append("void main() {\n");
|
||||||
template.append(data.interpolantName)
|
template.append(data.interpolantName)
|
||||||
.append(" o;\n");
|
.append(" o;\n");
|
||||||
ITemplate.assignFields(template, data.interpolant, "o.", "v2f_");
|
Template.assignFields(template, data.interpolant, "o.", "v2f_");
|
||||||
|
|
||||||
template.append(data.fragmentMain.call("o"))
|
template.append(data.fragmentMain.call("o"))
|
||||||
.append(";\n");
|
.append(";\n");
|
||||||
|
|
|
@ -3,13 +3,14 @@ package com.jozufozu.flywheel.backend.pipeline;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.jozufozu.flywheel.backend.pipeline.error.ErrorReporter;
|
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||||
import com.jozufozu.flywheel.backend.pipeline.parse.ShaderFunction;
|
import com.jozufozu.flywheel.backend.source.error.ErrorReporter;
|
||||||
import com.jozufozu.flywheel.backend.pipeline.parse.ShaderStruct;
|
import com.jozufozu.flywheel.backend.source.parse.ShaderFunction;
|
||||||
import com.jozufozu.flywheel.backend.pipeline.parse.Variable;
|
import com.jozufozu.flywheel.backend.source.parse.ShaderStruct;
|
||||||
import com.jozufozu.flywheel.backend.pipeline.span.Span;
|
import com.jozufozu.flywheel.backend.source.parse.Variable;
|
||||||
|
import com.jozufozu.flywheel.backend.source.span.Span;
|
||||||
|
|
||||||
public class OneShotData {
|
public class OneShotProgramMetaData {
|
||||||
|
|
||||||
public final SourceFile file;
|
public final SourceFile file;
|
||||||
public final ShaderFunction vertexMain;
|
public final ShaderFunction vertexMain;
|
||||||
|
@ -19,7 +20,7 @@ public class OneShotData {
|
||||||
public final ShaderStruct vertex;
|
public final ShaderStruct vertex;
|
||||||
public final ShaderFunction fragmentMain;
|
public final ShaderFunction fragmentMain;
|
||||||
|
|
||||||
public OneShotData(SourceFile file) {
|
public OneShotProgramMetaData(SourceFile file) {
|
||||||
this.file = file;
|
this.file = file;
|
||||||
|
|
||||||
Optional<ShaderFunction> maybeVertexMain = file.findFunction("vertex");
|
Optional<ShaderFunction> maybeVertexMain = file.findFunction("vertex");
|
||||||
|
@ -27,29 +28,32 @@ public class OneShotData {
|
||||||
|
|
||||||
if (!maybeVertexMain.isPresent()) {
|
if (!maybeVertexMain.isPresent()) {
|
||||||
ErrorReporter.generateFileError(file, "could not find \"vertex\" function");
|
ErrorReporter.generateFileError(file, "could not find \"vertex\" function");
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!maybeFragmentMain.isPresent()) {
|
if (!maybeFragmentMain.isPresent()) {
|
||||||
ErrorReporter.generateFileError(file, "could not find \"fragment\" function");
|
ErrorReporter.generateMissingFunction(file, "fragment", "\"fragment\" function not defined");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!maybeVertexMain.isPresent() || !maybeFragmentMain.isPresent()) {
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
}
|
}
|
||||||
|
|
||||||
vertexMain = maybeVertexMain.get();
|
vertexMain = maybeVertexMain.get();
|
||||||
fragmentMain = maybeFragmentMain.get();
|
fragmentMain = maybeFragmentMain.get();
|
||||||
ImmutableList<Variable> parameters = fragmentMain.getParameters();
|
ImmutableList<Variable> fragmentParameters = fragmentMain.getParameters();
|
||||||
ImmutableList<Variable> vertexParameters = vertexMain.getParameters();
|
ImmutableList<Variable> vertexParameters = vertexMain.getParameters();
|
||||||
|
|
||||||
if (vertexParameters.size() != 1) {
|
if (vertexParameters.size() != 1) {
|
||||||
ErrorReporter.generateSpanError(vertexMain.getArgs(), "a basic model requires vertex function to have one argument");
|
ErrorReporter.generateSpanError(vertexMain.getArgs(), "a basic model requires vertex function to have one argument");
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parameters.size() != 1) {
|
if (fragmentParameters.size() != 1) {
|
||||||
ErrorReporter.generateSpanError(fragmentMain.getArgs(), "instancing requires fragment function to have 1 argument");
|
ErrorReporter.generateSpanError(fragmentMain.getArgs(), "fragment function must have exactly one argument");
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (vertexParameters.size() != 1 || fragmentParameters.size() != 1) {
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
interpolantName = vertexMain.getType();
|
interpolantName = vertexMain.getType();
|
||||||
vertexName = vertexParameters.get(0)
|
vertexName = vertexParameters.get(0)
|
||||||
|
@ -59,10 +63,10 @@ public class OneShotData {
|
||||||
Optional<ShaderStruct> maybeVertex = file.findStruct(vertexName);
|
Optional<ShaderStruct> maybeVertex = file.findStruct(vertexName);
|
||||||
|
|
||||||
if (!maybeVertex.isPresent())
|
if (!maybeVertex.isPresent())
|
||||||
ErrorReporter.generateMissingStruct(file, vertexName);
|
ErrorReporter.generateMissingStruct(file, vertexName, "struct not defined");
|
||||||
|
|
||||||
if (!maybeInterpolant.isPresent())
|
if (!maybeInterpolant.isPresent())
|
||||||
ErrorReporter.generateMissingStruct(file, interpolantName);
|
ErrorReporter.generateMissingStruct(file, interpolantName, "struct not defined");
|
||||||
|
|
||||||
if (!maybeVertex.isPresent() || !maybeInterpolant.isPresent()) {
|
if (!maybeVertex.isPresent() || !maybeInterpolant.isPresent()) {
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
|
@ -1,18 +1,17 @@
|
||||||
package com.jozufozu.flywheel.backend.pipeline;
|
package com.jozufozu.flywheel.backend.pipeline;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
||||||
import com.jozufozu.flywheel.backend.loading.ProtoProgram;
|
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||||
|
|
||||||
public class OneShotTemplate implements ITemplate {
|
public class OneShotTemplate extends Template<OneShotProgramMetaData> {
|
||||||
|
|
||||||
public static final OneShotTemplate INSTANCE = new OneShotTemplate();
|
public static final OneShotTemplate INSTANCE = new OneShotTemplate();
|
||||||
|
|
||||||
|
public OneShotTemplate() {
|
||||||
private final Map<SourceFile, OneShotData> datas = new HashMap<>();
|
super(OneShotProgramMetaData::new);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void generateTemplateSource(StringBuilder builder, ShaderType type, SourceFile file) {
|
public void generateTemplateSource(StringBuilder builder, ShaderType type, SourceFile file) {
|
||||||
|
@ -24,45 +23,42 @@ public class OneShotTemplate implements ITemplate {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void attachAttributes(ProtoProgram program, SourceFile file) {
|
public Collection<ShaderInput> getShaderInputs(SourceFile file) {
|
||||||
OneShotData data = getData(file);
|
OneShotProgramMetaData data = getMetadata(file);
|
||||||
data.vertex.addPrefixedAttributes(program, "a_v_");
|
|
||||||
}
|
|
||||||
|
|
||||||
public OneShotData getData(SourceFile file) {
|
return ShaderInput.fromStruct(data.vertex, "a_v_");
|
||||||
return datas.computeIfAbsent(file, OneShotData::new);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void vertexFooter(StringBuilder template, SourceFile file) {
|
public void vertexFooter(StringBuilder template, SourceFile file) {
|
||||||
OneShotData data = getData(file);
|
OneShotProgramMetaData data = getMetadata(file);
|
||||||
|
|
||||||
ITemplate.prefixFields(template, data.vertex, "attribute", "a_v_");
|
Template.prefixFields(template, data.vertex, "attribute", "a_v_");
|
||||||
ITemplate.prefixFields(template, data.interpolant, "varying", "v2f_");
|
Template.prefixFields(template, data.interpolant, "varying", "v2f_");
|
||||||
|
|
||||||
template.append("void main() {\n");
|
template.append("void main() {\n");
|
||||||
template.append(data.vertexName)
|
template.append(data.vertexName)
|
||||||
.append(" v;\n");
|
.append(" v;\n");
|
||||||
ITemplate.assignFields(template, data.vertex, "v.", "a_v_");
|
Template.assignFields(template, data.vertex, "v.", "a_v_");
|
||||||
|
|
||||||
template.append(data.interpolantName)
|
template.append(data.interpolantName)
|
||||||
.append(" o = ")
|
.append(" o = ")
|
||||||
.append(data.vertexMain.call("v"))
|
.append(data.vertexMain.call("v"))
|
||||||
.append(";\n");
|
.append(";\n");
|
||||||
|
|
||||||
ITemplate.assignFields(template, data.interpolant, "v2f_", "o.");
|
Template.assignFields(template, data.interpolant, "v2f_", "o.");
|
||||||
|
|
||||||
template.append('}');
|
template.append('}');
|
||||||
}
|
}
|
||||||
|
|
||||||
public void fragmentFooter(StringBuilder template, SourceFile file) {
|
public void fragmentFooter(StringBuilder template, SourceFile file) {
|
||||||
OneShotData data = getData(file);
|
OneShotProgramMetaData data = getMetadata(file);
|
||||||
|
|
||||||
ITemplate.prefixFields(template, data.interpolant, "varying", "v2f_");
|
Template.prefixFields(template, data.interpolant, "varying", "v2f_");
|
||||||
|
|
||||||
template.append("void main() {\n");
|
template.append("void main() {\n");
|
||||||
template.append(data.interpolant.name)
|
template.append(data.interpolant.name)
|
||||||
.append(" o;\n");
|
.append(" o;\n");
|
||||||
ITemplate.assignFields(template, data.interpolant, "o.", "v2f_");
|
Template.assignFields(template, data.interpolant, "o.", "v2f_");
|
||||||
|
|
||||||
template.append(data.fragmentMain.call("o"))
|
template.append(data.fragmentMain.call("o"))
|
||||||
.append(";\n");
|
.append(";\n");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package com.jozufozu.flywheel.backend.loading;
|
package com.jozufozu.flywheel.backend.pipeline;
|
||||||
|
|
||||||
import static org.lwjgl.opengl.GL20.GL_LINK_STATUS;
|
import static org.lwjgl.opengl.GL20.GL_LINK_STATUS;
|
||||||
import static org.lwjgl.opengl.GL20.GL_TRUE;
|
import static org.lwjgl.opengl.GL20.GL_TRUE;
|
||||||
|
@ -9,53 +9,48 @@ import static org.lwjgl.opengl.GL20.glGetProgramInfoLog;
|
||||||
import static org.lwjgl.opengl.GL20.glGetProgrami;
|
import static org.lwjgl.opengl.GL20.glGetProgrami;
|
||||||
import static org.lwjgl.opengl.GL20.glLinkProgram;
|
import static org.lwjgl.opengl.GL20.glLinkProgram;
|
||||||
|
|
||||||
import java.util.EnumMap;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.IntConsumer;
|
|
||||||
|
|
||||||
import org.lwjgl.opengl.GL20;
|
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.Backend;
|
import com.jozufozu.flywheel.backend.Backend;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.GlShader;
|
import com.jozufozu.flywheel.backend.gl.shader.GlShader;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
import it.unimi.dsi.fastutil.ints.IntList;
|
|
||||||
import net.minecraft.util.ResourceLocation;
|
|
||||||
|
|
||||||
public class ProtoProgram {
|
public class ProtoProgram {
|
||||||
public final int program;
|
public final int program;
|
||||||
|
public final WorldShader parent;
|
||||||
|
|
||||||
public ResourceLocation name;
|
|
||||||
private int attributeIndex;
|
private int attributeIndex;
|
||||||
|
|
||||||
private final IntList shaders;
|
private final List<GlShader> shaders;
|
||||||
|
|
||||||
public ProtoProgram() {
|
public ProtoProgram(WorldShader parent) {
|
||||||
|
this.parent = parent;
|
||||||
this.program = glCreateProgram();
|
this.program = glCreateProgram();
|
||||||
shaders = new IntArrayList(2);
|
shaders = new ObjectArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void attachShader(GlShader glShader) {
|
public ProtoProgram compilePart(ShaderType type) {
|
||||||
glAttachShader(this.program, glShader.handle());
|
GlShader shader = parent.compile(type);
|
||||||
}
|
attachShader(shader);
|
||||||
|
return this;
|
||||||
public void addAttribute(String name, int attributeCount) {
|
|
||||||
glBindAttribLocation(this.program, attributeIndex, name);
|
|
||||||
attributeIndex += attributeCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Links the attached shaders to this program.
|
* Links the attached shaders to this program.
|
||||||
*/
|
*/
|
||||||
public ProtoProgram link(ResourceLocation name) {
|
public ProtoProgram link() {
|
||||||
this.name = name;
|
|
||||||
|
parent.template.getShaderInputs(parent.mainFile)
|
||||||
|
.forEach(this::addAttribute);
|
||||||
|
|
||||||
glLinkProgram(this.program);
|
glLinkProgram(this.program);
|
||||||
|
|
||||||
String log = glGetProgramInfoLog(this.program);
|
String log = glGetProgramInfoLog(this.program);
|
||||||
|
|
||||||
if (!log.isEmpty()) {
|
if (!log.isEmpty()) {
|
||||||
Backend.log.debug("Program link log for " + name + ": " + log);
|
Backend.log.debug("Program link log for " + parent.name + ": " + log);
|
||||||
}
|
}
|
||||||
|
|
||||||
int result = glGetProgrami(this.program, GL_LINK_STATUS);
|
int result = glGetProgrami(this.program, GL_LINK_STATUS);
|
||||||
|
@ -68,7 +63,18 @@ public class ProtoProgram {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProtoProgram deleteLinkedShaders() {
|
public ProtoProgram deleteLinkedShaders() {
|
||||||
shaders.forEach((IntConsumer) GL20::glDeleteShader);
|
shaders.forEach(GlShader::delete);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void attachShader(GlShader glShader) {
|
||||||
|
shaders.add(glShader);
|
||||||
|
glAttachShader(this.program, glShader.handle());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addAttribute(ShaderInput shaderInput) {
|
||||||
|
glBindAttribLocation(this.program, attributeIndex, shaderInput.name);
|
||||||
|
attributeIndex += shaderInput.attribCount;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package com.jozufozu.flywheel.backend.pipeline;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.backend.source.parse.ShaderStruct;
|
||||||
|
import com.jozufozu.flywheel.backend.source.parse.StructField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A single input to a shader.
|
||||||
|
*/
|
||||||
|
public class ShaderInput {
|
||||||
|
public final CharSequence name;
|
||||||
|
public final int attribCount;
|
||||||
|
|
||||||
|
public ShaderInput(CharSequence name, int attribCount) {
|
||||||
|
this.name = name;
|
||||||
|
this.attribCount = attribCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShaderInput withPrefix(CharSequence prefix) {
|
||||||
|
return new ShaderInput(prefix.toString() + name, attribCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Collection<ShaderInput> fromStruct(ShaderStruct struct, String prefix) {
|
||||||
|
return struct.getFields()
|
||||||
|
.stream()
|
||||||
|
.map(ShaderInput::from)
|
||||||
|
.map(a -> a.withPrefix(prefix))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShaderInput from(StructField field) {
|
||||||
|
int attributeCount = TypeHelper.getAttributeCount(field.type);
|
||||||
|
|
||||||
|
return new ShaderInput(field.name, attributeCount);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
package com.jozufozu.flywheel.backend.pipeline;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
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.ShaderType;
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Shader files are written somewhat abstractly. Subclasses of Template handle those abstractions, using SourceFile
|
||||||
|
* metadata to generate shader code that OpenGL can use to call into our shader programs.
|
||||||
|
* </p>
|
||||||
|
* @param <D> Holds metadata, generates errors.
|
||||||
|
*/
|
||||||
|
public abstract class Template<D> {
|
||||||
|
|
||||||
|
private final Map<SourceFile, D> metadata = new HashMap<>();
|
||||||
|
|
||||||
|
private final Function<SourceFile, D> parser;
|
||||||
|
|
||||||
|
protected Template(Function<SourceFile, D> parser) {
|
||||||
|
this.parser = parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the necessary glue code here.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* See {@link InstancingTemplate} and {@link OneShotTemplate} for examples.
|
||||||
|
* </p>
|
||||||
|
* @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.
|
||||||
|
*/
|
||||||
|
public abstract void generateTemplateSource(StringBuilder builder, ShaderType type, SourceFile file);
|
||||||
|
|
||||||
|
public abstract Collection<ShaderInput> getShaderInputs(SourceFile file);
|
||||||
|
|
||||||
|
public D getMetadata(SourceFile file) {
|
||||||
|
return metadata.computeIfAbsent(file, parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GLSLVersion getVersion() {
|
||||||
|
return GLSLVersion.V120;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 void assignFields(StringBuilder builder, ShaderStruct struct, String prefix1, String prefix2) {
|
||||||
|
ImmutableList<StructField> fields = struct.getFields();
|
||||||
|
|
||||||
|
for (StructField field : fields) {
|
||||||
|
builder.append(prefix1)
|
||||||
|
.append(field.name)
|
||||||
|
.append(" = ")
|
||||||
|
.append(prefix2)
|
||||||
|
.append(field.name)
|
||||||
|
.append(";\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package com.jozufozu.flywheel.backend.loading;
|
package com.jozufozu.flywheel.backend.pipeline;
|
||||||
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
|
@ -1,37 +1,35 @@
|
||||||
package com.jozufozu.flywheel.backend.pipeline;
|
package com.jozufozu.flywheel.backend.pipeline;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.FileResolution;
|
import com.jozufozu.flywheel.backend.source.FileResolution;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.GlShader;
|
import com.jozufozu.flywheel.backend.gl.shader.GlShader;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
||||||
|
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||||
|
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
|
||||||
public class ShaderBuilder {
|
public class WorldShader {
|
||||||
|
|
||||||
public final ResourceLocation name;
|
public final ResourceLocation name;
|
||||||
public final ITemplate template;
|
public final Template<?> template;
|
||||||
public final FileResolution header;
|
public final CharSequence header;
|
||||||
|
|
||||||
public SourceFile mainFile;
|
public SourceFile mainFile;
|
||||||
private GLSLVersion version;
|
|
||||||
|
|
||||||
private StringBuilder source;
|
private CharSequence source;
|
||||||
private StringBuilder defines;
|
private StringBuilder defines;
|
||||||
|
|
||||||
public ShaderBuilder(ResourceLocation name, ITemplate template, FileResolution header) {
|
public WorldShader(ResourceLocation name, Template<?> template, FileResolution header) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.template = template;
|
this.template = template;
|
||||||
this.header = header;
|
this.header = Optional.ofNullable(header.getFile())
|
||||||
|
.map(SourceFile::generateFinalSource)
|
||||||
|
.orElse("");
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShaderBuilder setVersion(GLSLVersion version) {
|
public WorldShader setDefines(List<String> defs) {
|
||||||
this.version = version;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShaderBuilder setDefines(List<String> defs) {
|
|
||||||
defines = new StringBuilder();
|
defines = new StringBuilder();
|
||||||
|
|
||||||
for (String def : defs) {
|
for (String def : defs) {
|
||||||
|
@ -42,35 +40,37 @@ public class ShaderBuilder {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShaderBuilder setMainSource(SourceFile file) {
|
public WorldShader setMainSource(SourceFile file) {
|
||||||
if (mainFile == file) return this;
|
if (mainFile == file) return this;
|
||||||
|
|
||||||
mainFile = file;
|
mainFile = file;
|
||||||
source = new StringBuilder();
|
source = file.generateFinalSource();
|
||||||
|
|
||||||
file.generateFinalSource(source);
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlShader compile(ResourceLocation name, ShaderType type) {
|
public GlShader compile(ShaderType type) {
|
||||||
|
|
||||||
StringBuilder finalSource = new StringBuilder();
|
StringBuilder finalSource = new StringBuilder();
|
||||||
|
|
||||||
finalSource.append("#version ")
|
finalSource.append("#version ")
|
||||||
.append(version)
|
.append(template.getVersion())
|
||||||
.append('\n')
|
.append('\n')
|
||||||
.append("#define ")
|
.append("#define ")
|
||||||
.append(type.define)
|
.append(type.define)
|
||||||
.append('\n')
|
.append('\n')
|
||||||
.append(defines != null ? defines : "");
|
.append(defines != null ? defines : "")
|
||||||
SourceFile file = header.getFile();
|
.append(header)
|
||||||
if (file != null) {
|
.append('\n')
|
||||||
file.generateFinalSource(finalSource);
|
.append(source)
|
||||||
}
|
.append('\n');
|
||||||
mainFile.generateFinalSource(finalSource);
|
|
||||||
template.generateTemplateSource(finalSource, type, mainFile);
|
template.generateTemplateSource(finalSource, type, mainFile);
|
||||||
|
|
||||||
return new GlShader(name, type, finalSource);
|
return new GlShader(name, type, finalSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ProtoProgram createProgram() {
|
||||||
|
return new ProtoProgram(this);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,22 +1,15 @@
|
||||||
package com.jozufozu.flywheel.backend.pipeline;
|
package com.jozufozu.flywheel.backend.pipeline;
|
||||||
|
|
||||||
import static org.lwjgl.opengl.GL11.GL_TRUE;
|
|
||||||
import static org.lwjgl.opengl.GL20.GL_LINK_STATUS;
|
|
||||||
import static org.lwjgl.opengl.GL20.glGetProgramInfoLog;
|
import static org.lwjgl.opengl.GL20.glGetProgramInfoLog;
|
||||||
import static org.lwjgl.opengl.GL20.glGetProgrami;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import org.lwjgl.opengl.GL20;
|
import com.jozufozu.flywheel.backend.source.FileResolution;
|
||||||
|
import com.jozufozu.flywheel.backend.source.ShaderSources;
|
||||||
import com.jozufozu.flywheel.backend.Backend;
|
|
||||||
import com.jozufozu.flywheel.backend.FileResolution;
|
|
||||||
import com.jozufozu.flywheel.backend.ShaderSources;
|
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.GlShader;
|
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
||||||
import com.jozufozu.flywheel.backend.loading.ProtoProgram;
|
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||||
import com.jozufozu.flywheel.core.shader.ExtensibleGlProgram;
|
import com.jozufozu.flywheel.core.shader.ExtensibleGlProgram;
|
||||||
import com.jozufozu.flywheel.core.shader.GameStateProgram;
|
import com.jozufozu.flywheel.core.shader.GameStateProgram;
|
||||||
import com.jozufozu.flywheel.core.shader.IMultiProgram;
|
import com.jozufozu.flywheel.core.shader.IMultiProgram;
|
||||||
|
@ -32,10 +25,10 @@ public class WorldShaderPipeline<P extends WorldProgram> implements IShaderPipel
|
||||||
|
|
||||||
private final ExtensibleGlProgram.Factory<P> factory;
|
private final ExtensibleGlProgram.Factory<P> factory;
|
||||||
|
|
||||||
private final ITemplate template;
|
private final Template<?> template;
|
||||||
private final FileResolution header;
|
private final FileResolution header;
|
||||||
|
|
||||||
public WorldShaderPipeline(ShaderSources sources, ExtensibleGlProgram.Factory<P> factory, ITemplate template, FileResolution header) {
|
public WorldShaderPipeline(ShaderSources sources, ExtensibleGlProgram.Factory<P> factory, Template<?> template, FileResolution header) {
|
||||||
this.sources = sources;
|
this.sources = sources;
|
||||||
this.factory = factory;
|
this.factory = factory;
|
||||||
this.template = template;
|
this.template = template;
|
||||||
|
@ -44,48 +37,40 @@ public class WorldShaderPipeline<P extends WorldProgram> implements IShaderPipel
|
||||||
|
|
||||||
public IMultiProgram<P> compile(ProgramSpec spec) {
|
public IMultiProgram<P> compile(ProgramSpec spec) {
|
||||||
|
|
||||||
SourceFile file = sources.source(spec.vert);
|
SourceFile file = sources.source(spec.source);
|
||||||
|
|
||||||
return compile(spec.name, file, spec.getStates());
|
return compile(spec.name, file, spec.getStates());
|
||||||
}
|
}
|
||||||
|
|
||||||
public IMultiProgram<P> compile(ResourceLocation name, SourceFile file, List<ProgramState> variants) {
|
public IMultiProgram<P> compile(ResourceLocation name, SourceFile file, List<ProgramState> variants) {
|
||||||
ShaderBuilder shader = new ShaderBuilder(name, template, header)
|
WorldShader shader = new WorldShader(name, template, header)
|
||||||
.setMainSource(file)
|
.setMainSource(file);
|
||||||
.setVersion(GLSLVersion.V110);
|
|
||||||
|
|
||||||
GameStateProgram.Builder<P> builder = GameStateProgram.builder(compile(shader, name, null));
|
GameStateProgram.Builder<P> builder = GameStateProgram.builder(compile(shader, null));
|
||||||
|
|
||||||
for (ProgramState variant : variants) {
|
for (ProgramState variant : variants) {
|
||||||
builder.withVariant(variant.getContext(), compile(shader, name, variant));
|
builder.withVariant(variant.getContext(), compile(shader, variant));
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private P compile(ShaderBuilder shader, ResourceLocation name, @Nullable ProgramState variant) {
|
private P compile(WorldShader shader, @Nullable ProgramState variant) {
|
||||||
|
|
||||||
if (variant != null) {
|
if (variant != null) {
|
||||||
shader.setDefines(variant.getDefines());
|
shader.setDefines(variant.getDefines());
|
||||||
}
|
}
|
||||||
|
|
||||||
GlShader vertex = shader.compile(name, ShaderType.VERTEX);
|
ProtoProgram program = shader.createProgram()
|
||||||
GlShader fragment = shader.compile(name, ShaderType.FRAGMENT);
|
.compilePart(ShaderType.VERTEX)
|
||||||
|
.compilePart(ShaderType.FRAGMENT)
|
||||||
ProtoProgram program = new ProtoProgram();
|
.link()
|
||||||
|
.deleteLinkedShaders();
|
||||||
program.attachShader(vertex);
|
|
||||||
program.attachShader(fragment);
|
|
||||||
|
|
||||||
template.attachAttributes(program, shader.mainFile);
|
|
||||||
|
|
||||||
program.link(name);
|
|
||||||
program.deleteLinkedShaders();
|
|
||||||
|
|
||||||
if (variant != null) {
|
if (variant != null) {
|
||||||
return factory.create(name, program.program, variant.getExtensions());
|
return factory.create(shader.name, program.program, variant.getExtensions());
|
||||||
} else {
|
} else {
|
||||||
return factory.create(name, program.program, null);
|
return factory.create(shader.name, program.program, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
package com.jozufozu.flywheel.backend.pipeline.error;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.Backend;
|
|
||||||
import com.jozufozu.flywheel.backend.pipeline.SourceFile;
|
|
||||||
import com.jozufozu.flywheel.backend.pipeline.parse.ShaderStruct;
|
|
||||||
import com.jozufozu.flywheel.backend.pipeline.span.Span;
|
|
||||||
|
|
||||||
public class ErrorReporter {
|
|
||||||
|
|
||||||
public static void generateSpanError(Span span, String message) {
|
|
||||||
SourceFile file = span.getSourceFile();
|
|
||||||
|
|
||||||
ErrorBuilder builder = new ErrorBuilder();
|
|
||||||
|
|
||||||
CharSequence error = builder.error(message)
|
|
||||||
.in(file)
|
|
||||||
.pointAt(span, 2)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
Backend.log.error(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void generateFileError(SourceFile file, String message) {
|
|
||||||
|
|
||||||
ErrorBuilder builder = new ErrorBuilder();
|
|
||||||
|
|
||||||
CharSequence error = builder.error(message)
|
|
||||||
.in(file)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
Backend.log.error(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void generateMissingStruct(SourceFile file, Span vertexName) {
|
|
||||||
Optional<Span> span = file.parent.index.getStructDefinitionsMatching(vertexName)
|
|
||||||
.stream()
|
|
||||||
.findFirst()
|
|
||||||
.map(ShaderStruct::getName);
|
|
||||||
ErrorBuilder builder = new ErrorBuilder();
|
|
||||||
|
|
||||||
ErrorBuilder error = builder.error("struct not defined")
|
|
||||||
.in(file)
|
|
||||||
.pointAt(vertexName, 2)
|
|
||||||
.hintIncludeFor(span.orElse(null));
|
|
||||||
|
|
||||||
Backend.log.error(error.build());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
package com.jozufozu.flywheel.backend.source;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.backend.Backend;
|
||||||
|
import com.jozufozu.flywheel.backend.source.error.ErrorBuilder;
|
||||||
|
import com.jozufozu.flywheel.backend.source.span.Span;
|
||||||
|
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reference to a source file that might not be loaded when the owning object is created.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* FileResolutions are used primarily while parsing import statements. {@link FileResolution#file} is initially
|
||||||
|
* null, but will be populated later on, after <em>all</em> SourceFiles are loaded (assuming
|
||||||
|
* {@link FileResolution#fileLoc} references an actual file).
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public class FileResolution {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spans that have references that resolved to this.
|
||||||
|
*/
|
||||||
|
private final List<Span> foundSpans = new ArrayList<>();
|
||||||
|
private final ShaderSources parent;
|
||||||
|
private final ResourceLocation fileLoc;
|
||||||
|
private SourceFile file;
|
||||||
|
|
||||||
|
public FileResolution(ShaderSources parent, ResourceLocation fileLoc) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.fileLoc = fileLoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceLocation getFileLoc() {
|
||||||
|
return fileLoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public SourceFile getFile() {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store the given span so this resolution can know all the places that reference the file.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Used for error reporting.
|
||||||
|
* </p>
|
||||||
|
* @param span A span where this file is referenced.
|
||||||
|
*/
|
||||||
|
public void addSpan(Span span) {
|
||||||
|
foundSpans.add(span);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check to see if this file actually resolves to something.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Called after all files are loaded. If we can't find the file here, it doesn't exist.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
void resolve() {
|
||||||
|
|
||||||
|
try {
|
||||||
|
file = this.parent.source(fileLoc);
|
||||||
|
} catch (RuntimeException error) {
|
||||||
|
ErrorBuilder builder = new ErrorBuilder();
|
||||||
|
builder.error(String.format("could not find source for file %s", fileLoc));
|
||||||
|
// print the location of all places where this file was referenced
|
||||||
|
for (Span span : foundSpans) {
|
||||||
|
builder.in(span.getSourceFile())
|
||||||
|
.pointAt(span, 2);
|
||||||
|
}
|
||||||
|
Backend.log.error(builder.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void invalidate() {
|
||||||
|
foundSpans.clear();
|
||||||
|
file = null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
package com.jozufozu.flywheel.backend.source;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
|
import com.google.common.collect.MultimapBuilder;
|
||||||
|
import com.jozufozu.flywheel.backend.source.parse.ShaderFunction;
|
||||||
|
import com.jozufozu.flywheel.backend.source.parse.ShaderStruct;
|
||||||
|
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indexes many shader source definitions to allow for error fix suggestions.
|
||||||
|
*/
|
||||||
|
public class Index {
|
||||||
|
|
||||||
|
private final Multimap<String, ShaderStruct> knownStructs = MultimapBuilder.hashKeys()
|
||||||
|
.hashSetValues()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
private final Multimap<String, ShaderFunction> knownFunctions = MultimapBuilder.hashKeys()
|
||||||
|
.hashSetValues()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
public Index(Map<ResourceLocation, SourceFile> sources) {
|
||||||
|
Collection<SourceFile> files = sources.values();
|
||||||
|
|
||||||
|
for (SourceFile file : files) {
|
||||||
|
file.getStructs().forEach(knownStructs::put);
|
||||||
|
file.getFunctions().forEach(knownFunctions::put);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<ShaderStruct> getStructDefinitionsMatching(CharSequence name) {
|
||||||
|
return knownStructs.get(name.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<ShaderFunction> getFunctionDefinitionsMatching(CharSequence name) {
|
||||||
|
return knownFunctions.get(name.toString());
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package com.jozufozu.flywheel.backend.loading;
|
package com.jozufozu.flywheel.backend.source;
|
||||||
|
|
||||||
public class ShaderLoadingException extends RuntimeException {
|
public class ShaderLoadingException extends RuntimeException {
|
||||||
public ShaderLoadingException() {
|
public ShaderLoadingException() {
|
|
@ -1,4 +1,4 @@
|
||||||
package com.jozufozu.flywheel.backend;
|
package com.jozufozu.flywheel.backend.source;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -7,16 +7,14 @@ import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
import com.jozufozu.flywheel.backend.Backend;
|
||||||
|
import com.jozufozu.flywheel.backend.IShaderContext;
|
||||||
|
import com.jozufozu.flywheel.backend.ResourceUtil;
|
||||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
|
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
|
||||||
import com.jozufozu.flywheel.backend.loading.ShaderLoadingException;
|
|
||||||
import com.jozufozu.flywheel.backend.pipeline.SourceFile;
|
|
||||||
import com.jozufozu.flywheel.core.crumbling.CrumblingRenderer;
|
import com.jozufozu.flywheel.core.crumbling.CrumblingRenderer;
|
||||||
import com.jozufozu.flywheel.core.shader.spec.ProgramSpec;
|
import com.jozufozu.flywheel.core.shader.spec.ProgramSpec;
|
||||||
import com.jozufozu.flywheel.event.GatherContextEvent;
|
import com.jozufozu.flywheel.event.GatherContextEvent;
|
||||||
|
@ -36,6 +34,13 @@ import net.minecraftforge.resource.IResourceType;
|
||||||
import net.minecraftforge.resource.ISelectiveResourceReloadListener;
|
import net.minecraftforge.resource.ISelectiveResourceReloadListener;
|
||||||
import net.minecraftforge.resource.VanillaResourceType;
|
import net.minecraftforge.resource.VanillaResourceType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main entity for loading shaders.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This class is responsible for invoking the loading, parsing, and compilation stages.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
public class ShaderSources implements ISelectiveResourceReloadListener {
|
public class ShaderSources implements ISelectiveResourceReloadListener {
|
||||||
public static final String SHADER_DIR = "flywheel/shaders/";
|
public static final String SHADER_DIR = "flywheel/shaders/";
|
||||||
public static final String PROGRAM_DIR = "flywheel/programs/";
|
public static final String PROGRAM_DIR = "flywheel/programs/";
|
||||||
|
@ -70,7 +75,7 @@ public class ShaderSources implements ISelectiveResourceReloadListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
public FileResolution resolveFile(ResourceLocation fileLoc) {
|
public FileResolution resolveFile(ResourceLocation fileLoc) {
|
||||||
return resolutions.computeIfAbsent(fileLoc, FileResolution::new);
|
return resolutions.computeIfAbsent(fileLoc, l -> new FileResolution(this, l));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
|
@ -86,17 +91,17 @@ public class ShaderSources implements ISelectiveResourceReloadListener {
|
||||||
if (backend.gl20()) {
|
if (backend.gl20()) {
|
||||||
shouldCrash = false;
|
shouldCrash = false;
|
||||||
|
|
||||||
backend.clearContexts();
|
backend._clearContexts();
|
||||||
|
resolutions.values().forEach(FileResolution::invalidate);
|
||||||
|
shaderSources.clear();
|
||||||
ModLoader.get()
|
ModLoader.get()
|
||||||
.postEvent(new GatherContextEvent(backend));
|
.postEvent(new GatherContextEvent(backend));
|
||||||
|
|
||||||
resolutions.values().forEach(FileResolution::invalidate);
|
|
||||||
|
|
||||||
loadProgramSpecs(manager);
|
loadProgramSpecs(manager);
|
||||||
loadShaderSources(manager);
|
loadShaderSources(manager);
|
||||||
|
|
||||||
for (FileResolution resolution : resolutions.values()) {
|
for (FileResolution resolution : resolutions.values()) {
|
||||||
resolution.resolve(this);
|
resolution.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (IShaderContext<?> context : backend.allContexts()) {
|
for (IShaderContext<?> context : backend.allContexts()) {
|
|
@ -1,29 +1,22 @@
|
||||||
package com.jozufozu.flywheel.backend.pipeline;
|
package com.jozufozu.flywheel.backend.source;
|
||||||
|
|
||||||
import java.util.ArrayDeque;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Queue;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.jozufozu.flywheel.backend.FileResolution;
|
import com.jozufozu.flywheel.backend.source.parse.Import;
|
||||||
import com.jozufozu.flywheel.backend.ShaderSources;
|
import com.jozufozu.flywheel.backend.source.parse.ShaderFunction;
|
||||||
import com.jozufozu.flywheel.backend.pipeline.parse.Import;
|
import com.jozufozu.flywheel.backend.source.parse.ShaderStruct;
|
||||||
import com.jozufozu.flywheel.backend.pipeline.parse.ShaderFunction;
|
import com.jozufozu.flywheel.backend.source.span.CharPos;
|
||||||
import com.jozufozu.flywheel.backend.pipeline.parse.ShaderStruct;
|
import com.jozufozu.flywheel.backend.source.span.ErrorSpan;
|
||||||
import com.jozufozu.flywheel.backend.pipeline.span.CharPos;
|
import com.jozufozu.flywheel.backend.source.span.Span;
|
||||||
import com.jozufozu.flywheel.backend.pipeline.span.ErrorSpan;
|
import com.jozufozu.flywheel.backend.source.span.StringSpan;
|
||||||
import com.jozufozu.flywheel.backend.pipeline.span.Span;
|
|
||||||
import com.jozufozu.flywheel.backend.pipeline.span.StringSpan;
|
|
||||||
import com.jozufozu.flywheel.util.StringUtil;
|
import com.jozufozu.flywheel.util.StringUtil;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||||
|
@ -142,6 +135,12 @@ public class SourceFile {
|
||||||
return "#use " + '"' + name + '"';
|
return "#use " + '"' + name + '"';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CharSequence generateFinalSource() {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
generateFinalSource(builder);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
public void generateFinalSource(StringBuilder source) {
|
public void generateFinalSource(StringBuilder source) {
|
||||||
for (Import include : getIncludes()) {
|
for (Import include : getIncludes()) {
|
||||||
SourceFile file = include.getFile();
|
SourceFile file = include.getFile();
|
|
@ -1,11 +1,7 @@
|
||||||
package com.jozufozu.flywheel.backend.pipeline.error;
|
package com.jozufozu.flywheel.backend.source.error;
|
||||||
|
|
||||||
import java.util.Optional;
|
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||||
|
import com.jozufozu.flywheel.backend.source.span.Span;
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.pipeline.SourceFile;
|
|
||||||
import com.jozufozu.flywheel.backend.pipeline.span.Span;
|
|
||||||
import com.jozufozu.flywheel.util.FlwUtil;
|
import com.jozufozu.flywheel.util.FlwUtil;
|
||||||
|
|
||||||
public class ErrorBuilder {
|
public class ErrorBuilder {
|
||||||
|
@ -40,6 +36,11 @@ public class ErrorBuilder {
|
||||||
return line(String.valueOf(no), content);
|
return line(String.valueOf(no), content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ErrorBuilder numberedLine(int no, int width, CharSequence content) {
|
||||||
|
String fmt = "%1$" + width + 's';
|
||||||
|
return line(String.format(fmt, no), content);
|
||||||
|
}
|
||||||
|
|
||||||
public ErrorBuilder line(CharSequence leftColumn, CharSequence rightColumn) {
|
public ErrorBuilder line(CharSequence leftColumn, CharSequence rightColumn) {
|
||||||
|
|
||||||
internal.append(leftColumn)
|
internal.append(leftColumn)
|
||||||
|
@ -54,10 +55,10 @@ public class ErrorBuilder {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ErrorBuilder hintIncludeFor(Span span) {
|
public ErrorBuilder hintIncludeFor(Span span, CharSequence msg) {
|
||||||
if (span == null) return this;
|
if (span == null) return this;
|
||||||
|
|
||||||
hint("add " + span.getSourceFile().importStatement())
|
hint("add " + span.getSourceFile().importStatement() + " " + msg)
|
||||||
.in(span.getSourceFile())
|
.in(span.getSourceFile())
|
||||||
.pointAt(span, 1);
|
.pointAt(span, 1);
|
||||||
|
|
||||||
|
@ -77,14 +78,13 @@ public class ErrorBuilder {
|
||||||
|
|
||||||
int digits = FlwUtil.numDigits(lastLine);
|
int digits = FlwUtil.numDigits(lastLine);
|
||||||
|
|
||||||
|
|
||||||
int firstCol = span.getStart().getCol();
|
int firstCol = span.getStart().getCol();
|
||||||
int lastCol = span.getEnd().getCol();
|
int lastCol = span.getEnd().getCol();
|
||||||
|
|
||||||
for (int i = firstLine; i <= lastLine; i++) {
|
for (int i = firstLine; i <= lastLine; i++) {
|
||||||
CharSequence line = file.getLine(i);
|
CharSequence line = file.getLine(i);
|
||||||
|
|
||||||
numberedLine(i + 1, line);
|
numberedLine(i + 1, digits, line);
|
||||||
|
|
||||||
if (i == spanLine) {
|
if (i == spanLine) {
|
||||||
line(FlwUtil.repeatChar(' ', digits), generateUnderline(firstCol, lastCol));
|
line(FlwUtil.repeatChar(' ', digits), generateUnderline(firstCol, lastCol));
|
|
@ -0,0 +1,73 @@
|
||||||
|
package com.jozufozu.flywheel.backend.source.error;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.backend.Backend;
|
||||||
|
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||||
|
import com.jozufozu.flywheel.backend.source.parse.ShaderFunction;
|
||||||
|
import com.jozufozu.flywheel.backend.source.parse.ShaderStruct;
|
||||||
|
import com.jozufozu.flywheel.backend.source.span.Span;
|
||||||
|
|
||||||
|
public class ErrorReporter {
|
||||||
|
|
||||||
|
public static void generateSpanError(Span span, String message) {
|
||||||
|
SourceFile file = span.getSourceFile();
|
||||||
|
|
||||||
|
ErrorBuilder builder = new ErrorBuilder();
|
||||||
|
|
||||||
|
CharSequence error = builder.error(message)
|
||||||
|
.in(file)
|
||||||
|
.pointAt(span, 2)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Backend.log.error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void generateFileError(SourceFile file, String message) {
|
||||||
|
|
||||||
|
ErrorBuilder builder = new ErrorBuilder();
|
||||||
|
|
||||||
|
CharSequence error = builder.error(message)
|
||||||
|
.in(file)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Backend.log.error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void generateMissingStruct(SourceFile file, Span vertexName, CharSequence msg) {
|
||||||
|
generateMissingStruct(file, vertexName, msg, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void generateMissingStruct(SourceFile file, Span vertexName, CharSequence msg, CharSequence hint) {
|
||||||
|
Optional<Span> span = file.parent.index.getStructDefinitionsMatching(vertexName)
|
||||||
|
.stream()
|
||||||
|
.findFirst()
|
||||||
|
.map(ShaderStruct::getName);
|
||||||
|
ErrorBuilder builder = new ErrorBuilder();
|
||||||
|
|
||||||
|
ErrorBuilder error = builder.error(msg)
|
||||||
|
.in(file)
|
||||||
|
.pointAt(vertexName, 2)
|
||||||
|
.hintIncludeFor(span.orElse(null), hint);
|
||||||
|
|
||||||
|
Backend.log.error(error.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void generateMissingFunction(SourceFile file, CharSequence functionName, CharSequence msg) {
|
||||||
|
generateMissingFunction(file, functionName, msg, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void generateMissingFunction(SourceFile file, CharSequence functionName, CharSequence msg, CharSequence hint) {
|
||||||
|
Optional<Span> span = file.parent.index.getFunctionDefinitionsMatching(functionName)
|
||||||
|
.stream()
|
||||||
|
.findFirst()
|
||||||
|
.map(ShaderFunction::getName);
|
||||||
|
ErrorBuilder builder = new ErrorBuilder();
|
||||||
|
|
||||||
|
ErrorBuilder error = builder.error(msg)
|
||||||
|
.in(file)
|
||||||
|
.hintIncludeFor(span.orElse(null), hint);
|
||||||
|
|
||||||
|
Backend.log.error(error.build());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault
|
||||||
|
package com.jozufozu.flywheel.backend.source.error;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
|
|
||||||
|
import mcp.MethodsReturnNonnullByDefault;
|
|
@ -1,5 +1,5 @@
|
||||||
@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault
|
@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault
|
||||||
package com.jozufozu.flywheel.backend.loading;
|
package com.jozufozu.flywheel.backend.source;
|
||||||
|
|
||||||
import javax.annotation.ParametersAreNonnullByDefault;
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package com.jozufozu.flywheel.backend.pipeline.parse;
|
package com.jozufozu.flywheel.backend.source.parse;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.pipeline.span.Span;
|
import com.jozufozu.flywheel.backend.source.span.Span;
|
||||||
|
|
||||||
public abstract class AbstractShaderElement {
|
public abstract class AbstractShaderElement {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package com.jozufozu.flywheel.backend.pipeline.parse;
|
package com.jozufozu.flywheel.backend.source.parse;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -6,11 +6,11 @@ import java.util.Optional;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.FileResolution;
|
import com.jozufozu.flywheel.backend.source.FileResolution;
|
||||||
import com.jozufozu.flywheel.backend.ShaderSources;
|
import com.jozufozu.flywheel.backend.source.ShaderSources;
|
||||||
import com.jozufozu.flywheel.backend.pipeline.error.ErrorReporter;
|
import com.jozufozu.flywheel.backend.source.error.ErrorReporter;
|
||||||
import com.jozufozu.flywheel.backend.pipeline.SourceFile;
|
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||||
import com.jozufozu.flywheel.backend.pipeline.span.Span;
|
import com.jozufozu.flywheel.backend.source.span.Span;
|
||||||
|
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package com.jozufozu.flywheel.backend.pipeline.parse;
|
package com.jozufozu.flywheel.backend.source.parse;
|
||||||
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.jozufozu.flywheel.backend.pipeline.span.Span;
|
import com.jozufozu.flywheel.backend.source.span.Span;
|
||||||
|
|
||||||
public class ShaderFunction extends AbstractShaderElement {
|
public class ShaderFunction extends AbstractShaderElement {
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
package com.jozufozu.flywheel.backend.pipeline.parse;
|
package com.jozufozu.flywheel.backend.source.parse;
|
||||||
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.jozufozu.flywheel.backend.loading.ProtoProgram;
|
import com.jozufozu.flywheel.backend.source.span.Span;
|
||||||
import com.jozufozu.flywheel.backend.loading.TypeHelper;
|
|
||||||
import com.jozufozu.flywheel.backend.pipeline.span.Span;
|
|
||||||
|
|
||||||
public class ShaderStruct extends AbstractShaderElement {
|
public class ShaderStruct extends AbstractShaderElement {
|
||||||
|
|
||||||
|
@ -65,14 +63,6 @@ public class ShaderStruct extends AbstractShaderElement {
|
||||||
return fields.build();
|
return fields.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addPrefixedAttributes(ProtoProgram builder, String prefix) {
|
|
||||||
for (StructField field : fields) {
|
|
||||||
int attributeCount = TypeHelper.getAttributeCount(field.type);
|
|
||||||
|
|
||||||
builder.addAttribute(prefix + field.name, attributeCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "struct " + name;
|
return "struct " + name;
|
|
@ -1,9 +1,8 @@
|
||||||
package com.jozufozu.flywheel.backend.pipeline.parse;
|
package com.jozufozu.flywheel.backend.source.parse;
|
||||||
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.pipeline.error.ErrorReporter;
|
import com.jozufozu.flywheel.backend.source.span.Span;
|
||||||
import com.jozufozu.flywheel.backend.pipeline.span.Span;
|
|
||||||
|
|
||||||
public class StructField extends AbstractShaderElement {
|
public class StructField extends AbstractShaderElement {
|
||||||
public static final Pattern fieldPattern = Pattern.compile("(\\S+)\\s*(\\S+);");
|
public static final Pattern fieldPattern = Pattern.compile("(\\S+)\\s*(\\S+);");
|
|
@ -1,7 +1,6 @@
|
||||||
package com.jozufozu.flywheel.backend.pipeline.parse;
|
package com.jozufozu.flywheel.backend.source.parse;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.pipeline.error.ErrorReporter;
|
import com.jozufozu.flywheel.backend.source.span.Span;
|
||||||
import com.jozufozu.flywheel.backend.pipeline.span.Span;
|
|
||||||
|
|
||||||
public class Variable extends AbstractShaderElement {
|
public class Variable extends AbstractShaderElement {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
@ParametersAreNonnullByDefault
|
@ParametersAreNonnullByDefault
|
||||||
@MethodsReturnNonnullByDefault
|
@MethodsReturnNonnullByDefault
|
||||||
package com.jozufozu.flywheel.backend.pipeline.parse;
|
package com.jozufozu.flywheel.backend.source.parse;
|
||||||
|
|
||||||
import javax.annotation.ParametersAreNonnullByDefault;
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package com.jozufozu.flywheel.backend.pipeline.span;
|
package com.jozufozu.flywheel.backend.source.span;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A position in a file.
|
* A position in a file.
|
|
@ -1,6 +1,6 @@
|
||||||
package com.jozufozu.flywheel.backend.pipeline.span;
|
package com.jozufozu.flywheel.backend.source.span;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.pipeline.SourceFile;
|
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a (syntactically) malformed segment of code.
|
* Represents a (syntactically) malformed segment of code.
|
|
@ -1,8 +1,8 @@
|
||||||
package com.jozufozu.flywheel.backend.pipeline.span;
|
package com.jozufozu.flywheel.backend.source.span;
|
||||||
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.pipeline.SourceFile;
|
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A span of code in a {@link SourceFile}.
|
* A span of code in a {@link SourceFile}.
|
|
@ -1,6 +1,6 @@
|
||||||
package com.jozufozu.flywheel.backend.pipeline.span;
|
package com.jozufozu.flywheel.backend.source.span;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.pipeline.SourceFile;
|
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||||
|
|
||||||
public class StringSpan extends Span {
|
public class StringSpan extends Span {
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault
|
||||||
|
package com.jozufozu.flywheel.backend.source.span;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
||||||
|
|
||||||
|
import mcp.MethodsReturnNonnullByDefault;
|
|
@ -2,7 +2,7 @@ package com.jozufozu.flywheel.core;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.Flywheel;
|
import com.jozufozu.flywheel.Flywheel;
|
||||||
import com.jozufozu.flywheel.backend.Backend;
|
import com.jozufozu.flywheel.backend.Backend;
|
||||||
import com.jozufozu.flywheel.backend.FileResolution;
|
import com.jozufozu.flywheel.backend.source.FileResolution;
|
||||||
import com.jozufozu.flywheel.backend.ResourceUtil;
|
import com.jozufozu.flywheel.backend.ResourceUtil;
|
||||||
import com.jozufozu.flywheel.backend.SpecMetaRegistry;
|
import com.jozufozu.flywheel.backend.SpecMetaRegistry;
|
||||||
import com.jozufozu.flywheel.backend.pipeline.IShaderPipeline;
|
import com.jozufozu.flywheel.backend.pipeline.IShaderPipeline;
|
||||||
|
@ -40,8 +40,8 @@ public class Contexts {
|
||||||
IShaderPipeline<CrumblingProgram> crumblingPipeline = new WorldShaderPipeline<>(backend.sources, CrumblingProgram::new, InstancingTemplate.INSTANCE, crumblingBuiltins);
|
IShaderPipeline<CrumblingProgram> crumblingPipeline = new WorldShaderPipeline<>(backend.sources, CrumblingProgram::new, InstancingTemplate.INSTANCE, crumblingBuiltins);
|
||||||
IShaderPipeline<WorldProgram> worldPipeline = new WorldShaderPipeline<>(backend.sources, WorldProgram::new, InstancingTemplate.INSTANCE, worldBuiltins);
|
IShaderPipeline<WorldProgram> worldPipeline = new WorldShaderPipeline<>(backend.sources, WorldProgram::new, InstancingTemplate.INSTANCE, worldBuiltins);
|
||||||
|
|
||||||
CRUMBLING = backend.register(new WorldContext<>(backend, crumblingPipeline).withName(Names.CRUMBLING));
|
CRUMBLING = backend.register(WorldContext.builder(backend, Names.CRUMBLING).build(crumblingPipeline));
|
||||||
WORLD = backend.register(new WorldContext<>(backend, worldPipeline).withName(Names.WORLD));
|
WORLD = backend.register(WorldContext.builder(backend, Names.WORLD).build(worldPipeline));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Names {
|
public static class Names {
|
||||||
|
|
|
@ -1,40 +1,33 @@
|
||||||
package com.jozufozu.flywheel.core;
|
package com.jozufozu.flywheel.core;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.Backend;
|
import com.jozufozu.flywheel.backend.Backend;
|
||||||
import com.jozufozu.flywheel.backend.ShaderContext;
|
import com.jozufozu.flywheel.backend.IShaderContext;
|
||||||
import com.jozufozu.flywheel.backend.material.MaterialSpec;
|
import com.jozufozu.flywheel.backend.material.MaterialSpec;
|
||||||
import com.jozufozu.flywheel.backend.pipeline.IShaderPipeline;
|
import com.jozufozu.flywheel.backend.pipeline.IShaderPipeline;
|
||||||
|
import com.jozufozu.flywheel.core.shader.IMultiProgram;
|
||||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||||
import com.jozufozu.flywheel.core.shader.spec.ProgramSpec;
|
import com.jozufozu.flywheel.core.shader.spec.ProgramSpec;
|
||||||
|
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
|
||||||
public class WorldContext<P extends WorldProgram> extends ShaderContext<P> {
|
public class WorldContext<P extends WorldProgram> implements IShaderContext<P> {
|
||||||
protected ResourceLocation name;
|
public final Backend backend;
|
||||||
protected Supplier<Stream<ResourceLocation>> specStream;
|
protected final Map<ResourceLocation, IMultiProgram<P>> programs = new HashMap<>();
|
||||||
|
protected final ResourceLocation name;
|
||||||
|
protected final Supplier<Stream<ResourceLocation>> specStream;
|
||||||
|
|
||||||
public final IShaderPipeline<P> pipeline;
|
public final IShaderPipeline<P> pipeline;
|
||||||
|
|
||||||
public WorldContext(Backend backend, IShaderPipeline<P> factory) {
|
public WorldContext(Backend backend, ResourceLocation name, Supplier<Stream<ResourceLocation>> specStream, IShaderPipeline<P> pipeline) {
|
||||||
super(backend);
|
this.backend = backend;
|
||||||
this.pipeline = factory;
|
|
||||||
|
|
||||||
specStream = () -> backend.allMaterials()
|
|
||||||
.stream()
|
|
||||||
.map(MaterialSpec::getProgramName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public WorldContext<P> withName(ResourceLocation name) {
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public WorldContext<P> withSpecStream(Supplier<Stream<ResourceLocation>> specStream) {
|
|
||||||
this.specStream = specStream;
|
this.specStream = specStream;
|
||||||
return this;
|
this.pipeline = pipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -59,4 +52,45 @@ public class WorldContext<P extends WorldProgram> extends ShaderContext<P> {
|
||||||
backend.sources.notifyError();
|
backend.sources.notifyError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Supplier<P> getProgramSupplier(ResourceLocation spec) {
|
||||||
|
return programs.get(spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete() {
|
||||||
|
programs.values()
|
||||||
|
.forEach(IMultiProgram::delete);
|
||||||
|
programs.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Builder builder(Backend backend, ResourceLocation name) {
|
||||||
|
return new Builder(backend, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
private final Backend backend;
|
||||||
|
private final ResourceLocation name;
|
||||||
|
private Supplier<Stream<ResourceLocation>> specStream;
|
||||||
|
|
||||||
|
public Builder(Backend backend, ResourceLocation name) {
|
||||||
|
this.backend = backend;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setSpecStream(Supplier<Stream<ResourceLocation>> specStream) {
|
||||||
|
this.specStream = specStream;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <P extends WorldProgram> WorldContext<P> build(IShaderPipeline<P> pipeline) {
|
||||||
|
if (specStream == null) {
|
||||||
|
specStream = () -> backend.allMaterials()
|
||||||
|
.stream()
|
||||||
|
.map(MaterialSpec::getProgramName);
|
||||||
|
}
|
||||||
|
return new WorldContext<>(backend, name, specStream, pipeline);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,56 +1,54 @@
|
||||||
package com.jozufozu.flywheel.core.shader.spec;
|
package com.jozufozu.flywheel.core.shader.spec;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.backend.source.SourceFile;
|
||||||
import com.mojang.serialization.Codec;
|
import com.mojang.serialization.Codec;
|
||||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
|
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object describing a shader program that can be loaded by flywheel.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* These are defined through json. All ProgramSpecs in <code>assets/modid/flywheel/programs</code> are parsed and
|
||||||
|
* processed. One ProgramSpec typically specifies one "material" that can be used in game to render things.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* All shader source files in <code>assets/modid/flywheel/shaders</code> are completely loaded and parsed into
|
||||||
|
* {@link SourceFile SourceFiles}, but not compiled until one of them is
|
||||||
|
* referenced by a ProgramSpec.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
public class ProgramSpec {
|
public class ProgramSpec {
|
||||||
|
|
||||||
// TODO: Block model style inheritance?
|
// TODO: Block model style inheritance?
|
||||||
public static final Codec<ProgramSpec> CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
public static final Codec<ProgramSpec> CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||||
ResourceLocation.CODEC.fieldOf("vert")
|
ResourceLocation.CODEC.fieldOf("source")
|
||||||
.forGetter(ProgramSpec::getVert),
|
.forGetter(ProgramSpec::getSource),
|
||||||
ResourceLocation.CODEC.fieldOf("frag")
|
|
||||||
.forGetter(ProgramSpec::getFrag),
|
|
||||||
ProgramState.CODEC.listOf()
|
ProgramState.CODEC.listOf()
|
||||||
.optionalFieldOf("states", Collections.emptyList())
|
.optionalFieldOf("states", Collections.emptyList())
|
||||||
.forGetter(ProgramSpec::getStates))
|
.forGetter(ProgramSpec::getStates))
|
||||||
.apply(instance, ProgramSpec::new));
|
.apply(instance, ProgramSpec::new));
|
||||||
|
|
||||||
public ResourceLocation name;
|
public ResourceLocation name;
|
||||||
public final ResourceLocation vert;
|
public final ResourceLocation source;
|
||||||
public final ResourceLocation frag;
|
|
||||||
|
|
||||||
public final List<ProgramState> states;
|
public final List<ProgramState> states;
|
||||||
|
|
||||||
public ProgramSpec(ResourceLocation vert, ResourceLocation frag, List<ProgramState> states) {
|
public ProgramSpec(ResourceLocation source, List<ProgramState> states) {
|
||||||
this.vert = vert;
|
this.source = source;
|
||||||
this.frag = frag;
|
|
||||||
this.states = states;
|
this.states = states;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProgramSpec(ResourceLocation name, ResourceLocation vert, ResourceLocation frag) {
|
|
||||||
this.name = name;
|
|
||||||
this.vert = vert;
|
|
||||||
this.frag = frag;
|
|
||||||
this.states = new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(ResourceLocation name) {
|
public void setName(ResourceLocation name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResourceLocation getVert() {
|
public ResourceLocation getSource() {
|
||||||
return vert;
|
return source;
|
||||||
}
|
|
||||||
|
|
||||||
public ResourceLocation getFrag() {
|
|
||||||
return frag;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ProgramState> getStates() {
|
public List<ProgramState> getStates() {
|
||||||
|
|
|
@ -95,6 +95,9 @@ public class RenderHooksMixin {
|
||||||
|
|
||||||
// Instancing
|
// Instancing
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This gets called when a block is marked for rerender by vanilla.
|
||||||
|
*/
|
||||||
@Inject(at = @At("TAIL"), method = "setBlockDirty(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;Lnet/minecraft/block/BlockState;)V")
|
@Inject(at = @At("TAIL"), method = "setBlockDirty(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;Lnet/minecraft/block/BlockState;)V")
|
||||||
private void checkUpdate(BlockPos pos, BlockState lastState, BlockState newState, CallbackInfo ci) {
|
private void checkUpdate(BlockPos pos, BlockState lastState, BlockState newState, CallbackInfo ci) {
|
||||||
InstancedRenderDispatcher.getTiles(level)
|
InstancedRenderDispatcher.getTiles(level)
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
{
|
{
|
||||||
"vert": "flywheel:model.vert",
|
"source": "flywheel:model.vert",
|
||||||
"frag": "flywheel:block.frag",
|
|
||||||
"states": [
|
"states": [
|
||||||
{
|
{
|
||||||
"when": {
|
"when": {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
{
|
{
|
||||||
"vert": "flywheel:oriented.vert",
|
"source": "flywheel:oriented.vert",
|
||||||
"frag": "flywheel:block.frag",
|
|
||||||
"states": [
|
"states": [
|
||||||
{
|
{
|
||||||
"when": {
|
"when": {
|
||||||
|
|
Loading…
Reference in a new issue