mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-02-04 17:24:59 +01:00
Cleaner compilation
- Check for errors immediately after loading shaders - Done through FileResolution - Add class SourceChecks to - Throw away GatherContextEvent, do everything on client init - Unify FileResolution and Resolver, PartialModel style - Pass around error reporter to detect errors during load
This commit is contained in:
parent
a7a716b469
commit
c65992ec0e
51 changed files with 443 additions and 551 deletions
|
@ -76,15 +76,16 @@ public class Flywheel {
|
|||
forgeEventBus.<ReloadRenderersEvent>addListener(ProgramCompiler::invalidateAll);
|
||||
forgeEventBus.addListener(Models::onReload);
|
||||
|
||||
modEventBus.addListener(LayoutShaders::flwInit);
|
||||
modEventBus.addListener(InstanceShaders::flwInit);
|
||||
modEventBus.addListener(MaterialShaders::flwInit);
|
||||
modEventBus.addListener(Contexts::flwInit);
|
||||
modEventBus.addListener(PartialModel::onModelRegistry);
|
||||
modEventBus.addListener(PartialModel::onModelBake);
|
||||
modEventBus.addListener(StitchedSprite::onTextureStitchPre);
|
||||
modEventBus.addListener(StitchedSprite::onTextureStitchPost);
|
||||
|
||||
LayoutShaders.init();
|
||||
InstanceShaders.init();
|
||||
Contexts.init();
|
||||
MaterialShaders.init();
|
||||
|
||||
VanillaInstances.init();
|
||||
|
||||
// https://github.com/Jozufozu/Flywheel/issues/69
|
||||
|
|
|
@ -1,18 +1,17 @@
|
|||
package com.jozufozu.flywheel.backend;
|
||||
|
||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
|
||||
import com.jozufozu.flywheel.core.GameStateRegistry;
|
||||
import com.jozufozu.flywheel.core.crumbling.CrumblingRenderer;
|
||||
import com.jozufozu.flywheel.core.source.Resolver;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.jozufozu.flywheel.core.source.ShaderLoadingException;
|
||||
import com.jozufozu.flywheel.core.source.ShaderSources;
|
||||
import com.jozufozu.flywheel.event.GatherContextEvent;
|
||||
import com.jozufozu.flywheel.core.source.error.ErrorReporter;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.server.packs.resources.ReloadableResourceManager;
|
||||
import net.minecraft.server.packs.resources.ResourceManager;
|
||||
import net.minecraft.server.packs.resources.ResourceManagerReloadListener;
|
||||
import net.minecraftforge.fml.ModLoader;
|
||||
|
||||
/**
|
||||
* The main entity for loading shaders.
|
||||
|
@ -22,7 +21,6 @@ import net.minecraftforge.fml.ModLoader;
|
|||
* </p>
|
||||
*/
|
||||
public class Loader implements ResourceManagerReloadListener {
|
||||
private boolean firstLoad = true;
|
||||
|
||||
Loader() {
|
||||
// Can be null when running datagenerators due to the unfortunate time we call this
|
||||
|
@ -39,15 +37,15 @@ public class Loader implements ResourceManagerReloadListener {
|
|||
public void onResourceManagerReload(ResourceManager manager) {
|
||||
Backend.refresh();
|
||||
|
||||
GameStateRegistry._clear();
|
||||
var errorReporter = new ErrorReporter();
|
||||
ShaderSources sources = new ShaderSources(errorReporter, manager);
|
||||
|
||||
Resolver.INSTANCE.invalidate();
|
||||
ModLoader.get()
|
||||
.postEvent(new GatherContextEvent(firstLoad));
|
||||
FileResolution.run(errorReporter, sources);
|
||||
|
||||
ShaderSources sources = new ShaderSources(manager);
|
||||
|
||||
Resolver.INSTANCE.run(sources);
|
||||
if (errorReporter.hasErrored()) {
|
||||
errorReporter.dump();
|
||||
throw new ShaderLoadingException("Failed to resolve all source files, see log for details");
|
||||
}
|
||||
|
||||
Backend.LOGGER.info("Loaded all shader sources.");
|
||||
|
||||
|
@ -58,6 +56,5 @@ public class Loader implements ResourceManagerReloadListener {
|
|||
CrumblingRenderer.reset();
|
||||
}
|
||||
|
||||
firstLoad = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,16 @@
|
|||
package com.jozufozu.flywheel.backend.gl;
|
||||
|
||||
public enum GLSLVersion {
|
||||
V110(110),
|
||||
V120(120),
|
||||
V130(130),
|
||||
V140(140),
|
||||
V150(150),
|
||||
V330(330),
|
||||
V400(400),
|
||||
V410(410),
|
||||
V420(420),
|
||||
V430(430),
|
||||
;
|
||||
|
||||
public final int version;
|
||||
|
|
|
@ -1,34 +1,37 @@
|
|||
package com.jozufozu.flywheel.backend.gl.shader;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.lwjgl.opengl.GL20;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.GlObject;
|
||||
import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
|
||||
import com.jozufozu.flywheel.core.shader.ShaderConstants;
|
||||
import com.jozufozu.flywheel.core.source.ShaderLoadingException;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class GlShader extends GlObject {
|
||||
|
||||
public final ResourceLocation name;
|
||||
public final ShaderType type;
|
||||
private final List<ResourceLocation> parts;
|
||||
private final ShaderConstants constants;
|
||||
|
||||
public GlShader(ResourceLocation name, ShaderType type, String source) {
|
||||
this.name = name;
|
||||
public GlShader(String source, ShaderType type, List<ResourceLocation> parts, ShaderConstants constants) {
|
||||
this.parts = parts;
|
||||
this.type = type;
|
||||
this.constants = constants;
|
||||
int handle = GL20.glCreateShader(type.glEnum);
|
||||
|
||||
GlCompat.safeShaderSource(handle, source);
|
||||
GL20.glCompileShader(handle);
|
||||
|
||||
// File dir = new File(Minecraft.getInstance().gameDirectory, "flywheel_sources");
|
||||
// dir.mkdirs();
|
||||
// File file = new File(dir, name.toString().replaceAll("[:/]", "_"));
|
||||
// try (FileWriter writer = new FileWriter(file)) {
|
||||
// writer.write(source);
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
dumpSource(source, type);
|
||||
|
||||
// String log = GL20.glGetShaderInfoLog(handle);
|
||||
//
|
||||
|
@ -38,7 +41,7 @@ public class GlShader extends GlObject {
|
|||
// }
|
||||
|
||||
if (GL20.glGetShaderi(handle, GL20.GL_COMPILE_STATUS) != GL20.GL_TRUE) {
|
||||
throw new ShaderLoadingException("Could not compile " + name + ". See log for details.");
|
||||
throw new ShaderLoadingException("Could not compile " + getName() + ". See log for details.");
|
||||
}
|
||||
|
||||
setHandle(handle);
|
||||
|
@ -49,4 +52,22 @@ public class GlShader extends GlObject {
|
|||
GL20.glDeleteShader(handle);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return parts.stream()
|
||||
.map(ResourceLocation::toString)
|
||||
.map(s -> s.replaceAll("/", "_")
|
||||
.replaceAll(":", "\\$"))
|
||||
.collect(Collectors.joining(";")) + ';' + Integer.toHexString(constants.hashCode());
|
||||
}
|
||||
|
||||
private void dumpSource(String source, ShaderType type) {
|
||||
File dir = new File(Minecraft.getInstance().gameDirectory, "flywheel_sources");
|
||||
dir.mkdirs();
|
||||
File file = new File(dir, type.getFileName(getName()));
|
||||
try (FileWriter writer = new FileWriter(file)) {
|
||||
writer.write(source);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,21 +3,27 @@ package com.jozufozu.flywheel.backend.gl.shader;
|
|||
import org.lwjgl.opengl.GL20;
|
||||
|
||||
public enum ShaderType {
|
||||
VERTEX("vertex", "VERTEX_SHADER", GL20.GL_VERTEX_SHADER),
|
||||
FRAGMENT("fragment", "FRAGMENT_SHADER", GL20.GL_FRAGMENT_SHADER),
|
||||
VERTEX("vertex", "VERTEX_SHADER", "vert", GL20.GL_VERTEX_SHADER),
|
||||
FRAGMENT("fragment", "FRAGMENT_SHADER", "frag", GL20.GL_FRAGMENT_SHADER),
|
||||
;
|
||||
|
||||
public final String name;
|
||||
public final String define;
|
||||
public final String extension;
|
||||
public final int glEnum;
|
||||
|
||||
ShaderType(String name, String define, int glEnum) {
|
||||
ShaderType(String name, String define, String extension, int glEnum) {
|
||||
this.name = name;
|
||||
this.define = define;
|
||||
this.extension = extension;
|
||||
this.glEnum = glEnum;
|
||||
}
|
||||
|
||||
public String getDefineStatement() {
|
||||
return "#define " + define + "\n";
|
||||
}
|
||||
|
||||
public String getFileName(String baseName) {
|
||||
return baseName + "." + extension;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ import com.jozufozu.flywheel.core.CoreShaderInfoMap.CoreShaderInfo;
|
|||
import com.jozufozu.flywheel.core.GameStateRegistry;
|
||||
import com.jozufozu.flywheel.core.RenderContext;
|
||||
import com.jozufozu.flywheel.core.compile.ProgramCompiler;
|
||||
import com.jozufozu.flywheel.core.compile.ProgramContext;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
import com.jozufozu.flywheel.core.vertex.Formats;
|
||||
import com.jozufozu.flywheel.util.Textures;
|
||||
|
@ -155,7 +154,7 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
alphaDiscard = 0;
|
||||
}
|
||||
|
||||
P program = context.getProgram(new ProgramContext(Formats.POS_TEX_NORMAL, instanceType.getInstanceShader(), material.getVertexShader(), material.getFragmentShader(), alphaDiscard, coreShaderInfo.fogType(), GameStateRegistry.takeSnapshot()));
|
||||
P program = context.getProgram(new ProgramCompiler.Context(Formats.POS_TEX_NORMAL, instanceType.getInstanceShader(), material.getVertexShader(), material.getFragmentShader(), alphaDiscard, coreShaderInfo.fogType(), GameStateRegistry.takeSnapshot()));
|
||||
|
||||
program.bind();
|
||||
program.uploadUniforms(camX, camY, camZ, viewProjection, level);
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
package com.jozufozu.flywheel.core;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
||||
import com.jozufozu.flywheel.core.compile.ProgramCompiler;
|
||||
import com.jozufozu.flywheel.core.crumbling.CrumblingProgram;
|
||||
import com.jozufozu.flywheel.core.shader.NormalDebugStateProvider;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.jozufozu.flywheel.core.source.Resolver;
|
||||
import com.jozufozu.flywheel.event.GatherContextEvent;
|
||||
import com.jozufozu.flywheel.core.source.SourceChecks;
|
||||
import com.jozufozu.flywheel.util.ResourceUtil;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
@ -17,16 +17,23 @@ public class Contexts {
|
|||
public static ProgramCompiler<WorldProgram> WORLD;
|
||||
public static ProgramCompiler<CrumblingProgram> CRUMBLING;
|
||||
|
||||
public static void flwInit(GatherContextEvent event) {
|
||||
public static void init() {
|
||||
GameStateRegistry.register(NormalDebugStateProvider.INSTANCE);
|
||||
|
||||
FileResolution worldVertex = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.WORLD, ".vert"));
|
||||
FileResolution worldFragment = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.WORLD, ".frag"));
|
||||
FileResolution crumblingVertex = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.CRUMBLING, ".vert"));
|
||||
FileResolution crumblingFragment = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.CRUMBLING, ".frag"));
|
||||
var checkFrag = SourceChecks.checkFunctionArity("flw_contextFragment", 0);
|
||||
var checkVert = SourceChecks.checkFunctionArity("flw_contextVertex", 0);
|
||||
|
||||
WORLD = ProgramCompiler.create(WorldProgram::new, worldVertex, worldFragment);
|
||||
CRUMBLING = ProgramCompiler.create(CrumblingProgram::new, crumblingVertex, crumblingFragment);
|
||||
var worldVertex = FileResolution.get(ResourceUtil.subPath(Names.WORLD, ".vert"))
|
||||
.validateWith(checkVert);
|
||||
var worldFragment = FileResolution.get(ResourceUtil.subPath(Names.WORLD, ".frag"))
|
||||
.validateWith(checkFrag);
|
||||
var crumblingVertex = FileResolution.get(ResourceUtil.subPath(Names.CRUMBLING, ".vert"))
|
||||
.validateWith(checkVert);
|
||||
var crumblingFragment = FileResolution.get(ResourceUtil.subPath(Names.CRUMBLING, ".frag"))
|
||||
.validateWith(checkFrag);
|
||||
|
||||
WORLD = ProgramCompiler.create(WorldProgram::new, worldVertex, worldFragment, GLSLVersion.V330);
|
||||
CRUMBLING = ProgramCompiler.create(CrumblingProgram::new, crumblingVertex, crumblingFragment, GLSLVersion.V330);
|
||||
}
|
||||
|
||||
public static class Names {
|
||||
|
|
|
@ -51,8 +51,4 @@ public class GameStateRegistry {
|
|||
}
|
||||
return shaderConstants;
|
||||
}
|
||||
|
||||
public static void _clear() {
|
||||
PROVIDERS.clear();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,9 +2,14 @@ package com.jozufozu.flywheel.core.compile;
|
|||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
||||
import com.jozufozu.flywheel.core.source.SourceFile;
|
||||
|
||||
public class CompileUtil {
|
||||
|
||||
|
@ -45,4 +50,11 @@ public class CompileUtil {
|
|||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String generateDebugName(SourceFile... stages) {
|
||||
return Stream.of(stages)
|
||||
.map(SourceFile::toString)
|
||||
.collect(Collectors.joining(" -> "));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package com.jozufozu.flywheel.core.compile;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
||||
|
@ -12,92 +11,57 @@ import com.jozufozu.flywheel.core.shader.ShaderConstants;
|
|||
import com.jozufozu.flywheel.core.shader.StateSnapshot;
|
||||
import com.jozufozu.flywheel.core.source.FileIndexImpl;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.jozufozu.flywheel.core.source.ShaderLoadingException;
|
||||
import com.jozufozu.flywheel.core.source.SourceFile;
|
||||
import com.jozufozu.flywheel.core.source.error.ErrorReporter;
|
||||
import com.jozufozu.flywheel.core.source.parse.ShaderFunction;
|
||||
import com.jozufozu.flywheel.core.source.parse.Variable;
|
||||
|
||||
/**
|
||||
* Handles compilation and deletion of fragment shaders.
|
||||
*/
|
||||
public class FragmentCompiler extends Memoizer<FragmentCompiler.Context, GlShader> {
|
||||
private final FileResolution contextShader;
|
||||
private final GLSLVersion glslVersion;
|
||||
|
||||
public FragmentCompiler(FileResolution contextShader) {
|
||||
public FragmentCompiler(FileResolution contextShader, GLSLVersion glslVersion) {
|
||||
this.contextShader = contextShader;
|
||||
this.glslVersion = glslVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GlShader _create(Context key) {
|
||||
StringBuilder finalSource = new StringBuilder();
|
||||
|
||||
finalSource.append(CompileUtil.generateHeader(GLSLVersion.V150, ShaderType.FRAGMENT));
|
||||
finalSource.append(CompileUtil.generateHeader(glslVersion, ShaderType.FRAGMENT));
|
||||
|
||||
key.getShaderConstants().writeInto(finalSource);
|
||||
ShaderConstants shaderConstants = key.getShaderConstants();
|
||||
shaderConstants.writeInto(finalSource);
|
||||
finalSource.append('\n');
|
||||
|
||||
FileIndexImpl index = new FileIndexImpl();
|
||||
|
||||
//
|
||||
// MATERIAL
|
||||
|
||||
SourceFile materialShader = key.materialShader;
|
||||
|
||||
Optional<ShaderFunction> maybeMaterialFragment = materialShader.findFunction("flw_materialFragment");
|
||||
|
||||
if (maybeMaterialFragment.isEmpty()) {
|
||||
ErrorReporter.generateMissingFunction(materialShader, "flw_materialFragment", "\"flw_materialFragment\" function not defined");
|
||||
throw new ShaderLoadingException();
|
||||
}
|
||||
|
||||
ShaderFunction materialFragment = maybeMaterialFragment.get();
|
||||
ImmutableList<Variable> params = materialFragment.getParameters();
|
||||
|
||||
if (params.size() != 0) {
|
||||
ErrorReporter.generateSpanError(materialFragment.getArgs(), "\"flw_materialFragment\" function must not have any arguments");
|
||||
throw new ShaderLoadingException();
|
||||
}
|
||||
|
||||
materialShader.generateFinalSource(index, finalSource);
|
||||
|
||||
//
|
||||
// CONTEXT
|
||||
|
||||
SourceFile contextShaderSource = contextShader.getFile();
|
||||
|
||||
Optional<ShaderFunction> maybeContextFragment = contextShaderSource.findFunction("flw_contextFragment");
|
||||
|
||||
if (maybeContextFragment.isEmpty()) {
|
||||
ErrorReporter.generateMissingFunction(contextShaderSource, "flw_contextFragment", "\"flw_contextFragment\" function not defined");
|
||||
throw new ShaderLoadingException();
|
||||
}
|
||||
|
||||
ShaderFunction contextFragment = maybeContextFragment.get();
|
||||
params = contextFragment.getParameters();
|
||||
|
||||
if (params.size() != 0) {
|
||||
ErrorReporter.generateSpanError(contextFragment.getArgs(), "\"flw_contextFragment\" function must not have any arguments");
|
||||
throw new ShaderLoadingException();
|
||||
}
|
||||
|
||||
contextShaderSource.generateFinalSource(index, finalSource);
|
||||
|
||||
//
|
||||
// MAIN
|
||||
|
||||
finalSource.append(generateFooter());
|
||||
|
||||
return new GlShader(contextShader.getFile().name, ShaderType.FRAGMENT, finalSource.toString());
|
||||
return new GlShader(finalSource.toString(), ShaderType.FRAGMENT, ImmutableList.of(materialShader.name, contextShaderSource.name), shaderConstants);
|
||||
}
|
||||
|
||||
protected String generateFooter() {
|
||||
StringBuilder footer = new StringBuilder();
|
||||
|
||||
footer.append("""
|
||||
return """
|
||||
void main() {
|
||||
flw_materialFragment();
|
||||
|
||||
flw_contextFragment();
|
||||
}
|
||||
"""
|
||||
);
|
||||
|
||||
return footer.toString();
|
||||
""";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -107,34 +71,12 @@ public class FragmentCompiler extends Memoizer<FragmentCompiler.Context, GlShade
|
|||
|
||||
/**
|
||||
* Represents the conditions under which a shader is compiled.
|
||||
* @param materialShader The fragment material shader source.
|
||||
* @param alphaDiscard Alpha threshold below which fragments are discarded.
|
||||
* @param fogType Which type of fog should be applied.
|
||||
* @param ctx The shader constants to apply.
|
||||
*/
|
||||
public static final class Context {
|
||||
/**
|
||||
* The fragment material shader source.
|
||||
*/
|
||||
private final SourceFile materialShader;
|
||||
|
||||
/**
|
||||
* Alpha threshold below which fragments are discarded.
|
||||
*/
|
||||
private final float alphaDiscard;
|
||||
|
||||
/**
|
||||
* Which type of fog should be applied.
|
||||
*/
|
||||
private final FogType fogType;
|
||||
|
||||
/**
|
||||
* The shader constants to apply.
|
||||
*/
|
||||
private final StateSnapshot ctx;
|
||||
|
||||
public Context(SourceFile materialShader, float alphaDiscard, FogType fogType, StateSnapshot ctx) {
|
||||
this.materialShader = materialShader;
|
||||
this.alphaDiscard = alphaDiscard;
|
||||
this.fogType = fogType;
|
||||
this.ctx = ctx;
|
||||
}
|
||||
public record Context(SourceFile materialShader, float alphaDiscard, FogType fogType, StateSnapshot ctx) {
|
||||
|
||||
public ShaderConstants getShaderConstants() {
|
||||
ShaderConstants shaderConstants = ctx.getShaderConstants();
|
||||
|
@ -146,23 +88,5 @@ public class FragmentCompiler extends Memoizer<FragmentCompiler.Context, GlShade
|
|||
|
||||
return shaderConstants;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
if (obj == null || obj.getClass() != this.getClass()) return false;
|
||||
var that = (Context) obj;
|
||||
return materialShader == that.materialShader && Objects.equals(this.ctx, that.ctx) && Float.floatToIntBits(this.alphaDiscard) == Float.floatToIntBits(that.alphaDiscard) && fogType == that.fogType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(materialShader, alphaDiscard, fogType, ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Context[" + "materialShader=" + materialShader + ", " + "alphaDiscard=" + alphaDiscard + ", " + "fogType=" + fogType + ", " + "ctx=" + ctx + ']';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,8 +21,6 @@ public class ProgramAssembler {
|
|||
public final int program;
|
||||
private final ResourceLocation name;
|
||||
|
||||
private final List<GlShader> shaders = new ObjectArrayList<>();
|
||||
|
||||
public ProgramAssembler(ResourceLocation name) {
|
||||
this.name = name;
|
||||
this.program = glCreateProgram();
|
||||
|
@ -49,13 +47,7 @@ public class ProgramAssembler {
|
|||
return this;
|
||||
}
|
||||
|
||||
public ProgramAssembler deleteLinkedShaders() {
|
||||
shaders.forEach(GlShader::delete);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ProgramAssembler attachShader(GlShader glShader) {
|
||||
shaders.add(glShader);
|
||||
glAttachShader(this.program, glShader.handle());
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,11 @@ package com.jozufozu.flywheel.core.compile;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.core.CoreShaderInfoMap;
|
||||
import com.jozufozu.flywheel.core.shader.StateSnapshot;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
|
||||
|
||||
|
@ -14,8 +18,11 @@ import com.jozufozu.flywheel.event.ReloadRenderersEvent;
|
|||
* This class is responsible for compiling programs on the fly. An instance of this class will keep a cache of
|
||||
* compiled programs, and will only compile a program if it is not already in the cache.
|
||||
* </p>
|
||||
* <p>
|
||||
* A ProgramCompiler is also responsible for deleting programs and shaders on renderer reload.
|
||||
* </p>
|
||||
*/
|
||||
public class ProgramCompiler<P extends GlProgram> extends Memoizer<ProgramContext, P> {
|
||||
public class ProgramCompiler<P extends GlProgram> extends Memoizer<ProgramCompiler.Context, P> {
|
||||
|
||||
private static final List<ProgramCompiler<?>> ALL_COMPILERS = new ArrayList<>();
|
||||
|
||||
|
@ -39,8 +46,8 @@ public class ProgramCompiler<P extends GlProgram> extends Memoizer<ProgramContex
|
|||
* @param <P> The type of program to compile.
|
||||
* @return A program compiler.
|
||||
*/
|
||||
public static <P extends GlProgram> ProgramCompiler<P> create(GlProgram.Factory<P> factory, FileResolution vertexContextShader, FileResolution fragmentContextShader) {
|
||||
return new ProgramCompiler<>(factory, new VertexCompiler(vertexContextShader), new FragmentCompiler(fragmentContextShader));
|
||||
public static <P extends GlProgram> ProgramCompiler<P> create(GlProgram.Factory<P> factory, FileResolution vertexContextShader, FileResolution fragmentContextShader, GLSLVersion glslVersion) {
|
||||
return new ProgramCompiler<>(factory, new VertexCompiler(vertexContextShader, glslVersion), new FragmentCompiler(fragmentContextShader, glslVersion));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -49,7 +56,7 @@ public class ProgramCompiler<P extends GlProgram> extends Memoizer<ProgramContex
|
|||
* @param ctx The context of compilation.
|
||||
* @return A compiled GlProgram.
|
||||
*/
|
||||
public P getProgram(ProgramContext ctx) {
|
||||
public P getProgram(Context ctx) {
|
||||
return super.get(ctx);
|
||||
}
|
||||
|
||||
|
@ -61,10 +68,10 @@ public class ProgramCompiler<P extends GlProgram> extends Memoizer<ProgramContex
|
|||
}
|
||||
|
||||
@Override
|
||||
protected P _create(ProgramContext ctx) {
|
||||
return new ProgramAssembler(ctx.instanceShader.getFileLoc())
|
||||
.attachShader(vertexCompiler.get(new VertexCompiler.Context(ctx.vertexType, ctx.instanceShader.getFile(), ctx.vertexMaterialShader.getFile(), ctx.ctx)))
|
||||
.attachShader(fragmentCompiler.get(new FragmentCompiler.Context(ctx.fragmentMaterialShader.getFile(), ctx.alphaDiscard, ctx.fogType, ctx.ctx)))
|
||||
protected P _create(Context ctx) {
|
||||
return new ProgramAssembler(ctx.instanceShader().getFileLoc())
|
||||
.attachShader(vertexCompiler.get(new VertexCompiler.Context(ctx.vertexType(), ctx.instanceShader().getFile(), ctx.vertexMaterialShader().getFile(), ctx.ctx())))
|
||||
.attachShader(fragmentCompiler.get(new FragmentCompiler.Context(ctx.fragmentMaterialShader().getFile(), ctx.alphaDiscard(), ctx.fogType(), ctx.ctx())))
|
||||
.link()
|
||||
.build(this.factory);
|
||||
}
|
||||
|
@ -77,4 +84,19 @@ public class ProgramCompiler<P extends GlProgram> extends Memoizer<ProgramContex
|
|||
public static void invalidateAll(ReloadRenderersEvent ignored) {
|
||||
ALL_COMPILERS.forEach(ProgramCompiler::invalidate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the entire context of a program's usage.
|
||||
*
|
||||
* @param vertexType The vertexType the program should be adapted for.
|
||||
* @param instanceShader The instance shader to use.
|
||||
* @param vertexMaterialShader The vertex material shader to use.
|
||||
* @param fragmentMaterialShader The fragment material shader to use.
|
||||
* @param alphaDiscard Alpha threshold below which pixels are discarded.
|
||||
* @param fogType Which type of fog should be applied.
|
||||
* @param ctx A snapshot of the game state.
|
||||
*/
|
||||
public record Context(VertexType vertexType, FileResolution instanceShader, FileResolution vertexMaterialShader,
|
||||
FileResolution fragmentMaterialShader, float alphaDiscard, CoreShaderInfoMap.CoreShaderInfo.FogType fogType, StateSnapshot ctx) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
package com.jozufozu.flywheel.core.compile;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.core.CoreShaderInfoMap.CoreShaderInfo.FogType;
|
||||
import com.jozufozu.flywheel.core.shader.StateSnapshot;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
|
||||
/**
|
||||
* Represents the entire context of a program's usage.
|
||||
*/
|
||||
public final class ProgramContext {
|
||||
|
||||
public final VertexType vertexType;
|
||||
public final FileResolution instanceShader;
|
||||
public final FileResolution vertexMaterialShader;
|
||||
public final FileResolution fragmentMaterialShader;
|
||||
public final float alphaDiscard;
|
||||
public final FogType fogType;
|
||||
public final StateSnapshot ctx;
|
||||
|
||||
/**
|
||||
* @param vertexType The vertexType the program should be adapted for.
|
||||
* @param instanceShader The instance shader to use.
|
||||
* @param vertexMaterialShader The vertex material shader to use.
|
||||
* @param fragmentMaterialShader The fragment material shader to use.
|
||||
* @param alphaDiscard Alpha threshold below which pixels are discarded.
|
||||
* @param fogType Which type of fog should be applied.
|
||||
* @param ctx A snapshot of the game state.
|
||||
*/
|
||||
public ProgramContext(VertexType vertexType, FileResolution instanceShader, FileResolution vertexMaterialShader, FileResolution fragmentMaterialShader, float alphaDiscard, FogType fogType, StateSnapshot ctx) {
|
||||
this.vertexType = vertexType;
|
||||
this.instanceShader = instanceShader;
|
||||
this.vertexMaterialShader = vertexMaterialShader;
|
||||
this.fragmentMaterialShader = fragmentMaterialShader;
|
||||
this.alphaDiscard = alphaDiscard;
|
||||
this.fogType = fogType;
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
var that = (ProgramContext) o;
|
||||
return vertexType == that.vertexType && instanceShader == that.instanceShader && vertexMaterialShader == that.vertexMaterialShader && fragmentMaterialShader == that.fragmentMaterialShader && ctx.equals(that.ctx) && Float.floatToIntBits(alphaDiscard) == Float.floatToIntBits(that.alphaDiscard) && fogType == that.fogType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(vertexType, instanceShader, vertexMaterialShader, fragmentMaterialShader, alphaDiscard, fogType, ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ProgramContext{" + "vertexType=" + vertexType + ", instanceShader=" + instanceShader + ", vertexMaterialShader=" + vertexMaterialShader + ", fragmentMaterialShader=" + fragmentMaterialShader + ", alphaDiscard=" + alphaDiscard + ", fogType=" + fogType + ", ctx=" + ctx + '}';
|
||||
}
|
||||
}
|
|
@ -1,8 +1,5 @@
|
|||
package com.jozufozu.flywheel.core.compile;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
||||
|
@ -11,132 +8,63 @@ import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
|||
import com.jozufozu.flywheel.core.shader.StateSnapshot;
|
||||
import com.jozufozu.flywheel.core.source.FileIndexImpl;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.jozufozu.flywheel.core.source.ShaderLoadingException;
|
||||
import com.jozufozu.flywheel.core.source.SourceFile;
|
||||
import com.jozufozu.flywheel.core.source.error.ErrorReporter;
|
||||
import com.jozufozu.flywheel.core.source.parse.ShaderFunction;
|
||||
import com.jozufozu.flywheel.core.source.parse.ShaderStruct;
|
||||
import com.jozufozu.flywheel.core.source.parse.StructField;
|
||||
import com.jozufozu.flywheel.core.source.parse.Variable;
|
||||
import com.jozufozu.flywheel.core.source.span.Span;
|
||||
|
||||
/**
|
||||
* Handles compilation and deletion of vertex shaders.
|
||||
*/
|
||||
public class VertexCompiler extends Memoizer<VertexCompiler.Context, GlShader> {
|
||||
private final FileResolution contextShader;
|
||||
private final GLSLVersion glslVersion;
|
||||
|
||||
public VertexCompiler(FileResolution contextShader) {
|
||||
public VertexCompiler(FileResolution contextShader, GLSLVersion glslVersion) {
|
||||
this.contextShader = contextShader;
|
||||
this.glslVersion = glslVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GlShader _create(Context key) {
|
||||
StringBuilder finalSource = new StringBuilder();
|
||||
|
||||
finalSource.append(CompileUtil.generateHeader(GLSLVersion.V330, ShaderType.VERTEX));
|
||||
finalSource.append(CompileUtil.generateHeader(glslVersion, ShaderType.VERTEX));
|
||||
|
||||
key.ctx.getShaderConstants().writeInto(finalSource);
|
||||
var shaderConstants = key.ctx.getShaderConstants();
|
||||
shaderConstants.writeInto(finalSource);
|
||||
finalSource.append('\n');
|
||||
|
||||
FileIndexImpl index = new FileIndexImpl();
|
||||
var index = new FileIndexImpl();
|
||||
|
||||
//
|
||||
|
||||
SourceFile layoutShader = key.vertexType.getLayoutShader().getFile();
|
||||
|
||||
Optional<ShaderFunction> maybeLayoutVertex = layoutShader.findFunction("flw_layoutVertex");
|
||||
|
||||
if (maybeLayoutVertex.isEmpty()) {
|
||||
ErrorReporter.generateMissingFunction(layoutShader, "flw_layoutVertex", "\"flw_layoutVertex\" function not defined");
|
||||
throw new ShaderLoadingException();
|
||||
}
|
||||
|
||||
ShaderFunction layoutVertex = maybeLayoutVertex.get();
|
||||
ImmutableList<Variable> params = layoutVertex.getParameters();
|
||||
|
||||
if (params.size() != 0) {
|
||||
ErrorReporter.generateSpanError(layoutVertex.getArgs(), "\"flw_layoutVertex\" function must not have any arguments");
|
||||
throw new ShaderLoadingException();
|
||||
}
|
||||
// LAYOUT
|
||||
|
||||
var layoutShader = key.vertexType.getLayoutShader().getFile();
|
||||
layoutShader.generateFinalSource(index, finalSource);
|
||||
|
||||
//
|
||||
|
||||
SourceFile instanceShader = key.instanceShader;
|
||||
|
||||
Optional<ShaderFunction> maybeInstanceVertex = instanceShader.findFunction("flw_instanceVertex");
|
||||
|
||||
if (maybeInstanceVertex.isEmpty()) {
|
||||
ErrorReporter.generateMissingFunction(instanceShader, "flw_instanceVertex", "\"flw_instanceVertex\" function not defined");
|
||||
throw new ShaderLoadingException();
|
||||
}
|
||||
|
||||
ShaderFunction instanceVertex = maybeInstanceVertex.get();
|
||||
params = instanceVertex.getParameters();
|
||||
|
||||
if (params.size() != 1) {
|
||||
ErrorReporter.generateSpanError(instanceVertex.getArgs(), "\"flw_instanceVertex\" function must have exactly 1 argument");
|
||||
throw new ShaderLoadingException();
|
||||
}
|
||||
|
||||
Span instanceName = params.get(0).type;
|
||||
Optional<ShaderStruct> maybeInstance = instanceShader.findStruct(instanceName);
|
||||
|
||||
if (maybeInstance.isEmpty()) {
|
||||
ErrorReporter.generateMissingStruct(instanceShader, instanceName, "instance struct not defined");
|
||||
throw new ShaderLoadingException();
|
||||
}
|
||||
|
||||
ShaderStruct instance = maybeInstance.get();
|
||||
// INSTANCE
|
||||
|
||||
var instanceShader = key.instanceShader;
|
||||
instanceShader.generateFinalSource(index, finalSource);
|
||||
|
||||
//
|
||||
|
||||
SourceFile materialShader = key.materialShader;
|
||||
|
||||
Optional<ShaderFunction> maybeMaterialVertex = materialShader.findFunction("flw_materialVertex");
|
||||
|
||||
if (maybeMaterialVertex.isEmpty()) {
|
||||
ErrorReporter.generateMissingFunction(materialShader, "flw_materialVertex", "\"flw_materialVertex\" function not defined");
|
||||
throw new ShaderLoadingException();
|
||||
}
|
||||
|
||||
ShaderFunction materialVertex = maybeMaterialVertex.get();
|
||||
params = materialVertex.getParameters();
|
||||
|
||||
if (params.size() != 0) {
|
||||
ErrorReporter.generateSpanError(materialVertex.getArgs(), "\"flw_materialVertex\" function must not have any arguments");
|
||||
throw new ShaderLoadingException();
|
||||
}
|
||||
// MATERIAL
|
||||
|
||||
var materialShader = key.materialShader;
|
||||
materialShader.generateFinalSource(index, finalSource);
|
||||
|
||||
//
|
||||
|
||||
SourceFile contextShaderSource = contextShader.getFile();
|
||||
|
||||
Optional<ShaderFunction> maybeContextVertex = contextShaderSource.findFunction("flw_contextVertex");
|
||||
|
||||
if (maybeContextVertex.isEmpty()) {
|
||||
ErrorReporter.generateMissingFunction(contextShaderSource, "flw_contextVertex", "\"flw_contextVertex\" function not defined");
|
||||
throw new ShaderLoadingException();
|
||||
}
|
||||
|
||||
ShaderFunction contextVertex = maybeContextVertex.get();
|
||||
params = contextVertex.getParameters();
|
||||
|
||||
if (params.size() != 0) {
|
||||
ErrorReporter.generateSpanError(contextVertex.getArgs(), "\"flw_contextVertex\" function must not have any arguments");
|
||||
throw new ShaderLoadingException();
|
||||
}
|
||||
// CONTEXT
|
||||
|
||||
var contextShaderSource = contextShader.getFile();
|
||||
contextShaderSource.generateFinalSource(index, finalSource);
|
||||
|
||||
//
|
||||
// MAIN
|
||||
|
||||
finalSource.append(generateFooter(key.vertexType, instance));
|
||||
var instanceStruct = instanceShader.findFunction("flw_instanceVertex")
|
||||
.flatMap(f -> f.getParameterType(0)
|
||||
.findStruct())
|
||||
.orElseThrow();
|
||||
finalSource.append(generateFooter(key.vertexType, instanceStruct));
|
||||
|
||||
return new GlShader(instanceShader.name, ShaderType.VERTEX, finalSource.toString());
|
||||
return new GlShader(finalSource.toString(), ShaderType.VERTEX, ImmutableList.of(layoutShader.name, instanceShader.name, materialShader.name, contextShaderSource.name), shaderConstants);
|
||||
}
|
||||
|
||||
protected String generateFooter(VertexType vertexType, ShaderStruct instance) {
|
||||
|
@ -203,45 +131,12 @@ public class VertexCompiler extends Memoizer<VertexCompiler.Context, GlShader> {
|
|||
value.delete();
|
||||
}
|
||||
|
||||
public static class Context {
|
||||
/**
|
||||
* The vertex type to use.
|
||||
*/
|
||||
private final VertexType vertexType;
|
||||
|
||||
/**
|
||||
* The instance shader source.
|
||||
*/
|
||||
private final SourceFile instanceShader;
|
||||
|
||||
/**
|
||||
* The vertex material shader source.
|
||||
*/
|
||||
private final SourceFile materialShader;
|
||||
|
||||
/**
|
||||
* The shader constants to apply.
|
||||
*/
|
||||
private final StateSnapshot ctx;
|
||||
|
||||
public Context(VertexType vertexType, SourceFile instanceShader, SourceFile materialShader, StateSnapshot ctx) {
|
||||
this.vertexType = vertexType;
|
||||
this.instanceShader = instanceShader;
|
||||
this.materialShader = materialShader;
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
var that = (Context) o;
|
||||
return vertexType == that.vertexType && instanceShader == that.instanceShader && materialShader == that.materialShader && ctx.equals(that.ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(vertexType, instanceShader, materialShader, ctx);
|
||||
}
|
||||
/**
|
||||
* @param vertexType The vertex type to use.
|
||||
* @param instanceShader The instance shader source.
|
||||
* @param materialShader The vertex material shader source.
|
||||
* @param ctx The shader constants to apply.
|
||||
*/
|
||||
public record Context(VertexType vertexType, SourceFile instanceShader, SourceFile materialShader, StateSnapshot ctx) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,7 @@ package com.jozufozu.flywheel.core.material;
|
|||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.jozufozu.flywheel.core.source.Resolver;
|
||||
import com.jozufozu.flywheel.event.GatherContextEvent;
|
||||
import com.jozufozu.flywheel.core.source.SourceChecks;
|
||||
import com.jozufozu.flywheel.util.ResourceUtil;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
@ -13,10 +12,16 @@ public class MaterialShaders {
|
|||
public static FileResolution DEFAULT_FRAGMENT;
|
||||
public static FileResolution SHADED_VERTEX;
|
||||
|
||||
public static void flwInit(GatherContextEvent event) {
|
||||
DEFAULT_VERTEX = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.DEFAULT, ".vert"));
|
||||
DEFAULT_FRAGMENT = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.DEFAULT, ".frag"));
|
||||
SHADED_VERTEX = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.SHADED, ".vert"));
|
||||
public static void init() {
|
||||
var checkVert = SourceChecks.checkFunctionArity("flw_materialVertex", 0);
|
||||
var checkFrag = SourceChecks.checkFunctionArity("flw_materialFragment", 0);
|
||||
|
||||
DEFAULT_VERTEX = FileResolution.get(ResourceUtil.subPath(Names.DEFAULT, ".vert"))
|
||||
.validateWith(checkVert);
|
||||
DEFAULT_FRAGMENT = FileResolution.get(ResourceUtil.subPath(Names.DEFAULT, ".frag"))
|
||||
.validateWith(checkFrag);
|
||||
SHADED_VERTEX = FileResolution.get(ResourceUtil.subPath(Names.SHADED, ".vert"))
|
||||
.validateWith(checkVert);
|
||||
}
|
||||
|
||||
public static class Names {
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.jozufozu.flywheel.core.shader;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A class for manipulating a list of {@code #define} directives.
|
||||
|
@ -52,4 +53,17 @@ public class ShaderConstants {
|
|||
acc.append('\n');
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
ShaderConstants that = (ShaderConstants) o;
|
||||
return Objects.equals(definitions, that.definitions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(definitions);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ public class FileIndexImpl implements FileIndex {
|
|||
|
||||
@Override
|
||||
public boolean exists(SourceFile sourceFile) {
|
||||
return files.indexOf(sourceFile) != -1;
|
||||
return files.contains(sourceFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -68,10 +68,7 @@ public class FileIndexImpl implements FileIndex {
|
|||
@Nullable
|
||||
private ErrorBuilder parseCompilerError(String line) {
|
||||
try {
|
||||
ErrorBuilder error = ErrorBuilder.fromLogLine(this, line);
|
||||
if (error != null) {
|
||||
return error;
|
||||
}
|
||||
return ErrorBuilder.fromLogLine(this, line);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
package com.jozufozu.flywheel.core.source;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.core.source.error.ErrorBuilder;
|
||||
import com.jozufozu.flywheel.core.source.error.ErrorReporter;
|
||||
import com.jozufozu.flywheel.core.source.span.Span;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
@ -21,17 +23,73 @@ import net.minecraft.resources.ResourceLocation;
|
|||
*/
|
||||
public class FileResolution {
|
||||
|
||||
private static final Map<ResourceLocation, FileResolution> ALL = new HashMap<>();
|
||||
private static boolean tooLate = false;
|
||||
|
||||
/**
|
||||
* Extra info about where this resolution is required. Includes ProgramSpecs and shader Spans.
|
||||
* Extra info about where this resolution is required. Includes shader Spans.
|
||||
*/
|
||||
private final List<Consumer<ErrorBuilder>> extraCrashInfoProviders = new ArrayList<>();
|
||||
private final List<Span> neededAt = new ArrayList<>();
|
||||
private final List<BiConsumer<ErrorReporter, SourceFile>> checks = new ArrayList<>();
|
||||
|
||||
private final ResourceLocation fileLoc;
|
||||
|
||||
private SourceFile file;
|
||||
|
||||
FileResolution(ResourceLocation fileLoc) {
|
||||
this.fileLoc = fileLoc;
|
||||
}
|
||||
|
||||
public static FileResolution get(ResourceLocation file) {
|
||||
if (!tooLate) {
|
||||
return ALL.computeIfAbsent(file, FileResolution::new);
|
||||
} else {
|
||||
// Lock the map after resolution has run.
|
||||
FileResolution fileResolution = ALL.get(file);
|
||||
|
||||
// ...so crash immediately if the file isn't found.
|
||||
if (fileResolution == null) {
|
||||
throw new ShaderLoadingException("could not find source for file: " + file);
|
||||
}
|
||||
|
||||
return fileResolution;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try and resolve all referenced source files, printing errors if any aren't found.
|
||||
*/
|
||||
public static void run(ErrorReporter errorReporter, SourceFinder sources) {
|
||||
for (FileResolution resolution : ALL.values()) {
|
||||
resolution.resolveAndCheck(errorReporter, sources);
|
||||
}
|
||||
|
||||
tooLate = true;
|
||||
}
|
||||
|
||||
private void resolveAndCheck(ErrorReporter errorReporter, SourceFinder sources) {
|
||||
file = sources.findSource(fileLoc);
|
||||
|
||||
if (file == null) {
|
||||
ErrorBuilder builder = errorReporter.error(String.format("could not find source for file %s", fileLoc));
|
||||
for (Span location : neededAt) {
|
||||
builder.pointAtFile(location.getSourceFile())
|
||||
.pointAt(location, 1);
|
||||
}
|
||||
} else {
|
||||
runChecks(errorReporter);
|
||||
}
|
||||
|
||||
// Let the GC do its thing
|
||||
neededAt.clear();
|
||||
}
|
||||
|
||||
private void runChecks(ErrorReporter errorReporter) {
|
||||
for (var check : checks) {
|
||||
check.accept(errorReporter, file);
|
||||
}
|
||||
}
|
||||
|
||||
public ResourceLocation getFileLoc() {
|
||||
return fileLoc;
|
||||
}
|
||||
|
@ -53,45 +111,13 @@ public class FileResolution {
|
|||
* @param span A span where this file is referenced.
|
||||
*/
|
||||
public FileResolution addSpan(Span span) {
|
||||
extraCrashInfoProviders.add(builder -> builder.pointAtFile(span.getSourceFile())
|
||||
.pointAt(span, 1));
|
||||
neededAt.add(span);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void addSpec(ResourceLocation name) {
|
||||
extraCrashInfoProviders.add(builder -> builder.extra("needed by spec: " + name + ".json"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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>
|
||||
*
|
||||
* @return True if this file is resolved.
|
||||
*/
|
||||
boolean resolve(SourceFinder sources) {
|
||||
file = sources.findSource(fileLoc);
|
||||
|
||||
if (file == null) {
|
||||
ErrorBuilder builder = ErrorBuilder.error(String.format("could not find source for file %s", fileLoc));
|
||||
for (Consumer<ErrorBuilder> consumer : extraCrashInfoProviders) {
|
||||
consumer.accept(builder);
|
||||
}
|
||||
Backend.LOGGER.error(builder.build());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Let the GC do its thing
|
||||
extraCrashInfoProviders.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
void invalidate() {
|
||||
extraCrashInfoProviders.clear();
|
||||
file = null;
|
||||
public FileResolution validateWith(BiConsumer<ErrorReporter, SourceFile> check) {
|
||||
checks.add(check);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
package com.jozufozu.flywheel.core.source;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
/**
|
||||
* Manages deferred file resolution.
|
||||
*
|
||||
* <p>
|
||||
* Interns all file names in shader sources and program specs, deduplicating the final lookups and allowing for more
|
||||
* dev-friendly error reporting.
|
||||
* </p>
|
||||
*
|
||||
* @see FileResolution
|
||||
*/
|
||||
public class Resolver {
|
||||
|
||||
public static final Resolver INSTANCE = new Resolver();
|
||||
|
||||
private final Map<ResourceLocation, FileResolution> resolutions = new HashMap<>();
|
||||
private boolean hasRun = false;
|
||||
|
||||
public FileResolution get(ResourceLocation file) {
|
||||
if (!hasRun) {
|
||||
return resolutions.computeIfAbsent(file, FileResolution::new);
|
||||
} else {
|
||||
// Lock the map after resolution has run.
|
||||
FileResolution fileResolution = resolutions.get(file);
|
||||
|
||||
// ...so crash immediately if the file isn't found.
|
||||
if (fileResolution == null) {
|
||||
throw new RuntimeException("could not find source for file: " + file);
|
||||
}
|
||||
|
||||
return fileResolution;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try and resolve all referenced source files, printing errors if any aren't found.
|
||||
*/
|
||||
public void run(SourceFinder sources) {
|
||||
boolean needsCrash = false;
|
||||
for (FileResolution resolution : resolutions.values()) {
|
||||
if (!resolution.resolve(sources)) {
|
||||
needsCrash = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (needsCrash) {
|
||||
throw new ShaderLoadingException("Failed to resolve all source files, see log for details");
|
||||
}
|
||||
|
||||
hasRun = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates all FileResolutions.
|
||||
*
|
||||
* <p>
|
||||
* Called on resource reload.
|
||||
* </p>
|
||||
*/
|
||||
public void invalidate() {
|
||||
resolutions.values().forEach(FileResolution::invalidate);
|
||||
hasRun = false;
|
||||
}
|
||||
}
|
|
@ -2,9 +2,6 @@ package com.jozufozu.flywheel.core.source;
|
|||
|
||||
public class ShaderLoadingException extends RuntimeException {
|
||||
|
||||
public ShaderLoadingException() {
|
||||
}
|
||||
|
||||
public ShaderLoadingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import java.util.Map;
|
|||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.jozufozu.flywheel.core.source.error.ErrorReporter;
|
||||
import com.jozufozu.flywheel.util.ResourceUtil;
|
||||
import com.jozufozu.flywheel.util.StringUtil;
|
||||
|
||||
|
@ -20,14 +21,14 @@ import net.minecraft.server.packs.resources.ResourceManager;
|
|||
* The main object for loading and parsing source files.
|
||||
*/
|
||||
public class ShaderSources implements SourceFinder {
|
||||
public static final String SHADER_DIR = "flywheel/shaders/";
|
||||
public static final String SHADER_DIR = "flywheel/";
|
||||
public static final ArrayList<String> EXTENSIONS = Lists.newArrayList(".vert", ".vsh", ".frag", ".fsh", ".glsl");
|
||||
|
||||
private final Map<ResourceLocation, SourceFile> shaderSources = new HashMap<>();
|
||||
|
||||
public final Index index;
|
||||
|
||||
public ShaderSources(ResourceManager manager) {
|
||||
public ShaderSources(ErrorReporter errorReporter, ResourceManager manager) {
|
||||
Collection<ResourceLocation> allShaders = manager.listResources(SHADER_DIR, s -> {
|
||||
for (String ext : EXTENSIONS) {
|
||||
if (s.endsWith(ext)) return true;
|
||||
|
@ -41,7 +42,7 @@ public class ShaderSources implements SourceFinder {
|
|||
|
||||
ResourceLocation name = ResourceUtil.removePrefixUnchecked(location, SHADER_DIR);
|
||||
|
||||
shaderSources.put(name, new SourceFile(this, name, source));
|
||||
shaderSources.put(name, new SourceFile(errorReporter, this, name, source));
|
||||
} catch (IOException e) {
|
||||
//
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
package com.jozufozu.flywheel.core.source;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.core.source.error.ErrorReporter;
|
||||
import com.jozufozu.flywheel.core.source.parse.ShaderFunction;
|
||||
import com.jozufozu.flywheel.core.source.parse.Variable;
|
||||
|
||||
public class SourceChecks {
|
||||
|
||||
public static BiConsumer<ErrorReporter, SourceFile> checkFunctionArity(String name, int arity) {
|
||||
return (errorReporter, file) -> checkFunctionArity(errorReporter, file, name, arity);
|
||||
}
|
||||
|
||||
public static BiConsumer<ErrorReporter, SourceFile> checkFunctionParameterTypeExists(String name, int arity, int param) {
|
||||
return (errorReporter, file) -> {
|
||||
var func = checkFunctionArity(errorReporter, file, name, arity);
|
||||
|
||||
if (func == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var maybeStruct = func.getParameterType(param)
|
||||
.findStruct();
|
||||
|
||||
if (maybeStruct.isEmpty()) {
|
||||
errorReporter.generateMissingStruct(file, func.getParameterType(param), "struct not defined");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code null} if the function doesn't exist, or if the function has the wrong arity.
|
||||
*/
|
||||
@Nullable
|
||||
private static ShaderFunction checkFunctionArity(ErrorReporter errorReporter, SourceFile file, String name, int arity) {
|
||||
Optional<ShaderFunction> maybeFunc = file.findFunction(name);
|
||||
|
||||
if (maybeFunc.isEmpty()) {
|
||||
errorReporter.generateMissingFunction(file, name, "\"" + name + "\" function not defined");
|
||||
return null;
|
||||
}
|
||||
|
||||
ShaderFunction func = maybeFunc.get();
|
||||
ImmutableList<Variable> params = func.getParameters();
|
||||
if (params.size() != arity) {
|
||||
errorReporter.generateFunctionArgumentCountError(name, arity, func.getArgs());
|
||||
return null;
|
||||
}
|
||||
|
||||
return func;
|
||||
}
|
||||
}
|
|
@ -11,9 +11,11 @@ import java.util.regex.Matcher;
|
|||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.jozufozu.flywheel.core.source.error.ErrorReporter;
|
||||
import com.jozufozu.flywheel.core.source.parse.Import;
|
||||
import com.jozufozu.flywheel.core.source.parse.ShaderFunction;
|
||||
import com.jozufozu.flywheel.core.source.parse.ShaderStruct;
|
||||
import com.jozufozu.flywheel.core.source.parse.Variable;
|
||||
import com.jozufozu.flywheel.core.source.span.ErrorSpan;
|
||||
import com.jozufozu.flywheel.core.source.span.Span;
|
||||
import com.jozufozu.flywheel.core.source.span.StringSpan;
|
||||
|
@ -55,7 +57,7 @@ public class SourceFile {
|
|||
*/
|
||||
public final ImmutableList<Import> imports;
|
||||
|
||||
public SourceFile(ShaderSources parent, ResourceLocation name, String source) {
|
||||
public SourceFile(ErrorReporter errorReporter, ShaderSources parent, ResourceLocation name, String source) {
|
||||
this.parent = parent;
|
||||
this.name = name;
|
||||
this.source = source;
|
||||
|
@ -64,7 +66,7 @@ public class SourceFile {
|
|||
|
||||
List<Span> elisions = new ArrayList<>();
|
||||
|
||||
this.imports = parseImports(elisions);
|
||||
this.imports = parseImports(errorReporter, elisions);
|
||||
this.functions = parseFunctions();
|
||||
this.structs = parseStructs();
|
||||
|
||||
|
@ -233,7 +235,7 @@ public class SourceFile {
|
|||
* Records the contents of the directive into an {@link Import} object, and marks the directive for elision.
|
||||
* @param elisions
|
||||
*/
|
||||
private ImmutableList<Import> parseImports(List<Span> elisions) {
|
||||
private ImmutableList<Import> parseImports(ErrorReporter errorReporter, List<Span> elisions) {
|
||||
Matcher uses = Import.PATTERN.matcher(source);
|
||||
|
||||
Set<String> importedFiles = new HashSet<>();
|
||||
|
@ -245,9 +247,9 @@ public class SourceFile {
|
|||
|
||||
String fileName = file.get();
|
||||
if (importedFiles.add(fileName)) {
|
||||
Import import1 = Import.create(Resolver.INSTANCE, use, file);
|
||||
if (import1 != null) {
|
||||
imports.add(import1);
|
||||
var checked = Import.create(errorReporter, use, file);
|
||||
if (checked != null) {
|
||||
imports.add(checked);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -280,4 +282,15 @@ public class SourceFile {
|
|||
public String toString() {
|
||||
return name.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
// SourceFiles are only equal by reference.
|
||||
return this == o;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return System.identityHashCode(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.jozufozu.flywheel.core.source.error;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
|
@ -13,58 +14,78 @@ import com.jozufozu.flywheel.util.FlwUtil;
|
|||
|
||||
public class ErrorReporter {
|
||||
|
||||
public static void generateSpanError(Span span, String message) {
|
||||
SourceFile file = span.getSourceFile();
|
||||
private final List<ErrorBuilder> reportedErrors = new ArrayList<>();
|
||||
|
||||
String error = ErrorBuilder.error(message)
|
||||
.pointAtFile(file)
|
||||
.pointAt(span, 2)
|
||||
.build();
|
||||
|
||||
Backend.LOGGER.error(error);
|
||||
}
|
||||
|
||||
public static void generateFileError(SourceFile file, String message) {
|
||||
String error = ErrorBuilder.error(message)
|
||||
.pointAtFile(file)
|
||||
.build();
|
||||
|
||||
Backend.LOGGER.error(error);
|
||||
}
|
||||
|
||||
public static void generateMissingStruct(SourceFile file, Span vertexName, CharSequence msg) {
|
||||
public void generateMissingStruct(SourceFile file, Span vertexName, CharSequence msg) {
|
||||
generateMissingStruct(file, vertexName, msg, "");
|
||||
}
|
||||
|
||||
public static void generateMissingStruct(SourceFile file, Span vertexName, CharSequence msg, CharSequence hint) {
|
||||
public void generateMissingStruct(SourceFile file, Span vertexName, CharSequence msg, CharSequence hint) {
|
||||
Optional<Span> span = file.parent.index.getStructDefinitionsMatching(vertexName)
|
||||
.stream()
|
||||
.findFirst()
|
||||
.map(ShaderStruct::getName);
|
||||
|
||||
ErrorBuilder error = ErrorBuilder.error(msg)
|
||||
this.error(msg)
|
||||
.pointAtFile(file)
|
||||
.pointAt(vertexName, 1)
|
||||
.hintIncludeFor(span.orElse(null), hint);
|
||||
|
||||
Backend.LOGGER.error(error.build());
|
||||
}
|
||||
|
||||
public static void generateMissingFunction(SourceFile file, CharSequence functionName, CharSequence msg) {
|
||||
public void generateMissingFunction(SourceFile file, CharSequence functionName, CharSequence msg) {
|
||||
generateMissingFunction(file, functionName, msg, "");
|
||||
}
|
||||
|
||||
public static void generateMissingFunction(SourceFile file, CharSequence functionName, CharSequence msg, CharSequence hint) {
|
||||
public void generateMissingFunction(SourceFile file, CharSequence functionName, CharSequence msg, CharSequence hint) {
|
||||
Optional<Span> span = file.parent.index.getFunctionDefinitionsMatching(functionName)
|
||||
.stream()
|
||||
.findFirst()
|
||||
.map(ShaderFunction::getName);
|
||||
|
||||
ErrorBuilder error = ErrorBuilder.error(msg)
|
||||
this.error(msg)
|
||||
.pointAtFile(file)
|
||||
.hintIncludeFor(span.orElse(null), hint);
|
||||
}
|
||||
|
||||
Backend.LOGGER.error(error.build());
|
||||
public ErrorBuilder generateFunctionArgumentCountError(String name, int requiredArguments, Span span) {
|
||||
var msg = '"' + name + "\" function must ";
|
||||
|
||||
if (requiredArguments == 0) {
|
||||
msg += "not have any arguments";
|
||||
} else {
|
||||
msg += "have exactly " + requiredArguments + " argument" + (requiredArguments == 1 ? "" : "s");
|
||||
}
|
||||
|
||||
return generateSpanError(span, msg);
|
||||
}
|
||||
|
||||
public ErrorBuilder generateSpanError(Span span, String message) {
|
||||
SourceFile file = span.getSourceFile();
|
||||
|
||||
return error(message)
|
||||
.pointAtFile(file)
|
||||
.pointAt(span, 2);
|
||||
}
|
||||
|
||||
public ErrorBuilder generateFileError(SourceFile file, String message) {
|
||||
return error(message)
|
||||
.pointAtFile(file);
|
||||
}
|
||||
|
||||
public ErrorBuilder error(CharSequence msg) {
|
||||
var out = ErrorBuilder.error(msg);
|
||||
reportedErrors.add(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
public boolean hasErrored() {
|
||||
return !reportedErrors.isEmpty();
|
||||
}
|
||||
|
||||
public void dump() {
|
||||
for (var error : reportedErrors) {
|
||||
Backend.LOGGER.error(error.build());
|
||||
}
|
||||
}
|
||||
|
||||
public static void printLines(CharSequence source) {
|
||||
|
|
|
@ -6,7 +6,6 @@ import java.util.regex.Pattern;
|
|||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.jozufozu.flywheel.core.source.Resolver;
|
||||
import com.jozufozu.flywheel.core.source.SourceFile;
|
||||
import com.jozufozu.flywheel.core.source.error.ErrorReporter;
|
||||
import com.jozufozu.flywheel.core.source.span.Span;
|
||||
|
@ -26,16 +25,16 @@ public class Import extends AbstractShaderElement {
|
|||
}
|
||||
|
||||
@Nullable
|
||||
public static Import create(Resolver resolver, Span self, Span file) {
|
||||
public static Import create(ErrorReporter errorReporter, Span self, Span file) {
|
||||
ResourceLocation fileLocation;
|
||||
try {
|
||||
fileLocation = new ResourceLocation(file.get());
|
||||
} catch (ResourceLocationException e) {
|
||||
ErrorReporter.generateSpanError(file, "malformed source location");
|
||||
errorReporter.generateSpanError(file, "malformed source location");
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Import(self, resolver.get(fileLocation), file);
|
||||
return new Import(self, FileResolution.get(fileLocation), file);
|
||||
}
|
||||
|
||||
public FileResolution getResolution() {
|
||||
|
|
|
@ -52,6 +52,10 @@ public class ShaderFunction extends AbstractShaderElement {
|
|||
return name + "(" + String.join(", ", args) + ")";
|
||||
}
|
||||
|
||||
public Span getParameterType(int index) {
|
||||
return parameters.get(index).type;
|
||||
}
|
||||
|
||||
public ImmutableList<Variable> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
package com.jozufozu.flywheel.core.source.span;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import com.jozufozu.flywheel.core.source.SourceFile;
|
||||
import com.jozufozu.flywheel.core.source.parse.ShaderFunction;
|
||||
import com.jozufozu.flywheel.core.source.parse.ShaderStruct;
|
||||
|
||||
/**
|
||||
* A segment of code in a {@link SourceFile}.
|
||||
|
@ -121,4 +124,18 @@ public abstract class Span implements CharSequence {
|
|||
public static Span fromMatcher(Span superSpan, Matcher m) {
|
||||
return superSpan.subSpan(m.start(), m.end());
|
||||
}
|
||||
|
||||
public Optional<ShaderStruct> findStruct() {
|
||||
if (isErr()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return in.findStruct(this);
|
||||
}
|
||||
|
||||
public Optional<ShaderFunction> findFunction() {
|
||||
if (isErr()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return in.findFunction(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,7 @@ package com.jozufozu.flywheel.core.structs;
|
|||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.jozufozu.flywheel.core.source.Resolver;
|
||||
import com.jozufozu.flywheel.event.GatherContextEvent;
|
||||
import com.jozufozu.flywheel.core.source.SourceChecks;
|
||||
import com.jozufozu.flywheel.util.ResourceUtil;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
@ -12,9 +11,13 @@ public class InstanceShaders {
|
|||
public static FileResolution MODEL;
|
||||
public static FileResolution ORIENTED;
|
||||
|
||||
public static void flwInit(GatherContextEvent event) {
|
||||
MODEL = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.MODEL, ".vert"));
|
||||
ORIENTED = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.ORIENTED, ".vert"));
|
||||
public static void init() {
|
||||
var check = SourceChecks.checkFunctionParameterTypeExists("flw_instanceVertex", 1, 0);
|
||||
|
||||
MODEL = FileResolution.get(ResourceUtil.subPath(Names.MODEL, ".vert"))
|
||||
.validateWith(check);
|
||||
ORIENTED = FileResolution.get(ResourceUtil.subPath(Names.ORIENTED, ".vert"))
|
||||
.validateWith(check);
|
||||
}
|
||||
|
||||
public static class Names {
|
||||
|
|
|
@ -2,8 +2,7 @@ package com.jozufozu.flywheel.core.vertex;
|
|||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.jozufozu.flywheel.core.source.Resolver;
|
||||
import com.jozufozu.flywheel.event.GatherContextEvent;
|
||||
import com.jozufozu.flywheel.core.source.SourceChecks;
|
||||
import com.jozufozu.flywheel.util.ResourceUtil;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
@ -12,9 +11,14 @@ public class LayoutShaders {
|
|||
public static FileResolution BLOCK;
|
||||
public static FileResolution POS_TEX_NORMAL;
|
||||
|
||||
public static void flwInit(GatherContextEvent event) {
|
||||
BLOCK = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.BLOCK, ".vert"));
|
||||
POS_TEX_NORMAL = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.POS_TEX_NORMAL, ".vert"));
|
||||
public static void init() {
|
||||
var check = SourceChecks.checkFunctionArity("flw_layoutVertex", 0);
|
||||
|
||||
BLOCK = FileResolution.get(ResourceUtil.subPath(Names.BLOCK, ".vert"))
|
||||
.validateWith(check);
|
||||
|
||||
POS_TEX_NORMAL = FileResolution.get(ResourceUtil.subPath(Names.POS_TEX_NORMAL, ".vert"))
|
||||
.validateWith(check);
|
||||
}
|
||||
|
||||
public static class Names {
|
||||
|
|
|
@ -6,6 +6,7 @@ import com.jozufozu.flywheel.light.LightUpdater;
|
|||
import com.jozufozu.flywheel.util.WorldAttached;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.client.event.RenderGameOverlayEvent;
|
||||
import net.minecraftforge.event.TickEvent;
|
||||
|
@ -32,8 +33,10 @@ public class ForgeEvents {
|
|||
|
||||
@SubscribeEvent
|
||||
public static void tickLight(TickEvent.ClientTickEvent e) {
|
||||
if (e.phase == TickEvent.Phase.END && Backend.isGameActive())
|
||||
LightUpdater.get(Minecraft.getInstance().level).tick();
|
||||
if (e.phase == TickEvent.Phase.END && Backend.isGameActive()) {
|
||||
LightUpdater.get(Minecraft.getInstance().level)
|
||||
.tick();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
package com.jozufozu.flywheel.event;
|
||||
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
import net.minecraftforge.fml.event.IModBusEvent;
|
||||
|
||||
public class GatherContextEvent extends Event implements IModBusEvent {
|
||||
|
||||
private final boolean firstLoad;
|
||||
|
||||
public GatherContextEvent(boolean firstLoad) {
|
||||
this.firstLoad = firstLoad;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true iff it is the first time the event is fired.
|
||||
*/
|
||||
public boolean isFirstLoad() {
|
||||
return firstLoad;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue