| /* |
| * Copyright (c) 2009-2010 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.jme3.app; |
| |
| import com.jme3.app.state.AppState; |
| import com.jme3.font.BitmapFont; |
| import com.jme3.font.BitmapText; |
| import com.jme3.input.FlyByCamera; |
| import com.jme3.input.KeyInput; |
| import com.jme3.input.controls.ActionListener; |
| import com.jme3.input.controls.KeyTrigger; |
| import com.jme3.math.Quaternion; |
| import com.jme3.math.Vector3f; |
| import com.jme3.renderer.RenderManager; |
| import com.jme3.renderer.queue.RenderQueue.Bucket; |
| import com.jme3.scene.Node; |
| import com.jme3.scene.Spatial.CullHint; |
| import com.jme3.system.AppSettings; |
| import com.jme3.system.JmeContext.Type; |
| import com.jme3.system.JmeSystem; |
| import com.jme3.util.BufferUtils; |
| |
| /** |
| * <code>SimpleApplication</code> extends the {@link com.jme3.app.Application} |
| * class to provide default functionality like a first-person camera, |
| * and an accessible root node that is updated and rendered regularly. |
| * Additionally, <code>SimpleApplication</code> will display a statistics view |
| * using the {@link com.jme3.app.StatsView} class. It will display |
| * the current frames-per-second value on-screen in addition to the statistics. |
| * Several keys have special functionality in <code>SimpleApplication</code>:<br/> |
| * |
| * <table> |
| * <tr><td>Esc</td><td>- Close the application</td></tr> |
| * <tr><td>C</td><td>- Display the camera position and rotation in the console.</td></tr> |
| * <tr><td>M</td><td>- Display memory usage in the console.</td></tr> |
| * </table> |
| */ |
| public abstract class SimpleApplication extends Application { |
| |
| public static final String INPUT_MAPPING_EXIT = "SIMPLEAPP_Exit"; |
| public static final String INPUT_MAPPING_CAMERA_POS = DebugKeysAppState.INPUT_MAPPING_CAMERA_POS; |
| public static final String INPUT_MAPPING_MEMORY = DebugKeysAppState.INPUT_MAPPING_MEMORY; |
| public static final String INPUT_MAPPING_HIDE_STATS = "SIMPLEAPP_HideStats"; |
| |
| protected Node rootNode = new Node("Root Node"); |
| protected Node guiNode = new Node("Gui Node"); |
| protected BitmapText fpsText; |
| protected BitmapFont guiFont; |
| protected FlyByCamera flyCam; |
| protected boolean showSettings = true; |
| private AppActionListener actionListener = new AppActionListener(); |
| |
| private class AppActionListener implements ActionListener { |
| |
| public void onAction(String name, boolean value, float tpf) { |
| if (!value) { |
| return; |
| } |
| |
| if (name.equals(INPUT_MAPPING_EXIT)) { |
| stop(); |
| }else if (name.equals(INPUT_MAPPING_HIDE_STATS)){ |
| if (stateManager.getState(StatsAppState.class) != null) { |
| stateManager.getState(StatsAppState.class).toggleStats(); |
| } |
| } |
| } |
| } |
| |
| public SimpleApplication() { |
| this( new StatsAppState(), new FlyCamAppState(), new DebugKeysAppState() ); |
| } |
| |
| public SimpleApplication( AppState... initialStates ) { |
| super(); |
| |
| if (initialStates != null) { |
| for (AppState a : initialStates) { |
| if (a != null) { |
| stateManager.attach(a); |
| } |
| } |
| } |
| } |
| |
| @Override |
| public void start() { |
| // set some default settings in-case |
| // settings dialog is not shown |
| boolean loadSettings = false; |
| if (settings == null) { |
| setSettings(new AppSettings(true)); |
| loadSettings = true; |
| } |
| |
| // show settings dialog |
| if (showSettings) { |
| if (!JmeSystem.showSettingsDialog(settings, loadSettings)) { |
| return; |
| } |
| } |
| //re-setting settings they can have been merged from the registry. |
| setSettings(settings); |
| super.start(); |
| } |
| |
| /** |
| * Retrieves flyCam |
| * @return flyCam Camera object |
| * |
| */ |
| public FlyByCamera getFlyByCamera() { |
| return flyCam; |
| } |
| |
| /** |
| * Retrieves guiNode |
| * @return guiNode Node object |
| * |
| */ |
| public Node getGuiNode() { |
| return guiNode; |
| } |
| |
| /** |
| * Retrieves rootNode |
| * @return rootNode Node object |
| * |
| */ |
| public Node getRootNode() { |
| return rootNode; |
| } |
| |
| public boolean isShowSettings() { |
| return showSettings; |
| } |
| |
| /** |
| * Toggles settings window to display at start-up |
| * @param showSettings Sets true/false |
| * |
| */ |
| public void setShowSettings(boolean showSettings) { |
| this.showSettings = showSettings; |
| } |
| |
| @Override |
| public void initialize() { |
| super.initialize(); |
| |
| // Several things rely on having this |
| guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt"); |
| |
| guiNode.setQueueBucket(Bucket.Gui); |
| guiNode.setCullHint(CullHint.Never); |
| viewPort.attachScene(rootNode); |
| guiViewPort.attachScene(guiNode); |
| |
| if (inputManager != null) { |
| |
| // We have to special-case the FlyCamAppState because too |
| // many SimpleApplication subclasses expect it to exist in |
| // simpleInit(). But at least it only gets initialized if |
| // the app state is added. |
| if (stateManager.getState(FlyCamAppState.class) != null) { |
| flyCam = new FlyByCamera(cam); |
| flyCam.setMoveSpeed(1f); // odd to set this here but it did it before |
| stateManager.getState(FlyCamAppState.class).setCamera( flyCam ); |
| } |
| |
| if (context.getType() == Type.Display) { |
| inputManager.addMapping(INPUT_MAPPING_EXIT, new KeyTrigger(KeyInput.KEY_ESCAPE)); |
| } |
| |
| if (stateManager.getState(StatsAppState.class) != null) { |
| inputManager.addMapping(INPUT_MAPPING_HIDE_STATS, new KeyTrigger(KeyInput.KEY_F5)); |
| inputManager.addListener(actionListener, INPUT_MAPPING_HIDE_STATS); |
| } |
| |
| inputManager.addListener(actionListener, INPUT_MAPPING_EXIT); |
| } |
| |
| if (stateManager.getState(StatsAppState.class) != null) { |
| // Some of the tests rely on having access to fpsText |
| // for quick display. Maybe a different way would be better. |
| stateManager.getState(StatsAppState.class).setFont(guiFont); |
| fpsText = stateManager.getState(StatsAppState.class).getFpsText(); |
| } |
| |
| // call user code |
| simpleInitApp(); |
| } |
| |
| @Override |
| public void update() { |
| super.update(); // makes sure to execute AppTasks |
| if (speed == 0 || paused) { |
| return; |
| } |
| |
| float tpf = timer.getTimePerFrame() * speed; |
| |
| // update states |
| stateManager.update(tpf); |
| |
| // simple update and root node |
| simpleUpdate(tpf); |
| |
| rootNode.updateLogicalState(tpf); |
| guiNode.updateLogicalState(tpf); |
| |
| rootNode.updateGeometricState(); |
| guiNode.updateGeometricState(); |
| |
| // render states |
| stateManager.render(renderManager); |
| renderManager.render(tpf, context.isRenderable()); |
| simpleRender(renderManager); |
| stateManager.postRender(); |
| } |
| |
| public void setDisplayFps(boolean show) { |
| if (stateManager.getState(StatsAppState.class) != null) { |
| stateManager.getState(StatsAppState.class).setDisplayFps(show); |
| } |
| } |
| |
| public void setDisplayStatView(boolean show) { |
| if (stateManager.getState(StatsAppState.class) != null) { |
| stateManager.getState(StatsAppState.class).setDisplayStatView(show); |
| } |
| } |
| |
| public abstract void simpleInitApp(); |
| |
| public void simpleUpdate(float tpf) { |
| } |
| |
| public void simpleRender(RenderManager rm) { |
| } |
| } |