Merge branch '1.8-shaders' into 1.8

This commit is contained in:
johni0702
2016-11-10 21:22:08 +01:00
17 changed files with 375 additions and 70 deletions

View File

@@ -0,0 +1,23 @@
package com.replaymod.compat;
import com.replaymod.compat.shaders.ShaderBeginRender;
import com.replaymod.core.ReplayMod;
import net.minecraftforge.fml.common.FMLCommonHandler;
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 = FMLCommonHandler.instance().bus();
bus.register(new ShaderBeginRender());
}
}

View File

@@ -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();
}
}
}

View 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();
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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);
}
}

View File

@@ -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) {}
}
}

View File

@@ -19,6 +19,7 @@ public class LoadingPlugin implements IFMLLoadingPlugin {
MixinEnvironment.getDefaultEnvironment().addConfiguration("mixins.recording.replaymod.json"); MixinEnvironment.getDefaultEnvironment().addConfiguration("mixins.recording.replaymod.json");
MixinEnvironment.getDefaultEnvironment().addConfiguration("mixins.render.replaymod.json"); MixinEnvironment.getDefaultEnvironment().addConfiguration("mixins.render.replaymod.json");
MixinEnvironment.getDefaultEnvironment().addConfiguration("mixins.replay.replaymod.json"); MixinEnvironment.getDefaultEnvironment().addConfiguration("mixins.replay.replaymod.json");
MixinEnvironment.getDefaultEnvironment().addConfiguration("mixins.compat.shaders.replaymod.json");
CodeSource codeSource = getClass().getProtectionDomain().getCodeSource(); CodeSource codeSource = getClass().getProtectionDomain().getCodeSource();
if (codeSource != null) { if (codeSource != null) {

View File

@@ -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();

View File

@@ -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();
}
} }
} }

View File

@@ -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);
} }

View File

@@ -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;

View File

@@ -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);
} }

View File

@@ -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) {

View File

@@ -39,6 +39,8 @@ public abstract class MixinRenderGlobal {
setupTerrain(viewEntity, partialTicks, camera, replayModRender_hook.nextFrameId(), playerSpectator); setupTerrain(viewEntity, partialTicks, camera, replayModRender_hook.nextFrameId(), playerSpectator);
} while (displayListEntitiesDirty); } while (displayListEntitiesDirty);
displayListEntitiesDirty = true;
replayModRender_passThroughSetupTerrain = false; replayModRender_passThroughSetupTerrain = false;
ci.cancel(); ci.cancel();
} }

View File

@@ -20,6 +20,7 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.SoundCategory; import net.minecraft.client.audio.SoundCategory;
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.Timer; import net.minecraft.util.Timer;
import org.lwjgl.input.Mouse; import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display; import org.lwjgl.opengl.Display;
@@ -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,15 @@ public class VideoRenderer implements RenderInfo {
totalFrames = (int) (duration*fps/1000); totalFrames = (int) (duration*fps/1000);
ScaledResolution scaled = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight); updateDisplaySize();
ScaledResolution scaled = new ScaledResolution(mc, displayWidth, displayHeight);
gui.toMinecraft().setWorldAndResolution(mc, scaled.getScaledWidth(), scaled.getScaledHeight()); 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 +239,9 @@ public class VideoRenderer implements RenderInfo {
ReplayMod.soundHandler.playRenderSuccessSound(); ReplayMod.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 +261,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, mc.displayWidth, mc.displayHeight);
gui.toMinecraft().setWorldAndResolution(mc, scaled.getScaledWidth(), scaled.getScaledHeight());
try { try {
gui.toMinecraft().handleInput(); gui.toMinecraft().handleInput();
} catch (IOException e) { } catch (IOException e) {
@@ -252,18 +285,17 @@ public class VideoRenderer implements RenderInfo {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
ScaledResolution scaled = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight);
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 +317,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;
} }

View File

@@ -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": []
} }
] ]

View File

@@ -0,0 +1,12 @@
{
"required": false,
"package": "com.replaymod.compat.shaders.mixin",
"mixins": [],
"server": [],
"client": [
"MixinShaderEntityRenderer",
"MixinShaderRenderChunk",
"MixinShaderRenderGlobal"
],
"refmap": "mixins.replaymod.refmap.json"
}