Merge branch 'johni/1.13-pre' into johni/blend

This commit is contained in:
Jonas Herzig
2019-03-13 16:07:32 +01:00
177 changed files with 7973 additions and 3552 deletions

View File

@@ -1,12 +1,29 @@
package com.replaymod.render;
import com.replaymod.core.versions.MCVer;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableColor;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import net.minecraft.client.resources.I18n;
import org.lwjgl.util.ReadableColor;
import net.minecraft.util.Util;
import java.io.File;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Optional;
import static com.replaymod.render.ReplayModRender.LOGGER;
//#if MC>=11300
import org.apache.maven.artifact.versioning.ComparableVersion;
//#else
//#if MC>=10800
//$$ import net.minecraftforge.fml.common.versioning.ComparableVersion;
//#else
//$$ import cpw.mods.fml.common.versioning.ComparableVersion;
//#endif
//#endif
@Data
public class RenderSettings {
@@ -21,6 +38,14 @@ public class RenderSettings {
public String getDescription() {
return I18n.format("replaymod.gui.rendersettings.renderer." + name().toLowerCase() + ".description");
}
public boolean isSpherical() {
return this == EQUIRECTANGULAR || this == ODS;
}
public boolean hasFixedAspectRatio() {
return this == EQUIRECTANGULAR || this == ODS || this == CUBIC;
}
}
public enum EncodingPreset {
@@ -49,7 +74,7 @@ public class RenderSettings {
}
public String getValue() {
return "-y -f rawvideo -pix_fmt rgb24 -s %WIDTH%x%HEIGHT% -r %FPS% -i - %FILTERS%" + preset;
return "-y -f rawvideo -pix_fmt bgra -s %WIDTH%x%HEIGHT% -r %FPS% -i - %FILTERS%" + preset;
}
public String getFileExtension() {
@@ -94,7 +119,9 @@ public class RenderSettings {
private final boolean stabilizePitch;
private final boolean stabilizeRoll;
private final ReadableColor chromaKeyingColor;
private final boolean inject360Metadata;
private final int sphericalFovX;
private final int sphericalFovY;
private final boolean injectSphericalMetadata;
private final AntiAliasing antiAliasing;
private final String exportCommand;
@@ -131,12 +158,66 @@ public class RenderSettings {
}
public String getVideoFilters() {
if (antiAliasing == AntiAliasing.NONE) {
return "";
} else {
StringBuilder filters = new StringBuilder();
if (antiAliasing != AntiAliasing.NONE) {
double factor = 1.0 / antiAliasing.getFactor();
return String.format("-vf scale=iw*%1$s:ih*%1$s ", factor);
filters.append(String.format("-filter:v scale=iw*%1$s:ih*%1$s ", factor));
}
return filters.toString();
}
public String getExportCommandOrDefault() {
return exportCommand.isEmpty() ? findFFmpeg() : exportCommand;
}
private static String findFFmpeg() {
switch (Util.getOSType()) {
case WINDOWS:
// Allow windows users to unpack the ffmpeg archive into a sub-folder of their .minecraft folder
File inDotMinecraft = new File(MCVer.mcDataDir(MCVer.getMinecraft()), "ffmpeg/bin/ffmpeg.exe");
if (inDotMinecraft.exists()) {
LOGGER.debug("FFmpeg found in .minecraft/ffmpeg");
return inDotMinecraft.getAbsolutePath();
}
break;
case OSX:
// The PATH doesn't seem to be set as expected on OSX, therefore we check some common locations ourselves
for (String path : new String[]{"/usr/local/bin/ffmpeg", "/usr/bin/ffmpeg"}) {
File file = new File(path);
if (file.exists()) {
LOGGER.debug("Found FFmpeg at {}", path);
return path;
} else {
LOGGER.debug("FFmpeg not located at {}", path);
}
}
// Homebrew doesn't seem to reliably symlink its installed binaries either
File homebrewFolder = new File("/usr/local/Cellar/ffmpeg");
String[] homebrewVersions = homebrewFolder.list();
if (homebrewVersions != null) {
Optional<File> latestOpt = Arrays.stream(homebrewVersions)
.map(ComparableVersion::new) // Convert file name to comparable version
.sorted(Comparator.reverseOrder()) // Sort for latest version
.map(ComparableVersion::toString) // Convert back to file name
.map(v -> new File(new File(homebrewFolder, v), "bin/ffmpeg")) // Convert to binary files
.filter(File::exists) // Filter invalid installations (missing executable)
.findFirst(); // Take first one
if (latestOpt.isPresent()) {
File latest = latestOpt.get();
LOGGER.debug("Found {} versions of FFmpeg installed with homebrew, chose {}",
homebrewVersions.length, latest);
return latest.getAbsolutePath();
}
}
break;
case LINUX: // Linux users are entrusted to have their PATH configured correctly (most package manager do this)
case SOLARIS: // Never heard of anyone running this mod on Solaris having any problems
case UNKNOWN: // Unknown OS, just try to use "ffmpeg"
}
LOGGER.debug("Using default FFmpeg executable");
return "ffmpeg";
}
}

View File

@@ -1,65 +1,57 @@
package com.replaymod.render;
import com.replaymod.core.Module;
import com.replaymod.core.ReplayMod;
import com.replaymod.render.utils.RenderJob;
import com.replaymod.replay.events.ReplayCloseEvent;
import net.minecraft.crash.CrashReport;
import net.minecraft.util.ReportedException;
import net.minecraftforge.common.config.Configuration;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
//#if MC>=10800
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#if MC>=11300
import net.minecraftforge.eventbus.api.SubscribeEvent;
//#else
//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//#endif
//#else
//$$ import cpw.mods.fml.common.Mod;
//$$ import cpw.mods.fml.common.event.FMLPreInitializationEvent;
//$$ import cpw.mods.fml.common.eventhandler.SubscribeEvent;
//#endif
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import static com.replaymod.core.versions.MCVer.*;
@Mod(modid = ReplayModRender.MOD_ID,
version = "@MOD_VERSION@",
acceptedMinecraftVersions = "@MC_VERSION@",
acceptableRemoteVersions = "*",
//#if MC>=10800
clientSideOnly = true,
//#endif
useMetadata = true)
public class ReplayModRender {
public static final String MOD_ID = "replaymod-render";
@Mod.Instance(MOD_ID)
public class ReplayModRender implements Module {
{ instance = this; }
public static ReplayModRender instance;
private ReplayMod core;
public static Logger LOGGER;
public static Logger LOGGER = LogManager.getLogger();
private Configuration configuration;
private final List<RenderJob> renderQueue = new ArrayList<>();
public ReplayModRender(ReplayMod core) {
this.core = core;
core.getSettingsRegistry().register(Setting.class);
}
public ReplayMod getCore() {
return core;
}
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
LOGGER = event.getModLog();
core = ReplayMod.instance;
configuration = new Configuration(event.getSuggestedConfigurationFile());
@Override
public void initClient() {
FML_BUS.register(this);
core.getSettingsRegistry().register(Setting.class);
}
@SubscribeEvent
@@ -69,17 +61,17 @@ public class ReplayModRender {
public File getVideoFolder() {
String path = core.getSettingsRegistry().get(Setting.RENDER_PATH);
File folder = new File(path.startsWith("./") ? core.getMinecraft().mcDataDir : null, path);
File folder = new File(path.startsWith("./") ? mcDataDir(core.getMinecraft()) : null, path);
try {
FileUtils.forceMkdir(folder);
} catch (IOException e) {
throw new ReportedException(CrashReport.makeCrashReport(e, "Cannot create video folder."));
throw newReportedException(CrashReport.makeCrashReport(e, "Cannot create video folder."));
}
return folder;
}
public Configuration getConfiguration() {
return configuration;
public Path getRenderSettingsPath() {
return mcDataDir(core.getMinecraft()).toPath().resolve("config/replaymod-rendersettings.json");
}
public List<RenderJob> getRenderQueue() {

View File

@@ -1,19 +1,18 @@
package com.replaymod.render;
import com.replaymod.core.versions.MCVer;
import com.replaymod.render.frame.RGBFrame;
import com.replaymod.render.rendering.FrameConsumer;
import com.replaymod.render.rendering.VideoRenderer;
import com.replaymod.render.utils.ByteBufferPool;
import com.replaymod.render.utils.StreamPipe;
import net.minecraft.client.Minecraft;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import net.minecraft.crash.CrashReport;
import net.minecraft.crash.CrashReportCategory;
import net.minecraft.util.Util;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.TeeOutputStream;
import org.lwjgl.util.ReadableDimension;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -22,17 +21,8 @@ import java.io.IOException;
import java.io.OutputStream;
import java.nio.channels.Channels;
import java.nio.channels.WritableByteChannel;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
//#if MC>=10800
import net.minecraftforge.fml.common.versioning.ComparableVersion;
//#else
//$$ import cpw.mods.fml.common.versioning.ComparableVersion;
//#endif
import static com.replaymod.render.ReplayModRender.LOGGER;
import static org.apache.commons.lang3.Validate.isTrue;
@@ -64,7 +54,7 @@ public class VideoWriter implements FrameConsumer<RGBFrame> {
.replace("%BITRATE%", String.valueOf(settings.getBitRate()))
.replace("%FILTERS%", settings.getVideoFilters());
String executable = settings.getExportCommand().isEmpty() ? findFFmpeg() : settings.getExportCommand();
String executable = settings.getExportCommandOrDefault();
LOGGER.info("Starting {} with args: {}", executable, commandArgs);
String[] cmdline;
try {
@@ -78,7 +68,7 @@ public class VideoWriter implements FrameConsumer<RGBFrame> {
} catch (IOException e) {
throw new NoFFmpegException(e);
}
File exportLogFile = new File(Minecraft.getMinecraft().mcDataDir, "export.log");
File exportLogFile = new File(MCVer.mcDataDir(MCVer.getMinecraft()), "export.log");
OutputStream exportLogOut = new TeeOutputStream(new FileOutputStream(exportLogFile), ffmpegLog);
new StreamPipe(process.getInputStream(), exportLogOut).start();
new StreamPipe(process.getErrorStream(), exportLogOut).start();
@@ -86,54 +76,6 @@ public class VideoWriter implements FrameConsumer<RGBFrame> {
channel = Channels.newChannel(outputStream);
}
private String findFFmpeg() {
switch (Util.getOSType()) {
case WINDOWS:
// Allow windows users to unpack the ffmpeg archive into a sub-folder of their .minecraft folder
File inDotMinecraft = new File(Minecraft.getMinecraft().mcDataDir, "ffmpeg/bin/ffmpeg.exe");
if (inDotMinecraft.exists()) {
LOGGER.debug("FFmpeg found in .minecraft/ffmpeg");
return inDotMinecraft.getAbsolutePath();
}
break;
case OSX:
// The PATH doesn't seem to be set as expected on OSX, therefore we check some common locations ourselves
for (String path : new String[]{"/usr/local/bin/ffmpeg", "/usr/bin/ffmpeg"}) {
File file = new File(path);
if (file.exists()) {
LOGGER.debug("Found FFmpeg at {}", path);
return path;
} else {
LOGGER.debug("FFmpeg not located at {}", path);
}
}
// Homebrew doesn't seem to reliably symlink its installed binaries either
File homebrewFolder = new File("/usr/local/Cellar/ffmpeg");
String[] homebrewVersions = homebrewFolder.list();
if (homebrewVersions != null) {
Optional<File> latestOpt = Arrays.stream(homebrewVersions)
.map(ComparableVersion::new) // Convert file name to comparable version
.sorted(Comparator.reverseOrder()) // Sort for latest version
.map(ComparableVersion::toString) // Convert back to file name
.map(v -> new File(new File(homebrewFolder, v), "bin/ffmpeg")) // Convert to binary files
.filter(File::exists) // Filter invalid installations (missing executable)
.findFirst(); // Take first one
if (latestOpt.isPresent()) {
File latest = latestOpt.get();
LOGGER.debug("Found {} versions of FFmpeg installed with homebrew, chose {}",
homebrewVersions.length, latest);
return latest.getAbsolutePath();
}
}
break;
case LINUX: // Linux users are entrusted to have their PATH configured correctly (most package manager do this)
case SOLARIS: // Never heard of anyone running this mod on Solaris having any problems
case UNKNOWN: // Unknown OS, just try to use "ffmpeg"
}
LOGGER.debug("Using default FFmpeg executable");
return "ffmpeg";
}
@Override
public void close() throws IOException {
IOUtils.closeQuietly(outputStream);
@@ -182,9 +124,9 @@ public class VideoWriter implements FrameConsumer<RGBFrame> {
}
CrashReport report = CrashReport.makeCrashReport(t, "Exporting frame");
CrashReportCategory exportDetails = report.makeCategory("Export details");
exportDetails.addCrashSection("Export command", settings.getExportCommand());
exportDetails.addCrashSection("Export args", commandArgs);
Minecraft.getMinecraft().crashed(report);
MCVer.addDetail(exportDetails, "Export command", settings::getExportCommand);
MCVer.addDetail(exportDetails, "Export args", commandArgs::toString);
MCVer.getMinecraft().crashed(report);
}
}

View File

@@ -5,10 +5,16 @@ import com.replaymod.render.blend.BlendMeshBuilder;
import com.replaymod.render.blend.Exporter;
import com.replaymod.render.blend.data.DMesh;
import com.replaymod.render.blend.data.DObject;
import net.minecraft.client.model.ModelBox;
import net.minecraft.client.model.ModelRenderer;
import org.lwjgl.opengl.GL11;
//#if MC>=11300
import net.minecraft.client.renderer.entity.model.ModelBox;
import net.minecraft.client.renderer.entity.model.ModelRenderer;
//#else
//$$ import net.minecraft.client.model.ModelBox;
//$$ import net.minecraft.client.model.ModelRenderer;
//#endif
import java.io.IOException;
import static com.replaymod.core.versions.MCVer.*;

View File

@@ -4,8 +4,8 @@ import com.replaymod.render.frame.OpenGlFrame;
import com.replaymod.render.rendering.Frame;
import com.replaymod.render.utils.ByteBufferPool;
import com.replaymod.render.utils.PixelBufferObject;
import net.minecraft.client.renderer.OpenGlHelper;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -19,7 +19,7 @@ public abstract class MultiFramePboOpenGlFrameCapturer<F extends Frame, D extend
super(worldRenderer, renderInfo);
data = type.getEnumConstants();
int bufferSize = framePixels * 3 * data.length;
int bufferSize = framePixels * 4 * data.length;
pbo = new PixelBufferObject(bufferSize, PixelBufferObject.Usage.READ);
otherPBO = new PixelBufferObject(bufferSize, PixelBufferObject.Usage.READ);
}
@@ -47,7 +47,7 @@ public abstract class MultiFramePboOpenGlFrameCapturer<F extends Frame, D extend
ByteBuffer pboBuffer = pbo.mapReadOnly();
OpenGlFrame[] frames = new OpenGlFrame[data.length];
int frameBufferSize = getFrameWidth() * getFrameHeight() * 3;
int frameBufferSize = getFrameWidth() * getFrameHeight() * 4;
for (int i = 0; i < frames.length; i++) {
ByteBuffer frameBuffer = ByteBufferPool.allocate(frameBufferSize);
pboBuffer.limit(pboBuffer.position() + frameBufferSize);
@@ -79,17 +79,10 @@ public abstract class MultiFramePboOpenGlFrameCapturer<F extends Frame, D extend
protected OpenGlFrame captureFrame(int frameId, D captureData) {
pbo.bind();
GL11.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 1);
GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
int offset = captureData.ordinal() * getFrameWidth() * getFrameHeight() * 3;
if (OpenGlHelper.isFramebufferEnabled()) {
frameBuffer().bindFramebufferTexture();
GL11.glGetTexImage(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, offset);
frameBuffer().unbindFramebufferTexture();
} else {
GL11.glReadPixels(0, 0, getFrameWidth(), getFrameHeight(), GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, offset);
}
int offset = captureData.ordinal() * getFrameWidth() * getFrameHeight() * 4;
frameBuffer().bindFramebuffer(true);
GL11.glReadPixels(0, 0, getFrameWidth(), getFrameHeight(), GL12.GL_BGRA, GL11.GL_UNSIGNED_BYTE, offset);
frameBuffer().unbindFramebuffer();
pbo.unbind();
return null;

View File

@@ -6,14 +6,11 @@ import com.replaymod.render.frame.ODSOpenGlFrame;
import com.replaymod.render.frame.OpenGlFrame;
import com.replaymod.render.rendering.FrameCapturer;
import com.replaymod.render.shader.Program;
import net.minecraft.client.Minecraft;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import net.minecraft.crash.CrashReport;
import net.minecraft.util.ReportedException;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.util.ReadableDimension;
//#if MC>=10800
import net.minecraft.client.renderer.GlStateManager;
import static net.minecraft.client.renderer.GlStateManager.*;
//#else
//$$ import com.replaymod.render.hooks.GLStateTracker.BooleanState;
@@ -36,9 +33,7 @@ public class ODSFrameCapturer implements FrameCapturer<ODSOpenGlFrame> {
private final Program.Uniform leftEyeVariable;
private final BooleanState[] previousStates = new BooleanState[3];
private final BooleanState previousFogState;
private final Minecraft mc = Minecraft.getMinecraft();
private BooleanState previousFogState;
public ODSFrameCapturer(WorldRenderer worldRenderer, final RenderInfo renderInfo, int frameSize) {
RenderInfo fakeInfo = new RenderInfo() {
@@ -62,9 +57,9 @@ public class ODSFrameCapturer implements FrameCapturer<ODSOpenGlFrame> {
@Override
public float updateForNextFrame() {
if (call++ % 2 == 0) {
shaderProgram.stopUsing();
unbindProgram();
partialTicks = renderInfo.updateForNextFrame();
shaderProgram.use();
bindProgram();
}
return partialTicks;
}
@@ -78,30 +73,43 @@ public class ODSFrameCapturer implements FrameCapturer<ODSOpenGlFrame> {
right = new CubicStereoFrameCapturer(worldRenderer, fakeInfo, frameSize);
try {
shaderProgram = new Program(vertexResource, fragmentResource);
shaderProgram.use();
leftEyeVariable = shaderProgram.getUniformVariable("leftEye");
directionVariable = shaderProgram.getUniformVariable("direction");
setTexture("texture", 0);
setTexture("lightMap", 1);
linkState(0, "textureEnabled");
linkState(1, "lightMapEnabled");
linkState(2, "hurtTextureEnabled");
final Program.Uniform uniform = shaderProgram.getUniformVariable("fogEnabled");
previousFogState = fog();
uniform.set(previousFogState.currentState);
fog(new BooleanState(previousFogState.capability) {
@Override
public void setState(boolean state) {
super.setState(state);
uniform.set(state);
}
});
shaderProgram.stopUsing();
} catch (Exception e) {
throw new ReportedException(CrashReport.makeCrashReport(e, "Creating ODS shaders"));
throw newReportedException(CrashReport.makeCrashReport(e, "Creating ODS shaders"));
}
}
private void bindProgram() {
shaderProgram.use();
setTexture("texture", 0);
setTexture("lightMap", 1);
linkState(0, "textureEnabled");
linkState(1, "lightMapEnabled");
linkState(2, "hurtTextureEnabled");
final Program.Uniform uniform = shaderProgram.getUniformVariable("fogEnabled");
previousFogState = fog();
uniform.set(previousFogState.currentState);
fog(new BooleanState(previousFogState.capability) {
{ currentState = previousFogState.currentState; }
@Override
public void setState(boolean state) {
super.setState(state);
uniform.set(state);
}
});
}
private void unbindProgram() {
for (int i = 0; i < previousStates.length; i++) {
previousStates[i].currentState = texture2DState(i).currentState;
texture2DState(i, previousStates[i]);
}
previousFogState.currentState = fog().currentState;
fog(previousFogState);
shaderProgram.stopUsing();
}
private void setTexture(String texture, int i) {
shaderProgram.getUniformVariable(texture).set(i);
}
@@ -111,6 +119,7 @@ public class ODSFrameCapturer implements FrameCapturer<ODSOpenGlFrame> {
previousStates[id] = texture2DState(id);
uniform.set(previousStates[id].currentState);
texture2DState(id, new BooleanState(previousStates[id].capability) {
{ currentState = previousStates[id].currentState; }
@Override
public void setState(boolean state) {
super.setState(state);
@@ -126,12 +135,12 @@ public class ODSFrameCapturer implements FrameCapturer<ODSOpenGlFrame> {
@Override
public ODSOpenGlFrame process() {
shaderProgram.use();
bindProgram();
leftEyeVariable.set(true);
CubicOpenGlFrame leftFrame = left.process();
leftEyeVariable.set(false);
CubicOpenGlFrame rightFrame = right.process();
shaderProgram.stopUsing();
unbindProgram();
if (leftFrame != null && rightFrame != null) {
return new ODSOpenGlFrame(leftFrame, rightFrame);
@@ -144,10 +153,6 @@ public class ODSFrameCapturer implements FrameCapturer<ODSOpenGlFrame> {
left.close();
right.close();
shaderProgram.delete();
for (int i = 0; i < previousStates.length; i++) {
texture2DState(i, previousStates[i]);
}
fog(previousFogState);
}
private class CubicStereoFrameCapturer extends CubicPboOpenGlFrameCapturer {

View File

@@ -1,16 +1,17 @@
package com.replaymod.render.capturer;
import com.replaymod.core.versions.MCVer;
import com.replaymod.render.frame.OpenGlFrame;
import com.replaymod.render.rendering.Frame;
import com.replaymod.render.rendering.FrameCapturer;
import com.replaymod.render.utils.ByteBufferPool;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import de.johni0702.minecraft.gui.utils.lwjgl.WritableDimension;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.shader.Framebuffer;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.Dimension;
import org.lwjgl.util.ReadableDimension;
import org.lwjgl.util.WritableDimension;
import org.lwjgl.opengl.GL12;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -30,7 +31,7 @@ public abstract class OpenGlFrameCapturer<F extends Frame, D extends CaptureData
protected int framesDone;
private Framebuffer frameBuffer;
private final Minecraft mc = Minecraft.getMinecraft();
private final Minecraft mc = MCVer.getMinecraft();
public OpenGlFrameCapturer(WorldRenderer worldRenderer, RenderInfo renderInfo) {
this.worldRenderer = worldRenderer;
@@ -64,7 +65,7 @@ public abstract class OpenGlFrameCapturer<F extends Frame, D extends CaptureData
protected Framebuffer frameBuffer() {
if (frameBuffer == null) {
frameBuffer = Minecraft.getMinecraft().getFramebuffer();
frameBuffer = mc.getFramebuffer();
}
return frameBuffer;
}
@@ -96,30 +97,28 @@ public abstract class OpenGlFrameCapturer<F extends Frame, D extends CaptureData
}
protected OpenGlFrame captureFrame(int frameId, D captureData) {
GL11.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 1);
GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
ByteBuffer buffer = ByteBufferPool.allocate(getFrameWidth() * getFrameHeight() * 3);
if (OpenGlHelper.isFramebufferEnabled()) {
frameBuffer().bindFramebufferTexture();
GL11.glGetTexImage(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, buffer);
frameBuffer().unbindFramebufferTexture();
} else {
GL11.glReadPixels(0, 0, getFrameWidth(), getFrameHeight(), GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, buffer);
}
ByteBuffer buffer = ByteBufferPool.allocate(getFrameWidth() * getFrameHeight() * 4);
frameBuffer().bindFramebuffer(true);
GL11.glReadPixels(0, 0, getFrameWidth(), getFrameHeight(), GL12.GL_BGRA, GL11.GL_UNSIGNED_BYTE, buffer);
frameBuffer().unbindFramebuffer();
buffer.rewind();
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);
//#if MC>=11300
Framebuffer fb = mc.getFramebuffer();
if (fb.framebufferWidth != width || fb.framebufferHeight != height) {
fb.createFramebuffer(width, height);
}
}
private void setWindowSize(int width, int height) {
mc.resize(width, height);
mc.mainWindow.framebufferWidth = width;
mc.mainWindow.framebufferHeight = height;
//#else
//$$ if (width != mc.displayWidth || height != mc.displayHeight) {
//$$ mc.resize(width, height);
//$$ }
//#endif
}
@Override

View File

@@ -1,7 +1,7 @@
package com.replaymod.render.capturer;
import com.replaymod.render.RenderSettings;
import org.lwjgl.util.ReadableDimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
public interface RenderInfo {
ReadableDimension getFrameSize();

View File

@@ -3,9 +3,9 @@ package com.replaymod.render.capturer;
import com.replaymod.render.frame.OpenGlFrame;
import com.replaymod.render.utils.ByteBufferPool;
import com.replaymod.render.utils.PixelBufferObject;
import net.minecraft.client.renderer.OpenGlHelper;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.ReadableDimension;
import org.lwjgl.opengl.GL12;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -18,7 +18,7 @@ public class SimplePboOpenGlFrameCapturer extends OpenGlFrameCapturer<OpenGlFram
super(worldRenderer, renderInfo);
ReadableDimension size = renderInfo.getFrameSize();
bufferSize = size.getHeight() * size.getWidth() * 3;
bufferSize = size.getHeight() * size.getWidth() * 4;
pbo = new PixelBufferObject(bufferSize, PixelBufferObject.Usage.READ);
otherPBO = new PixelBufferObject(bufferSize, PixelBufferObject.Usage.READ);
}
@@ -64,16 +64,9 @@ public class SimplePboOpenGlFrameCapturer extends OpenGlFrameCapturer<OpenGlFram
protected OpenGlFrame captureFrame(int frameId, CaptureData data) {
pbo.bind();
GL11.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 1);
GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
if (OpenGlHelper.isFramebufferEnabled()) {
frameBuffer().bindFramebufferTexture();
GL11.glGetTexImage(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, 0);
frameBuffer().unbindFramebufferTexture();
} else {
GL11.glReadPixels(0, 0, getFrameWidth(), getFrameHeight(), GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, 0);
}
frameBuffer().bindFramebuffer(true);
GL11.glReadPixels(0, 0, getFrameWidth(), getFrameHeight(), GL12.GL_BGRA, GL11.GL_UNSIGNED_BYTE, 0);
frameBuffer().unbindFramebuffer();
pbo.unbind();
return null;

View File

@@ -5,7 +5,11 @@ import lombok.Getter;
import lombok.RequiredArgsConstructor;
//#if MC>=10800
import net.minecraftforge.fml.common.eventhandler.Event;
//#if MC>=11300
import net.minecraftforge.eventbus.api.Event;
//#else
//$$ import net.minecraftforge.fml.common.eventhandler.Event;
//#endif
//#else
//$$ import cpw.mods.fml.common.eventhandler.Event;
//#endif

View File

@@ -1,9 +1,9 @@
package com.replaymod.render.frame;
import com.replaymod.render.rendering.Frame;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.lwjgl.util.ReadableDimension;
import java.nio.ByteBuffer;

View File

@@ -1,9 +1,9 @@
package com.replaymod.render.frame;
import com.replaymod.render.rendering.Frame;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import lombok.Getter;
import org.apache.commons.lang3.Validate;
import org.lwjgl.util.ReadableDimension;
import java.nio.ByteBuffer;
@@ -18,9 +18,9 @@ public class RGBFrame implements Frame {
private final ByteBuffer byteBuffer;
public RGBFrame(int frameId, ReadableDimension size, ByteBuffer byteBuffer) {
Validate.isTrue(size.getWidth() * size.getHeight() * 3 == byteBuffer.remaining(),
Validate.isTrue(size.getWidth() * size.getHeight() * 4 == byteBuffer.remaining(),
"Buffer size is %d (cap: %d) but should be %d",
byteBuffer.remaining(), byteBuffer.capacity(), size.getWidth() * size.getHeight() * 3);
byteBuffer.remaining(), byteBuffer.capacity(), size.getWidth() * size.getHeight() * 4);
this.frameId = frameId;
this.size = size;
this.byteBuffer = byteBuffer;

View File

@@ -13,11 +13,12 @@ import de.johni0702.minecraft.gui.layout.HorizontalLayout;
import de.johni0702.minecraft.gui.layout.VerticalLayout;
import net.minecraft.crash.CrashReport;
import net.minecraft.crash.CrashReportCategory;
import net.minecraft.util.ReportedException;
import java.util.Arrays;
import java.util.function.Consumer;
import static com.replaymod.core.versions.MCVer.addDetail;
import static com.replaymod.core.versions.MCVer.newReportedException;
import static com.replaymod.render.ReplayModRender.LOGGER;
public class GuiExportFailed extends GuiScreen {
@@ -31,9 +32,9 @@ public class GuiExportFailed extends GuiScreen {
// If they haven't, then this is probably a faulty ffmpeg installation and there's nothing we can do
CrashReport crashReport = CrashReport.makeCrashReport(e, "Exporting video");
CrashReportCategory details = crashReport.makeCategory("Export details");
details.addCrashSection("Settings", settings);
details.addCrashSection("FFmpeg log", e.getLog());
throw new ReportedException(crashReport);
addDetail(details, "Settings", settings::toString);
addDetail(details, "FFmpeg log", e::getLog);
throw newReportedException(crashReport);
} else {
// If they have, ask them whether it was intentional
GuiExportFailed gui = new GuiExportFailed(e, doRestart);
@@ -93,7 +94,9 @@ public class GuiExportFailed extends GuiScreen {
oldSettings.isStabilizePitch(),
oldSettings.isStabilizeRoll(),
oldSettings.getChromaKeyingColor(),
oldSettings.isInject360Metadata(),
oldSettings.getSphericalFovX(),
oldSettings.getSphericalFovY(),
oldSettings.isInjectSphericalMetadata(),
oldSettings.getAntiAliasing(),
oldSettings.getExportCommand(),
oldSettings.getEncodingPreset().getValue(),

View File

@@ -27,10 +27,10 @@ import de.johni0702.minecraft.gui.layout.HorizontalLayout;
import de.johni0702.minecraft.gui.popup.AbstractGuiPopup;
import de.johni0702.minecraft.gui.popup.GuiYesNoPopup;
import de.johni0702.minecraft.gui.utils.Colors;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import net.minecraft.client.gui.GuiErrorScreen;
import net.minecraft.crash.CrashReport;
import org.lwjgl.util.Dimension;
import org.lwjgl.util.ReadableDimension;
import javax.annotation.Nullable;
import java.util.List;

View File

@@ -1,5 +1,6 @@
package com.replaymod.render.gui;
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.gson.Gson;
@@ -27,18 +28,22 @@ import de.johni0702.minecraft.gui.popup.GuiFileChooserPopup;
import de.johni0702.minecraft.gui.utils.Colors;
import de.johni0702.minecraft.gui.utils.Consumer;
import de.johni0702.minecraft.gui.utils.Utils;
import de.johni0702.minecraft.gui.utils.lwjgl.Color;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableColor;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import net.minecraft.client.gui.GuiErrorScreen;
import net.minecraft.client.resources.I18n;
import net.minecraft.crash.CrashReport;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.common.config.Property;
import org.lwjgl.util.Color;
import org.lwjgl.util.Dimension;
import org.lwjgl.util.ReadableColor;
import org.lwjgl.util.ReadableDimension;
import javax.annotation.Nullable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
@@ -128,7 +133,7 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
new GuiLabel().setI18nText("replaymod.gui.rendersettings.renderer"), renderMethodDropdown,
new GuiLabel().setI18nText("replaymod.gui.rendersettings.presets"), encodingPresetDropdown,
new GuiLabel().setI18nText("replaymod.gui.rendersettings.customresolution"), videoResolutionPanel,
new GuiLabel().setI18nText("replaymod.gui.settings.bitrate"), new GuiPanel().addElements(null,
new GuiLabel().setI18nText("replaymod.gui.rendersettings.bitrate"), new GuiPanel().addElements(null,
new GuiPanel().addElements(null, bitRateField, bitRateUnit).setLayout(new HorizontalLayout()),
frameRateSlider).setLayout(new HorizontalLayout(HorizontalLayout.Alignment.RIGHT).setSpacing(3)),
new GuiLabel().setI18nText("replaymod.gui.rendersettings.outputfile"), outputFileButton)
@@ -149,8 +154,22 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
.setI18nLabel("replaymod.gui.rendersettings.chromakey");
public final GuiColorPicker chromaKeyingColor = new GuiColorPicker().setSize(30, 15);
public final GuiCheckbox inject360Metadata = new GuiCheckbox()
.setI18nLabel("replaymod.gui.rendersettings.360metadata");
public static final int MIN_SPHERICAL_FOV = 120;
public static final int MAX_SPHERICAL_FOV = 360;
public static final int SPHERICAL_FOV_STEP_SIZE = 5;
public final GuiSlider sphericalFovSlider = new GuiSlider()
.onValueChanged(new Runnable() {
@Override
public void run() {
sphericalFovSlider.setText(I18n.format("replaymod.gui.rendersettings.sphericalFov")
+ ": " + (MIN_SPHERICAL_FOV + sphericalFovSlider.getValue() * SPHERICAL_FOV_STEP_SIZE) + "°");
updateInputs();
}
}).setSize(200, 20).setSteps((MAX_SPHERICAL_FOV - MIN_SPHERICAL_FOV) / SPHERICAL_FOV_STEP_SIZE);
public final GuiCheckbox injectSphericalMetadata = new GuiCheckbox()
.setI18nLabel("replaymod.gui.rendersettings.sphericalmetadata");
public final GuiDropdownMenu<RenderSettings.AntiAliasing> antiAliasingDropdown = new GuiDropdownMenu<RenderSettings.AntiAliasing>()
.setSize(200, 20).setValues(RenderSettings.AntiAliasing.values()).setSelected(RenderSettings.AntiAliasing.NONE);
@@ -161,8 +180,7 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
.addElements(new GridLayout.Data(0, 0.5),
new GuiLabel().setI18nText("replaymod.gui.rendersettings.stabilizecamera"), stabilizePanel,
chromaKeyingCheckbox, chromaKeyingColor,
inject360Metadata,
new GuiLabel(), // to show the anti-aliasing options in a new line
injectSphericalMetadata, sphericalFovSlider,
new GuiLabel().setI18nText("replaymod.gui.rendersettings.antialiasing"), antiAliasingDropdown));
public final GuiTextField exportCommand = new GuiTextField().setI18nHint("replaymod.gui.rendersettings.command")
@@ -280,7 +298,13 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
this.replayHandler = replayHandler;
this.timeline = timeline;
String json = getConfigProperty(ReplayModRender.instance.getConfiguration()).getString();
String json = "{}";
try {
json = new String(Files.readAllBytes(getSettingsPath()), StandardCharsets.UTF_8);
} catch (NoSuchFileException | FileNotFoundException ignored) {
} catch (IOException e) {
LOGGER.error("Reading render settings:", e);
}
RenderSettings settings = new GsonBuilder()
.registerTypeAdapter(RenderSettings.class, (InstanceCreator<RenderSettings>) type -> getDefaultRenderSettings())
.registerTypeAdapter(ReadableColor.class, new Gson().getAdapter(Color.class))
@@ -289,8 +313,13 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
}
protected void updateInputs() {
RenderSettings.RenderMethod renderMethod = renderMethodDropdown.getSelectedValue();
// Enable/Disable video with input
videoWidth.setEnabled(!renderMethod.hasFixedAspectRatio());
// Validate video width and height
String error = isResolutionValid();
String error = updateResolution();
if (error == null) {
renderButton.setEnabled().setTooltip(null);
videoWidth.setTextColor(Colors.WHITE);
@@ -311,7 +340,7 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
}
// Enable/Disable camera stabilization checkboxes
switch (renderMethodDropdown.getSelectedValue()) {
switch (renderMethod) {
case CUBIC:
case EQUIRECTANGULAR:
case ODS:
@@ -321,52 +350,94 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
stabilizePanel.forEach(IGuiCheckbox.class).setDisabled();
}
// Enable/Disable Spherical FOV slider
sphericalFovSlider.setEnabled(renderMethod.isSpherical());
// Enable/Disable inject metadata checkbox
if (encodingPresetDropdown.getSelectedValue().getFileExtension().equals("mp4")
&& (renderMethodDropdown.getSelectedValue() == RenderSettings.RenderMethod.EQUIRECTANGULAR
|| renderMethodDropdown.getSelectedValue() == RenderSettings.RenderMethod.ODS)) {
inject360Metadata.setEnabled().setTooltip(null);
&& renderMethod.isSpherical()) {
injectSphericalMetadata.setEnabled().setTooltip(null);
} else {
inject360Metadata.setDisabled().setTooltip(new GuiTooltip().setColor(Colors.RED)
.setI18nText("replaymod.gui.rendersettings.360metadata.error"));
injectSphericalMetadata.setDisabled().setTooltip(new GuiTooltip().setColor(Colors.RED)
.setI18nText("replaymod.gui.rendersettings.sphericalmetadata.error"));
}
}
protected String isResolutionValid() {
protected String updateResolution() {
RenderSettings.EncodingPreset preset = encodingPresetDropdown.getSelectedValue();
RenderSettings.RenderMethod method = renderMethodDropdown.getSelectedValue();
int videoWidth = this.videoWidth.getInteger();
int videoHeight = this.videoHeight.getInteger();
int videoWidth;
if (method.hasFixedAspectRatio()) {
// cubic rendering requires an aspect ratio of 4:3,
// therefore the height must be divisible by 3
if (method == RenderSettings.RenderMethod.CUBIC && videoHeight % 3 != 0) {
return "replaymod.gui.rendersettings.customresolution.warning.cubic.height";
}
int sphericalFov = MIN_SPHERICAL_FOV + sphericalFovSlider.getValue() * SPHERICAL_FOV_STEP_SIZE;
videoWidth = videoWidthForHeight(method, videoHeight, sphericalFov, sphericalFov);
this.videoWidth.setValue(videoWidth);
} else {
videoWidth = this.videoWidth.getInteger();
}
// Make sure the export arguments haven't been changed manually
if (exportArguments.getText().equals(preset.getValue())) {
// Yuv420 requires both dimensions to be even
if (preset.isYuv420()
&& (videoWidth % 2 != 0 || videoHeight % 2 != 0)) {
if (method == RenderSettings.RenderMethod.CUBIC) {
// cubic yuv rendering has the special case that the height must be
// divisible by both 3 and 2 - tell the user about it with a special message
return "replaymod.gui.rendersettings.customresolution.warning.yuv420.cubic";
}
return "replaymod.gui.rendersettings.customresolution.warning.yuv420";
}
}
if (method == RenderSettings.RenderMethod.CUBIC
&& (videoWidth * 3 / 4 != videoHeight || videoWidth * 3 % 4 != 0)) {
return "replaymod.gui.rendersettings.customresolution.warning.cubic";
}
if (method == RenderSettings.RenderMethod.EQUIRECTANGULAR
&& (videoWidth / 2 != videoHeight || videoWidth % 2 != 0)) {
return "replaymod.gui.rendersettings.customresolution.warning.equirectangular";
}
if (method == RenderSettings.RenderMethod.ODS
&& videoWidth != videoHeight) {
return "replaymod.gui.rendersettings.customresolution.warning.ods";
}
//#if MC<10800
//$$ if (method == RenderSettings.RenderMethod.BLEND) {
//$$ return "replaymod.gui.rendersettings.no_blend_on_1_7_10";
//$$ }
//#endif
return null;
}
protected int videoWidthForHeight(RenderSettings.RenderMethod method, int height,
int sphericalFovX, int sphericalFovY) {
if (method.isSpherical()) {
if (sphericalFovY < 180) {
// calculate the non-cropped height of the video
height = Math.round(height * 180 / (float) sphericalFovY);
}
int width = height * 2;
if (sphericalFovX < 360) {
// crop the resulting width
width = Math.round(width * (float) sphericalFovX / 360);
}
if (method == RenderSettings.RenderMethod.ODS) {
width = Math.round(width / 2f);
}
return width;
} else if (method == RenderSettings.RenderMethod.CUBIC) {
Preconditions.checkArgument(height % 3 == 0);
return height / 3 * 4;
}
throw new IllegalArgumentException();
}
public void load(RenderSettings settings) {
renderMethodDropdown.setSelected(settings.getRenderMethod());
encodingPresetDropdown.setSelected(settings.getEncodingPreset());
@@ -402,7 +473,8 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
chromaKeyingCheckbox.setChecked(true);
chromaKeyingColor.setColor(settings.getChromaKeyingColor());
}
inject360Metadata.setChecked(settings.isInject360Metadata());
sphericalFovSlider.setValue((settings.getSphericalFovX() - MIN_SPHERICAL_FOV) / SPHERICAL_FOV_STEP_SIZE);
injectSphericalMetadata.setChecked(settings.isInjectSphericalMetadata());
antiAliasingDropdown.setSelected(settings.getAntiAliasing());
exportCommand.setText(settings.getExportCommand());
exportArguments.setText(settings.getExportArguments());
@@ -411,6 +483,8 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
}
public RenderSettings save(boolean serialize) {
int sphericalFov = MIN_SPHERICAL_FOV + sphericalFovSlider.getValue() * SPHERICAL_FOV_STEP_SIZE;
return new RenderSettings(
renderMethodDropdown.getSelectedValue(),
encodingPresetDropdown.getSelectedValue(),
@@ -424,7 +498,8 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
stabilizePitch.isChecked() && (serialize || stabilizePitch.isEnabled()),
stabilizeRoll.isChecked() && (serialize || stabilizeRoll.isEnabled()),
chromaKeyingCheckbox.isChecked() ? chromaKeyingColor.getColor() : null,
inject360Metadata.isChecked() && (serialize || inject360Metadata.isEnabled()),
sphericalFov, Math.min(180, sphericalFov),
injectSphericalMetadata.isChecked() && (serialize || injectSphericalMetadata.isEnabled()),
antiAliasingDropdown.getSelectedValue(),
exportCommand.getText(),
exportArguments.getText(),
@@ -438,23 +513,24 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
return new File(folder, fileName + "." + encodingPreset.getFileExtension());
}
protected Path getSettingsPath() {
return ReplayModRender.instance.getRenderSettingsPath();
}
private RenderSettings getDefaultRenderSettings() {
return new RenderSettings(RenderSettings.RenderMethod.DEFAULT, RenderSettings.EncodingPreset.MP4_DEFAULT, 1920, 1080, 60, 10 << 20, null,
true, false, false, false, null, false, RenderSettings.AntiAliasing.NONE, "", RenderSettings.EncodingPreset.MP4_DEFAULT.getValue(), false);
true, false, false, false, null, 360, 180, false, RenderSettings.AntiAliasing.NONE, "", RenderSettings.EncodingPreset.MP4_DEFAULT.getValue(), false);
}
@Override
public void close() {
RenderSettings settings = save(true);
String json = new Gson().toJson(settings);
Configuration config = ReplayModRender.instance.getConfiguration();
getConfigProperty(config).set(json);
config.save();
}
protected Property getConfigProperty(Configuration configuration) {
return configuration.get("rendersettings", "settings", "{}",
"Last state of the render settings GUI. Internal use only.");
try {
Files.write(getSettingsPath(), json.getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
LOGGER.error("Saving render settings:", e);
}
}
public ReplayHandler getReplayHandler() {

View File

@@ -1,6 +1,7 @@
package com.replaymod.render.gui;
import com.replaymod.core.SettingsRegistry;
import com.replaymod.core.versions.MCVer;
import com.replaymod.render.RenderSettings;
import com.replaymod.render.ReplayModRender;
import com.replaymod.render.Setting;
@@ -13,13 +14,8 @@ import de.johni0702.minecraft.gui.layout.CustomLayout;
import de.johni0702.minecraft.gui.layout.HorizontalLayout;
import de.johni0702.minecraft.gui.layout.VerticalLayout;
import lombok.RequiredArgsConstructor;
import net.minecraft.util.Util;
import org.apache.logging.log4j.LogManager;
import org.lwjgl.Sys;
import java.awt.*;
import java.io.File;
import java.io.IOException;
@RequiredArgsConstructor
public class GuiRenderingDone extends GuiScreen {
@@ -34,30 +30,7 @@ public class GuiRenderingDone extends GuiScreen {
public final GuiButton openFolder = new GuiButton().onClick(new Runnable() {
@Override
public void run() {
File folder = videoFile.getParentFile();
String path = folder.getAbsolutePath();
// First try OS specific methods
try {
switch (Util.getOSType()) {
case WINDOWS:
Runtime.getRuntime().exec(String.format("cmd.exe /C start \"Open file\" \"%s\"", path));
return;
case OSX:
Runtime.getRuntime().exec(new String[]{"/usr/bin/open", path});
return;
}
} catch (IOException e) {
LogManager.getLogger().error("Cannot open file", e);
}
// Otherwise try the java way
try {
Desktop.getDesktop().browse(folder.toURI());
} catch (Throwable throwable) {
// And if all fails, lwjgl
Sys.openURL("file://" + path);
}
MCVer.openFile(videoFile.getParentFile());
}
}).setSize(200, 20).setI18nLabel("replaymod.gui.openfolder");

View File

@@ -11,18 +11,23 @@ import de.johni0702.minecraft.gui.element.GuiButton;
import de.johni0702.minecraft.gui.element.GuiCheckbox;
import de.johni0702.minecraft.gui.element.GuiLabel;
import de.johni0702.minecraft.gui.element.advanced.GuiProgressBar;
import de.johni0702.minecraft.gui.function.Tickable;
import de.johni0702.minecraft.gui.layout.CustomLayout;
import de.johni0702.minecraft.gui.layout.HorizontalLayout;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadablePoint;
import net.minecraft.client.renderer.texture.DynamicTexture;
import net.minecraft.client.resources.I18n;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.util.Dimension;
import org.lwjgl.util.ReadableDimension;
import org.lwjgl.util.ReadablePoint;
//#if MC>=11300
import net.minecraft.client.renderer.texture.NativeImage;
//#endif
import java.nio.ByteBuffer;
public class GuiVideoRenderer extends GuiScreen {
public class GuiVideoRenderer extends GuiScreen implements Tickable {
private static final ResourceLocation NO_PREVIEW_TEXTURE = new ResourceLocation("replaymod", "logo.jpg");
private final VideoRenderer renderer;
@@ -135,7 +140,7 @@ public class GuiVideoRenderer extends GuiScreen {
private int currentIndex = 0;
@Override
public void draw(GuiRenderer guiRenderer, ReadableDimension size, RenderInfo renderInfo) {
public void tick() {
long current = System.currentTimeMillis();
//first, update the total render time (only if rendering is not paused and has already started)
@@ -206,8 +211,6 @@ public class GuiVideoRenderer extends GuiScreen {
int framesDone = renderer.getFramesDone(), framesTotal = renderer.getTotalFrames();
progressBar.setI18nLabel("replaymod.gui.rendering.progress", framesDone, framesTotal);
progressBar.setProgress((float) framesDone / framesTotal);
super.draw(guiRenderer, size, renderInfo);
}
private String secToString(int seconds) {
@@ -229,7 +232,11 @@ public class GuiVideoRenderer extends GuiScreen {
final int videoHeight = videoSize.getHeight();
if (previewTexture == null) {
previewTexture = new DynamicTexture(videoWidth, videoHeight);
//#if MC>=11300
previewTexture = new DynamicTexture(videoWidth, videoHeight, true);
//#else
//$$ previewTexture = new DynamicTexture(videoWidth, videoHeight);
//#endif
}
if (previewTextureDirty) {
@@ -263,13 +270,27 @@ public class GuiVideoRenderer extends GuiScreen {
ByteBuffer buffer = frame.getByteBuffer();
buffer.mark();
synchronized (this) {
int[] data = previewTexture.getTextureData();
// 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);
//#if MC>=11300
NativeImage data = previewTexture.getTextureData();
assert data != null;
for (int y = 0; y < data.getHeight(); y++) {
for (int x = 0; x < data.getWidth(); x++) {
int r = buffer.get() & 0xff;
int g = buffer.get() & 0xff;
int b = buffer.get() & 0xff;
int value = 0xff << 24 | b << 16 | g << 8 | r;
data.setPixelRGBA(x, y, value); // actually takes ABGR, not RGBA
}
}
//#else
//$$ int[] data = previewTexture.getTextureData();
//$$ // 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);
//$$ }
//#endif
previewTextureDirty = true;
}
buffer.reset();

View File

@@ -3,8 +3,6 @@ package com.replaymod.render.hooks;
import com.replaymod.render.utils.JailingQueue;
import net.minecraft.client.renderer.RegionRenderCacheBuilder;
import net.minecraft.client.renderer.RenderGlobal;
import net.minecraft.client.renderer.chunk.ChunkCompileTaskGenerator;
import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher;
import net.minecraft.client.renderer.chunk.ChunkRenderWorker;
import net.minecraft.client.renderer.chunk.RenderChunk;
@@ -12,6 +10,14 @@ import net.minecraft.client.renderer.chunk.RenderChunk;
import java.lang.reflect.Field;
import java.util.Iterator;
//#if MC>=11300
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.chunk.ChunkRenderTask;
//#else
//$$ import net.minecraft.client.renderer.RenderGlobal;
//$$ import net.minecraft.client.renderer.chunk.ChunkCompileTaskGenerator;
//#endif
//#if MC>=10904
import java.util.concurrent.PriorityBlockingQueue;
//#else
@@ -22,14 +28,28 @@ import static com.replaymod.core.versions.MCVer.*;
public class ChunkLoadingRenderGlobal {
private final RenderGlobal hooked;
//#if MC>=11300
private final WorldRenderer hooked;
//#else
//$$ private final RenderGlobal hooked;
//#endif
private ChunkRenderDispatcher renderDispatcher;
private JailingQueue<ChunkCompileTaskGenerator> workerJailingQueue;
//#if MC>=11300
private JailingQueue<ChunkRenderTask> workerJailingQueue;
//#else
//$$ private JailingQueue<ChunkCompileTaskGenerator> workerJailingQueue;
//#endif
private CustomChunkRenderWorker renderWorker;
private int frame;
@SuppressWarnings("unchecked")
public ChunkLoadingRenderGlobal(RenderGlobal renderGlobal) {
public ChunkLoadingRenderGlobal(
//#if MC>=11300
WorldRenderer renderGlobal
//#else
//$$ RenderGlobal renderGlobal
//#endif
) {
this.hooked = renderGlobal;
setup(renderGlobal.renderDispatcher);
@@ -51,14 +71,22 @@ public class ChunkLoadingRenderGlobal {
int workerThreads = renderDispatcher.listThreadedWorkers.size();
//#if MC>=10904
PriorityBlockingQueue<ChunkCompileTaskGenerator> queueChunkUpdates = renderDispatcher.queueChunkUpdates;
//#if MC>=11300
PriorityBlockingQueue<ChunkRenderTask> queueChunkUpdates = renderDispatcher.queueChunkUpdates;
//#else
//$$ PriorityBlockingQueue<ChunkCompileTaskGenerator> queueChunkUpdates = renderDispatcher.queueChunkUpdates;
//#endif
//#else
//$$ BlockingQueue<ChunkCompileTaskGenerator> queueChunkUpdates = renderDispatcher.queueChunkUpdates;
//#endif
workerJailingQueue = new JailingQueue<>(queueChunkUpdates);
renderDispatcher.queueChunkUpdates = workerJailingQueue;
//#if MC>=10904
ChunkCompileTaskGenerator element = new ChunkCompileTaskGenerator(null, null, 0);
//#if MC>=11300
ChunkRenderTask element = new ChunkRenderTask(null, null, 0);
//#else
//$$ ChunkCompileTaskGenerator element = new ChunkCompileTaskGenerator(null, null, 0);
//#endif
//#else
//$$ ChunkCompileTaskGenerator element = new ChunkCompileTaskGenerator(null, null);
//#endif
@@ -75,7 +103,11 @@ public class ChunkLoadingRenderGlobal {
renderDispatcher.queueChunkUpdates = queueChunkUpdates;
try {
Field hookField = RenderGlobal.class.getField("replayModRender_hook");
//#if MC>=11300
Field hookField = WorldRenderer.class.getField("replayModRender_hook");
//#else
//$$ Field hookField = RenderGlobal.class.getField("replayModRender_hook");
//#endif
hookField.set(hooked, this);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new Error(e);
@@ -119,7 +151,11 @@ public class ChunkLoadingRenderGlobal {
workerJailingQueue.freeAll();
try {
Field hookField = RenderGlobal.class.getField("replayModRender_hook");
//#if MC>=11300
Field hookField = WorldRenderer.class.getField("replayModRender_hook");
//#else
//$$ Field hookField = RenderGlobal.class.getField("replayModRender_hook");
//#endif
hookField.set(hooked, null);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new Error(e);
@@ -139,7 +175,13 @@ public class ChunkLoadingRenderGlobal {
}
@Override
protected void processTask(ChunkCompileTaskGenerator p_178474_1_) throws InterruptedException {
protected void processTask(
//#if MC>=11300
ChunkRenderTask p_178474_1_
//#else
//$$ ChunkCompileTaskGenerator p_178474_1_
//#endif
) throws InterruptedException {
super.processTask(p_178474_1_);
}
}

View File

@@ -1,5 +1,6 @@
package com.replaymod.render.hooks;
import com.replaymod.core.versions.MCVer;
import com.replaymod.render.RenderSettings;
import com.replaymod.render.capturer.CaptureData;
import com.replaymod.render.capturer.RenderInfo;
@@ -8,8 +9,12 @@ import lombok.Getter;
import net.minecraft.client.Minecraft;
//#if MC>=10800
import net.minecraft.client.renderer.GlStateManager;
import net.minecraftforge.fml.common.FMLCommonHandler;
//#if MC>=11300
import net.minecraftforge.fml.hooks.BasicEventHooks;
//#else
//$$ import net.minecraft.client.renderer.GlStateManager;
//$$ import net.minecraftforge.fml.common.FMLCommonHandler;
//#endif
//#else
//$$ import com.replaymod.core.versions.MCVer.GlStateManager;
//$$ import cpw.mods.fml.common.FMLCommonHandler;
@@ -18,7 +23,7 @@ import net.minecraftforge.fml.common.FMLCommonHandler;
import java.io.IOException;
public class EntityRendererHandler implements WorldRenderer {
public final Minecraft mc = Minecraft.getMinecraft();
public final Minecraft mc = MCVer.getMinecraft();
@Getter
protected final RenderSettings settings;
@@ -44,21 +49,33 @@ public class EntityRendererHandler implements WorldRenderer {
}
public void renderWorld(float partialTicks, long finishTimeNano) {
FMLCommonHandler.instance().onRenderTickStart(partialTicks);
mc.entityRenderer.updateLightmap(partialTicks);
GlStateManager.enableDepth();
GlStateManager.enableAlpha();
GlStateManager.alphaFunc(516, 0.5F);
//#if MC>=11300
BasicEventHooks.onRenderTickStart(partialTicks);
//#else
//$$ FMLCommonHandler.instance().onRenderTickStart(partialTicks);
//#endif
//#if MC>=11300
mc.entityRenderer.renderWorld(partialTicks, finishTimeNano);
//#else
//$$ mc.entityRenderer.updateLightmap(partialTicks);
//$$
//$$ GlStateManager.enableDepth();
//$$ GlStateManager.enableAlpha();
//$$ GlStateManager.alphaFunc(516, 0.5F);
//$$
//#if MC>=10800
mc.entityRenderer.renderWorldPass(2, partialTicks, finishTimeNano);
//$$ mc.entityRenderer.renderWorldPass(2, partialTicks, finishTimeNano);
//#else
//$$ mc.entityRenderer.renderWorld(partialTicks, finishTimeNano);
//#endif
//#endif
FMLCommonHandler.instance().onRenderTickEnd(partialTicks);
//#if MC>=11300
BasicEventHooks.onRenderTickEnd(partialTicks);
//#else
//$$ FMLCommonHandler.instance().onRenderTickEnd(partialTicks);
//#endif
}
@Override
@@ -71,10 +88,6 @@ public class EntityRendererHandler implements WorldRenderer {
this.omnidirectional = omnidirectional;
}
public interface GluPerspective {
void replayModRender_gluPerspective(float fovY, float aspect, float zNear, float zFar);
}
public interface IEntityRenderer {
void replayModRender_setHandler(EntityRendererHandler handler);
EntityRendererHandler replayModRender_getHandler();

View File

@@ -4,6 +4,8 @@ import com.coremedia.iso.IsoFile;
import com.coremedia.iso.boxes.*;
import com.google.common.primitives.Bytes;
import com.googlecode.mp4parser.BasicContainer;
import com.replaymod.render.RenderSettings;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
@@ -30,12 +32,20 @@ public class MetadataInjector {
"<GSpherical:Stitched>true</GSpherical:Stitched> " +
"<GSpherical:StitchingSoftware>"+STITCHING_SOFTWARE+"</GSpherical:StitchingSoftware> " +
"<GSpherical:ProjectionType>equirectangular</GSpherical:ProjectionType> ";
private static final String SPHERICAL_CROP_XML =
"<GSpherical:FullPanoWidthPixels>%d</GSpherical:FullPanoWidthPixels> " +
"<GSpherical:FullPanoHeightPixels>%d</GSpherical:FullPanoHeightPixels> " +
"<GSpherical:CroppedAreaImageWidthPixels>%d</GSpherical:CroppedAreaImageWidthPixels> " +
"<GSpherical:CroppedAreaImageHeightPixels>%d</GSpherical:CroppedAreaImageHeightPixels> " +
"<GSpherical:CroppedAreaLeftPixels>%d</GSpherical:CroppedAreaLeftPixels> " +
"<GSpherical:CroppedAreaTopPixels>%d</GSpherical:CroppedAreaTopPixels> ";
private static final String STEREO_XML_CONTENTS = "<GSpherical:StereoMode>top-bottom</GSpherical:StereoMode>";
private static final String SPHERICAL_XML_FOOTER = "</rdf:SphericalVideo>";
private static final String XML_360_METADATA = SPHERICAL_XML_HEADER + SPHERICAL_XML_CONTENTS + SPHERICAL_XML_FOOTER;
private static final String XML_ODS_METADATA = SPHERICAL_XML_HEADER + SPHERICAL_XML_CONTENTS
+ STEREO_XML_CONTENTS + SPHERICAL_XML_FOOTER;
private static final String XML_MONO_METADATA = SPHERICAL_XML_HEADER + SPHERICAL_XML_CONTENTS
+ SPHERICAL_CROP_XML + SPHERICAL_XML_FOOTER;
private static final String XML_STEREO_METADATA = SPHERICAL_XML_HEADER + SPHERICAL_XML_CONTENTS
+ SPHERICAL_CROP_XML + STEREO_XML_CONTENTS + SPHERICAL_XML_FOOTER;
/**
* These bytes are taken from the variable 'spherical_uuid_id'
@@ -48,18 +58,43 @@ public class MetadataInjector {
(byte)0x02, (byte)0x52, (byte)0x1f, (byte)0xdd
};
private static final byte[] BYTES_360_METADATA = Bytes.concat(UUID_BYTES, XML_360_METADATA.getBytes());
private static final byte[] BYTES_ODS_METADATA = Bytes.concat(UUID_BYTES, XML_ODS_METADATA.getBytes());
public static void injectMetadata(RenderSettings.RenderMethod renderMethod, File videoFile,
int videoWidth, int videoHeight,
int sphericalFovX, int sphericalFovY) {
String xmlString;
switch (renderMethod) {
case EQUIRECTANGULAR:
xmlString = XML_MONO_METADATA;
break;
case ODS:
xmlString = XML_STEREO_METADATA;
break;
default:
throw new IllegalArgumentException("Invalid render method");
}
public static void inject360Metadata(File videoFile) {
writeMetadata(videoFile, BYTES_360_METADATA);
Dimension original = getOriginalDimensions(videoWidth, videoHeight, sphericalFovX, sphericalFovY);
writeMetadata(videoFile, String.format(xmlString,
original.getWidth(), original.getHeight(), videoWidth, videoHeight,
(original.getWidth() - videoWidth) / 2, (original.getHeight() - videoHeight) / 2));
}
public static void injectODSMetadata(File videoFile) {
writeMetadata(videoFile, BYTES_ODS_METADATA);
private static Dimension getOriginalDimensions(int videoWidth, int videoHeight,
int sphericalFovX, int sphericalFovY) {
if (sphericalFovX < 360) {
videoWidth = Math.round(videoWidth * 360 / (float) sphericalFovX);
}
if (sphericalFovY < 180) {
videoHeight = Math.round(videoHeight * 180 / (float) sphericalFovY);
}
return new Dimension(videoWidth, videoHeight);
}
private static void writeMetadata(File videoFile, byte[] metadata) {
private static void writeMetadata(File videoFile, String metadata) {
byte[] bytes = Bytes.concat(UUID_BYTES, metadata.getBytes());
File tempFile = null;
FileOutputStream videoFileOutputStream = null;
IsoFile tempIsoFile = null;
@@ -80,7 +115,7 @@ public class MetadataInjector {
//create a new UserBox, which actually contains the Metadata bytes
UserBox metadataBox = new UserBox(new byte[0]);
metadataBox.setData(metadata);
metadataBox.setData(bytes);
//add the Metadata UserBox to the Movie Track
trackBox.addBox(metadataBox);
@@ -97,7 +132,7 @@ public class MetadataInjector {
videoFileOutputStream = new FileOutputStream(videoFile);
tempIsoFile.getBox(videoFileOutputStream.getChannel());
} catch(Exception e) {
LOGGER.error("360 Degree Metadata couldn't be injected", e);
LOGGER.error("Spherical Metadata couldn't be injected", e);
} finally {
IOUtils.closeQuietly(tempIsoFile);
IOUtils.closeQuietly(videoFileOutputStream);

View File

@@ -1,20 +1,16 @@
package com.replaymod.render.mixin;
import com.replaymod.core.versions.MCVer;
import com.replaymod.render.RenderSettings;
import com.replaymod.render.capturer.CubicOpenGlFrameCapturer;
import com.replaymod.render.capturer.StereoscopicOpenGlFrameCapturer;
import com.replaymod.render.hooks.EntityRendererHandler;
import com.replaymod.replay.camera.CameraEntity;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableColor;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.EntityRenderer;
import net.minecraft.client.renderer.RenderGlobal;
import net.minecraft.client.settings.GameSettings;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.ReadableColor;
import org.lwjgl.util.glu.Project;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
@@ -22,6 +18,18 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
//#if MC>=11300
import net.minecraft.client.GameSettings;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.Matrix4f;
import net.minecraft.client.renderer.WorldRenderer;
//#else
//$$ import net.minecraft.client.renderer.EntityRenderer;
//$$ import net.minecraft.client.renderer.RenderGlobal;
//$$ import net.minecraft.client.settings.GameSettings;
//$$ import org.lwjgl.util.glu.Project;
//#endif
//#if MC>=10904
import net.minecraft.util.math.RayTraceResult;
//#else
@@ -31,13 +39,18 @@ import net.minecraft.util.math.RayTraceResult;
//#if MC>=10800
import net.minecraft.client.renderer.GlStateManager;
//#else
//$$ import net.minecraft.entity.EntityLivingBase;
//$$ import com.replaymod.core.versions.MCVer.GlStateManager;
//#endif
import static com.replaymod.core.versions.MCVer.*;
@Mixin(value = EntityRenderer.class)
public abstract class MixinEntityRenderer implements EntityRendererHandler.IEntityRenderer, EntityRendererHandler.GluPerspective {
//#if MC>=11300
@Mixin(value = GameRenderer.class)
//#else
//$$ @Mixin(value = EntityRenderer.class)
//#endif
public abstract class MixinEntityRenderer implements EntityRendererHandler.IEntityRenderer {
@Shadow
public Minecraft mc;
@@ -64,18 +77,21 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti
//$$ }
//#endif
@Inject(method = "setupFog", at = @At("HEAD"), cancellable = true)
private void replayModRender_onSetupFog(int fogDistanceFlag, float partialTicks, CallbackInfo ci) {
if (replayModRender_handler == null) return;
if (replayModRender_handler.getSettings().getChromaKeyingColor() != null) {
ci.cancel();
}
}
// Moved to MixinFogRenderer in 1.13
//#if MC<11300
//$$ @Inject(method = "setupFog", at = @At("HEAD"), cancellable = true)
//$$ private void replayModRender_onSetupFog(int fogDistanceFlag, float partialTicks, CallbackInfo ci) {
//$$ if (replayModRender_handler == null) return;
//$$ if (replayModRender_handler.getSettings().getChromaKeyingColor() != null) {
//$$ ci.cancel();
//$$ }
//$$ }
//#endif
@Inject(method = "orientCamera", at = @At("HEAD"))
private void replayModRender_resetRotationIfNeeded(float partialTicks, CallbackInfo ci) {
if (replayModRender_handler != null) {
Entity entity = getRenderViewEntity(Minecraft.getMinecraft());
Entity entity = getRenderViewEntity(MCVer.getMinecraft());
RenderSettings settings = replayModRender_handler.getSettings();
if (settings.isStabilizeYaw()) {
entity.prevRotationYaw = entity.rotationYaw = 0;
@@ -96,9 +112,15 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti
private float orgRoll;
@Inject(method = "setupCameraTransform", at = @At("HEAD"))
private void replayModRender_beforeSetupCameraTransform(float partialTicks, int renderPass, CallbackInfo ci) {
private void replayModRender_beforeSetupCameraTransform(
float partialTicks,
//#if MC<11300
//$$ int renderPass,
//#endif
CallbackInfo ci
) {
if (replayModRender_handler != null) {
Entity entity = getRenderViewEntity(Minecraft.getMinecraft());
Entity entity = getRenderViewEntity(MCVer.getMinecraft());
orgYaw = entity.rotationYaw;
orgPitch = entity.rotationPitch;
orgPrevYaw = entity.prevRotationYaw;
@@ -108,9 +130,15 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti
}
@Inject(method = "setupCameraTransform", at = @At("RETURN"))
private void replayModRender_afterSetupCameraTransform(float partialTicks, int renderPass, CallbackInfo ci) {
private void replayModRender_afterSetupCameraTransform(
float partialTicks,
//#if MC<11300
//$$ int renderPass,
//#endif
CallbackInfo ci
) {
if (replayModRender_handler != null) {
Entity entity = getRenderViewEntity(Minecraft.getMinecraft());
Entity entity = getRenderViewEntity(MCVer.getMinecraft());
entity.rotationYaw = orgYaw;
entity.rotationPitch = orgPitch;
entity.prevRotationYaw = orgPrevYaw;
@@ -122,29 +150,46 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti
}
@Inject(method = "renderHand", at = @At("HEAD"), cancellable = true)
private void replayModRender_renderSpectatorHand(float partialTicks, int renderPass, CallbackInfo ci) {
private void replayModRender_renderSpectatorHand(
float partialTicks,
//#if MC<11300
//$$ int renderPass,
//#endif
CallbackInfo ci
) {
if (replayModRender_handler != null) {
if (replayModRender_handler.omnidirectional) {
// No spectator hands during 360° view, we wouldn't even know where to put it
ci.cancel();
return; // No spectator hands during 360° view, we wouldn't even know where to put it
}
Entity currentEntity = getRenderViewEntity(Minecraft.getMinecraft());
if (currentEntity instanceof EntityPlayer && !(currentEntity instanceof CameraEntity)) {
if (renderPass == 2) { // Need to update render pass
renderPass = replayModRender_handler.data == StereoscopicOpenGlFrameCapturer.Data.LEFT_EYE ? 1 : 0;
renderHand(partialTicks, renderPass);
ci.cancel();
} // else, render normally
//#if MC>=11300
}
//#else
//$$ } else {
//$$ Entity currentEntity = getRenderViewEntity(MCVer.getMinecraft());
//$$ if (currentEntity instanceof EntityPlayer && !(currentEntity instanceof CameraEntity)) {
//$$ if (renderPass == 2) { // Need to update render pass
//$$ renderPass = replayModRender_handler.data == StereoscopicOpenGlFrameCapturer.Data.LEFT_EYE ? 1 : 0;
//$$ renderHand(partialTicks, renderPass);
//$$ ci.cancel();
//$$ } // else, render normally
//$$ }
//$$ }
//#endif
}
}
@Shadow
public abstract void renderHand(float partialTicks, int renderPass);
//#if MC<11300
//$$ @Shadow
//$$ public abstract void renderHand(float partialTicks, int renderPass);
//#endif
//#if MC>=11300
@Redirect(method = "updateCameraAndRender(FJ)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/WorldRenderer;drawSelectionBox(Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/math/RayTraceResult;IF)V"))
private void replayModRender_drawSelectionBox(WorldRenderer instance, EntityPlayer player, RayTraceResult rtr, int alwaysZero, float partialTicks) {
//#else
//#if MC>=10904
@Redirect(method = "renderWorldPass", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/RenderGlobal;drawSelectionBox(Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/math/RayTraceResult;IF)V"))
private void replayModRender_drawSelectionBox(RenderGlobal instance, EntityPlayer player, RayTraceResult rtr, int alwaysZero, float partialTicks) {
//$$ @Redirect(method = "renderWorldPass", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/RenderGlobal;drawSelectionBox(Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/math/RayTraceResult;IF)V"))
//$$ private void replayModRender_drawSelectionBox(RenderGlobal instance, EntityPlayer player, RayTraceResult rtr, int alwaysZero, float partialTicks) {
//#else
//#if MC>=10800
//$$ @Redirect(method = "renderWorldPass", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/RenderGlobal;drawSelectionBox(Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/MovingObjectPosition;IF)V"))
@@ -152,6 +197,7 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti
//$$ @Redirect(method = "renderWorld", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/RenderGlobal;drawSelectionBox(Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/MovingObjectPosition;IF)V"))
//#endif
//$$ private void replayModRender_drawSelectionBox(RenderGlobal instance, EntityPlayer player, MovingObjectPosition rtr, int alwaysZero, float partialTicks) {
//#endif
//#endif
if (replayModRender_handler == null) {
instance.drawSelectionBox(player, rtr, alwaysZero, partialTicks);
@@ -160,38 +206,51 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti
private int orgRenderDistanceChunks;
//#if MC>=11300
@Inject(method = "updateCameraAndRender(FJ)V", at = @At(value = "JUMP", ordinal = 0))
//#else
//#if MC>=10800
@Inject(method = "renderWorldPass", at = @At(value = "JUMP", ordinal = 0))
//$$ @Inject(method = "renderWorldPass", at = @At(value = "JUMP", ordinal = 0))
//#else
//$$ @Inject(method = "renderWorld", at = @At(value = "INVOKE", ordinal = 0, shift = At.Shift.AFTER,
//$$ target = "Lnet/minecraft/client/renderer/culling/ClippingHelperImpl;getInstance()Lnet/minecraft/client/renderer/culling/ClippingHelper;"))
//#endif
//#endif
private void replayModRender_beforeRenderSky(CallbackInfo ci) {
if (replayModRender_handler != null && replayModRender_handler.getSettings().getChromaKeyingColor() != null) {
GameSettings settings = Minecraft.getMinecraft().gameSettings;
GameSettings settings = MCVer.getMinecraft().gameSettings;
orgRenderDistanceChunks = settings.renderDistanceChunks;
settings.renderDistanceChunks = 5; // Set render distance to 5 so we're always rendering sky when chroma keying
}
}
//#if MC>=11300
@Redirect(method = "updateCameraAndRender(FJ)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/WorldRenderer;renderSky(F)V"))
private void replayModRender_renderSky(WorldRenderer instance, float partialTicks) {
//#else
//#if MC>=10800
@Redirect(method = "renderWorldPass", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/RenderGlobal;renderSky(FI)V"))
private void replayModRender_renderSky(RenderGlobal instance, float partialTicks, int renderPass) {
//$$ @Redirect(method = "renderWorldPass", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/RenderGlobal;renderSky(FI)V"))
//$$ private void replayModRender_renderSky(RenderGlobal instance, float partialTicks, int renderPass) {
//#else
//$$ @Redirect(method = "renderWorld", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/RenderGlobal;renderSky(F)V"))
//$$ private void replayModRender_renderSky(RenderGlobal instance, float partialTicks) {
//#endif
//#endif
if (replayModRender_handler != null && replayModRender_handler.getSettings().getChromaKeyingColor() != null) {
Minecraft.getMinecraft().gameSettings.renderDistanceChunks = orgRenderDistanceChunks;
MCVer.getMinecraft().gameSettings.renderDistanceChunks = orgRenderDistanceChunks;
ReadableColor color = replayModRender_handler.getSettings().getChromaKeyingColor();
GlStateManager.clearColor(color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, 1);
GlStateManager.clear(GL11.GL_COLOR_BUFFER_BIT);
} else {
//#if MC>=11300
instance.renderSky(partialTicks);
//#else
//#if MC>=10800
instance.renderSky(partialTicks, renderPass);
//$$ instance.renderSky(partialTicks, renderPass);
//#else
//$$ instance.renderSky(partialTicks);
//#endif
//#endif
}
}
@@ -204,12 +263,18 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti
//#else
//$$ @Inject(method = "setupCameraTransform", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glLoadIdentity()V", shift = At.Shift.AFTER, ordinal = 0, remap = false))
//#endif
private void replayModRender_setupStereoscopicProjection(float partialTicks, int renderPass, CallbackInfo ci) {
private void replayModRender_setupStereoscopicProjection(
float partialTicks,
//#if MC<11300
//$$ int renderPass,
//#endif
CallbackInfo ci
) {
if (replayModRender_getHandler() != null) {
if (replayModRender_getHandler().data == StereoscopicOpenGlFrameCapturer.Data.LEFT_EYE) {
GlStateManager.translate(0.07, 0, 0);
GL11.glTranslatef(0.07f, 0, 0);
} else if (replayModRender_getHandler().data == StereoscopicOpenGlFrameCapturer.Data.RIGHT_EYE) {
GlStateManager.translate(-0.07, 0, 0);
GL11.glTranslatef(-0.07f, 0, 0);
}
}
}
@@ -219,12 +284,18 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti
//#else
//$$ @Inject(method = "setupCameraTransform", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glLoadIdentity()V", shift = At.Shift.AFTER, ordinal = 1, remap = false))
//#endif
private void replayModRender_setupStereoscopicModelView(float partialTicks, int renderPass, CallbackInfo ci) {
private void replayModRender_setupStereoscopicModelView(
float partialTicks,
//#if MC<11300
//$$ int renderPass,
//#endif
CallbackInfo ci
) {
if (replayModRender_getHandler() != null) {
if (replayModRender_getHandler().data == StereoscopicOpenGlFrameCapturer.Data.LEFT_EYE) {
GlStateManager.translate(0.1, 0, 0);
GL11.glTranslatef(0.1f, 0, 0);
} else if (replayModRender_getHandler().data == StereoscopicOpenGlFrameCapturer.Data.RIGHT_EYE) {
GlStateManager.translate(-0.1, 0, 0);
GL11.glTranslatef(-0.1f, 0, 0);
}
}
}
@@ -233,63 +304,91 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti
* Cubic Renderer
*/
@Redirect(method = "setupCameraTransform", at = @At(value = "INVOKE", target = "Lorg/lwjgl/util/glu/Project;gluPerspective(FFFF)V", remap = false))
private void replayModRender_gluPerspective$0(float fovY, float aspect, float zNear, float zFar) {
replayModRender_gluPerspective(fovY, aspect, zNear, zFar);
//#if MC>=11300
@Redirect(method = "setupCameraTransform", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/Matrix4f;perspective(DFFF)Lnet/minecraft/client/renderer/Matrix4f;"))
private Matrix4f replayModRender_perspective$0(double fovY, float aspect, float zNear, float zFar) {
return replayModRender_perspective((float) fovY, aspect, zNear, zFar);
}
//#if MC>=10800
@Redirect(method = "renderWorldPass", at = @At(value = "INVOKE", target = "Lorg/lwjgl/util/glu/Project;gluPerspective(FFFF)V", remap = false))
//#else
//$$ @Redirect(method = "renderHand", at = @At(value = "INVOKE", target = "Lorg/lwjgl/util/glu/Project;gluPerspective(FFFF)V", remap = false))
//#endif
private void replayModRender_gluPerspective$1(float fovY, float aspect, float zNear, float zFar) {
replayModRender_gluPerspective(fovY, aspect, zNear, zFar);
@Redirect(method = "updateCameraAndRender(FJ)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/Matrix4f;perspective(DFFF)Lnet/minecraft/client/renderer/Matrix4f;"))
private Matrix4f replayModRender_perspective$1(double fovY, float aspect, float zNear, float zFar) {
return replayModRender_perspective((float) fovY, aspect, zNear, zFar);
}
//#if MC>=10800
@Redirect(method = "renderCloudsCheck", at = @At(value = "INVOKE", target = "Lorg/lwjgl/util/glu/Project;gluPerspective(FFFF)V", remap = false))
private void replayModRender_gluPerspective$2(float fovY, float aspect, float zNear, float zFar) {
replayModRender_gluPerspective(fovY, aspect, zNear, zFar);
@Redirect(method = "renderCloudsCheck", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/Matrix4f;perspective(DFFF)Lnet/minecraft/client/renderer/Matrix4f;"))
private Matrix4f replayModRender_perspective$2(double fovY, float aspect, float zNear, float zFar) {
return replayModRender_perspective((float) fovY, aspect, zNear, zFar);
}
//#endif
@Override
public void replayModRender_gluPerspective(float fovY, float aspect, float zNear, float zFar) {
private Matrix4f replayModRender_perspective(float fovY, float aspect, float zNear, float zFar) {
if (replayModRender_getHandler() != null && replayModRender_getHandler().omnidirectional) {
fovY = 90;
aspect = 1;
}
Project.gluPerspective(fovY, aspect, zNear, zFar);
return Matrix4f.perspective(fovY, aspect, zNear, zFar);
}
//#else
//$$ @Redirect(method = "setupCameraTransform", at = @At(value = "INVOKE", target = "Lorg/lwjgl/util/glu/Project;gluPerspective(FFFF)V", remap = false))
//$$ private void replayModRender_gluPerspective$0(float fovY, float aspect, float zNear, float zFar) {
//$$ replayModRender_gluPerspective(fovY, aspect, zNear, zFar);
//$$ }
//$$
//#if MC>=10800
//$$ @Redirect(method = "renderWorldPass", at = @At(value = "INVOKE", target = "Lorg/lwjgl/util/glu/Project;gluPerspective(FFFF)V", remap = false))
//#else
//$$ @Redirect(method = "renderHand", at = @At(value = "INVOKE", target = "Lorg/lwjgl/util/glu/Project;gluPerspective(FFFF)V", remap = false))
//#endif
//$$ private void replayModRender_gluPerspective$1(float fovY, float aspect, float zNear, float zFar) {
//$$ replayModRender_gluPerspective(fovY, aspect, zNear, zFar);
//$$ }
//$$
//#if MC>=10800
//$$ @Redirect(method = "renderCloudsCheck", at = @At(value = "INVOKE", target = "Lorg/lwjgl/util/glu/Project;gluPerspective(FFFF)V", remap = false))
//$$ private void replayModRender_gluPerspective$2(float fovY, float aspect, float zNear, float zFar) {
//$$ replayModRender_gluPerspective(fovY, aspect, zNear, zFar);
//$$ }
//#endif
//$$
//$$ private void replayModRender_gluPerspective(float fovY, float aspect, float zNear, float zFar) {
//$$ if (replayModRender_getHandler() != null && replayModRender_getHandler().omnidirectional) {
//$$ fovY = 90;
//$$ aspect = 1;
//$$ }
//$$ Project.gluPerspective(fovY, aspect, zNear, zFar);
//$$ }
//#endif
@Inject(method = "orientCamera", at = @At("HEAD"))
private void replayModRender_setupCubicFrameRotation(float partialTicks, CallbackInfo ci) {
if (replayModRender_getHandler() != null && replayModRender_getHandler().data instanceof CubicOpenGlFrameCapturer.Data) {
switch ((CubicOpenGlFrameCapturer.Data) replayModRender_getHandler().data) {
case FRONT:
GlStateManager.rotate(0, 0.0F, 1.0F, 0.0F);
GL11.glRotatef(0, 0.0F, 1.0F, 0.0F);
break;
case RIGHT:
GlStateManager.rotate(90, 0.0F, 1.0F, 0.0F);
GL11.glRotatef(90, 0.0F, 1.0F, 0.0F);
break;
case BACK:
GlStateManager.rotate(180, 0.0F, 1.0F, 0.0F);
GL11.glRotatef(180, 0.0F, 1.0F, 0.0F);
break;
case LEFT:
GlStateManager.rotate(-90, 0.0F, 1.0F, 0.0F);
GL11.glRotatef(-90, 0.0F, 1.0F, 0.0F);
break;
case BOTTOM:
GlStateManager.rotate(90, 1.0F, 0.0F, 0.0F);
GL11.glRotatef(90, 1.0F, 0.0F, 0.0F);
break;
case TOP:
GlStateManager.rotate(-90, 1.0F, 0.0F, 0.0F);
GL11.glRotatef(-90, 1.0F, 0.0F, 0.0F);
break;
}
}
if (replayModRender_getHandler() != null && replayModRender_getHandler().omnidirectional) {
// Minecraft goes back a little so we have to revert that
GlStateManager.translate(0.0F, 0.0F, 0.1F);
//#if MC>=11300
GL11.glTranslatef(0.0F, 0.0F, -0.05F);
//#else
//$$ GL11.glTranslatef(0.0F, 0.0F, 0.1F);
//#endif
}
}
}

View File

@@ -0,0 +1,24 @@
//#if MC>=11300
package com.replaymod.render.mixin;
import com.replaymod.core.versions.MCVer;
import com.replaymod.render.hooks.EntityRendererHandler;
import net.minecraft.client.renderer.FogRenderer;
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(FogRenderer.class)
public abstract class MixinFogRenderer {
@Inject(method = "setupFog", at = @At("HEAD"), cancellable = true)
private void replayModRender_onSetupFog(int fogDistanceFlag, float partialTicks, CallbackInfo ci) {
EntityRendererHandler handler =
((EntityRendererHandler.IEntityRenderer) MCVer.getMinecraft().entityRenderer).replayModRender_getHandler();
if (handler == null) return;
if (handler.getSettings().getChromaKeyingColor() != null) {
ci.cancel();
}
}
}
//#endif

View File

@@ -1,7 +1,7 @@
package com.replaymod.render.mixin;
import com.replaymod.core.versions.MCVer;
import com.replaymod.render.hooks.EntityRendererHandler;
import net.minecraft.client.Minecraft;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@@ -21,7 +21,7 @@ import net.minecraft.client.renderer.culling.Frustum;
public abstract class MixinFrustum {
@Inject(method = "isBoxInFrustum", at = @At("HEAD"), cancellable = true)
public void isBoxInFrustum(double minX, double minY, double minZ, double maxX, double maxY, double maxZ, CallbackInfoReturnable<Boolean> ci) {
EntityRendererHandler handler = ((EntityRendererHandler.IEntityRenderer) Minecraft.getMinecraft().entityRenderer).replayModRender_getHandler();
EntityRendererHandler handler = ((EntityRendererHandler.IEntityRenderer) MCVer.getMinecraft().entityRenderer).replayModRender_getHandler();
if (handler != null && handler.omnidirectional && handler.data == null) {
// Normally the camera is always facing the direction of the omnidirectional image face that is currently
// getting rendered. With ODS however, the camera is always facing forwards and the turning happens in the

View File

@@ -1,10 +1,10 @@
package com.replaymod.render.mixin;
//#if MC>=10904
import com.replaymod.core.versions.MCVer;
import com.replaymod.render.blend.BlendState;
import com.replaymod.render.blend.exporters.ParticlesExporter;
import com.replaymod.render.hooks.EntityRendererHandler;
import net.minecraft.client.Minecraft;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.particle.ParticleManager;
import net.minecraft.entity.Entity;
@@ -48,7 +48,7 @@ public abstract class MixinParticleManager {
//$$ private void renderParticle(Particle particle, VertexBuffer vertexBuffer, Entity view, float partialTicks,
//#endif
float rotX, float rotXZ, float rotZ, float rotYZ, float rotXY) {
EntityRendererHandler handler = ((EntityRendererHandler.IEntityRenderer) Minecraft.getMinecraft().entityRenderer).replayModRender_getHandler();
EntityRendererHandler handler = ((EntityRendererHandler.IEntityRenderer) MCVer.getMinecraft().entityRenderer).replayModRender_getHandler();
if (handler != null && handler.omnidirectional) {
// Align all particles towards the camera
double dx = particle.prevPosX + (particle.posX - particle.prevPosX) * partialTicks - view.posX;

View File

@@ -1,7 +1,7 @@
package com.replaymod.render.mixin;
import com.replaymod.core.versions.MCVer;
import com.replaymod.render.hooks.EntityRendererHandler;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
@@ -13,7 +13,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
public abstract class MixinRender {
@Inject(method = "renderLivingLabel", at = @At("HEAD"), cancellable = true)
private void replayModRender_areAllNamesHidden(Entity entityIn, String str, double x, double y, double z, int maxDistance, CallbackInfo ci) {
EntityRendererHandler handler = ((EntityRendererHandler.IEntityRenderer) Minecraft.getMinecraft().entityRenderer).replayModRender_getHandler();
EntityRendererHandler handler = ((EntityRendererHandler.IEntityRenderer) MCVer.getMinecraft().entityRenderer).replayModRender_getHandler();
if (handler != null && !handler.getSettings().isRenderNameTags()) {
ci.cancel();
}

View File

@@ -2,7 +2,6 @@
package com.replaymod.render.mixin;
import com.replaymod.render.hooks.ChunkLoadingRenderGlobal;
import net.minecraft.client.renderer.RenderGlobal;
import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher;
import net.minecraft.client.renderer.culling.ICamera;
import net.minecraft.entity.Entity;
@@ -10,16 +9,25 @@ 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.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
//#if MC>=11300
import net.minecraft.client.renderer.WorldRenderer;
//#else
//$$ import net.minecraft.client.renderer.RenderGlobal;
//#endif
//#if MC<10904
//$$ import net.minecraft.client.renderer.chunk.RenderChunk;
//$$ import net.minecraft.util.BlockPos;
//$$ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
//#endif
@Mixin(RenderGlobal.class)
//#if MC>=11300
@Mixin(WorldRenderer.class)
//#else
//$$ @Mixin(RenderGlobal.class)
//#endif
public abstract class MixinRenderGlobal {
public ChunkLoadingRenderGlobal replayModRender_hook;
private boolean replayModRender_passThroughSetupTerrain;
@@ -31,12 +39,31 @@ public abstract class MixinRenderGlobal {
public ChunkRenderDispatcher renderDispatcher;
@Shadow
public abstract void setupTerrain(Entity viewEntity, double partialTicks, ICamera camera,
int frameCount, boolean playerSpectator);
public abstract void setupTerrain(
Entity viewEntity,
//#if MC>=11300
float partialTicks,
//#else
//$$ double partialTicks,
//#endif
ICamera camera,
int frameCount,
boolean playerSpectator
);
@Inject(method = "setupTerrain", at = @At("HEAD"), cancellable = true)
public void replayModRender_setupTerrain(Entity viewEntity, double partialTicks, ICamera camera,
int frameCount, boolean playerSpectator, CallbackInfo ci) {
private void replayModRender_setupTerrain(
Entity viewEntity,
//#if MC>=11300
float partialTicks,
//#else
//$$ double partialTicks,
//#endif
ICamera camera,
int frameCount,
boolean playerSpectator,
CallbackInfo ci
) {
if (replayModRender_hook != null && !replayModRender_passThroughSetupTerrain) {
replayModRender_passThroughSetupTerrain = true;

View File

@@ -1,7 +1,7 @@
package com.replaymod.render.mixin;
import com.replaymod.core.versions.MCVer;
import com.replaymod.render.hooks.EntityRendererHandler;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
@@ -23,13 +23,17 @@ public abstract class MixinRenderManager {
@Shadow
private float playerViewY;
@Inject(method = "doRenderEntity", at = @At("HEAD"))
//#if MC>=11300
@Inject(method = "renderEntity", at = @At("HEAD"))
//#else
//$$ @Inject(method = "doRenderEntity", at = @At("HEAD"))
//#endif
//#if MC>=10904
private void replayModRender_reorientForCubicRendering(Entity entity, double dx, double dy, double dz, float iDoNotKnow, float partialTicks, boolean iDoNotCare, CallbackInfo ci) {
//#else
//$$ private void replayModRender_reorientForCubicRendering(Entity entity, double dx, double dy, double dz, float iDoNotKnow, float partialTicks, boolean iDoNotCare, CallbackInfoReturnable<Boolean> ci) {
//#endif
EntityRendererHandler handler = ((EntityRendererHandler.IEntityRenderer) Minecraft.getMinecraft().entityRenderer).replayModRender_getHandler();
EntityRendererHandler handler = ((EntityRendererHandler.IEntityRenderer) MCVer.getMinecraft().entityRenderer).replayModRender_getHandler();
if (handler != null && handler.omnidirectional) {
double pitch = -Math.atan2(dy, Math.sqrt(dx * dx + dz * dz));
double yaw = -Math.atan2(dx, dz);

View File

@@ -3,7 +3,7 @@ package com.replaymod.render.processor;
import com.replaymod.render.frame.CubicOpenGlFrame;
import com.replaymod.render.frame.RGBFrame;
import com.replaymod.render.utils.ByteBufferPool;
import org.lwjgl.util.Dimension;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import java.nio.ByteBuffer;
@@ -15,7 +15,7 @@ public class CubicToRGBProcessor extends AbstractFrameProcessor<CubicOpenGlFrame
int size = rawFrame.getLeft().getSize().getWidth();
int width = size * 4;
int height = size * 3;
ByteBuffer result = ByteBufferPool.allocate(width * height * 3);
ByteBuffer result = ByteBufferPool.allocate(width * height * 4);
openGlBytesToRBG(rawFrame.getLeft().getByteBuffer(), size, 0, size, result, width);
openGlBytesToRBG(rawFrame.getFront().getByteBuffer(), size, size, size, result, width);
openGlBytesToRBG(rawFrame.getRight().getByteBuffer(), size, size * 2, size, result, width);

View File

@@ -3,8 +3,9 @@ package com.replaymod.render.processor;
import com.replaymod.render.frame.CubicOpenGlFrame;
import com.replaymod.render.frame.RGBFrame;
import com.replaymod.render.utils.ByteBufferPool;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import lombok.Getter;
import org.apache.commons.lang3.Validate;
import org.lwjgl.util.Dimension;
import java.nio.ByteBuffer;
@@ -18,6 +19,7 @@ public class EquirectangularToRGBProcessor extends AbstractFrameProcessor<CubicO
private static final byte IMAGE_TOP = 4;
private static final byte IMAGE_BOTTOM = 5;
@Getter
private final int frameSize;
private final int width;
private final int height;
@@ -26,18 +28,36 @@ public class EquirectangularToRGBProcessor extends AbstractFrameProcessor<CubicO
private final int[][] imageX;
private final int[][] imageY;
public EquirectangularToRGBProcessor(int outputWidth, int outputHeight, int sphericalFovX) {
// calculate the dimensions of the original equirectangular projection
// (before cropping according to FOV)
width = outputWidth;
height = outputHeight;
public EquirectangularToRGBProcessor(int frameSize) {
this.frameSize = frameSize;
int fullWidth;
if (sphericalFovX < 360) {
fullWidth = Math.round(width * 360 / (float) sphericalFovX);
} else {
fullWidth = width;
}
int fullHeight = fullWidth / 2;
frameSize = fullWidth / 4;
width = frameSize * 4;
height = frameSize * 2;
image = new byte[height][width];
imageX = new int[height][width];
imageY = new int[height][width];
for (int i = 0; i < width; i++) {
double yaw = PI * 2 * i / width;
int piQuarter = 8 * i / width - 4;
int xOffset = (fullWidth - width) / 2;
int yOffset = (fullHeight - height) / 2;
for (int x = 0; x < width; x++) {
// get x position relative to the full projection
int i = xOffset + x;
double yaw = PI * 2 * i / fullWidth;
int piQuarter = 8 * i / fullWidth - 4;
byte target;
if (piQuarter < -3) {
target = IMAGE_BACK;
@@ -50,13 +70,16 @@ public class EquirectangularToRGBProcessor extends AbstractFrameProcessor<CubicO
} else {
target = IMAGE_BACK;
}
double fYaw = (yaw + PI/4) % (PI / 2) - PI/4;
double fYaw = (yaw + PI / 4) % (PI / 2) - PI / 4;
double d = 1 / Math.cos(fYaw);
double gcXN = (Math.tan(fYaw) + 1) / 2;
for (int j = 0; j < height; j++) {
for (int y = 0; y < height; y++) {
// get y position relative to the full projection
int j = yOffset + y;
double cXN = gcXN;
byte pt = target;
double pitch = PI * j / height - PI / 2;
double pitch = PI * j / fullHeight - PI / 2;
double cYN = (Math.tan(pitch) * d + 1) / 2;
if (cYN >= 1) {
@@ -74,9 +97,9 @@ public class EquirectangularToRGBProcessor extends AbstractFrameProcessor<CubicO
int imgX = (int) Math.min(frameSize - 1, (cXN * frameSize));
int imgY = (int) Math.min(frameSize - 1, (cYN * frameSize));
image[j][i] = pt;
imageX[j][i] = imgX;
imageY[j][i] = frameSize - imgY - 1; // The OpenGl buffer contains data flipped vertically
image[y][x] = pt;
imageX[y][x] = imgX;
imageY[y][x] = frameSize - imgY - 1; // The OpenGl buffer contains data flipped vertically
}
}
}
@@ -85,13 +108,13 @@ public class EquirectangularToRGBProcessor extends AbstractFrameProcessor<CubicO
public RGBFrame process(CubicOpenGlFrame rawFrame) {
Validate.isTrue(rawFrame.getLeft().getSize().getWidth() == frameSize, "Frame size must be %d but was %d",
frameSize, rawFrame.getLeft().getSize().getWidth());
ByteBuffer result = ByteBufferPool.allocate(width * height * 3);
ByteBuffer result = ByteBufferPool.allocate(width * height * 4);
ByteBuffer[] images = {
rawFrame.getBack().getByteBuffer(), rawFrame.getFront().getByteBuffer(),
rawFrame.getLeft().getByteBuffer(), rawFrame.getRight().getByteBuffer(),
rawFrame.getTop().getByteBuffer(), rawFrame.getBottom().getByteBuffer()
};
byte[] pixel = new byte[3];
byte[] pixel = new byte[4];
byte[] image;
int[] imageX, imageY;
for (int y = 0; y < height; y++) {
@@ -100,7 +123,7 @@ public class EquirectangularToRGBProcessor extends AbstractFrameProcessor<CubicO
imageY = this.imageY[y];
for (int x = 0; x < width; x++) {
ByteBuffer source = images[image[x]];
source.position((imageX[x] + imageY[x] * frameSize) * 3);
source.position((imageX[x] + imageY[x] * frameSize) * 4);
source.get(pixel);
result.put(pixel);
}

View File

@@ -3,8 +3,8 @@ package com.replaymod.render.processor;
import com.replaymod.render.frame.ODSOpenGlFrame;
import com.replaymod.render.frame.RGBFrame;
import com.replaymod.render.utils.ByteBufferPool;
import org.lwjgl.util.Dimension;
import org.lwjgl.util.ReadableDimension;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -12,8 +12,8 @@ import java.nio.ByteBuffer;
public class ODSToRGBProcessor extends AbstractFrameProcessor<ODSOpenGlFrame, RGBFrame> {
private final EquirectangularToRGBProcessor processor;
public ODSToRGBProcessor(int frameSize) {
processor = new EquirectangularToRGBProcessor(frameSize);
public ODSToRGBProcessor(int outputWidth, int outputHeight, int sphericalFovX) {
processor = new EquirectangularToRGBProcessor(outputWidth, outputHeight / 2, sphericalFovX);
}
@Override
@@ -21,7 +21,7 @@ public class ODSToRGBProcessor extends AbstractFrameProcessor<ODSOpenGlFrame, RG
RGBFrame leftFrame = processor.process(rawFrame.getLeft());
RGBFrame rightFrame = processor.process(rawFrame.getRight());
ReadableDimension size = new Dimension(leftFrame.getSize().getWidth(), leftFrame.getSize().getHeight() * 2);
ByteBuffer result = ByteBufferPool.allocate(size.getWidth() * size.getHeight() * 3);
ByteBuffer result = ByteBufferPool.allocate(size.getWidth() * size.getHeight() * 4);
result.put(leftFrame.getByteBuffer());
result.put(rightFrame.getByteBuffer());
result.rewind();
@@ -34,4 +34,8 @@ public class ODSToRGBProcessor extends AbstractFrameProcessor<ODSOpenGlFrame, RG
public void close() throws IOException {
processor.close();
}
public int getFrameSize() {
return processor.getFrameSize();
}
}

View File

@@ -2,7 +2,7 @@ package com.replaymod.render.processor;
import com.replaymod.render.frame.OpenGlFrame;
import com.replaymod.render.frame.RGBFrame;
import org.lwjgl.util.ReadableDimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import java.nio.ByteBuffer;
@@ -15,7 +15,7 @@ public class OpenGlToRGBProcessor extends AbstractFrameProcessor<OpenGlFrame, RG
// Flip whole image in place
ReadableDimension size = rawFrame.getSize();
int rowSize = size.getWidth() * 3;
int rowSize = size.getWidth() * 4;
if (row == null || row.length < rowSize) {
row = new byte[rowSize];
rowSwap = new byte[rowSize];

View File

@@ -3,8 +3,8 @@ package com.replaymod.render.processor;
import com.replaymod.render.frame.RGBFrame;
import com.replaymod.render.frame.StereoscopicOpenGlFrame;
import com.replaymod.render.utils.ByteBufferPool;
import org.lwjgl.util.Dimension;
import org.lwjgl.util.ReadableDimension;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import java.nio.ByteBuffer;
@@ -17,7 +17,7 @@ public class StereoscopicToRGBProcessor extends AbstractFrameProcessor<Stereosco
int width = size.getWidth();
ByteBuffer leftBuffer = rawFrame.getLeft().getByteBuffer();
ByteBuffer rightBuffer = rawFrame.getRight().getByteBuffer();
ByteBuffer result = ByteBufferPool.allocate(width * 2 * size.getHeight() * 3);
ByteBuffer result = ByteBufferPool.allocate(width * 2 * size.getHeight() * 4);
openGlBytesToRBG(leftBuffer, width, 0, 0, result, width * 2);
openGlBytesToRBG(rightBuffer, width, size.getWidth(), 0, result, width * 2);
ByteBufferPool.release(leftBuffer);

View File

@@ -1,16 +1,23 @@
package com.replaymod.render.rendering;
import com.replaymod.core.versions.MCVer;
import lombok.RequiredArgsConstructor;
import net.minecraft.client.Minecraft;
import net.minecraft.crash.CrashReport;
import net.minecraft.util.ReportedException;
import org.lwjgl.opengl.Display;
//#if MC>=11300
import org.lwjgl.glfw.GLFW;
//#else
//$$ import org.lwjgl.opengl.Display;
//#endif
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import static com.replaymod.core.versions.MCVer.newReportedException;
public class Pipeline<R extends Frame, P extends Frame> implements Runnable {
private final FrameCapturer<R> capturer;
@@ -48,9 +55,13 @@ public class Pipeline<R extends Frame, P extends Frame> implements Runnable {
}
}, new ThreadPoolExecutor.DiscardPolicy());
Minecraft mc = Minecraft.getMinecraft();
Minecraft mc = MCVer.getMinecraft();
while (!capturer.isDone() && !Thread.currentThread().isInterrupted()) {
if (Display.isCloseRequested() || mc.hasCrashed) {
//#if MC>=11300
if (GLFW.glfwWindowShouldClose(mc.mainWindow.getHandle()) || mc.hasCrashed) {
//#else
//$$ if (Display.isCloseRequested() || mc.hasCrashed) {
//#endif
Thread.currentThread().interrupt();
return;
}
@@ -73,7 +84,7 @@ public class Pipeline<R extends Frame, P extends Frame> implements Runnable {
consumer.close();
} catch (Throwable t) {
CrashReport crashReport = CrashReport.makeCrashReport(t, "Cleaning up rendering pipeline");
throw new ReportedException(crashReport);
throw newReportedException(crashReport);
}
}
@@ -105,7 +116,7 @@ public class Pipeline<R extends Frame, P extends Frame> implements Runnable {
}
} catch (Throwable t) {
CrashReport crashReport = CrashReport.makeCrashReport(t, "Processing frame");
Minecraft.getMinecraft().crashed(crashReport);
MCVer.getMinecraft().crashed(crashReport);
}
}
}

View File

@@ -82,20 +82,28 @@ public class Pipelines {
public static Pipeline<CubicOpenGlFrame, RGBFrame> newEquirectangularPipeline(RenderInfo renderInfo, FrameConsumer<RGBFrame> consumer) {
RenderSettings settings = renderInfo.getRenderSettings();
EquirectangularToRGBProcessor processor = new EquirectangularToRGBProcessor(settings.getVideoWidth(),
settings.getVideoHeight(), settings.getSphericalFovX());
FrameCapturer<CubicOpenGlFrame> capturer;
if (PixelBufferObject.SUPPORTED) {
capturer = new CubicPboOpenGlFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo, settings.getVideoWidth() / 4);
capturer = new CubicPboOpenGlFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo, processor.getFrameSize());
} else {
capturer = new CubicOpenGlFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo, settings.getVideoWidth() / 4);
capturer = new CubicOpenGlFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo, processor.getFrameSize());
}
return new Pipeline<>(capturer, new EquirectangularToRGBProcessor(settings.getVideoWidth() / 4), consumer);
return new Pipeline<>(capturer, processor, consumer);
}
public static Pipeline<ODSOpenGlFrame, RGBFrame> newODSPipeline(RenderInfo renderInfo, FrameConsumer<RGBFrame> consumer) {
RenderSettings settings = renderInfo.getRenderSettings();
ODSToRGBProcessor processor = new ODSToRGBProcessor(settings.getVideoWidth(),
settings.getVideoHeight(), settings.getSphericalFovX());
FrameCapturer<ODSOpenGlFrame> capturer =
new ODSFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo, settings.getVideoWidth() / 4);
return new Pipeline<>(capturer, new ODSToRGBProcessor(settings.getVideoWidth() / 4), consumer);
new ODSFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo, processor.getFrameSize());
return new Pipeline<>(capturer, processor, consumer);
}
public static Pipeline<RGBFrame, RGBFrame> newBlendPipeline(RenderInfo renderInfo) {

View File

@@ -1,6 +1,7 @@
package com.replaymod.render.rendering;
import com.replaymod.core.utils.WrappedTimer;
import com.replaymod.core.versions.MCVer;
import com.replaymod.pathing.player.AbstractTimelinePlayer;
import com.replaymod.pathing.player.ReplayTimer;
import com.replaymod.pathing.properties.TimestampProperty;
@@ -19,15 +20,20 @@ import com.replaymod.replay.ReplayHandler;
import com.replaymod.replaystudio.pathing.path.Keyframe;
import com.replaymod.replaystudio.pathing.path.Path;
import com.replaymod.replaystudio.pathing.path.Timeline;
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.shader.Framebuffer;
import net.minecraft.util.Timer;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.util.Dimension;
import org.lwjgl.util.ReadableDimension;
//#if MC>=11300
import org.lwjgl.glfw.GLFW;
//#else
//$$ import net.minecraft.client.gui.ScaledResolution;
//$$ import org.lwjgl.input.Mouse;
//$$ import org.lwjgl.opengl.Display;
//#endif
//#if MC>=10904
import net.minecraft.util.SoundCategory;
@@ -57,7 +63,7 @@ import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT;
public class VideoRenderer implements RenderInfo {
private final Minecraft mc = Minecraft.getMinecraft();
private final Minecraft mc = MCVer.getMinecraft();
private final RenderSettings settings;
private final ReplayHandler replayHandler;
private final Timeline timeline;
@@ -158,12 +164,14 @@ public class VideoRenderer implements RenderInfo {
renderingPipeline.run();
if (settings.isInject360Metadata()) {
if (settings.getRenderMethod() == RenderSettings.RenderMethod.ODS) {
MetadataInjector.injectODSMetadata(settings.getOutputFile());
} else {
MetadataInjector.inject360Metadata(settings.getOutputFile());
}
if (mc.hasCrashed) {
throw newReportedException(mc.crashReporter);
}
if (settings.isInjectSphericalMetadata()) {
MetadataInjector.injectMetadata(settings.getRenderMethod(), settings.getOutputFile(),
settings.getTargetVideoWidth(), settings.getTargetVideoHeight(),
settings.getSphericalFovX(), settings.getSphericalFovY());
}
finish();
@@ -180,18 +188,28 @@ public class VideoRenderer implements RenderInfo {
@Override
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 MC>=11300
int displayWidthBefore = mc.mainWindow.framebufferWidth;
int displayHeightBefore = mc.mainWindow.framebufferHeight;
mc.mainWindow.framebufferWidth = displayWidth;
mc.mainWindow.framebufferHeight = displayHeight;
//#else
//$$ int displayWidthBefore = mc.displayWidth;
//$$ int displayHeightBefore = mc.displayHeight;
//$$ mc.displayWidth = displayWidth;
//$$ mc.displayHeight = displayHeight;
//#endif
if (!settings.isHighPerformance() || framesDone % fps == 0) {
drawGui();
}
// Updating the timer will cause the timeline player to update the game state
mc.timer.updateTimer();
mc.timer.updateTimer(
//#if MC>=11300
MCVer.milliTime()
//#endif
);
int elapsedTicks = mc.timer.elapsedTicks;
while (elapsedTicks-- > 0) {
@@ -199,8 +217,13 @@ public class VideoRenderer implements RenderInfo {
}
// change Minecraft's display size back
mc.displayWidth = displayWidthBefore;
mc.displayHeight = displayHeightBefore;
//#if MC>=11300
mc.mainWindow.framebufferWidth = displayWidthBefore;
mc.mainWindow.framebufferHeight = displayHeightBefore;
//#else
//$$ mc.displayWidth = displayWidthBefore;
//$$ mc.displayHeight = displayHeightBefore;
//#endif
framesDone++;
return mc.timer.renderPartialTicks;
@@ -216,31 +239,52 @@ public class VideoRenderer implements RenderInfo {
timelinePlayerFuture = timelinePlayer.start(timeline);
if (!OpenGlHelper.isFramebufferEnabled()) {
Display.setResizable(false);
//#if MC>=11300
GLFW.glfwSetWindowAttrib(mc.mainWindow.getHandle(), GLFW.GLFW_RESIZABLE, 1);
//#else
//$$ Display.setResizable(false);
//#endif
}
if (mc.gameSettings.showDebugInfo) {
debugInfoWasShown = true;
mc.gameSettings.showDebugInfo = false;
}
if (Mouse.isGrabbed()) {
//#if MC>=11300
if (mc.mouseHelper.isMouseGrabbed()) {
mouseWasGrabbed = true;
}
Mouse.setGrabbed(false);
mc.mouseHelper.ungrabMouse();
//#else
//$$ if (Mouse.isGrabbed()) {
//$$ mouseWasGrabbed = true;
//$$ }
//$$ Mouse.setGrabbed(false);
//#endif
// Mute all sounds except GUI sounds (buttons, etc.)
Map<SoundCategory, Float> mutedSounds = new EnumMap<>(SoundCategory.class);
//#if MC>=11300
originalSoundLevels = new EnumMap<>(SoundCategory.class);
for (SoundCategory category : SoundCategory.values()) {
mutedSounds.put(category, 0f);
if (category != SoundCategory.MASTER) {
originalSoundLevels.put(category, mc.gameSettings.getSoundLevel(category));
mc.gameSettings.setSoundLevel(category, 0);
}
}
//#else
//$$ Map<SoundCategory, Float> mutedSounds = new EnumMap<>(SoundCategory.class);
//$$ for (SoundCategory category : SoundCategory.values()) {
//$$ mutedSounds.put(category, 0f);
//$$ }
//#if MC>=10904
originalSoundLevels = mc.gameSettings.soundLevels;
mutedSounds.put(SoundCategory.MASTER, originalSoundLevels.get(SoundCategory.MASTER));
mc.gameSettings.soundLevels = mutedSounds;
//$$ originalSoundLevels = mc.gameSettings.soundLevels;
//$$ mutedSounds.put(SoundCategory.MASTER, originalSoundLevels.get(SoundCategory.MASTER));
//$$ mc.gameSettings.soundLevels = mutedSounds;
//#else
//$$ originalSoundLevels = mc.gameSettings.mapSoundLevels;
//$$ mutedSounds.put(SoundCategory.MASTER, (Float) originalSoundLevels.get(SoundCategory.MASTER));
//$$ mc.gameSettings.mapSoundLevels = mutedSounds;
//#endif
//#endif
fps = settings.getFramesPerSecond();
@@ -282,14 +326,28 @@ public class VideoRenderer implements RenderInfo {
timelinePlayer.onTick(new ReplayTimer.UpdatedEvent());
if (!OpenGlHelper.isFramebufferEnabled()) {
Display.setResizable(true);
//#if MC>=11300
GLFW.glfwSetWindowAttrib(mc.mainWindow.getHandle(), GLFW.GLFW_RESIZABLE, 0);
//#else
//$$ Display.setResizable(true);
//#endif
}
mc.gameSettings.showDebugInfo = debugInfoWasShown;
if (mouseWasGrabbed) {
mc.mouseHelper.grabMouseCursor();
//#if MC>=11300
mc.mouseHelper.grabMouse();
//#else
//$$ mc.mouseHelper.grabMouseCursor();
//#endif
}
//#if MC>=10904
mc.gameSettings.soundLevels = originalSoundLevels;
//#if MC>=11300
for (Map.Entry<SoundCategory, Float> entry : originalSoundLevels.entrySet()) {
mc.gameSettings.setSoundLevel(entry.getKey(), entry.getValue());
}
//#else
//$$ mc.gameSettings.soundLevels = originalSoundLevels;
//#endif
//#else
//$$ mc.gameSettings.mapSoundLevels = originalSoundLevels;
//#endif
@@ -311,7 +369,13 @@ public class VideoRenderer implements RenderInfo {
}
// Finally, resize the Minecraft framebuffer to the actual width/height of the window
mc.resize(displayWidth, displayHeight);
//#if MC>=11300
mc.getFramebuffer().createFramebuffer(displayWidth, displayHeight);
mc.mainWindow.framebufferWidth = displayWidth;
mc.mainWindow.framebufferHeight = displayHeight;
//#else
//$$ mc.resize(displayWidth, displayHeight);
//#endif
}
private void tick() {
@@ -322,14 +386,14 @@ public class VideoRenderer implements RenderInfo {
}
mc.currentScreen = gui.toMinecraft();
//#if MC>=10800
try {
mc.runTick();
} catch (IOException e) {
throw new RuntimeException(e);
}
//#if MC>=10800 && MC<11300
//$$ try {
//$$ mc.runTick();
//$$ } catch (IOException e) {
//$$ throw new RuntimeException(e);
//$$ }
//#else
//$$ mc.runTick();
mc.runTick();
//#endif
}
@@ -338,7 +402,11 @@ public class VideoRenderer implements RenderInfo {
// Resize the GUI framebuffer if the display size changed
if (!settings.isHighPerformance() && displaySizeChanged()) {
updateDisplaySize();
guiFramebuffer.createBindFramebuffer(mc.displayWidth, mc.displayHeight);
//#if MC>=11300
guiFramebuffer.createBindFramebuffer(mc.mainWindow.getFramebufferWidth(), mc.mainWindow.getFramebufferHeight());
//#else
//$$ guiFramebuffer.createBindFramebuffer(mc.displayWidth, mc.displayHeight);
//#endif
}
pushMatrix();
@@ -346,27 +414,47 @@ public class VideoRenderer implements RenderInfo {
enableTexture2D();
guiFramebuffer.bindFramebuffer(true);
mc.entityRenderer.setupOverlayRendering();
//#if MC>=11300
mc.mainWindow.setupOverlayRendering();
//#else
//$$ mc.entityRenderer.setupOverlayRendering();
//#endif
ScaledResolution scaled = newScaledResolution(mc);
gui.toMinecraft().setWorldAndResolution(mc, scaled.getScaledWidth(), scaled.getScaledHeight());
//#if MC>=11300
gui.toMinecraft().setWorldAndResolution(mc, mc.mainWindow.getScaledWidth(), mc.mainWindow.getScaledHeight());
//#else
//$$ ScaledResolution scaled = newScaledResolution(mc);
//$$ gui.toMinecraft().setWorldAndResolution(mc, scaled.getScaledWidth(), scaled.getScaledHeight());
//#endif
// Events are polled on 1.13+ in mainWindow.update which is called later
//#if MC<11300
//#if MC>=10800
try {
gui.toMinecraft().handleInput();
} catch (IOException e) {
// That's a strange exception from this kind of method O_o
// It isn't actually thrown here, so we'll deal with it the easy way
throw new RuntimeException(e);
}
//$$ try {
//$$ gui.toMinecraft().handleInput();
//$$ } catch (IOException e) {
//$$ // That's a strange exception from this kind of method O_o
//$$ // It isn't actually thrown here, so we'll deal with it the easy way
//$$ throw new RuntimeException(e);
//$$ }
//#else
//$$ gui.toMinecraft().handleInput();
//#endif
//#endif
int mouseX = Mouse.getX() * scaled.getScaledWidth() / mc.displayWidth;
int mouseY = scaled.getScaledHeight() - Mouse.getY() * scaled.getScaledHeight() / mc.displayHeight - 1;
//#if MC>=11300
int mouseX = (int) mc.mouseHelper.getMouseX();
int mouseY = (int) mc.mouseHelper.getMouseY();
gui.toMinecraft().drawScreen(mouseX, mouseY, 0);
gui.toMinecraft().tick();
gui.toMinecraft().render(mouseX, mouseY, 0);
//#else
//$$ int mouseX = Mouse.getX() * scaled.getScaledWidth() / mc.displayWidth;
//$$ int mouseY = scaled.getScaledHeight() - Mouse.getY() * scaled.getScaledHeight() / mc.displayHeight - 1;
//$$
//$$ gui.toMinecraft().updateScreen();
//$$ gui.toMinecraft().drawScreen(mouseX, mouseY, 0);
//#endif
guiFramebuffer.unbindFramebuffer();
popMatrix();
@@ -374,20 +462,30 @@ public class VideoRenderer implements RenderInfo {
guiFramebuffer.framebufferRender(displayWidth, displayHeight);
popMatrix();
// if not in high performance mode, update the gui size if screen size changed
// otherwise just swap the progress gui to screen
if (settings.isHighPerformance()) {
Display.update();
} else {
//#if MC>=11300
mc.mainWindow.update(false);
//#else
//$$ // if not in high performance mode, update the gui size if screen size changed
//$$ // otherwise just swap the progress gui to screen
//$$ if (settings.isHighPerformance()) {
//$$ Display.update();
//$$ } else {
//#if MC>=10800
mc.updateDisplay();
//$$ mc.updateDisplay();
//#else
//$$ mc.resetSize();
//#endif
//$$ }
//#endif
//#if MC>=11300
if (mc.mouseHelper.isMouseGrabbed()) {
mc.mouseHelper.ungrabMouse();
}
if (Mouse.isGrabbed()) {
Mouse.setGrabbed(false);
}
//#else
//$$ if (Mouse.isGrabbed()) {
//$$ Mouse.setGrabbed(false);
//$$ }
//#endif
if (paused) {
try {
Thread.sleep(50);
@@ -400,12 +498,21 @@ public class VideoRenderer implements RenderInfo {
}
private boolean displaySizeChanged() {
return displayWidth != Display.getWidth() || displayHeight != Display.getHeight();
//#if MC>=11300
return displayWidth != mc.mainWindow.getWidth() || displayHeight != mc.mainWindow.getHeight();
//#else
//$$ return displayWidth != Display.getWidth() || displayHeight != Display.getHeight();
//#endif
}
private void updateDisplaySize() {
displayWidth = Display.getWidth();
displayHeight = Display.getHeight();
//#if MC>=11300
displayWidth = mc.mainWindow.getWidth();
displayHeight = mc.mainWindow.getHeight();
//#else
//$$ displayWidth = Display.getWidth();
//$$ displayHeight = Display.getHeight();
//#endif
}
public int getFramesDone() {

View File

@@ -1,7 +1,6 @@
package com.replaymod.render.shader;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.IResource;
import com.replaymod.core.versions.MCVer;
import net.minecraft.util.ResourceLocation;
import org.apache.commons.io.IOUtils;
import org.lwjgl.opengl.ARBFragmentShader;
@@ -9,6 +8,12 @@ import org.lwjgl.opengl.ARBShaderObjects;
import org.lwjgl.opengl.ARBVertexShader;
import org.lwjgl.opengl.GL11;
//#if MC>=11300
import net.minecraft.resources.IResource;
//#else
//$$ import net.minecraft.client.resources.IResource;
//#endif
import java.io.InputStream;
import static org.lwjgl.opengl.ARBShaderObjects.*;
@@ -47,7 +52,7 @@ public class Program {
if(shader == 0)
throw new Exception("glCreateShaderObjectARB failed");
IResource resource = Minecraft.getMinecraft().getResourceManager().getResource(resourceLocation);
IResource resource = MCVer.getMinecraft().getResourceManager().getResource(resourceLocation);
try (InputStream is = resource.getInputStream()) {
glShaderSourceARB(shader, IOUtils.toString(is));
}

View File

@@ -1,12 +1,18 @@
package com.replaymod.render.utils;
import com.google.common.base.Objects;
import com.replaymod.core.versions.MCVer;
import lombok.RequiredArgsConstructor;
import net.minecraft.client.Minecraft;
import org.apache.logging.log4j.LogManager;
import org.lwjgl.opengl.ARBBufferObject;
import org.lwjgl.opengl.GLContext;
import org.lwjgl.opengl.Util;
//#if MC>=11300
import org.lwjgl.opengl.ARBVertexBufferObject;
import org.lwjgl.opengl.GL;
//#else
//$$ import org.lwjgl.opengl.ARBBufferObject;
//$$ import org.lwjgl.opengl.GLContext;
//$$ import org.lwjgl.opengl.Util;
//#endif
import java.nio.ByteBuffer;
@@ -14,6 +20,10 @@ import static org.lwjgl.opengl.ARBPixelBufferObject.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL21.GL_PIXEL_PACK_BUFFER;
//#if MC>=11300
import static org.lwjgl.opengl.ARBVertexBufferObject.*;
//#endif
public class PixelBufferObject {
@RequiredArgsConstructor
public enum Usage {
@@ -24,8 +34,13 @@ public class PixelBufferObject {
private final int arb, gl15;
}
public static final boolean SUPPORTED = GLContext.getCapabilities().GL_ARB_pixel_buffer_object || GLContext.getCapabilities().OpenGL15;
private static final boolean arb = !GLContext.getCapabilities().OpenGL15;
//#if MC>=11300
public static final boolean SUPPORTED = GL.getCapabilities().GL_ARB_pixel_buffer_object || GL.getCapabilities().OpenGL15;
private static final boolean arb = !GL.getCapabilities().OpenGL15;
//#else
//$$ public static final boolean SUPPORTED = GLContext.getCapabilities().GL_ARB_pixel_buffer_object || GLContext.getCapabilities().OpenGL15;
//$$ private static final boolean arb = !GLContext.getCapabilities().OpenGL15;
//#endif
private static ThreadLocal<Integer> bound = new ThreadLocal<>();
private static ThreadLocal<Integer> mapped = new ThreadLocal<>();
@@ -39,12 +54,20 @@ public class PixelBufferObject {
}
this.size = size;
this.handle = arb ? ARBBufferObject.glGenBuffersARB() : glGenBuffers();
//#if MC>=11300
this.handle = arb ? ARBVertexBufferObject.glGenBuffersARB() : glGenBuffers();
//#else
//$$ this.handle = arb ? ARBBufferObject.glGenBuffersARB() : glGenBuffers();
//#endif
bind();
if (arb) {
ARBBufferObject.glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, size, usage.arb);
//#if MC>=11300
ARBVertexBufferObject.glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, size, usage.arb);
//#else
//$$ ARBBufferObject.glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, size, usage.arb);
//#endif
} else {
glBufferData(GL_PIXEL_PACK_BUFFER, size, usage.gl15);
}
@@ -61,7 +84,11 @@ public class PixelBufferObject {
public void bind() {
if (arb) {
ARBBufferObject.glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, getHandle());
//#if MC>=11300
ARBVertexBufferObject.glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, getHandle());
//#else
//$$ ARBBufferObject.glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, getHandle());
//#endif
} else {
glBindBuffer(GL_PIXEL_PACK_BUFFER, getHandle());
}
@@ -71,7 +98,11 @@ public class PixelBufferObject {
public void unbind() {
checkBound();
if (arb) {
ARBBufferObject.glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
//#if MC>=11300
ARBVertexBufferObject.glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
//#else
//$$ ARBBufferObject.glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
//#endif
} else {
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
}
@@ -95,13 +126,19 @@ public class PixelBufferObject {
checkNotMapped();
ByteBuffer buffer;
if (arb) {
buffer = ARBBufferObject.glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB, size, null);
//#if MC>=11300
buffer = ARBVertexBufferObject.glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB, size, null);
//#else
//$$ buffer = ARBBufferObject.glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB, size, null);
//#endif
} else {
buffer = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY, size, null);
}
if (buffer == null) {
Util.checkGLError();
}
//#if MC<11300
//$$ if (buffer == null) {
//$$ Util.checkGLError();
//$$ }
//#endif
mapped.set(getHandle());
return buffer;
}
@@ -111,13 +148,19 @@ public class PixelBufferObject {
checkNotMapped();
ByteBuffer buffer;
if (arb) {
buffer = ARBBufferObject.glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_WRITE_ONLY_ARB, size, null);
//#if MC>=11300
buffer = ARBVertexBufferObject.glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_WRITE_ONLY_ARB, size, null);
//#else
//$$ buffer = ARBBufferObject.glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_WRITE_ONLY_ARB, size, null);
//#endif
} else {
buffer = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_WRITE_ONLY, size, null);
}
if (buffer == null) {
Util.checkGLError();
}
//#if MC<11300
//$$ if (buffer == null) {
//$$ Util.checkGLError();
//$$ }
//#endif
mapped.set(getHandle());
return buffer;
}
@@ -127,13 +170,19 @@ public class PixelBufferObject {
checkNotMapped();
ByteBuffer buffer;
if (arb) {
buffer = ARBBufferObject.glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_WRITE_ARB, size, null);
//#if MC>=11300
buffer = ARBVertexBufferObject.glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_WRITE_ARB, size, null);
//#else
//$$ buffer = ARBBufferObject.glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_WRITE_ARB, size, null);
//#endif
} else {
buffer = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_WRITE, size, null);
}
if (buffer == null) {
Util.checkGLError();
}
//#if MC<11300
//$$ if (buffer == null) {
//$$ Util.checkGLError();
//$$ }
//#endif
mapped.set(getHandle());
return buffer;
}
@@ -144,7 +193,11 @@ public class PixelBufferObject {
throw new IllegalStateException("Buffer not mapped.");
}
if (arb) {
ARBBufferObject.glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
//#if MC>=11300
ARBVertexBufferObject.glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
//#else
//$$ ARBBufferObject.glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
//#endif
} else {
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
}
@@ -154,7 +207,11 @@ public class PixelBufferObject {
public void delete() {
if (handle != -1) {
if (arb) {
ARBBufferObject.glDeleteBuffersARB(getHandle());
//#if MC>=11300
ARBVertexBufferObject.glDeleteBuffersARB(getHandle());
//#else
//$$ ARBBufferObject.glDeleteBuffersARB(getHandle());
//#endif
} else {
glDeleteBuffers(getHandle());
}
@@ -167,12 +224,7 @@ public class PixelBufferObject {
super.finalize();
if (handle != -1) {
LogManager.getLogger().warn("PBO garbage collected before deleted!");
Minecraft.getMinecraft().addScheduledTask(new Runnable() {
@Override
public void run() {
delete();
}
});
MCVer.getMinecraft().addScheduledTask(this::delete);
}
}
}

View File

@@ -1,6 +1,6 @@
package com.replaymod.render.utils;
import net.minecraft.client.Minecraft;
import com.replaymod.core.versions.MCVer;
import net.minecraft.util.ResourceLocation;
import org.apache.commons.io.IOUtils;
@@ -24,7 +24,7 @@ public class SoundHandler {
*/
public void playSound(ResourceLocation loc) {
try {
InputStream is = Minecraft.getMinecraft().getResourceManager().getResource(loc).getInputStream();
InputStream is = MCVer.getMinecraft().getResourceManager().getResource(loc).getInputStream();
byte[] bytes = IOUtils.toByteArray(is);
is.close();
AudioInputStream ais = AudioSystem.getAudioInputStream(new ByteArrayInputStream(bytes));

View File

@@ -13,12 +13,12 @@ public class Utils {
* @param width Target image width
*/
public static void openGlBytesToRBG(ByteBuffer buffer, int bufferWidth, int xOffset, int yOffset, ByteBuffer to, int width) {
byte[] rowBuf = new byte[bufferWidth * 3];
byte[] rowBuf = new byte[bufferWidth * 4];
// Copy image flipped vertically to target buffer
int rows = buffer.remaining() / 3 / bufferWidth;
int rows = buffer.remaining() / 4 / bufferWidth;
for (int i = 0; i < rows; i++) {
buffer.get(rowBuf);
to.position(((yOffset + rows - i - 1) * width + xOffset) * 3);
to.position(((yOffset + rows - i - 1) * width + xOffset) * 4);
to.put(rowBuf);
}
to.rewind();