Files
ReplayModCinematic/src/main/java/eu/crushedpixel/replaymod/gui/GuiVideoRenderer.java
CrushedPixel 34fe741cc4 Call Minecraft#updateDisplay in VideoRenderer if not in High Performance Mode, to resize the GuiVideoRenderer if user resized screen (requested by many users)
This has no side effects on the rendered video.
Change GuiVideoRenderer#initGui method to allow for resizing
2015-07-30 12:59:54 +02:00

306 lines
12 KiB
Java

package eu.crushedpixel.replaymod.gui;
import eu.crushedpixel.replaymod.gui.elements.GuiProgressBar;
import eu.crushedpixel.replaymod.utils.BoundingUtils;
import eu.crushedpixel.replaymod.utils.DurationUtils;
import eu.crushedpixel.replaymod.video.VideoRenderer;
import eu.crushedpixel.replaymod.video.frame.RGBFrame;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.renderer.texture.DynamicTexture;
import net.minecraft.client.renderer.texture.TextureUtil;
import net.minecraft.client.resources.I18n;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.client.config.GuiCheckBox;
import org.lwjgl.util.Dimension;
import org.lwjgl.util.ReadableDimension;
import java.awt.*;
import java.io.IOException;
import java.nio.ByteBuffer;
import static net.minecraft.client.renderer.GlStateManager.bindTexture;
import static net.minecraft.client.renderer.GlStateManager.color;
public class GuiVideoRenderer extends GuiScreen {
private static final ResourceLocation noPreviewTexture = new ResourceLocation("replaymod", "logo.jpg");
private final VideoRenderer renderer;
private final String SCREEN_TITLE = I18n.format("replaymod.gui.rendering.title");
private final String PAUSE_RENDERING = I18n.format("replaymod.gui.rendering.pause");
private final String RESUME_RENDERING = I18n.format("replaymod.gui.rendering.resume");
private final String CANCEL = I18n.format("replaymod.gui.rendering.cancel");
private final String CANCEL_CONFIRM = I18n.format("replaymod.gui.rendering.cancel.callback");
private final String PREVIEW = I18n.format("replaymod.gui.rendering.preview");
private GuiButton pauseButton;
private GuiButton cancelButton;
private GuiCheckBox previewCheckBox;
private GuiProgressBar progressBar;
private DynamicTexture previewTexture;
private boolean previewTextureDirty;
private boolean initialized = false;
public GuiVideoRenderer(VideoRenderer renderer) {
this.renderer = renderer;
}
@Override
@SuppressWarnings("unchecked") // I blame forge for not re-adding generics to that list
public void initGui() {
if(!initialized) {
String text = PAUSE_RENDERING;
pauseButton = new GuiButton(1, width / 2 - 152, height - 10 - 20, text);
text = CANCEL;
cancelButton = new GuiButton(1, width / 2 + 2, height - 10 - 20, text);
pauseButton.width = cancelButton.width = 150;
progressBar = new GuiProgressBar(10, height - 10 - 20 - 10 - 20, width-20, 20);
text = PREVIEW;
previewCheckBox = new GuiCheckBox(0, (width - fontRendererObj.getStringWidth(text)) / 2 - 8,
pauseButton.yPosition - 10 - 20 - 10 - 20 - 5 , text, false);
} else {
pauseButton.xPosition = width / 2 - 152;
pauseButton.yPosition = height - 10 - 20;
cancelButton.xPosition = width / 2 + 2;
cancelButton.yPosition = height - 10 - 20;
progressBar.setBounds(10, height - 10 - 20 - 10 - 20, width - 20, 20);
previewCheckBox.xPosition = (width - fontRendererObj.getStringWidth(PREVIEW)) / 2 - 8;
previewCheckBox.yPosition = pauseButton.yPosition - 10 - 20 - 10 - 20 - 5;
}
buttonList.add(pauseButton);
buttonList.add(cancelButton);
buttonList.add(previewCheckBox);
initialized = true;
super.initGui();
}
@Override
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
String cancelBefore = cancelButton.displayString;
super.mouseClicked(mouseX, mouseY, mouseButton);
String cancelAfter = cancelButton.displayString;
if (cancelBefore.equals(cancelAfter)) {
cancelButton.displayString = CANCEL;
}
}
@Override
protected void actionPerformed(GuiButton button) throws IOException {
if (button == pauseButton) {
if (PAUSE_RENDERING.equals(pauseButton.displayString)) {
renderer.setPaused(true);
pauseButton.displayString = RESUME_RENDERING;
} else if (RESUME_RENDERING.equals(pauseButton.displayString)) {
renderer.setPaused(false);
pauseButton.displayString = PAUSE_RENDERING;
} else {
throw new IllegalStateException(pauseButton.displayString);
}
} else if (button == cancelButton) {
if (CANCEL.equals(cancelButton.displayString)) {
cancelButton.displayString = CANCEL_CONFIRM;
} else if (CANCEL_CONFIRM.equals(cancelButton.displayString)) {
renderer.cancel();
}
}
}
//the total render time
private int renderTimeTaken = 0;
//the time at which the Screen was last updated
private long prevTime = -1;
//the time at which the rendering of the current frame started
private long frameStartTime = -1;
//the amount of frames that were rendered when the time left was last updated
private int prevRenderedFrames = 0;
//the estimated render time that is left (in seconds)
private int renderTimeLeft = 0;
//each of the durations the rendering process took for the last 50 frames
private int[] renderTimes = new int[50];
//the algorithm's current position in the renderTimes array
private int currentIndex = 0;
@Override
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
long current = System.currentTimeMillis();
//first, update the total render time (only if rendering is not paused and has already started)
if(!renderer.isPaused() && renderer.getFramesDone() > 0 && prevTime > -1) {
renderTimeTaken += (current - prevTime);
} else {
//if the rendering process is paused, we have to update the frame start time to prevent huge render times
//for the currently rendered frame(s)
frameStartTime = current;
}
//always update prevTime, so we don't get huge time jumps when unpausing the rendering process
prevTime = current;
//calculate estimated time left
//if the amount of rendered frames has increased since the last update
if(prevRenderedFrames < renderer.getFramesDone()) {
//we don't include the first frame in our calculations,
//as setting up the rendering process takes a few seconds
if(prevRenderedFrames > 0) {
//calculate the amount of frames that have been rendered since the last update
int framesRendered = renderer.getFramesDone() - prevRenderedFrames;
//calculate the time it took to render these frames
int renderTime = (int)(current - frameStartTime);
//calculate the average time it took for each of these frames to render
int avgRenderTime = renderTime/framesRendered;
//add all of the average render times to the render times array
for(int i=0; i<framesRendered; i++) {
renderTimes[currentIndex] = avgRenderTime;
currentIndex++;
if(currentIndex >= renderTimes.length) currentIndex = 0;
}
//the renderTimes array initially contains lots of zeros,
//so we count the amount of valid timespans
int validValues = 0;
int totalTime = 0;
for(int i : renderTimes) {
if(i > 0) {
totalTime += i;
validValues++;
}
}
//calculate the average render time for the previous [up to 50] frames
float averageRenderTime = validValues > 0 ? totalTime / validValues : 0;
//calculate the remaining render time in seconds
renderTimeLeft = Math.round((averageRenderTime * (renderer.getTotalFrames() - renderer.getFramesDone())) / 1000);
}
//set the render start time of the next frame(s) to the current timestamp
frameStartTime = current;
//update the amount of rendered frames for the last calculation
prevRenderedFrames = renderer.getFramesDone();
}
String takenString = I18n.format("replaymod.gui.rendering.timetaken")+": "+DurationUtils.convertSecondsToString(renderTimeTaken/1000);
String leftString = I18n.format("replaymod.gui.rendering.timeleft")+": "+DurationUtils.convertSecondsToString(renderTimeLeft);
int centerX = width / 2;
drawBackground(0);
drawCenteredString(fontRendererObj, SCREEN_TITLE, centerX, 5, Color.WHITE.getRGB());
String framesProgress = I18n.format("replaymod.gui.rendering.progress", renderer.getFramesDone(), renderer.getTotalFrames());
progressBar.setProgressString(framesProgress);
progressBar.setProgress((float) renderer.getFramesDone() / renderer.getTotalFrames());
progressBar.drawProgressBar();
int previewX = 10;
int previewWidth = width - 20;
int previewHeight = previewCheckBox.yPosition - 10 - 20;
int previewY = previewCheckBox.yPosition - 10 - previewHeight;
if(previewCheckBox.isChecked()) {
renderPreview(previewX, previewY, previewWidth, previewHeight);
} else {
renderNoPreview(previewX, previewY, previewWidth, previewHeight);
}
drawString(fontRendererObj, takenString, 12, previewCheckBox.yPosition + 5 + 20, Color.WHITE.getRGB());
drawString(fontRendererObj, leftString, width - 12 - fontRendererObj.getStringWidth(leftString),
previewCheckBox.yPosition + 5 + 20, Color.WHITE.getRGB());
super.drawScreen(mouseX, mouseY, partialTicks);
}
private synchronized void renderPreview(int x, int y, int width, int height) {
ReadableDimension videoSize = renderer.getFrameSize();
final int videoWidth = videoSize.getWidth();
final int videoHeight = videoSize.getHeight();
if (previewTexture == null) {
previewTexture = new DynamicTexture(videoWidth, videoHeight) {
@Override
public void updateDynamicTexture() {
bindTexture(getGlTextureId());
TextureUtil.uploadTextureSub(0, getTextureData(), videoWidth, videoHeight, 0, 0, true, false, false);
}
};
}
if (previewTextureDirty) {
previewTexture.updateDynamicTexture();
previewTextureDirty = false;
}
Dimension dimension = BoundingUtils.fitIntoBounds(new Dimension(videoSize), new Dimension(width, height));
x += (width - dimension.getWidth()) / 2;
y += (height - dimension.getHeight()) / 2;
width = dimension.getWidth();
height = dimension.getHeight();
color(1, 1, 1, 1);
bindTexture(previewTexture.getGlTextureId());
drawScaledCustomSizeModalRect(x, y, 0, 0, videoWidth, videoHeight, width, height, videoWidth, videoHeight);
}
private void renderNoPreview(int x, int y, int width, int height) {
int actualWidth = width;
int actualHeight = height;
if (width / height > 1280 / 720) {
actualWidth = height * 1280 / 720;
} else {
actualHeight = width * 720 / 1280;
}
x += (width - actualWidth) / 2;
y += (height - actualHeight) / 2;
Minecraft.getMinecraft().getTextureManager().bindTexture(noPreviewTexture);
color(1, 1, 1, 1);
drawScaledCustomSizeModalRect(x, y, 0, 0, 1280, 720, actualWidth, actualHeight, 1280, 720);
}
public void updatePreview(RGBFrame frame) {
if (previewCheckBox.isChecked() && previewTexture != null) {
ByteBuffer buffer = frame.getByteBuffer();
buffer.mark();
synchronized (this) {
int[] data = previewTexture.getTextureData();
for (int i = 0; i < data.length; i++) {
data[i] = 0xff << 24 | (buffer.get() & 0xff) << 16 | (buffer.get() & 0xff) << 8 | (buffer.get() & 0xff);
}
previewTextureDirty = true;
}
buffer.reset();
}
}
}