Merge branch '1.8' into 1.9.4
0ba5b0aMerge branch '1.8-shaders' into 1.8e5eb982Add Optifine compatibility to rendering by disabling their separate chunk loading queue Add compatibility to shaders that utilize the Shadow Map by manually setting displayListEntitiesDirty to false Call Shaders.beginRender in an Event Handler to avoid calling all of EntityRenderer#renderWorld3a28c5bDraw the GuiVideoRenderer on a separate framebuffer that has the actual size of the window instead of MC's framebuffer which may have a different size636ce7bAdd compatibility for GLSL Shaders92eb11aChange video preview to be compatible with Optifine
This commit is contained in:
23
src/main/java/com/replaymod/compat/ReplayModCompat.java
Normal file
23
src/main/java/com/replaymod/compat/ReplayModCompat.java
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package com.replaymod.compat;
|
||||||
|
|
||||||
|
import com.replaymod.compat.shaders.ShaderBeginRender;
|
||||||
|
import com.replaymod.core.ReplayMod;
|
||||||
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
|
import net.minecraftforge.fml.common.Mod;
|
||||||
|
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.EventBus;
|
||||||
|
|
||||||
|
@Mod(modid = ReplayModCompat.MOD_ID, useMetadata = true)
|
||||||
|
public class ReplayModCompat {
|
||||||
|
public static final String MOD_ID = "replaymod-compat";
|
||||||
|
|
||||||
|
@Mod.Instance(ReplayMod.MOD_ID)
|
||||||
|
private static ReplayMod core;
|
||||||
|
|
||||||
|
@Mod.EventHandler
|
||||||
|
public void init(FMLInitializationEvent event) {
|
||||||
|
EventBus bus = MinecraftForge.EVENT_BUS;
|
||||||
|
bus.register(new ShaderBeginRender());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package com.replaymod.compat.shaders;
|
||||||
|
|
||||||
|
import com.replaymod.render.hooks.EntityRendererHandler;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||||
|
import net.minecraftforge.fml.common.gameevent.TickEvent;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
|
||||||
|
public class ShaderBeginRender {
|
||||||
|
|
||||||
|
private final Minecraft mc = Minecraft.getMinecraft();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes Shaders#beginRender when rendering a video,
|
||||||
|
* as this would usually get called by EntityRenderer#renderWorld,
|
||||||
|
* which we're not calling during rendering.
|
||||||
|
*/
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onRenderTickStart(TickEvent.RenderTickEvent event) {
|
||||||
|
if (event.phase != TickEvent.Phase.START) return;
|
||||||
|
if (ShaderReflection.shaders_beginRender == null) return;
|
||||||
|
if (ShaderReflection.config_isShaders == null) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// check if video is being rendered
|
||||||
|
if (((EntityRendererHandler.IEntityRenderer) mc.entityRenderer).replayModRender_getHandler() == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// check if Shaders are enabled
|
||||||
|
if (!(boolean) (ShaderReflection.config_isShaders.invoke(null))) return;
|
||||||
|
|
||||||
|
ShaderReflection.shaders_beginRender.invoke(null, mc, mc.timer.elapsedPartialTicks, 0);
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
102
src/main/java/com/replaymod/compat/shaders/ShaderReflection.java
Normal file
102
src/main/java/com/replaymod/compat/shaders/ShaderReflection.java
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
package com.replaymod.compat.shaders;
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
public class ShaderReflection {
|
||||||
|
|
||||||
|
// Shaders.frameTimeCounter
|
||||||
|
public static Field shaders_frameTimeCounter;
|
||||||
|
|
||||||
|
// Shaders.isShadowPass
|
||||||
|
public static Field shaders_isShadowPass;
|
||||||
|
|
||||||
|
// Shaders.beginRender()
|
||||||
|
public static Method shaders_beginRender;
|
||||||
|
|
||||||
|
// RenderGlobal.chunksToUpdateForced (Optifine only)
|
||||||
|
public static Field renderGlobal_chunksToUpdateForced;
|
||||||
|
|
||||||
|
// Config.isShaders() (Optifine only)
|
||||||
|
public static Method config_isShaders;
|
||||||
|
|
||||||
|
static {
|
||||||
|
initFrameTimeCounter();
|
||||||
|
|
||||||
|
initIsShadowPass();
|
||||||
|
|
||||||
|
initBeginRender();
|
||||||
|
|
||||||
|
initChunksToUpdateForced();
|
||||||
|
|
||||||
|
initConfigIsShaders();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void initFrameTimeCounter() {
|
||||||
|
try {
|
||||||
|
shaders_frameTimeCounter = Class.forName("shadersmod.client.Shaders")
|
||||||
|
.getDeclaredField("frameTimeCounter");
|
||||||
|
shaders_frameTimeCounter.setAccessible(true);
|
||||||
|
} catch (ClassNotFoundException ignore) {
|
||||||
|
// no shaders mod installed
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
// the field wasn't found. Has it been renamed?
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void initIsShadowPass() {
|
||||||
|
try {
|
||||||
|
shaders_isShadowPass = Class.forName("shadersmod.client.Shaders")
|
||||||
|
.getDeclaredField("isShadowPass");
|
||||||
|
shaders_isShadowPass.setAccessible(true);
|
||||||
|
} catch (ClassNotFoundException ignore) {
|
||||||
|
// no shaders mod installed
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
// the field wasn't found. Has it been renamed?
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void initBeginRender() {
|
||||||
|
try {
|
||||||
|
shaders_beginRender = Class.forName("shadersmod.client.Shaders")
|
||||||
|
.getDeclaredMethod("beginRender", Minecraft.class, float.class, long.class);
|
||||||
|
shaders_frameTimeCounter.setAccessible(true);
|
||||||
|
} catch (ClassNotFoundException ignore) {
|
||||||
|
// no shaders mod installed
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
// the method wasn't found. Has it been renamed?
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void initChunksToUpdateForced() {
|
||||||
|
try {
|
||||||
|
renderGlobal_chunksToUpdateForced = Class.forName("net.minecraft.client.renderer.RenderGlobal")
|
||||||
|
.getDeclaredField("chunksToUpdateForced");
|
||||||
|
renderGlobal_chunksToUpdateForced.setAccessible(true);
|
||||||
|
} catch (ClassNotFoundException ignore) {
|
||||||
|
// no shaders mod installed
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
// the field wasn't found. Has it been renamed?
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void initConfigIsShaders() {
|
||||||
|
try {
|
||||||
|
config_isShaders = Class.forName("Config")
|
||||||
|
.getDeclaredMethod("isShaders");
|
||||||
|
config_isShaders.setAccessible(true);
|
||||||
|
} catch (ClassNotFoundException ignore) {
|
||||||
|
// no shaders mod installed
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
// the method wasn't found. Has it been renamed?
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.replaymod.compat.shaders.mixin;
|
||||||
|
|
||||||
|
import com.replaymod.compat.shaders.ShaderReflection;
|
||||||
|
import com.replaymod.replay.ReplayHandler;
|
||||||
|
import com.replaymod.replay.ReplayModReplay;
|
||||||
|
import net.minecraft.client.renderer.EntityRenderer;
|
||||||
|
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;
|
||||||
|
|
||||||
|
@Mixin(EntityRenderer.class)
|
||||||
|
public abstract class MixinShaderEntityRenderer {
|
||||||
|
|
||||||
|
@Inject(method = "renderWorldPass", at = @At("HEAD"))
|
||||||
|
private void replayModCompat_updateShaderFrameTimeCounter(CallbackInfo ignore) {
|
||||||
|
if (ReplayModReplay.instance.getReplayHandler() == null) return;
|
||||||
|
if (ShaderReflection.shaders_frameTimeCounter == null) return;
|
||||||
|
|
||||||
|
ReplayHandler replayHandler = ReplayModReplay.instance.getReplayHandler();
|
||||||
|
float timestamp = replayHandler.getReplaySender().currentTimeStamp() / 1000f % 3600f;
|
||||||
|
try {
|
||||||
|
ShaderReflection.shaders_frameTimeCounter.set(null, timestamp);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.replaymod.compat.shaders.mixin;
|
||||||
|
|
||||||
|
import com.replaymod.render.hooks.EntityRendererHandler;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.renderer.chunk.RenderChunk;
|
||||||
|
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.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(RenderChunk.class)
|
||||||
|
public abstract class MixinShaderRenderChunk {
|
||||||
|
|
||||||
|
private final Minecraft mc = Minecraft.getMinecraft();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the RenderChunk#isPlayerUpdate method that Optifine adds
|
||||||
|
* to always return true while rendering so no chunks are being added
|
||||||
|
* to a separate rendering queue
|
||||||
|
*/
|
||||||
|
@Inject(method = "isPlayerUpdate", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void replayModCompat_disableIsPlayerUpdate(CallbackInfoReturnable<Boolean> ci) {
|
||||||
|
if (((EntityRendererHandler.IEntityRenderer) mc.entityRenderer).replayModRender_getHandler() == null) return;
|
||||||
|
ci.setReturnValue(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package com.replaymod.compat.shaders.mixin;
|
||||||
|
|
||||||
|
import com.replaymod.compat.shaders.ShaderReflection;
|
||||||
|
import com.replaymod.render.hooks.EntityRendererHandler;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.renderer.RenderGlobal;
|
||||||
|
import net.minecraft.client.renderer.culling.ICamera;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin(RenderGlobal.class)
|
||||||
|
public abstract class MixinShaderRenderGlobal {
|
||||||
|
|
||||||
|
private final Minecraft mc = Minecraft.getMinecraft();
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
public boolean displayListEntitiesDirty;
|
||||||
|
|
||||||
|
@Inject(method = "setupTerrain", at = @At("HEAD"), cancellable = true)
|
||||||
|
public void replayModCompat_setupTerrain(Entity viewEntity, double partialTicks, ICamera camera,
|
||||||
|
int frameCount, boolean playerSpectator, CallbackInfo ci) {
|
||||||
|
if (((EntityRendererHandler.IEntityRenderer) mc.entityRenderer).replayModRender_getHandler() == null) return;
|
||||||
|
if (ShaderReflection.shaders_isShadowPass == null) return;
|
||||||
|
|
||||||
|
// when called by the shadow pass, displayListEntitiesDirty can't be set to false, as no chunk updates
|
||||||
|
// are being processed. As it's being set to true by ChunkLoadingRenderGlobal#updateChunks, we have to
|
||||||
|
// set it to false manually to exit the loop imposed by MixinRenderGlobal#replayModRender_setupTerrain.
|
||||||
|
try {
|
||||||
|
if ((boolean) ShaderReflection.shaders_isShadowPass.get(null) == true) {
|
||||||
|
displayListEntitiesDirty = false;
|
||||||
|
}
|
||||||
|
} catch (IllegalAccessException ignore) {}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ public class LoadingPlugin implements IFMLLoadingPlugin {
|
|||||||
Mixins.addConfiguration("mixins.recording.replaymod.json");
|
Mixins.addConfiguration("mixins.recording.replaymod.json");
|
||||||
Mixins.addConfiguration("mixins.render.replaymod.json");
|
Mixins.addConfiguration("mixins.render.replaymod.json");
|
||||||
Mixins.addConfiguration("mixins.replay.replaymod.json");
|
Mixins.addConfiguration("mixins.replay.replaymod.json");
|
||||||
|
Mixins.addConfiguration("mixins.compat.shaders.replaymod.json");
|
||||||
|
|
||||||
CodeSource codeSource = getClass().getProtectionDomain().getCodeSource();
|
CodeSource codeSource = getClass().getProtectionDomain().getCodeSource();
|
||||||
if (codeSource != null) {
|
if (codeSource != null) {
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ import com.replaymod.render.frame.ODSOpenGlFrame;
|
|||||||
import com.replaymod.render.frame.OpenGlFrame;
|
import com.replaymod.render.frame.OpenGlFrame;
|
||||||
import com.replaymod.render.rendering.FrameCapturer;
|
import com.replaymod.render.rendering.FrameCapturer;
|
||||||
import com.replaymod.render.shader.Program;
|
import com.replaymod.render.shader.Program;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.renderer.GlStateManager;
|
import net.minecraft.client.renderer.GlStateManager;
|
||||||
import net.minecraft.crash.CrashReport;
|
import net.minecraft.crash.CrashReport;
|
||||||
import net.minecraft.util.ReportedException;
|
import net.minecraft.util.ReportedException;
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
import org.lwjgl.util.Dimension;
|
|
||||||
import org.lwjgl.util.ReadableDimension;
|
import org.lwjgl.util.ReadableDimension;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -31,6 +31,8 @@ public class ODSFrameCapturer implements FrameCapturer<ODSOpenGlFrame> {
|
|||||||
private final BooleanState[] previousStates = new BooleanState[3];
|
private final BooleanState[] previousStates = new BooleanState[3];
|
||||||
private final BooleanState previousFogState;
|
private final BooleanState previousFogState;
|
||||||
|
|
||||||
|
private final Minecraft mc = Minecraft.getMinecraft();
|
||||||
|
|
||||||
public ODSFrameCapturer(WorldRenderer worldRenderer, final RenderInfo renderInfo, int frameSize) {
|
public ODSFrameCapturer(WorldRenderer worldRenderer, final RenderInfo renderInfo, int frameSize) {
|
||||||
RenderInfo fakeInfo = new RenderInfo() {
|
RenderInfo fakeInfo = new RenderInfo() {
|
||||||
private int call;
|
private int call;
|
||||||
@@ -143,6 +145,8 @@ public class ODSFrameCapturer implements FrameCapturer<ODSOpenGlFrame> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected OpenGlFrame renderFrame(int frameId, float partialTicks, CubicOpenGlFrameCapturer.Data captureData) {
|
protected OpenGlFrame renderFrame(int frameId, float partialTicks, CubicOpenGlFrameCapturer.Data captureData) {
|
||||||
|
resize(getFrameWidth(), getFrameHeight());
|
||||||
|
|
||||||
pushMatrix();
|
pushMatrix();
|
||||||
frameBuffer().bindFramebuffer(true);
|
frameBuffer().bindFramebuffer(true);
|
||||||
|
|
||||||
@@ -150,7 +154,7 @@ public class ODSFrameCapturer implements FrameCapturer<ODSOpenGlFrame> {
|
|||||||
enableTexture2D();
|
enableTexture2D();
|
||||||
|
|
||||||
directionVariable.set(captureData.ordinal());
|
directionVariable.set(captureData.ordinal());
|
||||||
worldRenderer.renderWorld(new Dimension(getFrameWidth(), getFrameHeight()), partialTicks, null);
|
worldRenderer.renderWorld(partialTicks, null);
|
||||||
|
|
||||||
frameBuffer().unbindFramebuffer();
|
frameBuffer().unbindFramebuffer();
|
||||||
popMatrix();
|
popMatrix();
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.replaymod.render.frame.OpenGlFrame;
|
|||||||
import com.replaymod.render.rendering.Frame;
|
import com.replaymod.render.rendering.Frame;
|
||||||
import com.replaymod.render.rendering.FrameCapturer;
|
import com.replaymod.render.rendering.FrameCapturer;
|
||||||
import com.replaymod.render.utils.ByteBufferPool;
|
import com.replaymod.render.utils.ByteBufferPool;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.renderer.OpenGlHelper;
|
import net.minecraft.client.renderer.OpenGlHelper;
|
||||||
import net.minecraft.client.shader.Framebuffer;
|
import net.minecraft.client.shader.Framebuffer;
|
||||||
import org.lwjgl.opengl.GL11;
|
import org.lwjgl.opengl.GL11;
|
||||||
@@ -24,6 +25,8 @@ public abstract class OpenGlFrameCapturer<F extends Frame, D extends CaptureData
|
|||||||
protected int framesDone;
|
protected int framesDone;
|
||||||
private Framebuffer frameBuffer;
|
private Framebuffer frameBuffer;
|
||||||
|
|
||||||
|
private final Minecraft mc = Minecraft.getMinecraft();
|
||||||
|
|
||||||
public OpenGlFrameCapturer(WorldRenderer worldRenderer, RenderInfo renderInfo) {
|
public OpenGlFrameCapturer(WorldRenderer worldRenderer, RenderInfo renderInfo) {
|
||||||
this.worldRenderer = worldRenderer;
|
this.worldRenderer = worldRenderer;
|
||||||
this.renderInfo = renderInfo;
|
this.renderInfo = renderInfo;
|
||||||
@@ -56,7 +59,7 @@ public abstract class OpenGlFrameCapturer<F extends Frame, D extends CaptureData
|
|||||||
|
|
||||||
protected Framebuffer frameBuffer() {
|
protected Framebuffer frameBuffer() {
|
||||||
if (frameBuffer == null) {
|
if (frameBuffer == null) {
|
||||||
frameBuffer = new Framebuffer(getFrameWidth(), getFrameHeight(), true);
|
frameBuffer = Minecraft.getMinecraft().getFramebuffer();
|
||||||
}
|
}
|
||||||
return frameBuffer;
|
return frameBuffer;
|
||||||
}
|
}
|
||||||
@@ -71,13 +74,15 @@ public abstract class OpenGlFrameCapturer<F extends Frame, D extends CaptureData
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected OpenGlFrame renderFrame(int frameId, float partialTicks, D captureData) {
|
protected OpenGlFrame renderFrame(int frameId, float partialTicks, D captureData) {
|
||||||
|
resize(getFrameWidth(), getFrameHeight());
|
||||||
|
|
||||||
pushMatrix();
|
pushMatrix();
|
||||||
frameBuffer().bindFramebuffer(true);
|
frameBuffer().bindFramebuffer(true);
|
||||||
|
|
||||||
clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
enableTexture2D();
|
enableTexture2D();
|
||||||
|
|
||||||
worldRenderer.renderWorld(frameSize, partialTicks, captureData);
|
worldRenderer.renderWorld(partialTicks, captureData);
|
||||||
|
|
||||||
frameBuffer().unbindFramebuffer();
|
frameBuffer().unbindFramebuffer();
|
||||||
popMatrix();
|
popMatrix();
|
||||||
@@ -102,11 +107,18 @@ public abstract class OpenGlFrameCapturer<F extends Frame, D extends CaptureData
|
|||||||
return new OpenGlFrame(frameId, new Dimension(getFrameWidth(), getFrameHeight()), buffer);
|
return new OpenGlFrame(frameId, new Dimension(getFrameWidth(), getFrameHeight()), buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void resize(int width, int height) {
|
||||||
|
if (width != mc.displayWidth || height != mc.displayHeight) {
|
||||||
|
setWindowSize(width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setWindowSize(int width, int height) {
|
||||||
|
mc.resize(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
worldRenderer.close();
|
worldRenderer.close();
|
||||||
if (frameBuffer != null) {
|
|
||||||
frameBuffer.deleteFramebuffer();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
package com.replaymod.render.capturer;
|
package com.replaymod.render.capturer;
|
||||||
|
|
||||||
import org.lwjgl.util.ReadableDimension;
|
|
||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
|
|
||||||
public interface WorldRenderer extends Closeable {
|
public interface WorldRenderer extends Closeable {
|
||||||
void renderWorld(ReadableDimension displaySize, float partialTicks, CaptureData data);
|
void renderWorld(float partialTicks, CaptureData data);
|
||||||
void setOmnidirectional(boolean omnidirectional);
|
void setOmnidirectional(boolean omnidirectional);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import de.johni0702.minecraft.gui.element.advanced.GuiProgressBar;
|
|||||||
import de.johni0702.minecraft.gui.layout.CustomLayout;
|
import de.johni0702.minecraft.gui.layout.CustomLayout;
|
||||||
import de.johni0702.minecraft.gui.layout.HorizontalLayout;
|
import de.johni0702.minecraft.gui.layout.HorizontalLayout;
|
||||||
import net.minecraft.client.renderer.texture.DynamicTexture;
|
import net.minecraft.client.renderer.texture.DynamicTexture;
|
||||||
import net.minecraft.client.renderer.texture.TextureUtil;
|
|
||||||
import net.minecraft.client.resources.I18n;
|
import net.minecraft.client.resources.I18n;
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
import org.lwjgl.util.Dimension;
|
import org.lwjgl.util.Dimension;
|
||||||
@@ -23,8 +22,6 @@ import org.lwjgl.util.ReadablePoint;
|
|||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import static net.minecraft.client.renderer.GlStateManager.bindTexture;
|
|
||||||
|
|
||||||
public class GuiVideoRenderer extends GuiScreen {
|
public class GuiVideoRenderer extends GuiScreen {
|
||||||
private static final ResourceLocation NO_PREVIEW_TEXTURE = new ResourceLocation("replaymod", "logo.jpg");
|
private static final ResourceLocation NO_PREVIEW_TEXTURE = new ResourceLocation("replaymod", "logo.jpg");
|
||||||
|
|
||||||
@@ -232,13 +229,7 @@ public class GuiVideoRenderer extends GuiScreen {
|
|||||||
final int videoHeight = videoSize.getHeight();
|
final int videoHeight = videoSize.getHeight();
|
||||||
|
|
||||||
if (previewTexture == null) {
|
if (previewTexture == null) {
|
||||||
previewTexture = new DynamicTexture(videoWidth, videoHeight) {
|
previewTexture = new DynamicTexture(videoWidth, videoHeight);
|
||||||
@Override
|
|
||||||
public void updateDynamicTexture() {
|
|
||||||
bindTexture(getGlTextureId());
|
|
||||||
TextureUtil.uploadTextureSub(0, getTextureData(), videoWidth, videoHeight, 0, 0, true, false, false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (previewTextureDirty) {
|
if (previewTextureDirty) {
|
||||||
@@ -273,7 +264,10 @@ public class GuiVideoRenderer extends GuiScreen {
|
|||||||
buffer.mark();
|
buffer.mark();
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
int[] data = previewTexture.getTextureData();
|
int[] data = previewTexture.getTextureData();
|
||||||
for (int i = 0; i < data.length; i++) {
|
// Optifine changes the texture data array to be three times as long (for use by shaders),
|
||||||
|
// we only want to initialize the first third which is why we use the length of the buffer instead
|
||||||
|
// of the length of the data array
|
||||||
|
for (int i = 0; buffer.remaining() > 0; i++) {
|
||||||
data[i] = 0xff << 24 | (buffer.get() & 0xff) << 16 | (buffer.get() & 0xff) << 8 | (buffer.get() & 0xff);
|
data[i] = 0xff << 24 | (buffer.get() & 0xff) << 16 | (buffer.get() & 0xff) << 8 | (buffer.get() & 0xff);
|
||||||
}
|
}
|
||||||
previewTextureDirty = true;
|
previewTextureDirty = true;
|
||||||
|
|||||||
@@ -5,14 +5,11 @@ import com.replaymod.render.capturer.CaptureData;
|
|||||||
import com.replaymod.render.capturer.WorldRenderer;
|
import com.replaymod.render.capturer.WorldRenderer;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.renderer.culling.ClippingHelper;
|
import net.minecraft.client.renderer.GlStateManager;
|
||||||
import net.minecraftforge.fml.common.FMLCommonHandler;
|
import net.minecraftforge.fml.common.FMLCommonHandler;
|
||||||
import org.lwjgl.util.ReadableDimension;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import static net.minecraft.client.renderer.GlStateManager.*;
|
|
||||||
|
|
||||||
public class EntityRendererHandler implements WorldRenderer {
|
public class EntityRendererHandler implements WorldRenderer {
|
||||||
public final Minecraft mc = Minecraft.getMinecraft();
|
public final Minecraft mc = Minecraft.getMinecraft();
|
||||||
|
|
||||||
@@ -29,37 +26,20 @@ public class EntityRendererHandler implements WorldRenderer {
|
|||||||
((IEntityRenderer) mc.entityRenderer).replayModRender_setHandler(this);
|
((IEntityRenderer) mc.entityRenderer).replayModRender_setHandler(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void withDisplaySize(int displayWidth, int displayHeight, Runnable runnable) {
|
|
||||||
final int prevWidth = mc.displayWidth;
|
|
||||||
final int prevHeight = mc.displayHeight;
|
|
||||||
mc.displayWidth = displayWidth;
|
|
||||||
mc.displayHeight = displayHeight;
|
|
||||||
|
|
||||||
runnable.run();
|
|
||||||
|
|
||||||
mc.displayWidth = prevWidth;
|
|
||||||
mc.displayHeight = prevHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderWorld(ReadableDimension displaySize, final float partialTicks, CaptureData data) {
|
public void renderWorld(final float partialTicks, CaptureData data) {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
withDisplaySize(displaySize.getWidth(), displaySize.getHeight(), new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
renderWorld(partialTicks, 0);
|
renderWorld(partialTicks, 0);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void renderWorld(float partialTicks, long finishTimeNano) {
|
public void renderWorld(float partialTicks, long finishTimeNano) {
|
||||||
FMLCommonHandler.instance().onRenderTickStart(partialTicks);
|
FMLCommonHandler.instance().onRenderTickStart(partialTicks);
|
||||||
|
|
||||||
mc.entityRenderer.updateLightmap(partialTicks);
|
mc.entityRenderer.updateLightmap(partialTicks);
|
||||||
|
|
||||||
enableDepth();
|
GlStateManager.enableDepth();
|
||||||
enableAlpha();
|
GlStateManager.enableAlpha();
|
||||||
alphaFunc(516, 0.5F);
|
GlStateManager.alphaFunc(516, 0.5F);
|
||||||
|
|
||||||
mc.entityRenderer.renderWorldPass(2, partialTicks, finishTimeNano);
|
mc.entityRenderer.renderWorldPass(2, partialTicks, finishTimeNano);
|
||||||
|
|
||||||
@@ -76,13 +56,6 @@ public class EntityRendererHandler implements WorldRenderer {
|
|||||||
this.omnidirectional = omnidirectional;
|
this.omnidirectional = omnidirectional;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class NoCullingClippingHelper extends ClippingHelper {
|
|
||||||
@Override
|
|
||||||
public boolean isBoxInFrustum(double p_78553_1_, double p_78553_3_, double p_78553_5_, double p_78553_7_, double p_78553_9_, double p_78553_11_) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface GluPerspective {
|
public interface GluPerspective {
|
||||||
void replayModRender_gluPerspective(float fovY, float aspect, float zNear, float zFar);
|
void replayModRender_gluPerspective(float fovY, float aspect, float zNear, float zFar);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import net.minecraft.client.Minecraft;
|
|||||||
import net.minecraft.client.renderer.EntityRenderer;
|
import net.minecraft.client.renderer.EntityRenderer;
|
||||||
import net.minecraft.client.renderer.GlStateManager;
|
import net.minecraft.client.renderer.GlStateManager;
|
||||||
import net.minecraft.client.renderer.RenderGlobal;
|
import net.minecraft.client.renderer.RenderGlobal;
|
||||||
import net.minecraft.client.renderer.culling.Frustum;
|
|
||||||
import net.minecraft.client.settings.GameSettings;
|
import net.minecraft.client.settings.GameSettings;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
@@ -49,14 +48,6 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Redirect(method = "renderWorldPass", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/culling/Frustum;setPosition(DDD)V"))
|
|
||||||
public void replayModRender_createNoCullingFrustum(Frustum frustum, double x, double y, double z) {
|
|
||||||
if (replayModRender_handler != null) {
|
|
||||||
frustum.clippingHelper = new EntityRendererHandler.NoCullingClippingHelper();
|
|
||||||
}
|
|
||||||
frustum.setPosition(x, y, z);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "orientCamera", at = @At("HEAD"))
|
@Inject(method = "orientCamera", at = @At("HEAD"))
|
||||||
private void replayModRender_resetRotationIfNeeded(float partialTicks, CallbackInfo ci) {
|
private void replayModRender_resetRotationIfNeeded(float partialTicks, CallbackInfo ci) {
|
||||||
if (replayModRender_handler != null) {
|
if (replayModRender_handler != null) {
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ public abstract class MixinRenderGlobal {
|
|||||||
replayModRender_hook.updateChunks();
|
replayModRender_hook.updateChunks();
|
||||||
} while (displayListEntitiesDirty);
|
} while (displayListEntitiesDirty);
|
||||||
|
|
||||||
|
displayListEntitiesDirty = true;
|
||||||
|
|
||||||
replayModRender_passThroughSetupTerrain = false;
|
replayModRender_passThroughSetupTerrain = false;
|
||||||
ci.cancel();
|
ci.cancel();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import com.replaymod.replaystudio.pathing.path.Timeline;
|
|||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.ScaledResolution;
|
import net.minecraft.client.gui.ScaledResolution;
|
||||||
import net.minecraft.client.renderer.OpenGlHelper;
|
import net.minecraft.client.renderer.OpenGlHelper;
|
||||||
|
import net.minecraft.client.shader.Framebuffer;
|
||||||
import net.minecraft.util.SoundCategory;
|
import net.minecraft.util.SoundCategory;
|
||||||
import net.minecraft.util.Timer;
|
import net.minecraft.util.Timer;
|
||||||
import org.lwjgl.input.Mouse;
|
import org.lwjgl.input.Mouse;
|
||||||
@@ -62,6 +63,9 @@ public class VideoRenderer implements RenderInfo {
|
|||||||
private boolean paused;
|
private boolean paused;
|
||||||
private boolean cancelled;
|
private boolean cancelled;
|
||||||
|
|
||||||
|
private Framebuffer guiFramebuffer;
|
||||||
|
private int displayWidth, displayHeight;
|
||||||
|
|
||||||
public VideoRenderer(RenderSettings settings, ReplayHandler replayHandler, Timeline timeline) throws IOException {
|
public VideoRenderer(RenderSettings settings, ReplayHandler replayHandler, Timeline timeline) throws IOException {
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
this.replayHandler = replayHandler;
|
this.replayHandler = replayHandler;
|
||||||
@@ -130,6 +134,13 @@ public class VideoRenderer implements RenderInfo {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float updateForNextFrame() {
|
public float updateForNextFrame() {
|
||||||
|
// because the jGui lib uses Minecraft's displayWidth and displayHeight values, update these temporarily
|
||||||
|
int displayWidthBefore = mc.displayWidth;
|
||||||
|
int displayHeightBefore = mc.displayHeight;
|
||||||
|
|
||||||
|
mc.displayWidth = displayWidth;
|
||||||
|
mc.displayHeight = displayHeight;
|
||||||
|
|
||||||
if (!settings.isHighPerformance() || framesDone % fps == 0) {
|
if (!settings.isHighPerformance() || framesDone % fps == 0) {
|
||||||
drawGui();
|
drawGui();
|
||||||
}
|
}
|
||||||
@@ -142,6 +153,10 @@ public class VideoRenderer implements RenderInfo {
|
|||||||
tick();
|
tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// change Minecraft's display size back
|
||||||
|
mc.displayWidth = displayWidthBefore;
|
||||||
|
mc.displayHeight = displayHeightBefore;
|
||||||
|
|
||||||
framesDone++;
|
framesDone++;
|
||||||
return mc.timer.renderPartialTicks;
|
return mc.timer.renderPartialTicks;
|
||||||
}
|
}
|
||||||
@@ -192,10 +207,12 @@ public class VideoRenderer implements RenderInfo {
|
|||||||
|
|
||||||
totalFrames = (int) (duration*fps/1000);
|
totalFrames = (int) (duration*fps/1000);
|
||||||
|
|
||||||
ScaledResolution scaled = new ScaledResolution(mc);
|
updateDisplaySize();
|
||||||
gui.toMinecraft().setWorldAndResolution(mc, scaled.getScaledWidth(), scaled.getScaledHeight());
|
|
||||||
|
|
||||||
chunkLoadingRenderGlobal = new ChunkLoadingRenderGlobal(mc.renderGlobal);
|
chunkLoadingRenderGlobal = new ChunkLoadingRenderGlobal(mc.renderGlobal);
|
||||||
|
|
||||||
|
// Set up our own framebuffer to render the GUI to
|
||||||
|
guiFramebuffer = new Framebuffer(displayWidth, displayHeight, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void finish() {
|
private void finish() {
|
||||||
@@ -219,6 +236,9 @@ public class VideoRenderer implements RenderInfo {
|
|||||||
new SoundHandler().playRenderSuccessSound();
|
new SoundHandler().playRenderSuccessSound();
|
||||||
|
|
||||||
new GuiRenderingDone(ReplayModRender.instance, videoWriter.getVideoFile(), totalFrames, settings).display();
|
new GuiRenderingDone(ReplayModRender.instance, videoWriter.getVideoFile(), totalFrames, settings).display();
|
||||||
|
|
||||||
|
// Finally, resize the Minecraft framebuffer to the actual width/height of the window
|
||||||
|
mc.resize(displayWidth, displayHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tick() {
|
private void tick() {
|
||||||
@@ -238,12 +258,22 @@ public class VideoRenderer implements RenderInfo {
|
|||||||
|
|
||||||
public void drawGui() {
|
public void drawGui() {
|
||||||
do {
|
do {
|
||||||
|
// Resize the GUI framebuffer if the display size changed
|
||||||
|
if (!settings.isHighPerformance() && displaySizeChanged()) {
|
||||||
|
updateDisplaySize();
|
||||||
|
guiFramebuffer.createBindFramebuffer(mc.displayWidth, mc.displayHeight);
|
||||||
|
}
|
||||||
|
|
||||||
pushMatrix();
|
pushMatrix();
|
||||||
clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
enableTexture2D();
|
enableTexture2D();
|
||||||
mc.getFramebuffer().bindFramebuffer(true);
|
guiFramebuffer.bindFramebuffer(true);
|
||||||
|
|
||||||
mc.entityRenderer.setupOverlayRendering();
|
mc.entityRenderer.setupOverlayRendering();
|
||||||
|
|
||||||
|
ScaledResolution scaled = new ScaledResolution(mc);
|
||||||
|
gui.toMinecraft().setWorldAndResolution(mc, scaled.getScaledWidth(), scaled.getScaledHeight());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
gui.toMinecraft().handleInput();
|
gui.toMinecraft().handleInput();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -252,18 +282,17 @@ public class VideoRenderer implements RenderInfo {
|
|||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScaledResolution scaled = new ScaledResolution(mc);
|
|
||||||
int mouseX = Mouse.getX() * scaled.getScaledWidth() / mc.displayWidth;
|
int mouseX = Mouse.getX() * scaled.getScaledWidth() / mc.displayWidth;
|
||||||
int mouseY = scaled.getScaledHeight() - Mouse.getY() * scaled.getScaledHeight() / mc.displayHeight - 1;
|
int mouseY = scaled.getScaledHeight() - Mouse.getY() * scaled.getScaledHeight() / mc.displayHeight - 1;
|
||||||
|
|
||||||
gui.toMinecraft().drawScreen(mouseX, mouseY, 0);
|
gui.toMinecraft().drawScreen(mouseX, mouseY, 0);
|
||||||
|
|
||||||
mc.getFramebuffer().unbindFramebuffer();
|
guiFramebuffer.unbindFramebuffer();
|
||||||
popMatrix();
|
popMatrix();
|
||||||
pushMatrix();
|
pushMatrix();
|
||||||
mc.getFramebuffer().framebufferRender(mc.displayWidth, mc.displayHeight);
|
guiFramebuffer.framebufferRender(displayWidth, displayHeight);
|
||||||
popMatrix();
|
popMatrix();
|
||||||
|
|
||||||
|
|
||||||
// if not in high performance mode, update the gui size if screen size changed
|
// if not in high performance mode, update the gui size if screen size changed
|
||||||
// otherwise just swap the progress gui to screen
|
// otherwise just swap the progress gui to screen
|
||||||
if (settings.isHighPerformance()) {
|
if (settings.isHighPerformance()) {
|
||||||
@@ -285,6 +314,15 @@ public class VideoRenderer implements RenderInfo {
|
|||||||
} while (paused);
|
} while (paused);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean displaySizeChanged() {
|
||||||
|
return displayWidth != Display.getWidth() || displayHeight != Display.getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDisplaySize() {
|
||||||
|
displayWidth = Display.getWidth();
|
||||||
|
displayHeight = Display.getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
public int getFramesDone() {
|
public int getFramesDone() {
|
||||||
return framesDone;
|
return framesDone;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,10 +29,7 @@ import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher;
|
|||||||
import org.lwjgl.opengl.Display;
|
import org.lwjgl.opengl.Display;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.*;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import static net.minecraft.client.renderer.GlStateManager.*;
|
import static net.minecraft.client.renderer.GlStateManager.*;
|
||||||
import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
|
import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
|
||||||
|
|||||||
@@ -116,5 +116,22 @@
|
|||||||
"parent": "replaymod",
|
"parent": "replaymod",
|
||||||
"screenshots": [],
|
"screenshots": [],
|
||||||
"dependencies": []
|
"dependencies": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"modid": "replaymod-compat",
|
||||||
|
"name": "Replay Mod - Compatibility",
|
||||||
|
"description": "Compatibility Module of the ReplayMod - Adds compatibility with other mods",
|
||||||
|
"version": "${version}",
|
||||||
|
"mcversion": "${mcversion}",
|
||||||
|
"url": "https://replaymod.com",
|
||||||
|
"updateUrl": "https://replaymod.com/download",
|
||||||
|
"authorList": [
|
||||||
|
"CrushedPixel",
|
||||||
|
"johni0702"
|
||||||
|
],
|
||||||
|
"logoFile": "replaymod_logo.png",
|
||||||
|
"parent": "replaymod",
|
||||||
|
"screenshots": [],
|
||||||
|
"dependencies": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
12
src/main/resources/mixins.compat.shaders.replaymod.json
Normal file
12
src/main/resources/mixins.compat.shaders.replaymod.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"required": false,
|
||||||
|
"package": "com.replaymod.compat.shaders.mixin",
|
||||||
|
"mixins": [],
|
||||||
|
"server": [],
|
||||||
|
"client": [
|
||||||
|
"MixinShaderEntityRenderer",
|
||||||
|
"MixinShaderRenderChunk",
|
||||||
|
"MixinShaderRenderGlobal"
|
||||||
|
],
|
||||||
|
"refmap": "mixins.replaymod.refmap.json"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user