From 7615499cef5dd842bbaa91000901e8a0d1f7194a Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Wed, 2 Mar 2022 16:39:30 +0100 Subject: [PATCH] Add option to preserve alpha channel in export (closes #661) Default off cause it being on by default had confused quite a few people. --- .../advancedscreenshots/GuiCreateScreenshot.java | 2 +- src/main/java/com/replaymod/render/EXRWriter.java | 14 ++++++++++---- src/main/java/com/replaymod/render/PNGWriter.java | 7 +++++-- .../java/com/replaymod/render/RenderSettings.java | 10 ++++++++++ .../com/replaymod/render/gui/GuiExportFailed.java | 1 + .../replaymod/render/gui/GuiRenderSettings.java | 7 ++++++- .../replaymod/render/rendering/VideoRenderer.java | 4 ++-- src/main/resources/assets/replaymod/lang | 2 +- 8 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/replaymod/extras/advancedscreenshots/GuiCreateScreenshot.java b/src/main/java/com/replaymod/extras/advancedscreenshots/GuiCreateScreenshot.java index 62d316cf..cda0409d 100644 --- a/src/main/java/com/replaymod/extras/advancedscreenshots/GuiCreateScreenshot.java +++ b/src/main/java/com/replaymod/extras/advancedscreenshots/GuiCreateScreenshot.java @@ -40,7 +40,7 @@ public class GuiCreateScreenshot extends GuiRenderSettings implements Loadable { new GuiLabel().setI18nText("replaymod.gui.advancedscreenshots.resolution"), videoResolutionPanel, new GuiLabel().setI18nText("replaymod.gui.rendersettings.outputfile"), outputFileButton); - resetChildren(advancedPanel).addElements(null, nametagCheckbox, new GuiPanel().setLayout( + resetChildren(advancedPanel).addElements(null, nametagCheckbox, alphaCheckbox , new GuiPanel().setLayout( new GridLayout().setCellsEqualSize(false).setColumns(2).setSpacingX(5).setSpacingY(15)) .addElements(new GridLayout.Data(0, 0.5), new GuiLabel().setI18nText("replaymod.gui.rendersettings.stabilizecamera"), stabilizePanel, diff --git a/src/main/java/com/replaymod/render/EXRWriter.java b/src/main/java/com/replaymod/render/EXRWriter.java index 1b2348fe..0bf981d8 100644 --- a/src/main/java/com/replaymod/render/EXRWriter.java +++ b/src/main/java/com/replaymod/render/EXRWriter.java @@ -28,9 +28,11 @@ import static org.lwjgl.util.tinyexr.TinyEXR.*; public class EXRWriter implements FrameConsumer { private final Path outputFolder; + private final boolean keepAlpha; - public EXRWriter(Path outputFolder) throws IOException { + public EXRWriter(Path outputFolder, boolean keepAlpha) throws IOException { this.outputFolder = outputFolder; + this.keepAlpha = keepAlpha; Files.createDirectories(outputFolder); } @@ -92,11 +94,15 @@ public class EXRWriter implements FrameConsumer { bgrChannels[(i + 3) % 4] = channel; } } + + int alphaMask = keepAlpha ? 0 : 0xff; + for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { - for (FloatBuffer channel : bgrChannels) { - channel.put(((int) bgra.get() & 0xff) / 255f); - } + bgrChannels[0].put(((int) bgra.get() & 0xff) / 255f); // b + bgrChannels[1].put(((int) bgra.get() & 0xff) / 255f); // g + bgrChannels[2].put(((int) bgra.get() & 0xff) / 255f); // r + bgrChannels[3].put(((int) bgra.get() & 0xff | alphaMask) / 255f); // a } } if (depthFrame != null && depthChannel != null) { diff --git a/src/main/java/com/replaymod/render/PNGWriter.java b/src/main/java/com/replaymod/render/PNGWriter.java index 846e63be..525d154d 100644 --- a/src/main/java/com/replaymod/render/PNGWriter.java +++ b/src/main/java/com/replaymod/render/PNGWriter.java @@ -19,9 +19,11 @@ import java.util.Map; public class PNGWriter implements FrameConsumer { private final Path outputFolder; + private final boolean keepAlpha; - public PNGWriter(Path outputFolder) throws IOException { + public PNGWriter(Path outputFolder, boolean keepAlpha) throws IOException { this.outputFolder = outputFolder; + this.keepAlpha = keepAlpha; Files.createDirectories(outputFolder); } @@ -47,6 +49,7 @@ public class PNGWriter implements FrameConsumer { } private void withImage(BitmapFrame frame, IOConsumer consumer) throws IOException { + byte alphaMask = (byte) (keepAlpha ? 0 : 0xff); ByteBuffer buffer = frame.getByteBuffer(); ReadableDimension size = frame.getSize(); int width = size.getWidth(); @@ -58,7 +61,7 @@ public class PNGWriter implements FrameConsumer { byte g = buffer.get(); byte r = buffer.get(); byte a = buffer.get(); - image.setRGBA(x, y, r, g, b, a); + image.setRGBA(x, y, r, g, b, a | alphaMask); } } consumer.accept(image); diff --git a/src/main/java/com/replaymod/render/RenderSettings.java b/src/main/java/com/replaymod/render/RenderSettings.java index e83d4947..b358b718 100644 --- a/src/main/java/com/replaymod/render/RenderSettings.java +++ b/src/main/java/com/replaymod/render/RenderSettings.java @@ -151,6 +151,7 @@ public class RenderSettings { private final File outputFile; private final boolean renderNameTags; + private final boolean includeAlphaChannel; private final boolean stabilizeYaw; private final boolean stabilizePitch; private final boolean stabilizeRoll; @@ -187,6 +188,7 @@ public class RenderSettings { false, false, false, + false, null, 360, 180, @@ -209,6 +211,7 @@ public class RenderSettings { int bitRate, File outputFile, boolean renderNameTags, + boolean includeAlphaChannel, boolean stabilizeYaw, boolean stabilizePitch, boolean stabilizeRoll, @@ -231,6 +234,7 @@ public class RenderSettings { this.bitRate = bitRate; this.outputFile = outputFile; this.renderNameTags = renderNameTags; + this.includeAlphaChannel = includeAlphaChannel; this.stabilizeYaw = stabilizeYaw; this.stabilizePitch = stabilizePitch; this.stabilizeRoll = stabilizeRoll; @@ -256,6 +260,7 @@ public class RenderSettings { bitRate, outputFile, renderNameTags, + includeAlphaChannel, stabilizeYaw, stabilizePitch, stabilizeRoll, @@ -415,6 +420,10 @@ public class RenderSettings { return renderNameTags; } + public boolean isIncludeAlphaChannel() { + return includeAlphaChannel; + } + public boolean isStabilizeYaw() { return stabilizeYaw; } @@ -478,6 +487,7 @@ public class RenderSettings { ", bitRate=" + bitRate + ", outputFile=" + outputFile + ", renderNameTags=" + renderNameTags + + ", includeAlphaChannel=" + includeAlphaChannel + ", stabilizeYaw=" + stabilizeYaw + ", stabilizePitch=" + stabilizePitch + ", stabilizeRoll=" + stabilizeRoll + diff --git a/src/main/java/com/replaymod/render/gui/GuiExportFailed.java b/src/main/java/com/replaymod/render/gui/GuiExportFailed.java index de5e9c0e..56f9229f 100644 --- a/src/main/java/com/replaymod/render/gui/GuiExportFailed.java +++ b/src/main/java/com/replaymod/render/gui/GuiExportFailed.java @@ -90,6 +90,7 @@ public class GuiExportFailed extends GuiScreen { oldSettings.getBitRate(), oldSettings.getOutputFile(), oldSettings.isRenderNameTags(), + oldSettings.isIncludeAlphaChannel(), oldSettings.isStabilizeYaw(), oldSettings.isStabilizePitch(), oldSettings.isStabilizeRoll(), diff --git a/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java b/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java index b8f67b17..170aa21a 100644 --- a/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java +++ b/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java @@ -148,6 +148,9 @@ public class GuiRenderSettings extends AbstractGuiPopup { public final GuiCheckbox nametagCheckbox = new GuiCheckbox() .setI18nLabel("replaymod.gui.rendersettings.nametags"); + public final GuiCheckbox alphaCheckbox = new GuiCheckbox() + .setI18nLabel("replaymod.gui.rendersettings.includealpha"); + public final GuiPanel stabilizePanel = new GuiPanel().setLayout(new HorizontalLayout().setSpacing(10)); public final GuiCheckbox stabilizeYaw = new GuiCheckbox(stabilizePanel) .setI18nLabel("replaymod.gui.yaw"); @@ -187,7 +190,7 @@ public class GuiRenderSettings extends AbstractGuiPopup { .setSize(200, 20).setValues(RenderSettings.AntiAliasing.values()).setSelected(RenderSettings.AntiAliasing.NONE); public final GuiPanel advancedPanel = new GuiPanel().setLayout(new VerticalLayout().setSpacing(15)) - .addElements(null, nametagCheckbox, new GuiPanel().setLayout( + .addElements(null, nametagCheckbox, alphaCheckbox, new GuiPanel().setLayout( new GridLayout().setCellsEqualSize(false).setColumns(2).setSpacingX(5).setSpacingY(15)) .addElements(new GridLayout.Data(0, 0.5), new GuiLabel().setI18nText("replaymod.gui.rendersettings.stabilizecamera"), stabilizePanel, @@ -522,6 +525,7 @@ public class GuiRenderSettings extends AbstractGuiPopup { } outputFileButton.setLabel(this.outputFile.getName()); nametagCheckbox.setChecked(settings.isRenderNameTags()); + alphaCheckbox.setChecked(settings.isIncludeAlphaChannel()); stabilizeYaw.setChecked(settings.isStabilizeYaw()); stabilizePitch.setChecked(settings.isStabilizePitch()); stabilizeRoll.setChecked(settings.isStabilizeRoll()); @@ -560,6 +564,7 @@ public class GuiRenderSettings extends AbstractGuiPopup { bitRateField.getInteger() << (10 * bitRateUnit.getSelected()), serialize && !userDefinedOutputFileName ? getParentFile(outputFile) : outputFile, nametagCheckbox.isChecked(), + alphaCheckbox.isChecked(), stabilizeYaw.isChecked() && (serialize || stabilizeYaw.isEnabled()), stabilizePitch.isChecked() && (serialize || stabilizePitch.isEnabled()), stabilizeRoll.isChecked() && (serialize || stabilizeRoll.isEnabled()), diff --git a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java index 9eb819d5..56d1daf6 100644 --- a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java +++ b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java @@ -136,12 +136,12 @@ public class VideoRenderer implements RenderInfo { FrameConsumer frameConsumer; if (settings.getEncodingPreset() == RenderSettings.EncodingPreset.EXR) { //#if MC>=11400 - frameConsumer = new EXRWriter(settings.getOutputFile().toPath()); + frameConsumer = new EXRWriter(settings.getOutputFile().toPath(), settings.isIncludeAlphaChannel()); //#else //$$ throw new UnsupportedOperationException("EXR requires LWJGL3"); //#endif } else if (settings.getEncodingPreset() == RenderSettings.EncodingPreset.PNG) { - frameConsumer = new PNGWriter(settings.getOutputFile().toPath()); + frameConsumer = new PNGWriter(settings.getOutputFile().toPath(), settings.isIncludeAlphaChannel()); } else { frameConsumer = new FFmpegWriter(this); } diff --git a/src/main/resources/assets/replaymod/lang b/src/main/resources/assets/replaymod/lang index 4b1698fc..188e85c4 160000 --- a/src/main/resources/assets/replaymod/lang +++ b/src/main/resources/assets/replaymod/lang @@ -1 +1 @@ -Subproject commit 4b1698fcf805fea05d6c3f0ca6c14c63d7e731db +Subproject commit 188e85c4dbc9296c81231c37d7c18bb92560b2e7