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:
@@ -40,7 +40,7 @@ public class GuiCreateScreenshot extends GuiRenderSettings implements Loadable {
|
|||||||
new GuiLabel().setI18nText("replaymod.gui.advancedscreenshots.resolution"), videoResolutionPanel,
|
new GuiLabel().setI18nText("replaymod.gui.advancedscreenshots.resolution"), videoResolutionPanel,
|
||||||
new GuiLabel().setI18nText("replaymod.gui.rendersettings.outputfile"), outputFileButton);
|
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))
|
new GridLayout().setCellsEqualSize(false).setColumns(2).setSpacingX(5).setSpacingY(15))
|
||||||
.addElements(new GridLayout.Data(0, 0.5),
|
.addElements(new GridLayout.Data(0, 0.5),
|
||||||
new GuiLabel().setI18nText("replaymod.gui.rendersettings.stabilizecamera"), stabilizePanel,
|
new GuiLabel().setI18nText("replaymod.gui.rendersettings.stabilizecamera"), stabilizePanel,
|
||||||
|
|||||||
@@ -28,9 +28,11 @@ import static org.lwjgl.util.tinyexr.TinyEXR.*;
|
|||||||
public class EXRWriter implements FrameConsumer<BitmapFrame> {
|
public class EXRWriter implements FrameConsumer<BitmapFrame> {
|
||||||
|
|
||||||
private final Path outputFolder;
|
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.outputFolder = outputFolder;
|
||||||
|
this.keepAlpha = keepAlpha;
|
||||||
|
|
||||||
Files.createDirectories(outputFolder);
|
Files.createDirectories(outputFolder);
|
||||||
}
|
}
|
||||||
@@ -92,11 +94,15 @@ public class EXRWriter implements FrameConsumer<BitmapFrame> {
|
|||||||
bgrChannels[(i + 3) % 4] = channel;
|
bgrChannels[(i + 3) % 4] = channel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int alphaMask = keepAlpha ? 0 : 0xff;
|
||||||
|
|
||||||
for (int y = 0; y < height; y++) {
|
for (int y = 0; y < height; y++) {
|
||||||
for (int x = 0; x < width; x++) {
|
for (int x = 0; x < width; x++) {
|
||||||
for (FloatBuffer channel : bgrChannels) {
|
bgrChannels[0].put(((int) bgra.get() & 0xff) / 255f); // b
|
||||||
channel.put(((int) bgra.get() & 0xff) / 255f);
|
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) {
|
if (depthFrame != null && depthChannel != null) {
|
||||||
|
|||||||
@@ -19,9 +19,11 @@ import java.util.Map;
|
|||||||
public class PNGWriter implements FrameConsumer<BitmapFrame> {
|
public class PNGWriter implements FrameConsumer<BitmapFrame> {
|
||||||
|
|
||||||
private final Path outputFolder;
|
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.outputFolder = outputFolder;
|
||||||
|
this.keepAlpha = keepAlpha;
|
||||||
|
|
||||||
Files.createDirectories(outputFolder);
|
Files.createDirectories(outputFolder);
|
||||||
}
|
}
|
||||||
@@ -47,6 +49,7 @@ public class PNGWriter implements FrameConsumer<BitmapFrame> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void withImage(BitmapFrame frame, IOConsumer<Image> consumer) throws IOException {
|
private void withImage(BitmapFrame frame, IOConsumer<Image> consumer) throws IOException {
|
||||||
|
byte alphaMask = (byte) (keepAlpha ? 0 : 0xff);
|
||||||
ByteBuffer buffer = frame.getByteBuffer();
|
ByteBuffer buffer = frame.getByteBuffer();
|
||||||
ReadableDimension size = frame.getSize();
|
ReadableDimension size = frame.getSize();
|
||||||
int width = size.getWidth();
|
int width = size.getWidth();
|
||||||
@@ -58,7 +61,7 @@ public class PNGWriter implements FrameConsumer<BitmapFrame> {
|
|||||||
byte g = buffer.get();
|
byte g = buffer.get();
|
||||||
byte r = buffer.get();
|
byte r = buffer.get();
|
||||||
byte a = 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);
|
consumer.accept(image);
|
||||||
|
|||||||
@@ -151,6 +151,7 @@ public class RenderSettings {
|
|||||||
private final File outputFile;
|
private final File outputFile;
|
||||||
|
|
||||||
private final boolean renderNameTags;
|
private final boolean renderNameTags;
|
||||||
|
private final boolean includeAlphaChannel;
|
||||||
private final boolean stabilizeYaw;
|
private final boolean stabilizeYaw;
|
||||||
private final boolean stabilizePitch;
|
private final boolean stabilizePitch;
|
||||||
private final boolean stabilizeRoll;
|
private final boolean stabilizeRoll;
|
||||||
@@ -187,6 +188,7 @@ public class RenderSettings {
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
null,
|
null,
|
||||||
360,
|
360,
|
||||||
180,
|
180,
|
||||||
@@ -209,6 +211,7 @@ public class RenderSettings {
|
|||||||
int bitRate,
|
int bitRate,
|
||||||
File outputFile,
|
File outputFile,
|
||||||
boolean renderNameTags,
|
boolean renderNameTags,
|
||||||
|
boolean includeAlphaChannel,
|
||||||
boolean stabilizeYaw,
|
boolean stabilizeYaw,
|
||||||
boolean stabilizePitch,
|
boolean stabilizePitch,
|
||||||
boolean stabilizeRoll,
|
boolean stabilizeRoll,
|
||||||
@@ -231,6 +234,7 @@ public class RenderSettings {
|
|||||||
this.bitRate = bitRate;
|
this.bitRate = bitRate;
|
||||||
this.outputFile = outputFile;
|
this.outputFile = outputFile;
|
||||||
this.renderNameTags = renderNameTags;
|
this.renderNameTags = renderNameTags;
|
||||||
|
this.includeAlphaChannel = includeAlphaChannel;
|
||||||
this.stabilizeYaw = stabilizeYaw;
|
this.stabilizeYaw = stabilizeYaw;
|
||||||
this.stabilizePitch = stabilizePitch;
|
this.stabilizePitch = stabilizePitch;
|
||||||
this.stabilizeRoll = stabilizeRoll;
|
this.stabilizeRoll = stabilizeRoll;
|
||||||
@@ -256,6 +260,7 @@ public class RenderSettings {
|
|||||||
bitRate,
|
bitRate,
|
||||||
outputFile,
|
outputFile,
|
||||||
renderNameTags,
|
renderNameTags,
|
||||||
|
includeAlphaChannel,
|
||||||
stabilizeYaw,
|
stabilizeYaw,
|
||||||
stabilizePitch,
|
stabilizePitch,
|
||||||
stabilizeRoll,
|
stabilizeRoll,
|
||||||
@@ -415,6 +420,10 @@ public class RenderSettings {
|
|||||||
return renderNameTags;
|
return renderNameTags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isIncludeAlphaChannel() {
|
||||||
|
return includeAlphaChannel;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isStabilizeYaw() {
|
public boolean isStabilizeYaw() {
|
||||||
return stabilizeYaw;
|
return stabilizeYaw;
|
||||||
}
|
}
|
||||||
@@ -478,6 +487,7 @@ public class RenderSettings {
|
|||||||
", bitRate=" + bitRate +
|
", bitRate=" + bitRate +
|
||||||
", outputFile=" + outputFile +
|
", outputFile=" + outputFile +
|
||||||
", renderNameTags=" + renderNameTags +
|
", renderNameTags=" + renderNameTags +
|
||||||
|
", includeAlphaChannel=" + includeAlphaChannel +
|
||||||
", stabilizeYaw=" + stabilizeYaw +
|
", stabilizeYaw=" + stabilizeYaw +
|
||||||
", stabilizePitch=" + stabilizePitch +
|
", stabilizePitch=" + stabilizePitch +
|
||||||
", stabilizeRoll=" + stabilizeRoll +
|
", stabilizeRoll=" + stabilizeRoll +
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ public class GuiExportFailed extends GuiScreen {
|
|||||||
oldSettings.getBitRate(),
|
oldSettings.getBitRate(),
|
||||||
oldSettings.getOutputFile(),
|
oldSettings.getOutputFile(),
|
||||||
oldSettings.isRenderNameTags(),
|
oldSettings.isRenderNameTags(),
|
||||||
|
oldSettings.isIncludeAlphaChannel(),
|
||||||
oldSettings.isStabilizeYaw(),
|
oldSettings.isStabilizeYaw(),
|
||||||
oldSettings.isStabilizePitch(),
|
oldSettings.isStabilizePitch(),
|
||||||
oldSettings.isStabilizeRoll(),
|
oldSettings.isStabilizeRoll(),
|
||||||
|
|||||||
@@ -148,6 +148,9 @@ public class GuiRenderSettings extends AbstractGuiPopup<GuiRenderSettings> {
|
|||||||
public final GuiCheckbox nametagCheckbox = new GuiCheckbox()
|
public final GuiCheckbox nametagCheckbox = new GuiCheckbox()
|
||||||
.setI18nLabel("replaymod.gui.rendersettings.nametags");
|
.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 GuiPanel stabilizePanel = new GuiPanel().setLayout(new HorizontalLayout().setSpacing(10));
|
||||||
public final GuiCheckbox stabilizeYaw = new GuiCheckbox(stabilizePanel)
|
public final GuiCheckbox stabilizeYaw = new GuiCheckbox(stabilizePanel)
|
||||||
.setI18nLabel("replaymod.gui.yaw");
|
.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);
|
.setSize(200, 20).setValues(RenderSettings.AntiAliasing.values()).setSelected(RenderSettings.AntiAliasing.NONE);
|
||||||
|
|
||||||
public final GuiPanel advancedPanel = new GuiPanel().setLayout(new VerticalLayout().setSpacing(15))
|
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))
|
new GridLayout().setCellsEqualSize(false).setColumns(2).setSpacingX(5).setSpacingY(15))
|
||||||
.addElements(new GridLayout.Data(0, 0.5),
|
.addElements(new GridLayout.Data(0, 0.5),
|
||||||
new GuiLabel().setI18nText("replaymod.gui.rendersettings.stabilizecamera"), stabilizePanel,
|
new GuiLabel().setI18nText("replaymod.gui.rendersettings.stabilizecamera"), stabilizePanel,
|
||||||
@@ -522,6 +525,7 @@ public class GuiRenderSettings extends AbstractGuiPopup<GuiRenderSettings> {
|
|||||||
}
|
}
|
||||||
outputFileButton.setLabel(this.outputFile.getName());
|
outputFileButton.setLabel(this.outputFile.getName());
|
||||||
nametagCheckbox.setChecked(settings.isRenderNameTags());
|
nametagCheckbox.setChecked(settings.isRenderNameTags());
|
||||||
|
alphaCheckbox.setChecked(settings.isIncludeAlphaChannel());
|
||||||
stabilizeYaw.setChecked(settings.isStabilizeYaw());
|
stabilizeYaw.setChecked(settings.isStabilizeYaw());
|
||||||
stabilizePitch.setChecked(settings.isStabilizePitch());
|
stabilizePitch.setChecked(settings.isStabilizePitch());
|
||||||
stabilizeRoll.setChecked(settings.isStabilizeRoll());
|
stabilizeRoll.setChecked(settings.isStabilizeRoll());
|
||||||
@@ -560,6 +564,7 @@ public class GuiRenderSettings extends AbstractGuiPopup<GuiRenderSettings> {
|
|||||||
bitRateField.getInteger() << (10 * bitRateUnit.getSelected()),
|
bitRateField.getInteger() << (10 * bitRateUnit.getSelected()),
|
||||||
serialize && !userDefinedOutputFileName ? getParentFile(outputFile) : outputFile,
|
serialize && !userDefinedOutputFileName ? getParentFile(outputFile) : outputFile,
|
||||||
nametagCheckbox.isChecked(),
|
nametagCheckbox.isChecked(),
|
||||||
|
alphaCheckbox.isChecked(),
|
||||||
stabilizeYaw.isChecked() && (serialize || stabilizeYaw.isEnabled()),
|
stabilizeYaw.isChecked() && (serialize || stabilizeYaw.isEnabled()),
|
||||||
stabilizePitch.isChecked() && (serialize || stabilizePitch.isEnabled()),
|
stabilizePitch.isChecked() && (serialize || stabilizePitch.isEnabled()),
|
||||||
stabilizeRoll.isChecked() && (serialize || stabilizeRoll.isEnabled()),
|
stabilizeRoll.isChecked() && (serialize || stabilizeRoll.isEnabled()),
|
||||||
|
|||||||
@@ -136,12 +136,12 @@ public class VideoRenderer implements RenderInfo {
|
|||||||
FrameConsumer<BitmapFrame> frameConsumer;
|
FrameConsumer<BitmapFrame> frameConsumer;
|
||||||
if (settings.getEncodingPreset() == RenderSettings.EncodingPreset.EXR) {
|
if (settings.getEncodingPreset() == RenderSettings.EncodingPreset.EXR) {
|
||||||
//#if MC>=11400
|
//#if MC>=11400
|
||||||
frameConsumer = new EXRWriter(settings.getOutputFile().toPath());
|
frameConsumer = new EXRWriter(settings.getOutputFile().toPath(), settings.isIncludeAlphaChannel());
|
||||||
//#else
|
//#else
|
||||||
//$$ throw new UnsupportedOperationException("EXR requires LWJGL3");
|
//$$ throw new UnsupportedOperationException("EXR requires LWJGL3");
|
||||||
//#endif
|
//#endif
|
||||||
} else if (settings.getEncodingPreset() == RenderSettings.EncodingPreset.PNG) {
|
} else if (settings.getEncodingPreset() == RenderSettings.EncodingPreset.PNG) {
|
||||||
frameConsumer = new PNGWriter(settings.getOutputFile().toPath());
|
frameConsumer = new PNGWriter(settings.getOutputFile().toPath(), settings.isIncludeAlphaChannel());
|
||||||
} else {
|
} else {
|
||||||
frameConsumer = new FFmpegWriter(this);
|
frameConsumer = new FFmpegWriter(this);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user