timedareagrapher.java
来自「java 3d game jme 工程开发源代码」· Java 代码 · 共 352 行
JAVA
352 行
/*
* Copyright (c) 2003-2009 jMonkeyEngine
* 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 'jMonkeyEngine' 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.jme.util.stat.graph;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.scene.Line;
import com.jme.scene.Node;
import com.jme.scene.TriMesh;
import com.jme.scene.Spatial.CullHint;
import com.jme.scene.state.BlendState;
import com.jme.system.DisplaySystem;
import com.jme.util.Debug;
import com.jme.util.geom.BufferUtils;
import com.jme.util.stat.MultiStatSample;
import com.jme.util.stat.StatCollector;
import com.jme.util.stat.StatType;
/**
* @author Joshua Slack
*/
public class TimedAreaGrapher extends AbstractStatGrapher implements TableLinkable {
public static final StatType Vertical = new StatType("_timedGrapher_vert");
public static final StatType Horizontal = new StatType("_timedGrapher_horiz");
public enum ConfigKeys {
Antialias,
ShowAreas,
Width,
Stipple,
Color,
}
protected Node graphRoot = new Node("root");
protected Line horizontals, verticals;
protected int eventCount = 0;
protected int threshold = 1;
protected float startMarker = 0;
private float off;
private float vSpan;
private int majorHBar = 20;
private int majorVBar = 10;
private HashMap<StatType, AreaEntry> entries = new HashMap<StatType, AreaEntry>();
private BlendState defBlendState = null;
public TimedAreaGrapher(int width, int height) {
super(width, height);
// Setup our static horizontal graph lines
createHLines();
defBlendState = DisplaySystem.getDisplaySystem().getRenderer().createBlendState();
defBlendState.setEnabled(true);
defBlendState.setBlendEnabled(true);
defBlendState.setSourceFunction(BlendState.SourceFunction.SourceAlpha);
defBlendState
.setDestinationFunction(BlendState.DestinationFunction.OneMinusSourceAlpha);
graphRoot.setRenderState(defBlendState);
}
public void statsUpdated() {
if (!isEnabled() || !Debug.updateGraphs)
return;
// Turn off stat collection while we draw this graph.
StatCollector.pause();
// some basic stats:
int texWidth = gWidth;
int texHeight = gHeight;
// On stat event:
// - check if enough events have been triggered to cause an update.
eventCount++;
off += StatCollector.getStartOffset();
if (eventCount < threshold) {
return;
} else {
eventCount = 0;
}
// - (Re)attach horizontal bars.
if (!graphRoot.equals(horizontals.getParent())) {
graphRoot.attachChild(horizontals);
horizontals.updateRenderState();
}
// - Check if we have valid vertical bars:
float newVSpan = calcVSpan();
if (verticals == null || newVSpan != vSpan) {
vSpan = newVSpan;
createVLines();
}
off %= (StatCollector.getSampleRate() * majorVBar);
// - (Re)attach vertical bars.
if (!graphRoot.equals(verticals.getParent())) {
graphRoot.attachChild(verticals);
verticals.updateRenderState();
}
// - shift verticals based on current time
shiftVerticals();
for (StatType type : entries.keySet()) {
entries.get(type).visited = false;
entries.get(type).verts.clear();
}
// - For each sample, add points and extend the lines of the
// corresponding Line objects.
synchronized (StatCollector.getHistorical()) {
for (int i = 0; i < StatCollector.getHistorical().size(); i++) {
MultiStatSample sample = StatCollector.getHistorical().get(i);
// First figure out the max value.
double max = 0;
for (StatType type : sample.values.keySet()) {
if (config.containsKey(type)) {
max += sample.values.get(type).val;
}
}
double accum = 0;
for (StatType type : sample.values.keySet()) {
if (config.containsKey(type)) {
AreaEntry entry = entries.get(type);
// Prepare our entry object as needed.
if (entry == null
|| entry.maxSamples != StatCollector
.getMaxSamples()) {
entry = new AreaEntry(StatCollector.getMaxSamples(), type);
entries.put(type, entry);
}
// average by max and bump by accumulated total.
double value = sample.values.get(type).val / sample.actualTime;
sample.values.get(type).average = value * 100;
Vector3f point1 = new Vector3f(i, (float)(value + accum), 0);
entry.verts.add(point1);
Vector3f point2 = new Vector3f(i, (float)(accum), 0);
entry.verts.add(point2);
entry.visited = true;
accum += value;
}
}
}
}
float scaleWidth = texWidth / (float)(StatCollector.getMaxSamples()-1);
float scaleHeight = texHeight / 1.02f;
for (Iterator<StatType> i = entries.keySet().iterator(); i.hasNext(); ) {
AreaEntry entry = entries.get(i.next());
// - Go through the entries list and remove any that were not
// visited.
if (!entry.visited) {
entry.area.removeFromParent();
i.remove();
continue;
}
// - Update the params with the verts and count.
FloatBuffer fb = BufferUtils.createFloatBuffer(entry.verts
.toArray(new Vector3f[] {}));
fb.rewind();
entry.area.setVertexBuffer(fb);
entry.area.setLocalScale(new Vector3f(scaleWidth, scaleHeight, 1));
entry.area.getIndexBuffer().limit(entry.verts.size());
// - attach to root as needed
if (!graphRoot.equals(entry.area.getParent())) {
graphRoot.attachChild(entry.area);
entry.area.updateRenderState();
}
}
// - Now, draw to texture via a TextureRenderer
texRenderer.render(graphRoot, tex);
// Turn stat collection back on.
StatCollector.resume();
}
private float calcVSpan() {
return texRenderer.getWidth() * majorVBar
/ StatCollector.getMaxSamples();
}
private void shiftVerticals() {
int texWidth = texRenderer.getWidth();
double xOffset = -(off * texWidth)
/ (StatCollector.getMaxSamples() * StatCollector
.getSampleRate());
verticals.getWorldTranslation().x = (float)xOffset;
}
public int getThreshold() {
return threshold;
}
public void setThreshold(int threshold) {
this.threshold = threshold;
}
// - Setup horizontal bars
private void createHLines() {
// some basic stats:
int texWidth = texRenderer.getWidth();
int texHeight = texRenderer.getHeight();
FloatBuffer verts = BufferUtils
.createVector3Buffer((int) (100 / majorHBar) * 2);
float div = texHeight * majorHBar / 100f;
for (int y = 0, i = 0; i < verts.capacity(); i+=6, y += div) {
verts.put(0).put(y).put(0);
verts.put(texWidth).put(y).put(0);
}
horizontals = new Line("horiz", verts, null, null, null);
horizontals.setMode(Line.Mode.Segments);
horizontals.setRenderQueueMode(Renderer.QUEUE_ORTHO);
horizontals.setDefaultColor(getColorConfig(TimedAreaGrapher.Horizontal, ConfigKeys.Color.name(), ColorRGBA.blue.clone()));
horizontals.setLineWidth(getIntConfig(TimedAreaGrapher.Horizontal, ConfigKeys.Width.name(), 1));
horizontals.setStipplePattern(getShortConfig(TimedAreaGrapher.Horizontal, ConfigKeys.Stipple.name(), (short) 0xFF00));
horizontals.setAntialiased(getBooleanConfig(TimedAreaGrapher.Horizontal, ConfigKeys.Antialias.name(), true));
}
// - Setup enough vertical bars to have one at every (10 X samplerate)
// secs... we'll need +1 bar.
private void createVLines() {
// some basic stats:
int texWidth = texRenderer.getWidth();
int texHeight = texRenderer.getHeight();
FloatBuffer verts = BufferUtils
.createVector3Buffer(((int) (texWidth / vSpan) + 1) * 2);
for (float x = vSpan; x <= texWidth + vSpan; x += vSpan) {
verts.put(x).put(0).put(0);
verts.put(x).put(texHeight).put(0);
}
verticals = new Line("vert", verts, null, null, null);
verticals.setMode(Line.Mode.Segments);
verticals.setRenderQueueMode(Renderer.QUEUE_ORTHO);
verticals.setDefaultColor(getColorConfig(TimedAreaGrapher.Vertical, ConfigKeys.Color.name(), ColorRGBA.red.clone()));
verticals.setLineWidth(getIntConfig(TimedAreaGrapher.Vertical, ConfigKeys.Width.name(), 1));
verticals.setStipplePattern(getShortConfig(TimedAreaGrapher.Vertical, ConfigKeys.Stipple.name(), (short) 0xFF00));
verticals.setAntialiased(getBooleanConfig(TimedAreaGrapher.Vertical, ConfigKeys.Antialias.name(), true));
}
class AreaEntry {
public ArrayList<Vector3f> verts = new ArrayList<Vector3f>();
public int maxSamples;
public boolean visited;
public TriMesh area;
public AreaEntry(int maxSamples, StatType type) {
this.maxSamples = maxSamples;
area = new TriMesh("a", BufferUtils.createVector3Buffer(maxSamples * 2),
null, null, null, BufferUtils.createIntBuffer(maxSamples * 2));
for (int i = 0; i < maxSamples * 2; i++) {
area.getIndexBuffer().put(i);
}
area.getIndexBuffer().rewind();
area.setRenderQueueMode(Renderer.QUEUE_ORTHO);
area.setMode(TriMesh.Mode.Strip);
area.setDefaultColor(getColorConfig(type, ConfigKeys.Color.name(), ColorRGBA.lightGray.clone()));
if (!getBooleanConfig(type, ConfigKeys.ShowAreas.name(), true)) {
area.setCullHint(CullHint.Always);
}
}
}
public Line updateLineKey(StatType type, Line lineKey) {
if (lineKey == null) {
lineKey = new Line("lk", BufferUtils.createVector3Buffer(2), null,
null, null);
FloatBuffer fb = BufferUtils.createFloatBuffer(new Vector3f[] {new Vector3f(0,0,0), new Vector3f(30, 0, 0)});
fb.rewind();
lineKey.setVertexBuffer(fb);
}
lineKey.setRenderQueueMode(Renderer.QUEUE_ORTHO);
lineKey.setMode(Line.Mode.Connected);
lineKey.setDefaultColor(getColorConfig(type, ConfigKeys.Color.name(), ColorRGBA.lightGray.clone()));
lineKey.setLineWidth(getIntConfig(type, ConfigKeys.Width.name(), 3));
lineKey.setStipplePattern(getShortConfig(type, ConfigKeys.Stipple.name(), (short) 0xFFFF));
lineKey.setAntialiased(getBooleanConfig(type, ConfigKeys.Antialias.name(), true));
if (!getBooleanConfig(type, ConfigKeys.ShowAreas.name(), true)) {
lineKey.setCullHint(CullHint.Always);
}
return lineKey;
}
public void reset() {
synchronized (StatCollector.getHistorical()) {
for (Iterator<StatType> i = entries.keySet().iterator(); i.hasNext(); ) {
AreaEntry entry = entries.get(i.next());
entry.area.removeFromParent();
i.remove();
}
}
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?