Add option to preserve alpha channel in export (closes #661)

Default off cause it being on by default had confused quite a few people.
This commit is contained in:
Jonas Herzig
2022-03-02 16:39:30 +01:00
parent d9da2e135c
commit 7615499cef
8 changed files with 36 additions and 11 deletions

View File

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

View File

@@ -28,9 +28,11 @@ import static org.lwjgl.util.tinyexr.TinyEXR.*;
public class EXRWriter implements FrameConsumer<BitmapFrame> {
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<BitmapFrame> {
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) {

View File

@@ -19,9 +19,11 @@ import java.util.Map;
public class PNGWriter implements FrameConsumer<BitmapFrame> {
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<BitmapFrame> {
}
private void withImage(BitmapFrame frame, IOConsumer<Image> 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<BitmapFrame> {
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);

View File

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

View File

@@ -90,6 +90,7 @@ public class GuiExportFailed extends GuiScreen {
oldSettings.getBitRate(),
oldSettings.getOutputFile(),
oldSettings.isRenderNameTags(),
oldSettings.isIncludeAlphaChannel(),
oldSettings.isStabilizeYaw(),
oldSettings.isStabilizePitch(),
oldSettings.isStabilizeRoll(),

View File

@@ -148,6 +148,9 @@ public class GuiRenderSettings extends AbstractGuiPopup<GuiRenderSettings> {
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<GuiRenderSettings> {
.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<GuiRenderSettings> {
}
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<GuiRenderSettings> {
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()),

View File

@@ -136,12 +136,12 @@ public class VideoRenderer implements RenderInfo {
FrameConsumer<BitmapFrame> 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);
}