mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-02-05 01:34:58 +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.<ReloadRenderersEvent>addListener(ProgramCompiler::invalidateAll);
|
||||||
forgeEventBus.addListener(Models::onReload);
|
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::onModelRegistry);
|
||||||
modEventBus.addListener(PartialModel::onModelBake);
|
modEventBus.addListener(PartialModel::onModelBake);
|
||||||
modEventBus.addListener(StitchedSprite::onTextureStitchPre);
|
modEventBus.addListener(StitchedSprite::onTextureStitchPre);
|
||||||
modEventBus.addListener(StitchedSprite::onTextureStitchPost);
|
modEventBus.addListener(StitchedSprite::onTextureStitchPost);
|
||||||
|
|
||||||
|
LayoutShaders.init();
|
||||||
|
InstanceShaders.init();
|
||||||
|
Contexts.init();
|
||||||
|
MaterialShaders.init();
|
||||||
|
|
||||||
VanillaInstances.init();
|
VanillaInstances.init();
|
||||||
|
|
||||||
// https://github.com/Jozufozu/Flywheel/issues/69
|
// https://github.com/Jozufozu/Flywheel/issues/69
|
||||||
|
|
|
@ -1,18 +1,17 @@
|
||||||
package com.jozufozu.flywheel.backend;
|
package com.jozufozu.flywheel.backend;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
|
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.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.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.Minecraft;
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
import net.minecraft.server.packs.resources.ReloadableResourceManager;
|
import net.minecraft.server.packs.resources.ReloadableResourceManager;
|
||||||
import net.minecraft.server.packs.resources.ResourceManager;
|
import net.minecraft.server.packs.resources.ResourceManager;
|
||||||
import net.minecraft.server.packs.resources.ResourceManagerReloadListener;
|
import net.minecraft.server.packs.resources.ResourceManagerReloadListener;
|
||||||
import net.minecraftforge.fml.ModLoader;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The main entity for loading shaders.
|
* The main entity for loading shaders.
|
||||||
|
@ -22,7 +21,6 @@ import net.minecraftforge.fml.ModLoader;
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
public class Loader implements ResourceManagerReloadListener {
|
public class Loader implements ResourceManagerReloadListener {
|
||||||
private boolean firstLoad = true;
|
|
||||||
|
|
||||||
Loader() {
|
Loader() {
|
||||||
// Can be null when running datagenerators due to the unfortunate time we call this
|
// 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) {
|
public void onResourceManagerReload(ResourceManager manager) {
|
||||||
Backend.refresh();
|
Backend.refresh();
|
||||||
|
|
||||||
GameStateRegistry._clear();
|
var errorReporter = new ErrorReporter();
|
||||||
|
ShaderSources sources = new ShaderSources(errorReporter, manager);
|
||||||
|
|
||||||
Resolver.INSTANCE.invalidate();
|
FileResolution.run(errorReporter, sources);
|
||||||
ModLoader.get()
|
|
||||||
.postEvent(new GatherContextEvent(firstLoad));
|
|
||||||
|
|
||||||
ShaderSources sources = new ShaderSources(manager);
|
if (errorReporter.hasErrored()) {
|
||||||
|
errorReporter.dump();
|
||||||
Resolver.INSTANCE.run(sources);
|
throw new ShaderLoadingException("Failed to resolve all source files, see log for details");
|
||||||
|
}
|
||||||
|
|
||||||
Backend.LOGGER.info("Loaded all shader sources.");
|
Backend.LOGGER.info("Loaded all shader sources.");
|
||||||
|
|
||||||
|
@ -58,6 +56,5 @@ public class Loader implements ResourceManagerReloadListener {
|
||||||
CrumblingRenderer.reset();
|
CrumblingRenderer.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
firstLoad = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,16 @@
|
||||||
package com.jozufozu.flywheel.backend.gl;
|
package com.jozufozu.flywheel.backend.gl;
|
||||||
|
|
||||||
public enum GLSLVersion {
|
public enum GLSLVersion {
|
||||||
|
V110(110),
|
||||||
|
V120(120),
|
||||||
|
V130(130),
|
||||||
|
V140(140),
|
||||||
V150(150),
|
V150(150),
|
||||||
V330(330),
|
V330(330),
|
||||||
|
V400(400),
|
||||||
|
V410(410),
|
||||||
|
V420(420),
|
||||||
|
V430(430),
|
||||||
;
|
;
|
||||||
|
|
||||||
public final int version;
|
public final int version;
|
||||||
|
|
|
@ -1,34 +1,37 @@
|
||||||
package com.jozufozu.flywheel.backend.gl.shader;
|
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 org.lwjgl.opengl.GL20;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.gl.GlObject;
|
import com.jozufozu.flywheel.backend.gl.GlObject;
|
||||||
import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
|
import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
|
||||||
|
import com.jozufozu.flywheel.core.shader.ShaderConstants;
|
||||||
import com.jozufozu.flywheel.core.source.ShaderLoadingException;
|
import com.jozufozu.flywheel.core.source.ShaderLoadingException;
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
public class GlShader extends GlObject {
|
public class GlShader extends GlObject {
|
||||||
|
|
||||||
public final ResourceLocation name;
|
|
||||||
public final ShaderType type;
|
public final ShaderType type;
|
||||||
|
private final List<ResourceLocation> parts;
|
||||||
|
private final ShaderConstants constants;
|
||||||
|
|
||||||
public GlShader(ResourceLocation name, ShaderType type, String source) {
|
public GlShader(String source, ShaderType type, List<ResourceLocation> parts, ShaderConstants constants) {
|
||||||
this.name = name;
|
this.parts = parts;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
this.constants = constants;
|
||||||
int handle = GL20.glCreateShader(type.glEnum);
|
int handle = GL20.glCreateShader(type.glEnum);
|
||||||
|
|
||||||
GlCompat.safeShaderSource(handle, source);
|
GlCompat.safeShaderSource(handle, source);
|
||||||
GL20.glCompileShader(handle);
|
GL20.glCompileShader(handle);
|
||||||
|
|
||||||
// File dir = new File(Minecraft.getInstance().gameDirectory, "flywheel_sources");
|
dumpSource(source, type);
|
||||||
// dir.mkdirs();
|
|
||||||
// File file = new File(dir, name.toString().replaceAll("[:/]", "_"));
|
|
||||||
// try (FileWriter writer = new FileWriter(file)) {
|
|
||||||
// writer.write(source);
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// e.printStackTrace();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// String log = GL20.glGetShaderInfoLog(handle);
|
// 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) {
|
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);
|
setHandle(handle);
|
||||||
|
@ -49,4 +52,22 @@ public class GlShader extends GlObject {
|
||||||
GL20.glDeleteShader(handle);
|
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;
|
import org.lwjgl.opengl.GL20;
|
||||||
|
|
||||||
public enum ShaderType {
|
public enum ShaderType {
|
||||||
VERTEX("vertex", "VERTEX_SHADER", GL20.GL_VERTEX_SHADER),
|
VERTEX("vertex", "VERTEX_SHADER", "vert", GL20.GL_VERTEX_SHADER),
|
||||||
FRAGMENT("fragment", "FRAGMENT_SHADER", GL20.GL_FRAGMENT_SHADER),
|
FRAGMENT("fragment", "FRAGMENT_SHADER", "frag", GL20.GL_FRAGMENT_SHADER),
|
||||||
;
|
;
|
||||||
|
|
||||||
public final String name;
|
public final String name;
|
||||||
public final String define;
|
public final String define;
|
||||||
|
public final String extension;
|
||||||
public final int glEnum;
|
public final int glEnum;
|
||||||
|
|
||||||
ShaderType(String name, String define, int glEnum) {
|
ShaderType(String name, String define, String extension, int glEnum) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.define = define;
|
this.define = define;
|
||||||
|
this.extension = extension;
|
||||||
this.glEnum = glEnum;
|
this.glEnum = glEnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDefineStatement() {
|
public String getDefineStatement() {
|
||||||
return "#define " + define + "\n";
|
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.GameStateRegistry;
|
||||||
import com.jozufozu.flywheel.core.RenderContext;
|
import com.jozufozu.flywheel.core.RenderContext;
|
||||||
import com.jozufozu.flywheel.core.compile.ProgramCompiler;
|
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.shader.WorldProgram;
|
||||||
import com.jozufozu.flywheel.core.vertex.Formats;
|
import com.jozufozu.flywheel.core.vertex.Formats;
|
||||||
import com.jozufozu.flywheel.util.Textures;
|
import com.jozufozu.flywheel.util.Textures;
|
||||||
|
@ -155,7 +154,7 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
||||||
alphaDiscard = 0;
|
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.bind();
|
||||||
program.uploadUniforms(camX, camY, camZ, viewProjection, level);
|
program.uploadUniforms(camX, camY, camZ, viewProjection, level);
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package com.jozufozu.flywheel.core;
|
package com.jozufozu.flywheel.core;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.Flywheel;
|
import com.jozufozu.flywheel.Flywheel;
|
||||||
|
import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
||||||
import com.jozufozu.flywheel.core.compile.ProgramCompiler;
|
import com.jozufozu.flywheel.core.compile.ProgramCompiler;
|
||||||
import com.jozufozu.flywheel.core.crumbling.CrumblingProgram;
|
import com.jozufozu.flywheel.core.crumbling.CrumblingProgram;
|
||||||
import com.jozufozu.flywheel.core.shader.NormalDebugStateProvider;
|
import com.jozufozu.flywheel.core.shader.NormalDebugStateProvider;
|
||||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||||
import com.jozufozu.flywheel.core.source.Resolver;
|
import com.jozufozu.flywheel.core.source.SourceChecks;
|
||||||
import com.jozufozu.flywheel.event.GatherContextEvent;
|
|
||||||
import com.jozufozu.flywheel.util.ResourceUtil;
|
import com.jozufozu.flywheel.util.ResourceUtil;
|
||||||
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
@ -17,16 +17,23 @@ public class Contexts {
|
||||||
public static ProgramCompiler<WorldProgram> WORLD;
|
public static ProgramCompiler<WorldProgram> WORLD;
|
||||||
public static ProgramCompiler<CrumblingProgram> CRUMBLING;
|
public static ProgramCompiler<CrumblingProgram> CRUMBLING;
|
||||||
|
|
||||||
public static void flwInit(GatherContextEvent event) {
|
public static void init() {
|
||||||
GameStateRegistry.register(NormalDebugStateProvider.INSTANCE);
|
GameStateRegistry.register(NormalDebugStateProvider.INSTANCE);
|
||||||
|
|
||||||
FileResolution worldVertex = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.WORLD, ".vert"));
|
var checkFrag = SourceChecks.checkFunctionArity("flw_contextFragment", 0);
|
||||||
FileResolution worldFragment = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.WORLD, ".frag"));
|
var checkVert = SourceChecks.checkFunctionArity("flw_contextVertex", 0);
|
||||||
FileResolution crumblingVertex = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.CRUMBLING, ".vert"));
|
|
||||||
FileResolution crumblingFragment = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.CRUMBLING, ".frag"));
|
|
||||||
|
|
||||||
WORLD = ProgramCompiler.create(WorldProgram::new, worldVertex, worldFragment);
|
var worldVertex = FileResolution.get(ResourceUtil.subPath(Names.WORLD, ".vert"))
|
||||||
CRUMBLING = ProgramCompiler.create(CrumblingProgram::new, crumblingVertex, crumblingFragment);
|
.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 {
|
public static class Names {
|
||||||
|
|
|
@ -51,8 +51,4 @@ public class GameStateRegistry {
|
||||||
}
|
}
|
||||||
return shaderConstants;
|
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.Matcher;
|
||||||
import java.util.regex.Pattern;
|
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.GLSLVersion;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
||||||
|
import com.jozufozu.flywheel.core.source.SourceFile;
|
||||||
|
|
||||||
public class CompileUtil {
|
public class CompileUtil {
|
||||||
|
|
||||||
|
@ -45,4 +50,11 @@ public class CompileUtil {
|
||||||
|
|
||||||
return 1;
|
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;
|
package com.jozufozu.flywheel.core.compile;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
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.shader.StateSnapshot;
|
||||||
import com.jozufozu.flywheel.core.source.FileIndexImpl;
|
import com.jozufozu.flywheel.core.source.FileIndexImpl;
|
||||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
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.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> {
|
public class FragmentCompiler extends Memoizer<FragmentCompiler.Context, GlShader> {
|
||||||
private final FileResolution contextShader;
|
private final FileResolution contextShader;
|
||||||
|
private final GLSLVersion glslVersion;
|
||||||
|
|
||||||
public FragmentCompiler(FileResolution contextShader) {
|
public FragmentCompiler(FileResolution contextShader, GLSLVersion glslVersion) {
|
||||||
this.contextShader = contextShader;
|
this.contextShader = contextShader;
|
||||||
|
this.glslVersion = glslVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected GlShader _create(Context key) {
|
protected GlShader _create(Context key) {
|
||||||
StringBuilder finalSource = new StringBuilder();
|
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');
|
finalSource.append('\n');
|
||||||
|
|
||||||
FileIndexImpl index = new FileIndexImpl();
|
FileIndexImpl index = new FileIndexImpl();
|
||||||
|
|
||||||
//
|
// MATERIAL
|
||||||
|
|
||||||
SourceFile materialShader = key.materialShader;
|
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);
|
materialShader.generateFinalSource(index, finalSource);
|
||||||
|
|
||||||
//
|
// CONTEXT
|
||||||
|
|
||||||
SourceFile contextShaderSource = contextShader.getFile();
|
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);
|
contextShaderSource.generateFinalSource(index, finalSource);
|
||||||
|
|
||||||
//
|
// MAIN
|
||||||
|
|
||||||
finalSource.append(generateFooter());
|
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() {
|
protected String generateFooter() {
|
||||||
StringBuilder footer = new StringBuilder();
|
return """
|
||||||
|
|
||||||
footer.append("""
|
|
||||||
void main() {
|
void main() {
|
||||||
flw_materialFragment();
|
flw_materialFragment();
|
||||||
|
|
||||||
flw_contextFragment();
|
flw_contextFragment();
|
||||||
}
|
}
|
||||||
"""
|
""";
|
||||||
);
|
|
||||||
|
|
||||||
return footer.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -107,34 +71,12 @@ public class FragmentCompiler extends Memoizer<FragmentCompiler.Context, GlShade
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the conditions under which a shader is compiled.
|
* 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 {
|
public record Context(SourceFile materialShader, float alphaDiscard, FogType fogType, StateSnapshot ctx) {
|
||||||
/**
|
|
||||||
* 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 ShaderConstants getShaderConstants() {
|
public ShaderConstants getShaderConstants() {
|
||||||
ShaderConstants shaderConstants = ctx.getShaderConstants();
|
ShaderConstants shaderConstants = ctx.getShaderConstants();
|
||||||
|
@ -146,23 +88,5 @@ public class FragmentCompiler extends Memoizer<FragmentCompiler.Context, GlShade
|
||||||
|
|
||||||
return shaderConstants;
|
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;
|
public final int program;
|
||||||
private final ResourceLocation name;
|
private final ResourceLocation name;
|
||||||
|
|
||||||
private final List<GlShader> shaders = new ObjectArrayList<>();
|
|
||||||
|
|
||||||
public ProgramAssembler(ResourceLocation name) {
|
public ProgramAssembler(ResourceLocation name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.program = glCreateProgram();
|
this.program = glCreateProgram();
|
||||||
|
@ -49,13 +47,7 @@ public class ProgramAssembler {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProgramAssembler deleteLinkedShaders() {
|
|
||||||
shaders.forEach(GlShader::delete);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProgramAssembler attachShader(GlShader glShader) {
|
public ProgramAssembler attachShader(GlShader glShader) {
|
||||||
shaders.add(glShader);
|
|
||||||
glAttachShader(this.program, glShader.handle());
|
glAttachShader(this.program, glShader.handle());
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,11 @@ package com.jozufozu.flywheel.core.compile;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
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.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.core.source.FileResolution;
|
||||||
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
|
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
|
* 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.
|
* compiled programs, and will only compile a program if it is not already in the cache.
|
||||||
* </p>
|
* </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<>();
|
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.
|
* @param <P> The type of program to compile.
|
||||||
* @return A program compiler.
|
* @return A program compiler.
|
||||||
*/
|
*/
|
||||||
public static <P extends GlProgram> ProgramCompiler<P> create(GlProgram.Factory<P> factory, FileResolution vertexContextShader, FileResolution 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), new FragmentCompiler(fragmentContextShader));
|
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.
|
* @param ctx The context of compilation.
|
||||||
* @return A compiled GlProgram.
|
* @return A compiled GlProgram.
|
||||||
*/
|
*/
|
||||||
public P getProgram(ProgramContext ctx) {
|
public P getProgram(Context ctx) {
|
||||||
return super.get(ctx);
|
return super.get(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,10 +68,10 @@ public class ProgramCompiler<P extends GlProgram> extends Memoizer<ProgramContex
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected P _create(ProgramContext ctx) {
|
protected P _create(Context ctx) {
|
||||||
return new ProgramAssembler(ctx.instanceShader.getFileLoc())
|
return new ProgramAssembler(ctx.instanceShader().getFileLoc())
|
||||||
.attachShader(vertexCompiler.get(new VertexCompiler.Context(ctx.vertexType, ctx.instanceShader.getFile(), ctx.vertexMaterialShader.getFile(), ctx.ctx)))
|
.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)))
|
.attachShader(fragmentCompiler.get(new FragmentCompiler.Context(ctx.fragmentMaterialShader().getFile(), ctx.alphaDiscard(), ctx.fogType(), ctx.ctx())))
|
||||||
.link()
|
.link()
|
||||||
.build(this.factory);
|
.build(this.factory);
|
||||||
}
|
}
|
||||||
|
@ -77,4 +84,19 @@ public class ProgramCompiler<P extends GlProgram> extends Memoizer<ProgramContex
|
||||||
public static void invalidateAll(ReloadRenderersEvent ignored) {
|
public static void invalidateAll(ReloadRenderersEvent ignored) {
|
||||||
ALL_COMPILERS.forEach(ProgramCompiler::invalidate);
|
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;
|
package com.jozufozu.flywheel.core.compile;
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||||
import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
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.shader.StateSnapshot;
|
||||||
import com.jozufozu.flywheel.core.source.FileIndexImpl;
|
import com.jozufozu.flywheel.core.source.FileIndexImpl;
|
||||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
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.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.ShaderStruct;
|
||||||
import com.jozufozu.flywheel.core.source.parse.StructField;
|
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> {
|
public class VertexCompiler extends Memoizer<VertexCompiler.Context, GlShader> {
|
||||||
private final FileResolution contextShader;
|
private final FileResolution contextShader;
|
||||||
|
private final GLSLVersion glslVersion;
|
||||||
|
|
||||||
public VertexCompiler(FileResolution contextShader) {
|
public VertexCompiler(FileResolution contextShader, GLSLVersion glslVersion) {
|
||||||
this.contextShader = contextShader;
|
this.contextShader = contextShader;
|
||||||
|
this.glslVersion = glslVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected GlShader _create(Context key) {
|
protected GlShader _create(Context key) {
|
||||||
StringBuilder finalSource = new StringBuilder();
|
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');
|
finalSource.append('\n');
|
||||||
|
|
||||||
FileIndexImpl index = new FileIndexImpl();
|
var index = new FileIndexImpl();
|
||||||
|
|
||||||
//
|
// LAYOUT
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
var layoutShader = key.vertexType.getLayoutShader().getFile();
|
||||||
layoutShader.generateFinalSource(index, finalSource);
|
layoutShader.generateFinalSource(index, finalSource);
|
||||||
|
|
||||||
//
|
// INSTANCE
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
|
var instanceShader = key.instanceShader;
|
||||||
instanceShader.generateFinalSource(index, finalSource);
|
instanceShader.generateFinalSource(index, finalSource);
|
||||||
|
|
||||||
//
|
// MATERIAL
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
var materialShader = key.materialShader;
|
||||||
materialShader.generateFinalSource(index, finalSource);
|
materialShader.generateFinalSource(index, finalSource);
|
||||||
|
|
||||||
//
|
// CONTEXT
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
var contextShaderSource = contextShader.getFile();
|
||||||
contextShaderSource.generateFinalSource(index, finalSource);
|
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) {
|
protected String generateFooter(VertexType vertexType, ShaderStruct instance) {
|
||||||
|
@ -203,45 +131,12 @@ public class VertexCompiler extends Memoizer<VertexCompiler.Context, GlShader> {
|
||||||
value.delete();
|
value.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Context {
|
/**
|
||||||
/**
|
* @param vertexType The vertex type to use.
|
||||||
* The vertex type to use.
|
* @param instanceShader The instance shader source.
|
||||||
*/
|
* @param materialShader The vertex material shader source.
|
||||||
private final VertexType vertexType;
|
* @param ctx The shader constants to apply.
|
||||||
|
*/
|
||||||
/**
|
public record Context(VertexType vertexType, SourceFile instanceShader, SourceFile materialShader, StateSnapshot ctx) {
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,7 @@ package com.jozufozu.flywheel.core.material;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.Flywheel;
|
import com.jozufozu.flywheel.Flywheel;
|
||||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||||
import com.jozufozu.flywheel.core.source.Resolver;
|
import com.jozufozu.flywheel.core.source.SourceChecks;
|
||||||
import com.jozufozu.flywheel.event.GatherContextEvent;
|
|
||||||
import com.jozufozu.flywheel.util.ResourceUtil;
|
import com.jozufozu.flywheel.util.ResourceUtil;
|
||||||
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
@ -13,10 +12,16 @@ public class MaterialShaders {
|
||||||
public static FileResolution DEFAULT_FRAGMENT;
|
public static FileResolution DEFAULT_FRAGMENT;
|
||||||
public static FileResolution SHADED_VERTEX;
|
public static FileResolution SHADED_VERTEX;
|
||||||
|
|
||||||
public static void flwInit(GatherContextEvent event) {
|
public static void init() {
|
||||||
DEFAULT_VERTEX = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.DEFAULT, ".vert"));
|
var checkVert = SourceChecks.checkFunctionArity("flw_materialVertex", 0);
|
||||||
DEFAULT_FRAGMENT = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.DEFAULT, ".frag"));
|
var checkFrag = SourceChecks.checkFunctionArity("flw_materialFragment", 0);
|
||||||
SHADED_VERTEX = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.SHADED, ".vert"));
|
|
||||||
|
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 {
|
public static class Names {
|
||||||
|
|
|
@ -3,6 +3,7 @@ package com.jozufozu.flywheel.core.shader;
|
||||||
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.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class for manipulating a list of {@code #define} directives.
|
* A class for manipulating a list of {@code #define} directives.
|
||||||
|
@ -52,4 +53,17 @@ public class ShaderConstants {
|
||||||
acc.append('\n');
|
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
|
@Override
|
||||||
public boolean exists(SourceFile sourceFile) {
|
public boolean exists(SourceFile sourceFile) {
|
||||||
return files.indexOf(sourceFile) != -1;
|
return files.contains(sourceFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -68,10 +68,7 @@ public class FileIndexImpl implements FileIndex {
|
||||||
@Nullable
|
@Nullable
|
||||||
private ErrorBuilder parseCompilerError(String line) {
|
private ErrorBuilder parseCompilerError(String line) {
|
||||||
try {
|
try {
|
||||||
ErrorBuilder error = ErrorBuilder.fromLogLine(this, line);
|
return ErrorBuilder.fromLogLine(this, line);
|
||||||
if (error != null) {
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
package com.jozufozu.flywheel.core.source;
|
package com.jozufozu.flywheel.core.source;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
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.ErrorBuilder;
|
||||||
|
import com.jozufozu.flywheel.core.source.error.ErrorReporter;
|
||||||
import com.jozufozu.flywheel.core.source.span.Span;
|
import com.jozufozu.flywheel.core.source.span.Span;
|
||||||
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
@ -21,17 +23,73 @@ import net.minecraft.resources.ResourceLocation;
|
||||||
*/
|
*/
|
||||||
public class FileResolution {
|
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 final ResourceLocation fileLoc;
|
||||||
|
|
||||||
private SourceFile file;
|
private SourceFile file;
|
||||||
|
|
||||||
FileResolution(ResourceLocation fileLoc) {
|
FileResolution(ResourceLocation fileLoc) {
|
||||||
this.fileLoc = 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() {
|
public ResourceLocation getFileLoc() {
|
||||||
return fileLoc;
|
return fileLoc;
|
||||||
}
|
}
|
||||||
|
@ -53,45 +111,13 @@ public class FileResolution {
|
||||||
* @param span A span where this file is referenced.
|
* @param span A span where this file is referenced.
|
||||||
*/
|
*/
|
||||||
public FileResolution addSpan(Span span) {
|
public FileResolution addSpan(Span span) {
|
||||||
extraCrashInfoProviders.add(builder -> builder.pointAtFile(span.getSourceFile())
|
neededAt.add(span);
|
||||||
.pointAt(span, 1));
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addSpec(ResourceLocation name) {
|
public FileResolution validateWith(BiConsumer<ErrorReporter, SourceFile> check) {
|
||||||
extraCrashInfoProviders.add(builder -> builder.extra("needed by spec: " + name + ".json"));
|
checks.add(check);
|
||||||
}
|
return this;
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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 class ShaderLoadingException extends RuntimeException {
|
||||||
|
|
||||||
public ShaderLoadingException() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShaderLoadingException(String message) {
|
public ShaderLoadingException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import java.util.Map;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
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.ResourceUtil;
|
||||||
import com.jozufozu.flywheel.util.StringUtil;
|
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.
|
* The main object for loading and parsing source files.
|
||||||
*/
|
*/
|
||||||
public class ShaderSources implements SourceFinder {
|
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");
|
public static final ArrayList<String> EXTENSIONS = Lists.newArrayList(".vert", ".vsh", ".frag", ".fsh", ".glsl");
|
||||||
|
|
||||||
private final Map<ResourceLocation, SourceFile> shaderSources = new HashMap<>();
|
private final Map<ResourceLocation, SourceFile> shaderSources = new HashMap<>();
|
||||||
|
|
||||||
public final Index index;
|
public final Index index;
|
||||||
|
|
||||||
public ShaderSources(ResourceManager manager) {
|
public ShaderSources(ErrorReporter errorReporter, ResourceManager manager) {
|
||||||
Collection<ResourceLocation> allShaders = manager.listResources(SHADER_DIR, s -> {
|
Collection<ResourceLocation> allShaders = manager.listResources(SHADER_DIR, s -> {
|
||||||
for (String ext : EXTENSIONS) {
|
for (String ext : EXTENSIONS) {
|
||||||
if (s.endsWith(ext)) return true;
|
if (s.endsWith(ext)) return true;
|
||||||
|
@ -41,7 +42,7 @@ public class ShaderSources implements SourceFinder {
|
||||||
|
|
||||||
ResourceLocation name = ResourceUtil.removePrefixUnchecked(location, SHADER_DIR);
|
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) {
|
} 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.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
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.Import;
|
||||||
import com.jozufozu.flywheel.core.source.parse.ShaderFunction;
|
import com.jozufozu.flywheel.core.source.parse.ShaderFunction;
|
||||||
import com.jozufozu.flywheel.core.source.parse.ShaderStruct;
|
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.ErrorSpan;
|
||||||
import com.jozufozu.flywheel.core.source.span.Span;
|
import com.jozufozu.flywheel.core.source.span.Span;
|
||||||
import com.jozufozu.flywheel.core.source.span.StringSpan;
|
import com.jozufozu.flywheel.core.source.span.StringSpan;
|
||||||
|
@ -55,7 +57,7 @@ public class SourceFile {
|
||||||
*/
|
*/
|
||||||
public final ImmutableList<Import> imports;
|
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.parent = parent;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.source = source;
|
this.source = source;
|
||||||
|
@ -64,7 +66,7 @@ public class SourceFile {
|
||||||
|
|
||||||
List<Span> elisions = new ArrayList<>();
|
List<Span> elisions = new ArrayList<>();
|
||||||
|
|
||||||
this.imports = parseImports(elisions);
|
this.imports = parseImports(errorReporter, elisions);
|
||||||
this.functions = parseFunctions();
|
this.functions = parseFunctions();
|
||||||
this.structs = parseStructs();
|
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.
|
* Records the contents of the directive into an {@link Import} object, and marks the directive for elision.
|
||||||
* @param elisions
|
* @param elisions
|
||||||
*/
|
*/
|
||||||
private ImmutableList<Import> parseImports(List<Span> elisions) {
|
private ImmutableList<Import> parseImports(ErrorReporter errorReporter, List<Span> elisions) {
|
||||||
Matcher uses = Import.PATTERN.matcher(source);
|
Matcher uses = Import.PATTERN.matcher(source);
|
||||||
|
|
||||||
Set<String> importedFiles = new HashSet<>();
|
Set<String> importedFiles = new HashSet<>();
|
||||||
|
@ -245,9 +247,9 @@ public class SourceFile {
|
||||||
|
|
||||||
String fileName = file.get();
|
String fileName = file.get();
|
||||||
if (importedFiles.add(fileName)) {
|
if (importedFiles.add(fileName)) {
|
||||||
Import import1 = Import.create(Resolver.INSTANCE, use, file);
|
var checked = Import.create(errorReporter, use, file);
|
||||||
if (import1 != null) {
|
if (checked != null) {
|
||||||
imports.add(import1);
|
imports.add(checked);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,4 +282,15 @@ public class SourceFile {
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return name.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;
|
package com.jozufozu.flywheel.core.source.error;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@ -13,58 +14,78 @@ import com.jozufozu.flywheel.util.FlwUtil;
|
||||||
|
|
||||||
public class ErrorReporter {
|
public class ErrorReporter {
|
||||||
|
|
||||||
public static void generateSpanError(Span span, String message) {
|
private final List<ErrorBuilder> reportedErrors = new ArrayList<>();
|
||||||
SourceFile file = span.getSourceFile();
|
|
||||||
|
|
||||||
String error = ErrorBuilder.error(message)
|
public void generateMissingStruct(SourceFile file, Span vertexName, CharSequence msg) {
|
||||||
.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) {
|
|
||||||
generateMissingStruct(file, vertexName, 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)
|
Optional<Span> span = file.parent.index.getStructDefinitionsMatching(vertexName)
|
||||||
.stream()
|
.stream()
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.map(ShaderStruct::getName);
|
.map(ShaderStruct::getName);
|
||||||
|
|
||||||
ErrorBuilder error = ErrorBuilder.error(msg)
|
this.error(msg)
|
||||||
.pointAtFile(file)
|
.pointAtFile(file)
|
||||||
.pointAt(vertexName, 1)
|
.pointAt(vertexName, 1)
|
||||||
.hintIncludeFor(span.orElse(null), hint);
|
.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, "");
|
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)
|
Optional<Span> span = file.parent.index.getFunctionDefinitionsMatching(functionName)
|
||||||
.stream()
|
.stream()
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.map(ShaderFunction::getName);
|
.map(ShaderFunction::getName);
|
||||||
|
|
||||||
ErrorBuilder error = ErrorBuilder.error(msg)
|
this.error(msg)
|
||||||
.pointAtFile(file)
|
.pointAtFile(file)
|
||||||
.hintIncludeFor(span.orElse(null), hint);
|
.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) {
|
public static void printLines(CharSequence source) {
|
||||||
|
|
|
@ -6,7 +6,6 @@ import java.util.regex.Pattern;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
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.SourceFile;
|
||||||
import com.jozufozu.flywheel.core.source.error.ErrorReporter;
|
import com.jozufozu.flywheel.core.source.error.ErrorReporter;
|
||||||
import com.jozufozu.flywheel.core.source.span.Span;
|
import com.jozufozu.flywheel.core.source.span.Span;
|
||||||
|
@ -26,16 +25,16 @@ public class Import extends AbstractShaderElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static Import create(Resolver resolver, Span self, Span file) {
|
public static Import create(ErrorReporter errorReporter, Span self, Span file) {
|
||||||
ResourceLocation fileLocation;
|
ResourceLocation fileLocation;
|
||||||
try {
|
try {
|
||||||
fileLocation = new ResourceLocation(file.get());
|
fileLocation = new ResourceLocation(file.get());
|
||||||
} catch (ResourceLocationException e) {
|
} catch (ResourceLocationException e) {
|
||||||
ErrorReporter.generateSpanError(file, "malformed source location");
|
errorReporter.generateSpanError(file, "malformed source location");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Import(self, resolver.get(fileLocation), file);
|
return new Import(self, FileResolution.get(fileLocation), file);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FileResolution getResolution() {
|
public FileResolution getResolution() {
|
||||||
|
|
|
@ -52,6 +52,10 @@ public class ShaderFunction extends AbstractShaderElement {
|
||||||
return name + "(" + String.join(", ", args) + ")";
|
return name + "(" + String.join(", ", args) + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Span getParameterType(int index) {
|
||||||
|
return parameters.get(index).type;
|
||||||
|
}
|
||||||
|
|
||||||
public ImmutableList<Variable> getParameters() {
|
public ImmutableList<Variable> getParameters() {
|
||||||
return parameters;
|
return parameters;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
package com.jozufozu.flywheel.core.source.span;
|
package com.jozufozu.flywheel.core.source.span;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.core.source.SourceFile;
|
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}.
|
* 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) {
|
public static Span fromMatcher(Span superSpan, Matcher m) {
|
||||||
return superSpan.subSpan(m.start(), m.end());
|
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.Flywheel;
|
||||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||||
import com.jozufozu.flywheel.core.source.Resolver;
|
import com.jozufozu.flywheel.core.source.SourceChecks;
|
||||||
import com.jozufozu.flywheel.event.GatherContextEvent;
|
|
||||||
import com.jozufozu.flywheel.util.ResourceUtil;
|
import com.jozufozu.flywheel.util.ResourceUtil;
|
||||||
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
@ -12,9 +11,13 @@ public class InstanceShaders {
|
||||||
public static FileResolution MODEL;
|
public static FileResolution MODEL;
|
||||||
public static FileResolution ORIENTED;
|
public static FileResolution ORIENTED;
|
||||||
|
|
||||||
public static void flwInit(GatherContextEvent event) {
|
public static void init() {
|
||||||
MODEL = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.MODEL, ".vert"));
|
var check = SourceChecks.checkFunctionParameterTypeExists("flw_instanceVertex", 1, 0);
|
||||||
ORIENTED = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.ORIENTED, ".vert"));
|
|
||||||
|
MODEL = FileResolution.get(ResourceUtil.subPath(Names.MODEL, ".vert"))
|
||||||
|
.validateWith(check);
|
||||||
|
ORIENTED = FileResolution.get(ResourceUtil.subPath(Names.ORIENTED, ".vert"))
|
||||||
|
.validateWith(check);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Names {
|
public static class Names {
|
||||||
|
|
|
@ -2,8 +2,7 @@ package com.jozufozu.flywheel.core.vertex;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.Flywheel;
|
import com.jozufozu.flywheel.Flywheel;
|
||||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||||
import com.jozufozu.flywheel.core.source.Resolver;
|
import com.jozufozu.flywheel.core.source.SourceChecks;
|
||||||
import com.jozufozu.flywheel.event.GatherContextEvent;
|
|
||||||
import com.jozufozu.flywheel.util.ResourceUtil;
|
import com.jozufozu.flywheel.util.ResourceUtil;
|
||||||
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
@ -12,9 +11,14 @@ public class LayoutShaders {
|
||||||
public static FileResolution BLOCK;
|
public static FileResolution BLOCK;
|
||||||
public static FileResolution POS_TEX_NORMAL;
|
public static FileResolution POS_TEX_NORMAL;
|
||||||
|
|
||||||
public static void flwInit(GatherContextEvent event) {
|
public static void init() {
|
||||||
BLOCK = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.BLOCK, ".vert"));
|
var check = SourceChecks.checkFunctionArity("flw_layoutVertex", 0);
|
||||||
POS_TEX_NORMAL = Resolver.INSTANCE.get(ResourceUtil.subPath(Names.POS_TEX_NORMAL, ".vert"));
|
|
||||||
|
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 {
|
public static class Names {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import com.jozufozu.flywheel.light.LightUpdater;
|
||||||
import com.jozufozu.flywheel.util.WorldAttached;
|
import com.jozufozu.flywheel.util.WorldAttached;
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.player.LocalPlayer;
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
import net.minecraftforge.client.event.RenderGameOverlayEvent;
|
import net.minecraftforge.client.event.RenderGameOverlayEvent;
|
||||||
import net.minecraftforge.event.TickEvent;
|
import net.minecraftforge.event.TickEvent;
|
||||||
|
@ -32,8 +33,10 @@ public class ForgeEvents {
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public static void tickLight(TickEvent.ClientTickEvent e) {
|
public static void tickLight(TickEvent.ClientTickEvent e) {
|
||||||
if (e.phase == TickEvent.Phase.END && Backend.isGameActive())
|
if (e.phase == TickEvent.Phase.END && Backend.isGameActive()) {
|
||||||
LightUpdater.get(Minecraft.getInstance().level).tick();
|
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