attempt to improve the fpsmeter
This commit is contained in:
parent
c741db3923
commit
8c53973fa5
|
@ -67,6 +67,7 @@ import yugecin.opsudance.events.ResolutionOrSkinChangedEvent;
|
||||||
import yugecin.opsudance.movers.factories.ExgonMoverFactory;
|
import yugecin.opsudance.movers.factories.ExgonMoverFactory;
|
||||||
import yugecin.opsudance.movers.factories.QuadraticBezierMoverFactory;
|
import yugecin.opsudance.movers.factories.QuadraticBezierMoverFactory;
|
||||||
import yugecin.opsudance.movers.slidermovers.DefaultSliderMoverController;
|
import yugecin.opsudance.movers.slidermovers.DefaultSliderMoverController;
|
||||||
|
import yugecin.opsudance.utils.CachedVariable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles all user options.
|
* Handles all user options.
|
||||||
|
@ -382,19 +383,38 @@ public class Options {
|
||||||
@Override
|
@Override
|
||||||
public void read(String s) { skinName = s; }
|
public void read(String s) { skinName = s; }
|
||||||
},
|
},
|
||||||
TARGET_FPS ("Frame Limiter", "FrameSync", "Higher values may cause high CPU usage.") {
|
TARGET_UPS ("target UPS", "targetUPS", "Higher values result in less input lag and smoother cursor trail, but may cause high CPU usage.", 480, 20, 1000) {
|
||||||
@Override
|
@Override
|
||||||
public String getValueString() {
|
public String getValueString() {
|
||||||
return String.format((getTargetFPS() == 60) ? "%dfps (vsync)" : "%dfps", getTargetFPS());
|
return String.format("%dups", val);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object[] getListItems() {
|
public void setValue(int value) {
|
||||||
String[] list = new String[targetFPS.length];
|
super.setValue(value);
|
||||||
for (int i = 0; i < targetFPS.length; i++) {
|
displayContainer.setUPS(value);
|
||||||
list[i] = String.format(targetFPS[i] == 60 ? "%dfps (vsync)" : "%dfps", targetFPS[i]);
|
}
|
||||||
|
},
|
||||||
|
TARGET_FPS ("FPS limit", "FPSlimit", "Higher values may cause high CPU usage. A value higher than the UPS has no effect.") {
|
||||||
|
@Override
|
||||||
|
public String getValueString() {
|
||||||
|
return String.format("%dfps", getTargetFPS());
|
||||||
|
}
|
||||||
|
|
||||||
|
private CachedVariable<Object[]> $_getListItems = new CachedVariable<>(new CachedVariable.Getter<Object[]>() {
|
||||||
|
@Override
|
||||||
|
public Object[] get() {
|
||||||
|
String[] list = new String[targetFPS.length];
|
||||||
|
for (int i = 0; i < targetFPS.length; i++) {
|
||||||
|
list[i] = String.format("%dfps", targetFPS[i]);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
}
|
}
|
||||||
return list;
|
});
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] getListItems() {
|
||||||
|
return $_getListItems.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -404,7 +424,9 @@ public class Options {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String write() { return Integer.toString(targetFPS[targetFPSindex]); }
|
public String write() {
|
||||||
|
return Integer.toString(targetFPS[targetFPSindex]);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(String s) {
|
public void read(String s) {
|
||||||
|
@ -417,7 +439,13 @@ public class Options {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
SHOW_FPS ("Show FPS Counter", "FpsCounter", "Show an FPS counter in the bottom-right hand corner.", true),
|
SHOW_FPS ("Show FPS Counters", "FpsCounter", "Show FPS and UPS counters in the bottom-right hand corner.", true),
|
||||||
|
USE_FPS_DELTAS ("Use deltas for FPS counters", "FpsCounterDeltas", "Show time between updates instead of updates per second.", false) {
|
||||||
|
@Override
|
||||||
|
public boolean showCondition() {
|
||||||
|
return SHOW_FPS.bool;
|
||||||
|
}
|
||||||
|
},
|
||||||
SHOW_UNICODE ("Prefer Non-English Metadata", "ShowUnicode", "Where available, song titles will be shown in their native language.", false) {
|
SHOW_UNICODE ("Prefer Non-English Metadata", "ShowUnicode", "Where available, song titles will be shown in their native language.", false) {
|
||||||
@Override
|
@Override
|
||||||
public void click() {
|
public void click() {
|
||||||
|
@ -1304,6 +1332,10 @@ public class Options {
|
||||||
*/
|
*/
|
||||||
public static int getTargetFPS() { return targetFPS[targetFPSindex]; }
|
public static int getTargetFPS() { return targetFPS[targetFPSindex]; }
|
||||||
|
|
||||||
|
public static int getTargetUPS() {
|
||||||
|
return GameOption.TARGET_UPS.val;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the target frame rate to the next available option, and sends a
|
* Sets the target frame rate to the next available option, and sends a
|
||||||
* bar notification about the action.
|
* bar notification about the action.
|
||||||
|
@ -1503,6 +1535,8 @@ public class Options {
|
||||||
*/
|
*/
|
||||||
public static boolean isFPSCounterEnabled() { return GameOption.SHOW_FPS.getBooleanValue(); }
|
public static boolean isFPSCounterEnabled() { return GameOption.SHOW_FPS.getBooleanValue(); }
|
||||||
|
|
||||||
|
public static boolean useDeltasForFPSCounter() { return GameOption.USE_FPS_DELTAS.getBooleanValue(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether or not hit lighting effects are enabled.
|
* Returns whether or not hit lighting effects are enabled.
|
||||||
* @return true if enabled
|
* @return true if enabled
|
||||||
|
|
|
@ -38,9 +38,10 @@ public class OptionsMenu {
|
||||||
GameOption.SCREEN_RESOLUTION,
|
GameOption.SCREEN_RESOLUTION,
|
||||||
GameOption.ALLOW_LARGER_RESOLUTIONS,
|
GameOption.ALLOW_LARGER_RESOLUTIONS,
|
||||||
GameOption.FULLSCREEN,
|
GameOption.FULLSCREEN,
|
||||||
// TODO d: UPS option
|
GameOption.TARGET_UPS,
|
||||||
GameOption.TARGET_FPS,
|
GameOption.TARGET_FPS,
|
||||||
GameOption.SHOW_FPS,
|
GameOption.SHOW_FPS,
|
||||||
|
GameOption.USE_FPS_DELTAS,
|
||||||
GameOption.SCREENSHOT_FORMAT,
|
GameOption.SCREENSHOT_FORMAT,
|
||||||
}),
|
}),
|
||||||
new OptionTab("SLIDER OPTIONS", new GameOption[]{
|
new OptionTab("SLIDER OPTIONS", new GameOption[]{
|
||||||
|
|
|
@ -153,12 +153,12 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
||||||
});
|
});
|
||||||
|
|
||||||
this.nativeDisplayMode = Display.getDisplayMode();
|
this.nativeDisplayMode = Display.getDisplayMode();
|
||||||
setUPS(1000);
|
|
||||||
setFPS(60);
|
|
||||||
targetBackgroundRenderInterval = 41; // ~24 fps
|
targetBackgroundRenderInterval = 41; // ~24 fps
|
||||||
lastFrame = getTime();
|
lastFrame = getTime();
|
||||||
delta = 1;
|
delta = 1;
|
||||||
renderDelta = 1;
|
renderDelta = 1;
|
||||||
|
|
||||||
|
Options.GameOption.displayContainer = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUPS(int ups) {
|
public void setUPS(int ups) {
|
||||||
|
@ -172,6 +172,9 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init(Class<? extends OpsuState> startingState) {
|
public void init(Class<? extends OpsuState> startingState) {
|
||||||
|
setUPS(Options.getTargetUPS());
|
||||||
|
setFPS(Options.getTargetFPS());
|
||||||
|
|
||||||
state = instanceContainer.provide(startingState);
|
state = instanceContainer.provide(startingState);
|
||||||
state.enter();
|
state.enter();
|
||||||
|
|
||||||
|
@ -192,6 +195,8 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
||||||
mouseX = input.getMouseX();
|
mouseX = input.getMouseX();
|
||||||
mouseY = input.getMouseY();
|
mouseY = input.getMouseY();
|
||||||
|
|
||||||
|
fpsState.update();
|
||||||
|
|
||||||
state.update();
|
state.update();
|
||||||
if (drawCursor) {
|
if (drawCursor) {
|
||||||
cursor.setCursorPosition(delta, mouseX, mouseY);
|
cursor.setCursorPosition(delta, mouseX, mouseY);
|
||||||
|
|
|
@ -17,42 +17,63 @@
|
||||||
*/
|
*/
|
||||||
package yugecin.opsudance.core.state.specialstates;
|
package yugecin.opsudance.core.state.specialstates;
|
||||||
|
|
||||||
|
import itdelatrisu.opsu.Options;
|
||||||
import itdelatrisu.opsu.ui.Fonts;
|
import itdelatrisu.opsu.ui.Fonts;
|
||||||
import org.newdawn.slick.Color;
|
import org.newdawn.slick.Color;
|
||||||
import org.newdawn.slick.Graphics;
|
import org.newdawn.slick.Graphics;
|
||||||
import yugecin.opsudance.core.DisplayContainer;
|
import yugecin.opsudance.core.DisplayContainer;
|
||||||
import yugecin.opsudance.core.events.EventListener;
|
import yugecin.opsudance.core.events.EventListener;
|
||||||
import yugecin.opsudance.events.ResolutionOrSkinChangedEvent;
|
import yugecin.opsudance.events.ResolutionOrSkinChangedEvent;
|
||||||
|
import yugecin.opsudance.utils.FPSMeter;
|
||||||
|
|
||||||
public class FpsRenderState implements EventListener<ResolutionOrSkinChangedEvent> {
|
public class FpsRenderState implements EventListener<ResolutionOrSkinChangedEvent> {
|
||||||
|
|
||||||
private final DisplayContainer displayContainer;
|
|
||||||
|
|
||||||
private final static Color GREEN = new Color(171, 218, 25);
|
private final static Color GREEN = new Color(171, 218, 25);
|
||||||
private final static Color ORANGE = new Color(255, 204, 34);
|
private final static Color ORANGE = new Color(255, 204, 34);
|
||||||
private final static Color DARKORANGE = new Color(255, 149, 24);
|
private final static Color DARKORANGE = new Color(255, 149, 24);
|
||||||
|
|
||||||
|
private final DisplayContainer displayContainer;
|
||||||
|
private final FPSMeter fpsMeter;
|
||||||
|
private final FPSMeter upsMeter;
|
||||||
|
|
||||||
private int x;
|
private int x;
|
||||||
private int y;
|
private int y;
|
||||||
private int singleHeight;
|
private int singleHeight;
|
||||||
|
|
||||||
public FpsRenderState(DisplayContainer displayContainer) {
|
public FpsRenderState(DisplayContainer displayContainer) {
|
||||||
this.displayContainer = displayContainer;
|
this.displayContainer = displayContainer;
|
||||||
|
fpsMeter = new FPSMeter(10);
|
||||||
|
upsMeter = new FPSMeter(10);
|
||||||
displayContainer.eventBus.subscribe(ResolutionOrSkinChangedEvent.class, this);
|
displayContainer.eventBus.subscribe(ResolutionOrSkinChangedEvent.class, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void update() {
|
||||||
|
upsMeter.update(displayContainer.delta);
|
||||||
|
}
|
||||||
|
|
||||||
public void render(Graphics g) {
|
public void render(Graphics g) {
|
||||||
|
fpsMeter.update(displayContainer.renderDelta);
|
||||||
|
if (!Options.isFPSCounterEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
int x = this.x;
|
int x = this.x;
|
||||||
int target = displayContainer.targetRenderInterval + (displayContainer.targetUpdateInterval % displayContainer.targetRenderInterval);
|
int fpsDeviation = displayContainer.delta % displayContainer.targetRenderInterval;
|
||||||
x = drawText(g, getColor(target, displayContainer.renderDelta), (1000 / displayContainer.renderDelta) + " fps", x, this.y);
|
x = drawText(g, getColor((int) (Options.getTargetFPS() * 0.9f) - fpsDeviation, fpsMeter.getValue()), getText(fpsMeter.getValue(), "fps"), x, this.y);
|
||||||
drawText(g, getColor(displayContainer.targetUpdateInterval, displayContainer.delta), (1000 / displayContainer.delta) + " ups", x, this.y);
|
drawText(g, getColor((int) (Options.getTargetUPS() * 0.9f), upsMeter.getValue()), getText(upsMeter.getValue(), "ups"), x, this.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getText(int value, String unit) {
|
||||||
|
if (Options.useDeltasForFPSCounter()) {
|
||||||
|
return String.format("%.2fms", 1000f / value);
|
||||||
|
}
|
||||||
|
return value + " " + unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Color getColor(int targetValue, int realValue) {
|
private Color getColor(int targetValue, int realValue) {
|
||||||
if (realValue <= targetValue) {
|
if (realValue >= targetValue) {
|
||||||
return GREEN;
|
return GREEN;
|
||||||
}
|
}
|
||||||
if (realValue <= targetValue * 1.15f) {
|
if (realValue >= targetValue * 0.85f) {
|
||||||
return ORANGE;
|
return ORANGE;
|
||||||
}
|
}
|
||||||
return DARKORANGE;
|
return DARKORANGE;
|
||||||
|
@ -64,7 +85,7 @@ public class FpsRenderState implements EventListener<ResolutionOrSkinChangedEven
|
||||||
private int drawText(Graphics g, Color color, String text, int x, int y) {
|
private int drawText(Graphics g, Color color, String text, int x, int y) {
|
||||||
int width = Fonts.SMALL.getWidth(text) + 10;
|
int width = Fonts.SMALL.getWidth(text) + 10;
|
||||||
g.setColor(color);
|
g.setColor(color);
|
||||||
g.fillRoundRect(x - width, y, width, singleHeight + 6, 2);
|
g.fillRoundRect(x - width, y, width, singleHeight + 6, 5, 25);
|
||||||
Fonts.SMALL.drawString(x - width + 3, y + 3, text, Color.black);
|
Fonts.SMALL.drawString(x - width + 3, y + 3, text, Color.black);
|
||||||
return x - width - 6;
|
return x - width - 6;
|
||||||
}
|
}
|
||||||
|
|
52
src/yugecin/opsudance/utils/FPSMeter.java
Normal file
52
src/yugecin/opsudance/utils/FPSMeter.java
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* opsu!dance - fork of opsu! with cursordance auto
|
||||||
|
* Copyright (C) 2017 yugecin
|
||||||
|
*
|
||||||
|
* opsu!dance is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* opsu!dance is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package yugecin.opsudance.utils;
|
||||||
|
|
||||||
|
public class FPSMeter {
|
||||||
|
|
||||||
|
private final int targetTimeBetweenUpdates;
|
||||||
|
|
||||||
|
private int[] measurements;
|
||||||
|
private int timeBetweenUpdates;
|
||||||
|
private int currentMeasureIndex;
|
||||||
|
|
||||||
|
public FPSMeter(int measurements) {
|
||||||
|
targetTimeBetweenUpdates = 1000 / measurements;
|
||||||
|
this.measurements = new int[measurements];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(int delta) {
|
||||||
|
timeBetweenUpdates += delta;
|
||||||
|
while (timeBetweenUpdates >= targetTimeBetweenUpdates) {
|
||||||
|
timeBetweenUpdates -= targetTimeBetweenUpdates;
|
||||||
|
measurements[currentMeasureIndex] = 0;
|
||||||
|
currentMeasureIndex = ++currentMeasureIndex % measurements.length;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < measurements.length; i++) {
|
||||||
|
if (i == currentMeasureIndex) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
measurements[i]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getValue() {
|
||||||
|
return measurements[currentMeasureIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user