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  */
32 package com.jme3.app;
33 
34 import com.jme3.app.state.AbstractAppState;
35 import com.jme3.app.state.AppStateManager;
36 import com.jme3.font.BitmapFont;
37 import com.jme3.font.BitmapText;
38 import com.jme3.renderer.RenderManager;
39 import com.jme3.scene.Node;
40 import 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  */
49 public 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 
StatsAppState()63     public StatsAppState() {
64     }
65 
StatsAppState( Node guiNode, BitmapFont guiFont )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      */
setFont( BitmapFont guiFont )77     void setFont( BitmapFont guiFont ) {
78         this.guiFont = guiFont;
79         this.fpsText = new BitmapText(guiFont, false);
80     }
81 
getFpsText()82     public BitmapText getFpsText() {
83         return fpsText;
84     }
85 
getStatsView()86     public StatsView getStatsView() {
87         return statsView;
88     }
89 
getSecondCounter()90     public float getSecondCounter() {
91         return secondCounter;
92     }
93 
toggleStats()94     public void toggleStats() {
95         setDisplayFps( !showFps );
96         setDisplayStatView( !showStats );
97     }
98 
setDisplayFps(boolean show)99     public void setDisplayFps(boolean show) {
100         showFps = show;
101         if (fpsText != null) {
102             fpsText.setCullHint(show ? CullHint.Never : CullHint.Always);
103         }
104     }
105 
setDisplayStatView(boolean show)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
initialize(AppStateManager stateManager, Application app)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      */
loadFpsText()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      */
loadStatsView()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
setEnabled(boolean enabled)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
update(float tpf)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
cleanup()200     public void cleanup() {
201         super.cleanup();
202 
203         guiNode.detachChild(statsView);
204         guiNode.detachChild(fpsText);
205     }
206 
207 
208 }
209