A complete 3D game development suite written purely in Java.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
jmonkeyengine/jme3-desktop/src/main/java/com/jme3/system/JmeDesktopSystem.java

357 lines
14 KiB

/*
* Copyright (c) 2009-2012 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.system;
import com.jme3.app.SettingsDialog;
import com.jme3.app.SettingsDialog.SelectionListener;
import com.jme3.asset.AssetNotFoundException;
import com.jme3.audio.AudioRenderer;
import com.jme3.audio.openal.AL;
import com.jme3.audio.openal.ALAudioRenderer;
import com.jme3.audio.openal.ALC;
import com.jme3.audio.openal.EFX;
import com.jme3.system.JmeContext.Type;
import com.jme3.util.Screenshots;
import java.awt.EventQueue;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.ImageOutputStream;
import javax.imageio.stream.MemoryCacheImageOutputStream;
import javax.swing.SwingUtilities;
/**
*
* @author Kirill Vainer, normenhansen
*/
public class JmeDesktopSystem extends JmeSystemDelegate {
@Override
public URL getPlatformAssetConfigURL() {
return Thread.currentThread().getContextClassLoader().getResource("com/jme3/asset/Desktop.cfg");
}
private static BufferedImage verticalFlip(BufferedImage original) {
AffineTransform tx = AffineTransform.getScaleInstance(1, -1);
tx.translate(0, -original.getHeight());
AffineTransformOp transformOp = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
BufferedImage awtImage = new BufferedImage(original.getWidth(), original.getHeight(), BufferedImage.TYPE_INT_BGR);
Graphics2D g2d = awtImage.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_SPEED);
g2d.drawImage(original, transformOp, 0, 0);
g2d.dispose();
return awtImage;
}
@Override
public void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException {
BufferedImage awtImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
Screenshots.convertScreenShot2(imageData.asIntBuffer(), awtImage);
ImageWriter writer = ImageIO.getImageWritersByFormatName(format).next();
ImageWriteParam writeParam = writer.getDefaultWriteParam();
if (format.equals("jpg")) {
JPEGImageWriteParam jpegParam = (JPEGImageWriteParam) writeParam;
jpegParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
jpegParam.setCompressionQuality(0.95f);
}
awtImage = verticalFlip(awtImage);
ImageOutputStream imgOut = new MemoryCacheImageOutputStream(outStream);
writer.setOutput(imgOut);
IIOImage outputImage = new IIOImage(awtImage, null, null);
try {
writer.write(null, outputImage, writeParam);
} finally {
imgOut.close();
writer.dispose();
}
}
@Override
public void showErrorDialog(String message) {
if (!GraphicsEnvironment.isHeadless()) {
final String msg = message;
EventQueue.invokeLater(new Runnable() {
public void run() {
ErrorDialog.showDialog(msg);
}
});
} else {
System.err.println("[JME ERROR] " + message);
}
}
@Override
public boolean showSettingsDialog(AppSettings sourceSettings, final boolean loadFromRegistry) {
if (SwingUtilities.isEventDispatchThread()) {
throw new IllegalStateException("Cannot run from EDT");
}
if (GraphicsEnvironment.isHeadless()) {
throw new IllegalStateException("Cannot show dialog in headless environment");
}
final AppSettings settings = new AppSettings(false);
settings.copyFrom(sourceSettings);
String iconPath = sourceSettings.getSettingsDialogImage();
if(iconPath == null){
iconPath = "";
}
final URL iconUrl = JmeSystem.class.getResource(iconPath.startsWith("/") ? iconPath : "/" + iconPath);
if (iconUrl == null) {
throw new AssetNotFoundException(sourceSettings.getSettingsDialogImage());
}
final AtomicBoolean done = new AtomicBoolean();
final AtomicInteger result = new AtomicInteger();
final Object lock = new Object();
final SelectionListener selectionListener = new SelectionListener() {
public void onSelection(int selection) {
synchronized (lock) {
done.set(true);
result.set(selection);
lock.notifyAll();
}
}
};
SwingUtilities.invokeLater(new Runnable() {
public void run() {
synchronized (lock) {
SettingsDialog dialog = new SettingsDialog(settings, iconUrl, loadFromRegistry);
dialog.setSelectionListener(selectionListener);
dialog.showDialog();
}
}
});
synchronized (lock) {
while (!done.get()) {
try {
lock.wait();
} catch (InterruptedException ex) {
}
}
}
sourceSettings.copyFrom(settings);
return result.get() == SettingsDialog.APPROVE_SELECTION;
}
private JmeContext newContextLwjgl(AppSettings settings, JmeContext.Type type) {
try {
Class<? extends JmeContext> ctxClazz = null;
switch (type) {
case Canvas:
ctxClazz = (Class<? extends JmeContext>) Class.forName("com.jme3.system.lwjgl.LwjglCanvas");
break;
case Display:
ctxClazz = (Class<? extends JmeContext>) Class.forName("com.jme3.system.lwjgl.LwjglDisplay");
break;
case OffscreenSurface:
ctxClazz = (Class<? extends JmeContext>) Class.forName("com.jme3.system.lwjgl.LwjglOffscreenBuffer");
break;
default:
throw new IllegalArgumentException("Unsupported context type " + type);
}
return ctxClazz.newInstance();
} catch (InstantiationException ex) {
logger.log(Level.SEVERE, "Failed to create context", ex);
} catch (IllegalAccessException ex) {
logger.log(Level.SEVERE, "Failed to create context", ex);
} catch (ClassNotFoundException ex) {
logger.log(Level.SEVERE, "CRITICAL ERROR: Context class is missing!\n"
+ "Make sure jme3_lwjgl-ogl is on the classpath.", ex);
}
return null;
}
private JmeContext newContextJogl(AppSettings settings, JmeContext.Type type) {
try {
Class<? extends JmeContext> ctxClazz = null;
switch (type) {
case Display:
ctxClazz = (Class<? extends JmeContext>) Class.forName("com.jme3.system.jogl.JoglNewtDisplay");
break;
case Canvas:
ctxClazz = (Class<? extends JmeContext>) Class.forName("com.jme3.system.jogl.JoglNewtCanvas");
break;
case OffscreenSurface:
ctxClazz = (Class<? extends JmeContext>) Class.forName("com.jme3.system.jogl.JoglOffscreenBuffer");
break;
default:
throw new IllegalArgumentException("Unsupported context type " + type);
}
return ctxClazz.newInstance();
} catch (InstantiationException ex) {
logger.log(Level.SEVERE, "Failed to create context", ex);
} catch (IllegalAccessException ex) {
logger.log(Level.SEVERE, "Failed to create context", ex);
} catch (ClassNotFoundException ex) {
logger.log(Level.SEVERE, "CRITICAL ERROR: Context class is missing!\n"
+ "Make sure jme3_jogl is on the classpath.", ex);
}
return null;
}
private JmeContext newContextCustom(AppSettings settings, JmeContext.Type type) {
try {
String className = settings.getRenderer().substring("CUSTOM".length());
Class<? extends JmeContext> ctxClazz = null;
ctxClazz = (Class<? extends JmeContext>) Class.forName(className);
return ctxClazz.newInstance();
} catch (InstantiationException ex) {
logger.log(Level.SEVERE, "Failed to create context", ex);
} catch (IllegalAccessException ex) {
logger.log(Level.SEVERE, "Failed to create context", ex);
} catch (ClassNotFoundException ex) {
logger.log(Level.SEVERE, "CRITICAL ERROR: Context class is missing!", ex);
}
return null;
}
@Override
public JmeContext newContext(AppSettings settings, Type contextType) {
initialize(settings);
JmeContext ctx;
if (settings.getRenderer() == null
|| settings.getRenderer().equals("NULL")
|| contextType == JmeContext.Type.Headless) {
ctx = new NullContext();
ctx.setSettings(settings);
} else if (settings.getRenderer().startsWith("LWJGL")) {
ctx = newContextLwjgl(settings, contextType);
ctx.setSettings(settings);
} else if (settings.getRenderer().startsWith("JOGL")) {
ctx = newContextJogl(settings, contextType);
ctx.setSettings(settings);
} else if (settings.getRenderer().startsWith("CUSTOM")) {
ctx = newContextCustom(settings, contextType);
ctx.setSettings(settings);
} else {
throw new UnsupportedOperationException(
"Unrecognizable renderer specified: "
+ settings.getRenderer());
}
return ctx;
}
private <T> T newObject(String className) {
try {
Class<T> clazz = (Class<T>) Class.forName(className);
return clazz.newInstance();
} catch (ClassNotFoundException ex) {
logger.log(Level.SEVERE, "CRITICAL ERROR: Audio implementation class is missing!\n"
+ "Make sure jme3_lwjgl-oal or jm3_joal is on the classpath.", ex);
} catch (IllegalAccessException ex) {
logger.log(Level.SEVERE, "Failed to create context", ex);
} catch (InstantiationException ex) {
logger.log(Level.SEVERE, "Failed to create context", ex);
}
return null;
}
@Override
public AudioRenderer newAudioRenderer(AppSettings settings) {
initialize(settings);
AL al;
ALC alc;
EFX efx;
if (settings.getAudioRenderer().startsWith("LWJGL")) {
al = newObject("com.jme3.audio.lwjgl.LwjglAL");
alc = newObject("com.jme3.audio.lwjgl.LwjglALC");
efx = newObject("com.jme3.audio.lwjgl.LwjglEFX");
} else if (settings.getAudioRenderer().startsWith("JOAL")) {
al = newObject("com.jme3.audio.joal.JoalAL");
alc = newObject("com.jme3.audio.joal.JoalALC");
efx = newObject("com.jme3.audio.joal.JoalEFX");
} else {
throw new UnsupportedOperationException(
"Unrecognizable audio renderer specified: "
+ settings.getAudioRenderer());
}
if (al == null || alc == null || efx == null) {
return null;
}
return new ALAudioRenderer(al, alc, efx);
}
@Override
public void initialize(AppSettings settings) {
if (initialized) {
return;
}
initialized = true;
9 years ago
logger.log(Level.INFO, getBuildInfo());
if (!lowPermissions) {
if (NativeLibraryLoader.isUsingNativeBullet()) {
NativeLibraryLoader.loadNativeLibrary("bulletjme", true);
}
}
}
@Override
public void showSoftKeyboard(boolean show) {
}
}