Files
ReplayModCinematic/src/main/java/eu/crushedpixel/replaymod/gui/elements/GuiTimeline.java
johni0702 9f3a97f65c Cleanup, relocate and split up GuiReplayOverlay
Merge gui resources into one texture
2015-05-26 01:08:22 +02:00

195 lines
7.2 KiB
Java

package eu.crushedpixel.replaymod.gui.elements;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
import static eu.crushedpixel.replaymod.gui.overlay.GuiReplayOverlay.TEXTURE_SIZE;
import static eu.crushedpixel.replaymod.gui.overlay.GuiReplayOverlay.replay_gui;
import static org.lwjgl.opengl.GL11.GL_BLEND;
import static org.lwjgl.opengl.GL11.glEnable;
public class GuiTimeline extends Gui {
protected static final int TEXTURE_WIDTH = 64;
protected static final int BORDER_TOP = 4;
protected static final int BORDER_BOTTOM = 3;
protected static final int HEIGHT = 22;
protected static final int TEXTURE_X = 64;
protected static final int TEXTURE_Y = 106;
protected static final int BORDER_LEFT = 4;
protected static final int BORDER_RIGHT = 4;
protected static final int BODY_WIDTH = TEXTURE_WIDTH - BORDER_LEFT - BORDER_RIGHT;
/**
* Current position of the cursor. Should normally be between 0 and {@link #timelineLength}.
*/
public int cursorPosition;
/**
* Total length of the timeline.
*/
public int timelineLength;
/**
* The time at the left border of this timeline (fraction of the total length).
*/
public double timeStart;
/**
* Zoom of this timeline. 1/10 allows the user to see 1/10 of the total length.
*/
public double zoom = 1;
/**
* Whether to draw markers on the timeline in regular time intervals.
* This draws the time at big markers above the timeline. Therefore extra space in negative y direction
* should be kept empty if markers are desired.
*/
public boolean showMarkers;
protected final int positionX;
protected final int positionY;
protected final int width;
public GuiTimeline(int positionX, int positionY, int width) {
this.positionX = positionX;
this.positionY = positionY;
this.width = width;
}
/**
* Returns the time which the mouse is at.
* @param mouseX X coordinate of the mouse
* @param mouseY Y coordinate of the mouse
* @return The time or -1 if the mouse isn't on the timeline
*/
public long getTimeAt(int mouseX, int mouseY) {
int left = positionX + BORDER_LEFT;
int right = positionX + width - BORDER_RIGHT;
int bodyWidth = width - BORDER_LEFT - BORDER_RIGHT;
if (mouseX >= left && mouseX <= right && mouseY >= positionY && mouseY <= positionY + HEIGHT) {
double segmentLength = timelineLength * zoom;
double segmentTime = segmentLength * (mouseX - left) / bodyWidth;
return Math.round(timeStart * timelineLength + segmentTime);
} else {
return -1;
}
}
public void draw(Minecraft mc, int mouseX, int mouseY) {
int bodyLeft = positionX + BORDER_LEFT;
int bodyRight = positionX + width - BORDER_RIGHT;
int bodyWidth = width - BORDER_LEFT - BORDER_RIGHT;
{
// We have to increase the border size as there is one pixel row which is part of the border while drawing
// but isn't during position calculations
int BORDER_LEFT = GuiTimeline.BORDER_LEFT + 1;
int BODY_WIDTH = GuiTimeline.BODY_WIDTH - 1;
// Left border
rect(positionX, positionY, TEXTURE_X, TEXTURE_Y, BORDER_LEFT, HEIGHT);
// Body
for (int i = bodyLeft; i < bodyRight; i += BODY_WIDTH) {
rect(i, positionY, TEXTURE_X + BORDER_LEFT, TEXTURE_Y, Math.min(BODY_WIDTH, bodyRight - i), HEIGHT);
}
// Right border
rect(bodyRight, positionY, TEXTURE_X + BORDER_LEFT + BODY_WIDTH, TEXTURE_Y, BORDER_RIGHT, HEIGHT);
}
long leftTime = Math.round(timeStart * timelineLength);
long rightTime = Math.round((timeStart + zoom) * timelineLength);
// Draw markers
if (showMarkers) {
int markerY = positionY + HEIGHT - BORDER_BOTTOM;
MarkerType mt = MarkerType.getMarkerType(zoom, timelineLength);
// Small markers
for (int s = 0; s <= timelineLength; s += mt.smallDistance) {
if (s <= rightTime && s >= leftTime) {
long positionInSegment = s - leftTime;
double fractionOfSegment = positionInSegment / (zoom * timelineLength);
int markerX = (int) (positionX + BORDER_LEFT + fractionOfSegment * bodyWidth);
drawVerticalLine(markerX, markerY - 3, markerY, 0xffffffff);
}
}
// Big markers
for (int s = 0; s <= timelineLength; s += mt.distance) {
if (s <= rightTime && s >= leftTime) {
long positionInSegment = s - leftTime;
double fractionOfSegment = positionInSegment / (zoom * timelineLength);
int markerX = (int) (positionX + BORDER_LEFT + fractionOfSegment * bodyWidth);
drawVerticalLine(markerX, markerY - 7, markerY, 0xffc0c0c0); // Light gray
// Write time above the timeline
long sec = Math.round(s / 1000.0);
String timestamp = String.format("%02d:%02ds", sec / 60, sec % 60);
drawCenteredString(mc.fontRendererObj, timestamp, markerX, positionY - 8, 0xffffffff);
}
}
}
// Draw the cursor if it's on the current timeline segment
if (cursorPosition >= leftTime && cursorPosition <= rightTime) {
long positionInSegment = cursorPosition - leftTime;
double fractionOfSegment = positionInSegment / (zoom * timelineLength);
int cursorX = (int) (positionX + BORDER_LEFT + fractionOfSegment * bodyWidth);
rect(cursorX - 2, positionY + BORDER_TOP, 84, 20, 5, 16);
}
// Draw time under cursor if the mouse is on the timeline
long mouseTime = getTimeAt(mouseX, mouseY);
if (mouseTime != -1) {
long sec = mouseTime / 1000;
String timestamp = String.format("%02d:%02ds", sec / 60, sec % 60);
drawCenteredString(mc.fontRendererObj, timestamp, mouseX, mouseY + 5, 0xffffffff);
}
}
protected void rect(int x, int y, int u, int v, int width, int height) {
Minecraft.getMinecraft().renderEngine.bindTexture(replay_gui);
glEnable(GL_BLEND);
drawModalRectWithCustomSizedTexture(x, y, u, v, width, height, TEXTURE_SIZE, TEXTURE_SIZE);
}
private enum MarkerType {
ONE_S(1000, 100),
FIVE_S(5 * 1000, 1000),
QUARTER_M(15 * 1000, 3 * 1000),
HALF_M(30 * 1000, 5 * 1000),
ONE_M(60 * 1000, 10 * 1000),
FIVE_M(5 * 60 * 1000, 50 * 1000);
int distance;
int smallDistance;
int maximum = 10;
MarkerType(int minimum, int smallDistance) {
this.distance = minimum;
this.smallDistance = smallDistance;
}
public static MarkerType getMarkerType(double scale, long totalLength) {
long seconds = Math.round(totalLength * scale);
for(MarkerType mt : values()) {
if(seconds / mt.distance <= 10) {
return mt;
}
}
return FIVE_M;
}
}
}