blob: aa8e74955aab91d388961e023883c9bad2be3a96 [file] [log] [blame]
Scott Barta59b2e682012-03-01 12:35:35 -08001/*
2 * Copyright (c) 2009-2010 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.AppState;
35import com.jme3.font.BitmapFont;
36import com.jme3.font.BitmapText;
37import com.jme3.input.FlyByCamera;
38import com.jme3.input.KeyInput;
39import com.jme3.input.controls.ActionListener;
40import com.jme3.input.controls.KeyTrigger;
41import com.jme3.math.Quaternion;
42import com.jme3.math.Vector3f;
43import com.jme3.renderer.RenderManager;
44import com.jme3.renderer.queue.RenderQueue.Bucket;
45import com.jme3.scene.Node;
46import com.jme3.scene.Spatial.CullHint;
47import com.jme3.system.AppSettings;
48import com.jme3.system.JmeContext.Type;
49import com.jme3.system.JmeSystem;
50import com.jme3.util.BufferUtils;
51
52/**
53 * <code>SimpleApplication</code> extends the {@link com.jme3.app.Application}
54 * class to provide default functionality like a first-person camera,
55 * and an accessible root node that is updated and rendered regularly.
56 * Additionally, <code>SimpleApplication</code> will display a statistics view
57 * using the {@link com.jme3.app.StatsView} class. It will display
58 * the current frames-per-second value on-screen in addition to the statistics.
59 * Several keys have special functionality in <code>SimpleApplication</code>:<br/>
60 *
61 * <table>
62 * <tr><td>Esc</td><td>- Close the application</td></tr>
63 * <tr><td>C</td><td>- Display the camera position and rotation in the console.</td></tr>
64 * <tr><td>M</td><td>- Display memory usage in the console.</td></tr>
65 * </table>
66 */
67public abstract class SimpleApplication extends Application {
68
69 public static final String INPUT_MAPPING_EXIT = "SIMPLEAPP_Exit";
70 public static final String INPUT_MAPPING_CAMERA_POS = DebugKeysAppState.INPUT_MAPPING_CAMERA_POS;
71 public static final String INPUT_MAPPING_MEMORY = DebugKeysAppState.INPUT_MAPPING_MEMORY;
72 public static final String INPUT_MAPPING_HIDE_STATS = "SIMPLEAPP_HideStats";
73
74 protected Node rootNode = new Node("Root Node");
75 protected Node guiNode = new Node("Gui Node");
76 protected BitmapText fpsText;
77 protected BitmapFont guiFont;
78 protected FlyByCamera flyCam;
79 protected boolean showSettings = true;
80 private AppActionListener actionListener = new AppActionListener();
81
82 private class AppActionListener implements ActionListener {
83
84 public void onAction(String name, boolean value, float tpf) {
85 if (!value) {
86 return;
87 }
88
89 if (name.equals(INPUT_MAPPING_EXIT)) {
90 stop();
91 }else if (name.equals(INPUT_MAPPING_HIDE_STATS)){
92 if (stateManager.getState(StatsAppState.class) != null) {
93 stateManager.getState(StatsAppState.class).toggleStats();
94 }
95 }
96 }
97 }
98
99 public SimpleApplication() {
100 this( new StatsAppState(), new FlyCamAppState(), new DebugKeysAppState() );
101 }
102
103 public SimpleApplication( AppState... initialStates ) {
104 super();
105
106 if (initialStates != null) {
107 for (AppState a : initialStates) {
108 if (a != null) {
109 stateManager.attach(a);
110 }
111 }
112 }
113 }
114
115 @Override
116 public void start() {
117 // set some default settings in-case
118 // settings dialog is not shown
119 boolean loadSettings = false;
120 if (settings == null) {
121 setSettings(new AppSettings(true));
122 loadSettings = true;
123 }
124
125 // show settings dialog
126 if (showSettings) {
127 if (!JmeSystem.showSettingsDialog(settings, loadSettings)) {
128 return;
129 }
130 }
131 //re-setting settings they can have been merged from the registry.
132 setSettings(settings);
133 super.start();
134 }
135
136 /**
137 * Retrieves flyCam
138 * @return flyCam Camera object
139 *
140 */
141 public FlyByCamera getFlyByCamera() {
142 return flyCam;
143 }
144
145 /**
146 * Retrieves guiNode
147 * @return guiNode Node object
148 *
149 */
150 public Node getGuiNode() {
151 return guiNode;
152 }
153
154 /**
155 * Retrieves rootNode
156 * @return rootNode Node object
157 *
158 */
159 public Node getRootNode() {
160 return rootNode;
161 }
162
163 public boolean isShowSettings() {
164 return showSettings;
165 }
166
167 /**
168 * Toggles settings window to display at start-up
169 * @param showSettings Sets true/false
170 *
171 */
172 public void setShowSettings(boolean showSettings) {
173 this.showSettings = showSettings;
174 }
175
176 @Override
177 public void initialize() {
178 super.initialize();
179
180 // Several things rely on having this
181 guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
182
183 guiNode.setQueueBucket(Bucket.Gui);
184 guiNode.setCullHint(CullHint.Never);
185 viewPort.attachScene(rootNode);
186 guiViewPort.attachScene(guiNode);
187
188 if (inputManager != null) {
189
190 // We have to special-case the FlyCamAppState because too
191 // many SimpleApplication subclasses expect it to exist in
192 // simpleInit(). But at least it only gets initialized if
193 // the app state is added.
194 if (stateManager.getState(FlyCamAppState.class) != null) {
195 flyCam = new FlyByCamera(cam);
196 flyCam.setMoveSpeed(1f); // odd to set this here but it did it before
197 stateManager.getState(FlyCamAppState.class).setCamera( flyCam );
198 }
199
200 if (context.getType() == Type.Display) {
201 inputManager.addMapping(INPUT_MAPPING_EXIT, new KeyTrigger(KeyInput.KEY_ESCAPE));
202 }
203
204 if (stateManager.getState(StatsAppState.class) != null) {
205 inputManager.addMapping(INPUT_MAPPING_HIDE_STATS, new KeyTrigger(KeyInput.KEY_F5));
206 inputManager.addListener(actionListener, INPUT_MAPPING_HIDE_STATS);
207 }
208
209 inputManager.addListener(actionListener, INPUT_MAPPING_EXIT);
210 }
211
212 if (stateManager.getState(StatsAppState.class) != null) {
213 // Some of the tests rely on having access to fpsText
214 // for quick display. Maybe a different way would be better.
215 stateManager.getState(StatsAppState.class).setFont(guiFont);
216 fpsText = stateManager.getState(StatsAppState.class).getFpsText();
217 }
218
219 // call user code
220 simpleInitApp();
221 }
222
223 @Override
224 public void update() {
225 super.update(); // makes sure to execute AppTasks
226 if (speed == 0 || paused) {
227 return;
228 }
229
230 float tpf = timer.getTimePerFrame() * speed;
231
232 // update states
233 stateManager.update(tpf);
234
235 // simple update and root node
236 simpleUpdate(tpf);
237
238 rootNode.updateLogicalState(tpf);
239 guiNode.updateLogicalState(tpf);
240
241 rootNode.updateGeometricState();
242 guiNode.updateGeometricState();
243
Scott Barta59b2e682012-03-01 12:35:35 -0800244 // render states
245 stateManager.render(renderManager);
246 renderManager.render(tpf, context.isRenderable());
247 simpleRender(renderManager);
248 stateManager.postRender();
249 }
250
251 public void setDisplayFps(boolean show) {
252 if (stateManager.getState(StatsAppState.class) != null) {
253 stateManager.getState(StatsAppState.class).setDisplayFps(show);
254 }
255 }
256
257 public void setDisplayStatView(boolean show) {
258 if (stateManager.getState(StatsAppState.class) != null) {
259 stateManager.getState(StatsAppState.class).setDisplayStatView(show);
260 }
261 }
262
263 public abstract void simpleInitApp();
264
265 public void simpleUpdate(float tpf) {
266 }
267
268 public void simpleRender(RenderManager rm) {
269 }
270}