1/*
2 * Copyright (c) 2009-2012 jMonkeyEngine
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 *   notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 *   notice, this list of conditions and the following disclaimer in the
14 *   documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17 *   may be used to endorse or promote products derived from this software
18 *   without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32package com.jme3.app;
33
34import com.jme3.app.state.AbstractAppState;
35import com.jme3.app.state.AppStateManager;
36import com.jme3.font.BitmapFont;
37import com.jme3.font.BitmapText;
38import com.jme3.renderer.RenderManager;
39import com.jme3.scene.Node;
40import com.jme3.scene.Spatial.CullHint;
41
42
43/**
44 *  Displays stats in SimpleApplication's GUI node or
45 *  using the node and font parameters provided.
46 *
47 *  @author    Paul Speed
48 */
49public class StatsAppState extends AbstractAppState {
50
51    private Application app;
52    protected StatsView statsView;
53    protected boolean showSettings = true;
54    private  boolean showFps = true;
55    private  boolean showStats = true;
56
57    protected Node guiNode;
58    protected float secondCounter = 0.0f;
59    protected int frameCounter = 0;
60    protected BitmapText fpsText;
61    protected BitmapFont guiFont;
62
63    public StatsAppState() {
64    }
65
66    public StatsAppState( Node guiNode, BitmapFont guiFont ) {
67        this.guiNode = guiNode;
68        this.guiFont = guiFont;
69    }
70
71    /**
72     *  Called by SimpleApplication to provide an early font
73     *  so that the fpsText can be created before init.  This
74     *  is because several applications expect to directly access
75     *  fpsText... unfortunately.
76     */
77    void setFont( BitmapFont guiFont ) {
78        this.guiFont = guiFont;
79        this.fpsText = new BitmapText(guiFont, false);
80    }
81
82    public BitmapText getFpsText() {
83        return fpsText;
84    }
85
86    public StatsView getStatsView() {
87        return statsView;
88    }
89
90    public float getSecondCounter() {
91        return secondCounter;
92    }
93
94    public void toggleStats() {
95        setDisplayFps( !showFps );
96        setDisplayStatView( !showStats );
97    }
98
99    public void setDisplayFps(boolean show) {
100        showFps = show;
101        if (fpsText != null) {
102            fpsText.setCullHint(show ? CullHint.Never : CullHint.Always);
103        }
104    }
105
106    public void setDisplayStatView(boolean show) {
107        showStats = show;
108        if (statsView != null ) {
109            statsView.setEnabled(show);
110            statsView.setCullHint(show ? CullHint.Never : CullHint.Always);
111        }
112    }
113
114    @Override
115    public void initialize(AppStateManager stateManager, Application app) {
116        super.initialize(stateManager, app);
117        this.app = app;
118
119        if (app instanceof SimpleApplication) {
120            SimpleApplication simpleApp = (SimpleApplication)app;
121            if (guiNode == null)
122                guiNode = simpleApp.guiNode;
123            if (guiFont == null )
124                guiFont = simpleApp.guiFont;
125        }
126
127        if (guiNode == null) {
128            throw new RuntimeException( "No guiNode specific and cannot be automatically determined." );
129        }
130
131        if (guiFont == null) {
132            guiFont = app.getAssetManager().loadFont("Interface/Fonts/Default.fnt");
133        }
134
135        loadFpsText();
136        loadStatsView();
137    }
138
139    /**
140     * Attaches FPS statistics to guiNode and displays it on the screen.
141     *
142     */
143    public void loadFpsText() {
144        if (fpsText == null) {
145            fpsText = new BitmapText(guiFont, false);
146        }
147
148        fpsText.setLocalTranslation(0, fpsText.getLineHeight(), 0);
149        fpsText.setText("Frames per second");
150        fpsText.setCullHint(showFps ? CullHint.Never : CullHint.Always);
151        guiNode.attachChild(fpsText);
152    }
153
154    /**
155     * Attaches Statistics View to guiNode and displays it on the screen
156     * above FPS statistics line.
157     *
158     */
159    public void loadStatsView() {
160        statsView = new StatsView("Statistics View",
161                                  app.getAssetManager(),
162                                  app.getRenderer().getStatistics());
163        // move it up so it appears above fps text
164        statsView.setLocalTranslation(0, fpsText.getLineHeight(), 0);
165        statsView.setEnabled(showStats);
166        statsView.setCullHint(showStats ? CullHint.Never : CullHint.Always);
167        guiNode.attachChild(statsView);
168    }
169
170    @Override
171    public void setEnabled(boolean enabled) {
172        super.setEnabled(enabled);
173
174        if (enabled) {
175            fpsText.setCullHint(showFps ? CullHint.Never : CullHint.Always);
176            statsView.setEnabled(showStats);
177            statsView.setCullHint(showStats ? CullHint.Never : CullHint.Always);
178        } else {
179            fpsText.setCullHint(CullHint.Always);
180            statsView.setEnabled(false);
181            statsView.setCullHint(CullHint.Always);
182        }
183    }
184
185    @Override
186    public void update(float tpf) {
187        if (showFps) {
188            secondCounter += app.getTimer().getTimePerFrame();
189            frameCounter ++;
190            if (secondCounter >= 1.0f) {
191                int fps = (int) (frameCounter / secondCounter);
192                fpsText.setText("Frames per second: " + fps);
193                secondCounter = 0.0f;
194                frameCounter = 0;
195            }
196        }
197    }
198
199    @Override
200    public void cleanup() {
201        super.cleanup();
202
203        guiNode.detachChild(statsView);
204        guiNode.detachChild(fpsText);
205    }
206
207
208}
209