diff --git a/src/main/java/com/simibubi/create/events/ClientEvents.java b/src/main/java/com/simibubi/create/events/ClientEvents.java index 25754d8c4..88d13aece 100644 --- a/src/main/java/com/simibubi/create/events/ClientEvents.java +++ b/src/main/java/com/simibubi/create/events/ClientEvents.java @@ -186,7 +186,6 @@ public class ClientEvents { ms.pop(); RenderWork.runAll(); - FastRenderDispatcher.endFrame(); } @SubscribeEvent diff --git a/src/main/java/com/simibubi/create/foundation/mixin/RenderHooksMixin.java b/src/main/java/com/simibubi/create/foundation/mixin/RenderHooksMixin.java index bf97e3c9b..da41425e6 100644 --- a/src/main/java/com/simibubi/create/foundation/mixin/RenderHooksMixin.java +++ b/src/main/java/com/simibubi/create/foundation/mixin/RenderHooksMixin.java @@ -49,7 +49,7 @@ public class RenderHooksMixin { Matrix4f viewProjection = stack.peek() .getModel() .copy(); - viewProjection.multiplyBackward(FastRenderDispatcher.getProjectionMatrix()); + viewProjection.multiplyBackward(Backend.projectionMatrix); FastRenderDispatcher.renderLayer(type, viewProjection, camX, camY, camZ); diff --git a/src/main/java/com/simibubi/create/foundation/mixin/StoreProjectionMatrixMixin.java b/src/main/java/com/simibubi/create/foundation/mixin/StoreProjectionMatrixMixin.java new file mode 100644 index 000000000..41294852d --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/mixin/StoreProjectionMatrixMixin.java @@ -0,0 +1,20 @@ +package com.simibubi.create.foundation.mixin; + +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.util.math.vector.Matrix4f; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import com.simibubi.create.foundation.render.backend.Backend; + +@Mixin(GameRenderer.class) +public class StoreProjectionMatrixMixin { + + @Inject(method = "loadProjectionMatrix", at = @At("TAIL")) + private void onProjectionMatrixLoad(Matrix4f projection, CallbackInfo ci) { + Backend.projectionMatrix = projection.copy(); + } +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/Backend.java b/src/main/java/com/simibubi/create/foundation/render/backend/Backend.java index 2e9f181b2..9c17503c9 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/Backend.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/Backend.java @@ -11,7 +11,7 @@ import org.lwjgl.opengl.GLCapabilities; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.render.backend.gl.GlFog; import com.simibubi.create.foundation.render.backend.gl.shader.GlProgram; -import com.simibubi.create.foundation.render.backend.gl.shader.ProgramGroup; +import com.simibubi.create.foundation.render.backend.gl.shader.IMultiProgram; import com.simibubi.create.foundation.render.backend.gl.shader.ProgramSpec; import com.simibubi.create.foundation.render.backend.gl.versioned.GlCompat; import com.simibubi.create.foundation.render.backend.instancing.IFlywheelWorld; @@ -20,13 +20,17 @@ import net.minecraft.client.Minecraft; import net.minecraft.resources.IReloadableResourceManager; import net.minecraft.resources.IResourceManager; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.vector.Matrix4f; import net.minecraft.world.World; import net.minecraftforge.resource.ISelectiveResourceReloadListener; public class Backend { - public static final Boolean SHADER_DEBUG_OUTPUT = true; - public static final Logger log = LogManager.getLogger(Backend.class); + + public static final ShaderLoader shaderLoader = new ShaderLoader(); + + public static Matrix4f projectionMatrix = new Matrix4f(); + public static GLCapabilities capabilities; public static GlCompat compat; @@ -34,7 +38,7 @@ public class Backend { private static boolean enabled; static final Map> registry = new HashMap<>(); - static final Map, ProgramGroup> programs = new HashMap<>(); + static final Map, IMultiProgram> programs = new HashMap<>(); public Backend() { throw new IllegalStateException(); @@ -54,7 +58,7 @@ public class Backend { @SuppressWarnings("unchecked") public static

> P getProgram(S spec) { - return (P) programs.get(spec).get(GlFog.getFogMode()); + return (P) programs.get(spec).get(); } public static boolean isFlywheelWorld(World world) { @@ -89,7 +93,7 @@ public class Backend { IResourceManager manager = mc.getResourceManager(); if (manager instanceof IReloadableResourceManager) { - ISelectiveResourceReloadListener listener = ShaderLoader::onResourceManagerReload; + ISelectiveResourceReloadListener listener = shaderLoader::onResourceManagerReload; ((IReloadableResourceManager) manager).addReloadListener(listener); } } diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/FastRenderDispatcher.java b/src/main/java/com/simibubi/create/foundation/render/backend/FastRenderDispatcher.java index 5658a30b3..f4deae1dc 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/FastRenderDispatcher.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/FastRenderDispatcher.java @@ -26,12 +26,6 @@ public class FastRenderDispatcher { public static WorldAttached> queuedUpdates = new WorldAttached<>(ConcurrentHashMap::newKeySet); - private static Matrix4f projectionMatrixThisFrame = null; - - public static void endFrame() { - projectionMatrixThisFrame = null; - } - public static void enqueueUpdate(TileEntity te) { queuedUpdates.get(te.getWorld()).add(te); } @@ -82,45 +76,4 @@ public class FastRenderDispatcher { layer.endDrawing(); } - - // copied from GameRenderer.renderWorld - public static Matrix4f getProjectionMatrix() { - if (projectionMatrixThisFrame != null) return projectionMatrixThisFrame; - - float partialTicks = AnimationTickHolder.getPartialTicks(); - Minecraft mc = Minecraft.getInstance(); - GameRenderer gameRenderer = mc.gameRenderer; - ClientPlayerEntity player = mc.player; - - MatrixStack matrixstack = new MatrixStack(); - matrixstack.peek() - .getModel() - .multiply(gameRenderer.getBasicProjectionMatrix(gameRenderer.getActiveRenderInfo(), partialTicks, true)); - gameRenderer.bobViewWhenHurt(matrixstack, partialTicks); - if (mc.gameSettings.viewBobbing) { - gameRenderer.bobView(matrixstack, partialTicks); - } - - float portalTime = MathHelper.lerp(partialTicks, player.prevTimeInPortal, player.timeInPortal); - if (portalTime > 0.0F) { - int i = 20; - if (player.isPotionActive(Effects.NAUSEA)) { - i = 7; - } - - float f1 = 5.0F / (portalTime * portalTime + 5.0F) - portalTime * 0.04F; - f1 = f1 * f1; - Vector3f vector3f = new Vector3f(0.0F, MathHelper.SQRT_2 / 2.0F, MathHelper.SQRT_2 / 2.0F); - matrixstack.multiply(vector3f.getDegreesQuaternion(((float)gameRenderer.rendererUpdateCount + partialTicks) * (float)i)); - matrixstack.scale(1.0F / f1, 1.0F, 1.0F); - float f2 = -((float)gameRenderer.rendererUpdateCount + partialTicks) * (float)i; - matrixstack.multiply(vector3f.getDegreesQuaternion(f2)); - } - - Matrix4f matrix4f = matrixstack.peek().getModel(); - gameRenderer.loadProjectionMatrix(matrix4f); - - projectionMatrixThisFrame = matrix4f; - return projectionMatrixThisFrame; - } } diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/ShaderLoader.java b/src/main/java/com/simibubi/create/foundation/render/backend/ShaderLoader.java index 9a8c9ec79..41c5dfb33 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/ShaderLoader.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/ShaderLoader.java @@ -28,9 +28,11 @@ import org.lwjgl.system.MemoryUtil; import com.google.common.collect.Lists; import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.foundation.render.backend.gl.GlFogMode; +import com.simibubi.create.foundation.render.backend.gl.shader.SingleProgram; import com.simibubi.create.foundation.render.backend.gl.shader.GlProgram; import com.simibubi.create.foundation.render.backend.gl.shader.GlShader; -import com.simibubi.create.foundation.render.backend.gl.shader.ProgramGroup; +import com.simibubi.create.foundation.render.backend.gl.shader.FogSensitiveProgram; +import com.simibubi.create.foundation.render.backend.gl.shader.IMultiProgram; import com.simibubi.create.foundation.render.backend.gl.shader.ProgramSpec; import com.simibubi.create.foundation.render.backend.gl.shader.ShaderConstants; import com.simibubi.create.foundation.render.backend.gl.shader.ShaderType; @@ -45,9 +47,12 @@ public class ShaderLoader { public static final String SHADER_DIR = "flywheel/shaders/"; public static final ArrayList EXTENSIONS = Lists.newArrayList(".vert", ".vsh", ".frag", ".fsh", ".glsl"); - static final Map shaderSource = new HashMap<>(); + // #flwinclude <"valid_namespace:valid/path_to_file.glsl"> + private static final Pattern includePattern = Pattern.compile("#flwinclude <\"([\\w\\d_]+:[\\w\\d_./]+)\">"); - static void onResourceManagerReload(IResourceManager manager, Predicate predicate) { + final Map shaderSource = new HashMap<>(); + + void onResourceManagerReload(IResourceManager manager, Predicate predicate) { if (predicate.test(VanillaResourceType.SHADERS)) { OptifineHandler.refresh(); Backend.refresh(); @@ -56,16 +61,16 @@ public class ShaderLoader { shaderSource.clear(); loadShaderSources(manager); - Backend.programs.values().forEach(ProgramGroup::delete); + Backend.programs.values().forEach(IMultiProgram::delete); Backend.programs.clear(); - Backend.registry.values().forEach(ShaderLoader::loadProgram); + Backend.registry.values().forEach(this::loadProgramFromSpec); Backend.log.info("Loaded all shader programs."); } } } - private static void loadShaderSources(IResourceManager manager){ + private void loadShaderSources(IResourceManager manager){ Collection allShaders = manager.getAllResourceLocations(SHADER_DIR, s -> { for (String ext : EXTENSIONS) { if (s.endsWith(ext)) return true; @@ -89,19 +94,26 @@ public class ShaderLoader { } } - static

> void loadProgram(S programSpec) { - Map programGroup = new EnumMap<>(GlFogMode.class); + private

> void loadProgramFromSpec(S programSpec) { - for (GlFogMode fogMode : GlFogMode.values()) { - programGroup.put(fogMode, loadProgram(programSpec, fogMode)); + if (programSpec.fogSensitive) { + Map programGroup = new EnumMap<>(GlFogMode.class); + + for (GlFogMode fogMode : GlFogMode.values()) { + programGroup.put(fogMode, loadProgram(programSpec, fogMode)); + } + + Backend.programs.put(programSpec, new FogSensitiveProgram<>(programGroup)); + } else { + P program = loadProgram(programSpec, GlFogMode.NONE); + + Backend.programs.put(programSpec, new SingleProgram<>(program)); } - Backend.programs.put(programSpec, new ProgramGroup<>(programGroup)); - Backend.log.debug("Loaded program {}", programSpec.name); } - private static

> P loadProgram(S programSpec, GlFogMode fogMode) { + private

> P loadProgram(S programSpec, GlFogMode fogMode) { GlShader vert = null; GlShader frag = null; try { @@ -124,16 +136,14 @@ public class ShaderLoader { } } - private static final Pattern includePattern = Pattern.compile("#flwinclude <\"([\\w\\d_]+:[\\w\\d_./]+)\">"); - - private static String processIncludes(ResourceLocation baseName, String source) { + private String processIncludes(ResourceLocation baseName, String source) { HashSet seen = new HashSet<>(); seen.add(baseName); return includeRecursive(source, seen).collect(Collectors.joining("\n")); } - private static Stream includeRecursive(String source, Set seen) { + private Stream includeRecursive(String source, Set seen) { return new BufferedReader(new StringReader(source)).lines().flatMap(line -> { Matcher matcher = includePattern.matcher(line); @@ -156,7 +166,7 @@ public class ShaderLoader { }); } - private static GlShader loadShader(ResourceLocation name, ShaderType type, ShaderConstants defines) { + private GlShader loadShader(ResourceLocation name, ShaderType type, ShaderConstants defines) { String source = shaderSource.get(name); source = processIncludes(name, source); @@ -168,7 +178,7 @@ public class ShaderLoader { return new GlShader(type, name, source); } - public static String readToString(InputStream is) { + public String readToString(InputStream is) { RenderSystem.assertThread(RenderSystem::isOnRenderThread); ByteBuffer bytebuffer = null; @@ -189,7 +199,7 @@ public class ShaderLoader { return null; } - public static ByteBuffer readToBuffer(InputStream is) throws IOException { + public ByteBuffer readToBuffer(InputStream is) throws IOException { ByteBuffer bytebuffer; if (is instanceof FileInputStream) { FileInputStream fileinputstream = (FileInputStream)is; diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ProgramGroup.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/FogSensitiveProgram.java similarity index 52% rename from src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ProgramGroup.java rename to src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/FogSensitiveProgram.java index 732a2f196..426dbc4ac 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ProgramGroup.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/FogSensitiveProgram.java @@ -2,21 +2,25 @@ package com.simibubi.create.foundation.render.backend.gl.shader; import java.util.Map; +import com.simibubi.create.foundation.render.backend.gl.GlFog; import com.simibubi.create.foundation.render.backend.gl.GlFogMode; -public class ProgramGroup

{ +public class FogSensitiveProgram

implements IMultiProgram

{ private final Map programs; - public ProgramGroup(Map programs) { + public FogSensitiveProgram(Map programs) { this.programs = programs; } - public P get(GlFogMode fogMode) { - return programs.get(fogMode); + @Override + public P get() { + return programs.get(GlFog.getFogMode()); } + @Override public void delete() { programs.values().forEach(GlProgram::delete); } + } diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/GlProgram.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/GlProgram.java index d450144b6..56dce3fd8 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/GlProgram.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/GlProgram.java @@ -38,7 +38,7 @@ public abstract class GlProgram extends GlObject { public int getUniformLocation(String uniform) { int index = GL20.glGetUniformLocation(this.handle(), uniform); - if (index < 0 && Backend.SHADER_DEBUG_OUTPUT) { + if (index < 0) { Backend.log.debug("No active uniform '{}' exists in program '{}'. Could be unused.", uniform, this.name); } @@ -106,7 +106,7 @@ public abstract class GlProgram extends GlObject { String log = GL20.glGetProgramInfoLog(this.program); - if (!log.isEmpty() && Backend.SHADER_DEBUG_OUTPUT) { + if (!log.isEmpty()) { Backend.log.debug("Program link log for " + this.name + ": " + log); } diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/IMultiProgram.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/IMultiProgram.java new file mode 100644 index 000000000..0fdf6cc7d --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/IMultiProgram.java @@ -0,0 +1,21 @@ +package com.simibubi.create.foundation.render.backend.gl.shader; + +/** + * Encapsulates any number of shader programs for use in similar contexts. + * Allows the implementor to choose which shader program to use based on arbitrary state. + * + * @param

+ */ +public interface IMultiProgram

{ + + /** + * Get the shader program most suited for the current game state. + * @return The one true program. + */ + P get(); + + /** + * Delete all shader programs encapsulated by your implementation. + */ + void delete(); +} diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ProgramSpec.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ProgramSpec.java index a7bc130af..26c3b0eb2 100644 --- a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ProgramSpec.java +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/ProgramSpec.java @@ -20,6 +20,8 @@ public class ProgramSpec

{ public final ArrayList attributes; + public final boolean fogSensitive; + public static

Builder

builder(String name, GlProgram.ProgramFactory

factory) { return builder(new ResourceLocation(Create.ID, name), factory); } @@ -28,16 +30,16 @@ public class ProgramSpec

{ return new Builder<>(name, factory); } - public ProgramSpec(ResourceLocation name, ResourceLocation vert, ResourceLocation frag, GlProgram.ProgramFactory

factory, ShaderConstants defines, ArrayList attributes) { + public ProgramSpec(ResourceLocation name, ResourceLocation vert, ResourceLocation frag, GlProgram.ProgramFactory

factory, ShaderConstants defines, ArrayList attributes, boolean fogSensitive) { this.name = name; this.vert = vert; this.frag = frag; this.defines = defines; - this.factory = factory; this.attributes = attributes; - } + this.fogSensitive = fogSensitive; + } public ResourceLocation getVert() { return vert; @@ -51,6 +53,7 @@ public class ProgramSpec

{ private ResourceLocation vert; private ResourceLocation frag; private ShaderConstants defines = ShaderConstants.EMPTY; + private boolean fogSensitive = true; private final ResourceLocation name; private final GlProgram.ProgramFactory

factory; @@ -77,13 +80,18 @@ public class ProgramSpec

{ return this; } - public & IVertexAttrib> Builder

addAttributes(Class attributeEnum) { + public Builder

setFogSensitive(boolean fogSensitive) { + this.fogSensitive = fogSensitive; + return this; + } + + public & IVertexAttrib> Builder

addAttributes(Class attributeEnum) { attributes.addAll(Arrays.asList(attributeEnum.getEnumConstants())); return this; } public ProgramSpec

createProgramSpec() { - return new ProgramSpec<>(name, vert, frag, factory, defines, attributes); + return new ProgramSpec<>(name, vert, frag, factory, defines, attributes, fogSensitive); } } } diff --git a/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/SingleProgram.java b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/SingleProgram.java new file mode 100644 index 000000000..c3ee700ab --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/render/backend/gl/shader/SingleProgram.java @@ -0,0 +1,19 @@ +package com.simibubi.create.foundation.render.backend.gl.shader; + +public class SingleProgram

implements IMultiProgram

{ + final P program; + + public SingleProgram(P program) { + this.program = program; + } + + @Override + public P get() { + return program; + } + + @Override + public void delete() { + program.delete(); + } +} diff --git a/src/main/resources/create.mixins.json b/src/main/resources/create.mixins.json index 81b7d6c55..6e988aa5a 100644 --- a/src/main/resources/create.mixins.json +++ b/src/main/resources/create.mixins.json @@ -13,10 +13,11 @@ "RenderHooksMixin", "ShaderCloseMixin", "TileRemoveMixin", - "EntityContraptionInteractionMixin" + "EntityContraptionInteractionMixin", + "StoreProjectionMatrixMixin" ], "injectors": { "defaultRequire": 1 }, "minVersion": "0.8" -} \ No newline at end of file +}