[java]
/*
- Copyright © 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
- 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
- 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
- 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.AppStateManager;
import com.jme3.input.JoyInput;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.TouchInput;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.renderer.Renderer;
import com.jme3.asset.AssetManager;
import com.jme3.audio.AudioContext;
import com.jme3.audio.AudioRenderer;
import com.jme3.audio.Listener;
import com.jme3.input.InputManager;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.system.AppSettings;
import com.jme3.system.JmeCanvasContext;
import com.jme3.system.JmeContext;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.jme3.system.JmeContext.Type;
import com.jme3.system.JmeSystem;
import com.jme3.system.NanoTimer;
import com.jme3.system.SystemListener;
import com.jme3.system.Timer;
/**
- The <code>Application</code> class represents an instance of a
- real-time 3D rendering jME application.
*
- An <code>Application</code> provides all the tools that are commonly used in jME3
- applications.
*
- jME3 applications should extend this class and call start() to begin the
- application.
*
*/
public class Application implements SystemListener {
private static final Logger logger = Logger.getLogger(Application.class.getName());
protected AssetManager assetManager;
protected AudioRenderer audioRenderer;
protected Renderer renderer;
protected RenderManager renderManager;
protected ViewPort viewPort;
protected ViewPort guiViewPort;
protected JmeContext context;
protected AppSettings settings;
protected Timer timer = new NanoTimer();
protected Camera cam;
protected Listener listener;
protected boolean inputEnabled = true;
protected boolean pauseOnFocus = true;
protected float speed = 1f;
protected boolean paused = false;
protected MouseInput mouseInput;
protected KeyInput keyInput;
protected JoyInput joyInput;
protected TouchInput touchInput;
protected InputManager inputManager;
protected AppStateManager stateManager;
protected java.applet.Applet applet;
private final ConcurrentLinkedQueue<AppTask<?>> taskQueue = new ConcurrentLinkedQueue<AppTask<?>>();
/**
- Create a new instance of <code>Application</code>.
*/
public Application(){
}
/**
- Returns true if pause on lost focus is enabled, false otherwise.
*
-
@return true if pause on lost focus is enabled
*
-
@see #setPauseOnLostFocus(boolean)
*/
public boolean isPauseOnLostFocus() {
return pauseOnFocus;
}
/**
- Enable or disable pause on lost focus.
- <p>
- By default, pause on lost focus is enabled.
- If enabled, the application will stop updating
- when it loses focus or becomes inactive (e.g. alt-tab).
- For online or real-time applications, this might not be preferable,
- so this feature should be set to disabled. For other applications,
- it is best to keep it on so that CPU usage is not used when
- not necessary.
*
-
@param pauseOnLostFocus True to enable pause on lost focus, false
- otherwise.
*/
public void setPauseOnLostFocus(boolean pauseOnLostFocus) {
this.pauseOnFocus = pauseOnLostFocus;
}
@Deprecated
public void setAssetManager(AssetManager assetManager){
if (this.assetManager != null)
throw new IllegalStateException("Can only set asset manager"
- " before initialization.");
this.assetManager = assetManager;
}
private void initAssetManager(){
if (settings != null){
String assetCfg = settings.getString("AssetConfigURL");
if (assetCfg != null){
URL url = null;
try {
url = new URL(assetCfg);
} catch (MalformedURLException ex) {
}
if (url == null) {
url = Application.class.getClassLoader().getResource(assetCfg);
if (url == null) {
logger.log(Level.SEVERE, "Unable to access AssetConfigURL in asset config:{0}", assetCfg);
return;
}
}
assetManager = JmeSystem.newAssetManager(url);
}
}
if (assetManager == null){
assetManager = JmeSystem.newAssetManager(
Thread.currentThread().getContextClassLoader()
.getResource("com/jme3/asset/Desktop.cfg"));
}
}
/**
- Set the display settings to define the display created.
- <p>
- Examples of display parameters include display pixel width and height,
- color bit depth, z-buffer bits, anti-aliasing samples, and update frequency.
- If this method is called while the application is already running, then
- {@link #restart() } must be called to apply the settings to the display.
*
-
@param settings The settings to set.
*/
public void setSettings(AppSettings settings){
this.settings = settings;
if (context != null && settings.useInput() != inputEnabled){
// may need to create or destroy input based
// on settings change
inputEnabled = !inputEnabled;
if (inputEnabled){
initInput();
}else{
destroyInput();
}
}else{
inputEnabled = settings.useInput();
}
}
/**
- Sets the Timer implementation that will be used for calculating
- frame times. By default, Application will use the Timer as returned
- by the current JmeContext implementation.
*/
public void setTimer(Timer timer){
this.timer = timer;
if (timer != null) {
timer.reset();
}
if (renderManager != null) {
renderManager.setTimer(timer);
}
}
private void initDisplay(){
// aquire important objects
// from the context
settings = context.getSettings();
// Only reset the timer if a user has not already provided one
if (timer == null) {
timer = context.getTimer();
}
renderer = context.getRenderer();
}
private void initAudio(){
if (settings.getAudioRenderer() != null && context.getType() != Type.Headless){
audioRenderer = JmeSystem.newAudioRenderer(settings);
audioRenderer.initialize();
AudioContext.setAudioRenderer(audioRenderer);
listener = new Listener();
audioRenderer.setListener(listener);
}
}
/**
- Creates the camera to use for rendering. Default values are perspective
- projection with 45° field of view, with near and far values 1 and 1000
- units respectively.
*/
private void initCamera(){
cam = new Camera(settings.getWidth(), settings.getHeight());
cam.setFrustumPerspective(45f, (float)cam.getWidth() / cam.getHeight(), 1f, 1000f);
cam.setLocation(new Vector3f(0f, 0f, 10f));
cam.lookAt(new Vector3f(0f, 0f, 0f), Vector3f.UNIT_Y);
renderManager = new RenderManager(renderer);
//Remy - 09/14/2010 setted the timer in the renderManager
renderManager.setTimer(timer);
viewPort = renderManager.createMainView("Default", cam);
viewPort.setClearFlags(true, true, true);
// Create a new cam for the gui
Camera guiCam = new Camera(settings.getWidth(), settings.getHeight());
guiViewPort = renderManager.createPostView("Gui Default", guiCam);
guiViewPort.setClearFlags(false, false, false);
}
/**
- Initializes mouse and keyboard input. Also
- initializes joystick input if joysticks are enabled in the
- AppSettings.
*/
private void initInput(){
mouseInput = context.getMouseInput();
if (mouseInput != null)
mouseInput.initialize();
keyInput = context.getKeyInput();
if (keyInput != null)
keyInput.initialize();
touchInput = context.getTouchInput();
if (touchInput != null)
touchInput.initialize();
if (!settings.getBoolean("DisableJoysticks")){
joyInput = context.getJoyInput();
if (joyInput != null)
joyInput.initialize();
}
inputManager = new InputManager(mouseInput, keyInput, joyInput, touchInput);
}
private void initStateManager(){
stateManager = new AppStateManager(this);
}
/**
-
@return The {@link AssetManager asset manager} for this application.
*/
public AssetManager getAssetManager(){
return assetManager;
}
/**
-
@return the {@link InputManager input manager}.
*/
public InputManager getInputManager(){
return inputManager;
}
/**
-
@return the {@link AppStateManager app state manager}
*/
public AppStateManager getStateManager() {
return stateManager;
}
/**
-
@return the {@link RenderManager render manager}
*/
public RenderManager getRenderManager() {
return renderManager;
}
/**
-
@return The {@link Renderer renderer} for the application
*/
public Renderer getRenderer(){
return renderer;
}
/**
-
@return The {@link AudioRenderer audio renderer} for the application
*/
public AudioRenderer getAudioRenderer() {
return audioRenderer;
}
/**
-
@return The {@link Listener listener} object for audio
*/
public Listener getListener() {
return listener;
}
/**
-
@return The {@link JmeContext display context} for the application
*/
public JmeContext getContext(){
return context;
}
/**
-
@return The {@link Camera camera} for the application
*/
public Camera getCamera(){
return cam;
}
/**
- Starts the application in {@link Type#Display display} mode.
*
-
@see #start(com.jme3.system.JmeContext.Type)
*/
public void start(){
start(JmeContext.Type.Display);
}
/**
- Starts the application.
- Creating a rendering context and executing
- the main loop in a separate thread.
*/
public void start(JmeContext.Type contextType){
if (context != null && context.isCreated()){
logger.warning("start() called when application already created!");
return;
}
if (settings == null){
settings = new AppSettings(true);
}
logger.log(Level.FINE, "Starting application: {0}", getClass().getName());
context = JmeSystem.newContext(settings, contextType);
context.setSystemListener(this);
context.create(false);
}
/**
- Initializes the application’s canvas for use.
- <p>
- After calling this method, cast the {@link #getContext() context} to
- {@link JmeCanvasContext},
- then acquire the canvas with {@link JmeCanvasContext#getCanvas() }
- and attach it to an AWT/Swing Frame.
- The rendering thread will start when the canvas becomes visible on
- screen, however if you wish to start the context immediately you
- may call {@link #startCanvas() } to force the rendering thread
- to start.
*
-
@see JmeCanvasContext
-
@see Type#Canvas
*/
public void createCanvas(){
if (context != null && context.isCreated()){
logger.warning("createCanvas() called when application already created!");
return;
}
if (settings == null){
settings = new AppSettings(true);
}
logger.log(Level.FINE, "Starting application: {0}", getClass().getName());
context = JmeSystem.newContext(settings, JmeContext.Type.Canvas);
context.setSystemListener(this);
}
/**
- Starts the rendering thread after createCanvas() has been called.
- <p>
- Same as calling startCanvas(false)
*
-
@see #startCanvas(boolean)
*/
public void startCanvas(){
startCanvas(false);
}
/**
- Starts the rendering thread after createCanvas() has been called.
- <p>
- Calling this method is optional, the canvas will start automatically
- when it becomes visible.
*
-
@param waitFor If true, the current thread will block until the
- rendering thread is running
*/
public void startCanvas(boolean waitFor){
context.create(waitFor);
}
/**
- Internal use only.
*/
public void reshape(int w, int h){
renderManager.notifyReshape(w, h);
}
/**
- Restarts the context, applying any changed settings.
- <p>
- Changes to the {@link AppSettings} of this Application are not
- applied immediately; calling this method forces the context
- to restart, applying the new settings.
*/
public void restart(){
context.setSettings(settings);
context.restart();
}
/**
- Requests the context to close, shutting down the main loop
- and making necessary cleanup operations.
*
- Same as calling stop(false)
*
-
@see #stop(boolean)
*/
public void stop(){
stop(false);
}
/**
- Requests the context to close, shutting down the main loop
- and making necessary cleanup operations.
- After the application has stopped, it cannot be used anymore.
*/
public void stop(boolean waitFor){
logger.log(Level.FINE, "Closing application: {0}", getClass().getName());
context.destroy(waitFor);
}
/**
- Do not call manually.
- Callback from ContextListener.
- <p>
- Initializes the <code>Application</code>, by creating a display and
- default camera. If display settings are not specified, a default
- 640x480 display is created. Default values are used for the camera;
- perspective projection with 45° field of view, with near
- and far values 1 and 1000 units respectively.
*/
public void initialize(){
if (assetManager == null){
initAssetManager();
}
initDisplay();
initCamera();
if (inputEnabled){
initInput();
}
initAudio();
initStateManager();
// update timer so that the next delta is not too large
// timer.update();
timer.reset();
// user code here…
}
/**
- Internal use only.
*/
public void handleError(String errMsg, Throwable t){
logger.log(Level.SEVERE, errMsg, t);
// user should add additional code to handle the error.
stop(); // stop the application
}
/**
- Internal use only.
*/
public void gainFocus(){
if (pauseOnFocus) {
paused = false;
context.setAutoFlushFrames(true);
if (inputManager != null) {
inputManager.reset();
}
}
}
/**
- Internal use only.
*/
public void loseFocus(){
if (pauseOnFocus){
paused = true;
context.setAutoFlushFrames(false);
}
}
/**
- Internal use only.
*/
public void requestClose(boolean esc){
context.destroy(false);
}
/**
- Enqueues a task/callable object to execute in the jME3
- rendering thread.
- <p>
- Callables are executed right at the beginning of the main loop.
- They are executed even if the application is currently paused
- or out of focus.
*/
public <V> Future<V> enqueue(Callable<V> callable) {
AppTask<V> task = new AppTask<V>(callable);
taskQueue.add(task);
return task;
}
/**
- Do not call manually.
- Callback from ContextListener.
*/
public void update(){
// Make sure the audio renderer is available to callables
AudioContext.setAudioRenderer(audioRenderer);
AppTask<?> task = taskQueue.poll();
toploop: do {
if (task == null) break;
while (task.isCancelled()) {
task = taskQueue.poll();
if (task == null) break toploop;
}
task.invoke();
} while (((task = taskQueue.poll()) != null));
if (speed == 0 || paused)
return;
timer.update();
if (inputEnabled){
inputManager.update(timer.getTimePerFrame());
}
if (audioRenderer != null){
audioRenderer.update(timer.getTimePerFrame());
}
// user code here…
}
protected void destroyInput(){
if (mouseInput != null)
mouseInput.destroy();
if (keyInput != null)
keyInput.destroy();
if (joyInput != null)
joyInput.destroy();
if (touchInput != null)
touchInput.destroy();
inputManager = null;
}
/**
- Do not call manually.
- Callback from ContextListener.
*/
public void destroy(){
stateManager.cleanup();
destroyInput();
if (audioRenderer != null)
audioRenderer.cleanup();
timer.reset();
}
/**
-
@return The GUI viewport. Which is used for the on screen
- statistics and FPS.
/
public ViewPort getGuiViewPort() {
return guiViewPort;
}
public ViewPort getViewPort() {
return viewPort;
}
void setApplet(java.applet.Applet applet) {
this.applet = applet;
}
public java.applet.Applet getApplet(){
return applet;
}
public void javascript(String method, Object arguments){
if(applet != null){
try {
getApplet().getAppletContext().showDocument
(new URL("javascript:"+ method+ "("" + arguments +"")"));
}
catch (MalformedURLException me) {}
}
}
}
[/java]
[java]
/
- Copyright © 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
- 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
- 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
- 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.system.AppSettings;
import com.jme3.system.JmeCanvasContext;
import com.jme3.system.JmeSystem;
import java.applet.Applet;
import java.awt.Canvas;
import java.awt.Graphics;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
/**
-
@author Kirill Vainer
*/
public class AppletHarness extends Applet {
public static final HashMap<Application, Applet> appToApplet
= new HashMap<Application, Applet>();
private JmeCanvasContext context;
private Canvas canvas;
private Application app;
private String appClass;
private URL appCfg = null;
private URL assetCfg = null;
public static Applet getApplet(Application app){
return appToApplet.get(app);
}
private void createCanvas(){
AppSettings settings = new AppSettings(true);
// load app cfg
if (appCfg != null){
InputStream in = null;
try {
in = appCfg.openStream();
settings.load(in);
in.close();
} catch (IOException ex){
// Called before application has been created …
// Display error message through AWT
JOptionPane.showMessageDialog(this, "An error has occured while "
- "loading applet configuration"
- ex.getMessage(),
“jME3 Applet”,
JOptionPane.ERROR_MESSAGE);
ex.printStackTrace();
} finally {
if (in != null)
try {
in.close();
} catch (IOException ex) {
}
}
}
if (assetCfg != null){
settings.putString(“AssetConfigURL”, assetCfg.toString());
}
settings.setWidth(getWidth());
settings.setHeight(getHeight());
JmeSystem.setLowPermissions(true);
try{
Class<? extends Application> clazz = (Class<? extends Application>) Class.forName(appClass);
app = clazz.newInstance();
}catch (ClassNotFoundException ex){
ex.printStackTrace();
}catch (InstantiationException ex){
ex.printStackTrace();
}catch (IllegalAccessException ex){
ex.printStackTrace();
}
appToApplet.put(app, this);
app.setSettings(settings);
app.createCanvas();
app.setApplet(this);
context = (JmeCanvasContext) app.getContext();
canvas = context.getCanvas();
canvas.setSize(getWidth(), getHeight());
add(canvas);
app.startCanvas();
app.javascript(“canvasReady”,"");
}
@Override
public final void update(Graphics g) {
canvas.setSize(getWidth(), getHeight());
}
@Override
public void init(){
appClass = getParameter(“AppClass”);
if (appClass == null)
throw new RuntimeException(“The required parameter AppClass isn’t specified!”);
try {
appCfg = new URL(getParameter(“AppSettingsURL”));
} catch (MalformedURLException ex) {
System.out.println(ex.getMessage());
appCfg = null;
}
try {
assetCfg = new URL(getParameter(“AssetConfigURL”));
} catch (MalformedURLException ex){
System.out.println(ex.getMessage());
assetCfg = getClass().getResource("/com/jme3/asset/Desktop.cfg");
}
createCanvas();
System.out.println(“applet:init”);
}
@Override
public void start(){
context.setAutoFlushFrames(true);
System.out.println(“applet:start”);
}
@Override
public void stop(){
context.setAutoFlushFrames(false);
System.out.println(“applet:stop”);
}
@Override
public void destroy(){
System.out.println(“applet:destroyStart”);
SwingUtilities.invokeLater(new Runnable(){
public void run(){
removeAll();
System.out.println(“applet:destroyRemoved”);
}
});
app.stop(true);
System.out.println(“applet:destroyDone”);
appToApplet.remove(app);
}
public Application getApp(){
return app;
}
}
[/java]
The above code adds a way to easily add javascript to applet games, both the applet talking to javascript and javascript talking to the applet
Heres a little example of it in action:
inside of my game class that is extending SimpleApplication
[java]
private void gameOver() {
stateManager.detach(bulletAppState);
hudText.setText(“GAMEOVER!!! Score:” + scoreCounter);
finalScore = scoreCounter;
javascript(“showScore”, finalScore + “”);
specialText.setText(“Spacebar to continue…”);
gameOver = true;
character_phys.setLinearVelocity(new Vector3f(0f, 0f, 0f));
}
public String getDirections(){
return “Press spacebar to go up and down. b and v are specials”;
}
[/java]
and in the applet webpage:
[java]
<script type=“text/javascript”>
function canvasReady(){
var dirs = document.applets[0].getApplet().getApp().getDirections();
document.getElementById(“directions”).innerHTML = dirs;
}
function showScore(s) {
document.getElementById(“score”).innerHTML = "your previous score: " + s ;
}
</script>
[/java]
kind of a weak example of calling a game method, but i thought i should demonstrate it.
Let me know what ya’all think