/* * Copyright (c) 2003-onwards Shaven Puppy Ltd * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of 'Shaven Puppy' nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.shavenpuppy.jglib.util; import org.lwjgl.Sys; import org.lwjgl.opengl.Display; import org.lwjgl.opengl.GL11; import org.lwjgl.util.glu.GLU; /** * FPS Graph Logger * Logs frame times elapsed and draws them as a FPS graph (with markers for 30, 60 and 120 fps). * * Either call logFrameTime() every frame with your time delta (if you're doing your own time-based movement) * or just call tick() every frame which calculates the time elapsed and logs it for you. * If using tick() you should probably call reset() before you start your game loop to avoid a huge spike * due to the time elapsed between construction and the start of logging. * * Don't try and use logFrameTime() and tick() at the same time, that's just weird (and will likely produce * weird results too). * * Calling .render() draws the graph to the screen using basic GL11 commands. It expects the default OpenGL * state (ie. anything fancy like lighting or texturing disabled) and should leave the state untouched * (although your current colour might have changed). * * @author John Campbell */ public class FpsGraph { private int[] samples; private long previousTime; public FpsGraph() { samples = new int[400]; reset(); } public FpsGraph(int numSamples) { samples = new int[numSamples]; reset(); } public void reset() { previousTime = Sys.getTime(); } public void tick() { long currentTime = Sys.getTime(); long diff = currentTime - previousTime; previousTime = currentTime; float timeDelta = (float)diff / Sys.getTimerResolution(); if (timeDelta > 0.2f) { timeDelta = 0.2f; } logFrameTime(timeDelta); } public void logFrameTime(float timeInSeconds) { // Old style scrolling behaviour { // Copy all back one for (int i=1; i<samples.length; i++) { samples[i-1] = samples[i]; } samples[ samples.length-1 ] = (int)(1f/timeInSeconds); } } public void render() { GL11.glMatrixMode(GL11.GL_PROJECTION); GL11.glPushMatrix(); GL11.glLoadIdentity(); GLU.gluOrtho2D(0, Display.getDisplayMode().getWidth(), 0, Display.getDisplayMode().getHeight()); GL11.glDisable(GL11.GL_DEPTH_TEST); GL11.glMatrixMode(GL11.GL_MODELVIEW); GL11.glPushMatrix(); { GL11.glTranslatef(10, 10, 0); GL11.glScalef(0.5f, 0.5f, 0f); int width = samples.length; int height = 120; // 60Hz & 120Hz lines GL11.glBegin(GL11.GL_LINES); { GL11.glColor3f(0.8f, 0.8f, 0.8f); GL11.glVertex2f(0f, 30f); GL11.glVertex2f(width, 30f); GL11.glVertex2f(0f, 60f); GL11.glVertex2f(width, 60f); GL11.glVertex2f(0f, 100f); GL11.glVertex2f(width, 100f); } GL11.glEnd(); // Trace line GL11.glBegin(GL11.GL_LINE_STRIP); { GL11.glVertex2f(0f, 0f); for (int i=0; i<samples.length; i++) { float GREEN_CUTOFF = 60f; float ORANGE_CUTOFF = 30f; if (samples[i] >= GREEN_CUTOFF) { GL11.glColor3f(0f, 1f, 0f); } else if (samples[i] >= ORANGE_CUTOFF) { GL11.glColor3f(1f, 0.6f, 0.1f); } else { GL11.glColor3f(1f, 0f, 0f); } // Clamp to height float y = Math.min(samples[i], height); GL11.glVertex2f(i, y); } } GL11.glEnd(); // Boundary lines GL11.glBegin(GL11.GL_LINE_LOOP); { GL11.glColor3f(0.4f, 0f, 1f); GL11.glVertex2f(0f, 0f); GL11.glVertex2f(width, 0f); GL11.glVertex2f(width, height); GL11.glVertex2f(0f, height); } GL11.glEnd(); GL11.glColor4f(1f, 1f, 1f, 1f); } GL11.glPopMatrix(); GL11.glMatrixMode(GL11.GL_PROJECTION); GL11.glPopMatrix(); } }