1 /* 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 */ 32 package com.jme3.system; 33 34 import com.jme3.app.SettingsDialog; 35 import com.jme3.app.SettingsDialog.SelectionListener; 36 import com.jme3.asset.AssetManager; 37 import com.jme3.asset.AssetNotFoundException; 38 import com.jme3.asset.DesktopAssetManager; 39 import com.jme3.audio.AudioRenderer; 40 import com.jme3.system.JmeContext.Type; 41 import java.io.IOException; 42 import java.net.URL; 43 import java.util.concurrent.atomic.AtomicBoolean; 44 import java.util.concurrent.atomic.AtomicInteger; 45 import java.util.logging.Level; 46 import javax.swing.SwingUtilities; 47 48 /** 49 * 50 * @author Kirill Vainer, normenhansen 51 */ 52 public class JmeDesktopSystem extends JmeSystemDelegate { 53 54 @Override 55 public AssetManager newAssetManager(URL configFile) { 56 return new DesktopAssetManager(configFile); 57 } 58 59 @Override 60 public AssetManager newAssetManager() { 61 return new DesktopAssetManager(null); 62 } 63 64 @Override 65 public boolean showSettingsDialog(AppSettings sourceSettings, final boolean loadFromRegistry) { 66 if (SwingUtilities.isEventDispatchThread()) { 67 throw new IllegalStateException("Cannot run from EDT"); 68 } 69 70 final AppSettings settings = new AppSettings(false); 71 settings.copyFrom(sourceSettings); 72 String iconPath = sourceSettings.getSettingsDialogImage(); 73 final URL iconUrl = JmeSystem.class.getResource(iconPath.startsWith("/") ? iconPath : "/" + iconPath); 74 if (iconUrl == null) { 75 throw new AssetNotFoundException(sourceSettings.getSettingsDialogImage()); 76 } 77 78 final AtomicBoolean done = new AtomicBoolean(); 79 final AtomicInteger result = new AtomicInteger(); 80 final Object lock = new Object(); 81 82 final SelectionListener selectionListener = new SelectionListener() { 83 84 public void onSelection(int selection) { 85 synchronized (lock) { 86 done.set(true); 87 result.set(selection); 88 lock.notifyAll(); 89 } 90 } 91 }; 92 SwingUtilities.invokeLater(new Runnable() { 93 94 public void run() { 95 synchronized (lock) { 96 SettingsDialog dialog = new SettingsDialog(settings, iconUrl, loadFromRegistry); 97 dialog.setSelectionListener(selectionListener); 98 dialog.showDialog(); 99 } 100 } 101 }); 102 103 synchronized (lock) { 104 while (!done.get()) { 105 try { 106 lock.wait(); 107 } catch (InterruptedException ex) { 108 } 109 } 110 } 111 112 sourceSettings.copyFrom(settings); 113 114 return result.get() == SettingsDialog.APPROVE_SELECTION; 115 } 116 117 private JmeContext newContextLwjgl(AppSettings settings, JmeContext.Type type) { 118 try { 119 Class<? extends JmeContext> ctxClazz = null; 120 switch (type) { 121 case Canvas: 122 ctxClazz = (Class<? extends JmeContext>) Class.forName("com.jme3.system.lwjgl.LwjglCanvas"); 123 break; 124 case Display: 125 ctxClazz = (Class<? extends JmeContext>) Class.forName("com.jme3.system.lwjgl.LwjglDisplay"); 126 break; 127 case OffscreenSurface: 128 ctxClazz = (Class<? extends JmeContext>) Class.forName("com.jme3.system.lwjgl.LwjglOffscreenBuffer"); 129 break; 130 default: 131 throw new IllegalArgumentException("Unsupported context type " + type); 132 } 133 134 return ctxClazz.newInstance(); 135 } catch (InstantiationException ex) { 136 logger.log(Level.SEVERE, "Failed to create context", ex); 137 } catch (IllegalAccessException ex) { 138 logger.log(Level.SEVERE, "Failed to create context", ex); 139 } catch (ClassNotFoundException ex) { 140 logger.log(Level.SEVERE, "CRITICAL ERROR: Context class is missing!\n" 141 + "Make sure jme3_lwjgl-ogl is on the classpath.", ex); 142 } 143 144 return null; 145 } 146 147 private JmeContext newContextJogl(AppSettings settings, JmeContext.Type type) { 148 try { 149 Class<? extends JmeContext> ctxClazz = null; 150 switch (type) { 151 case Display: 152 ctxClazz = (Class<? extends JmeContext>) Class.forName("com.jme3.system.jogl.JoglDisplay"); 153 break; 154 case Canvas: 155 ctxClazz = (Class<? extends JmeContext>) Class.forName("com.jme3.system.jogl.JoglCanvas"); 156 break; 157 default: 158 throw new IllegalArgumentException("Unsupported context type " + type); 159 } 160 161 return ctxClazz.newInstance(); 162 } catch (InstantiationException ex) { 163 logger.log(Level.SEVERE, "Failed to create context", ex); 164 } catch (IllegalAccessException ex) { 165 logger.log(Level.SEVERE, "Failed to create context", ex); 166 } catch (ClassNotFoundException ex) { 167 logger.log(Level.SEVERE, "CRITICAL ERROR: Context class is missing!\n" 168 + "Make sure jme3_jogl is on the classpath.", ex); 169 } 170 171 return null; 172 } 173 174 private JmeContext newContextCustom(AppSettings settings, JmeContext.Type type) { 175 try { 176 String className = settings.getRenderer().substring("CUSTOM".length()); 177 178 Class<? extends JmeContext> ctxClazz = null; 179 ctxClazz = (Class<? extends JmeContext>) Class.forName(className); 180 return ctxClazz.newInstance(); 181 } catch (InstantiationException ex) { 182 logger.log(Level.SEVERE, "Failed to create context", ex); 183 } catch (IllegalAccessException ex) { 184 logger.log(Level.SEVERE, "Failed to create context", ex); 185 } catch (ClassNotFoundException ex) { 186 logger.log(Level.SEVERE, "CRITICAL ERROR: Context class is missing!", ex); 187 } 188 189 return null; 190 } 191 192 @Override 193 public JmeContext newContext(AppSettings settings, Type contextType) { 194 initialize(settings); 195 JmeContext ctx; 196 if (settings.getRenderer() == null 197 || settings.getRenderer().equals("NULL") 198 || contextType == JmeContext.Type.Headless) { 199 ctx = new NullContext(); 200 ctx.setSettings(settings); 201 } else if (settings.getRenderer().startsWith("LWJGL")) { 202 ctx = newContextLwjgl(settings, contextType); 203 ctx.setSettings(settings); 204 } else if (settings.getRenderer().startsWith("JOGL")) { 205 ctx = newContextJogl(settings, contextType); 206 ctx.setSettings(settings); 207 } else if (settings.getRenderer().startsWith("CUSTOM")) { 208 ctx = newContextCustom(settings, contextType); 209 ctx.setSettings(settings); 210 } else { 211 throw new UnsupportedOperationException( 212 "Unrecognizable renderer specified: " 213 + settings.getRenderer()); 214 } 215 return ctx; 216 } 217 218 @Override 219 public AudioRenderer newAudioRenderer(AppSettings settings) { 220 initialize(settings); 221 Class<? extends AudioRenderer> clazz = null; 222 try { 223 if (settings.getAudioRenderer().startsWith("LWJGL")) { 224 clazz = (Class<? extends AudioRenderer>) Class.forName("com.jme3.audio.lwjgl.LwjglAudioRenderer"); 225 } else if (settings.getAudioRenderer().startsWith("JOAL")) { 226 clazz = (Class<? extends AudioRenderer>) Class.forName("com.jme3.audio.joal.JoalAudioRenderer"); 227 } else { 228 throw new UnsupportedOperationException( 229 "Unrecognizable audio renderer specified: " 230 + settings.getAudioRenderer()); 231 } 232 233 AudioRenderer ar = clazz.newInstance(); 234 return ar; 235 } catch (InstantiationException ex) { 236 logger.log(Level.SEVERE, "Failed to create context", ex); 237 } catch (IllegalAccessException ex) { 238 logger.log(Level.SEVERE, "Failed to create context", ex); 239 } catch (ClassNotFoundException ex) { 240 logger.log(Level.SEVERE, "CRITICAL ERROR: Audio implementation class is missing!\n" 241 + "Make sure jme3_lwjgl-oal or jm3_joal is on the classpath.", ex); 242 } 243 return null; 244 } 245 246 @Override 247 public void initialize(AppSettings settings) { 248 if (initialized) { 249 return; 250 } 251 252 initialized = true; 253 try { 254 if (!lowPermissions) { 255 // can only modify logging settings 256 // if permissions are available 257 // JmeFormatter formatter = new JmeFormatter(); 258 // Handler fileHandler = new FileHandler("jme.log"); 259 // fileHandler.setFormatter(formatter); 260 // Logger.getLogger("").addHandler(fileHandler); 261 // Handler consoleHandler = new ConsoleHandler(); 262 // consoleHandler.setFormatter(formatter); 263 // Logger.getLogger("").removeHandler(Logger.getLogger("").getHandlers()[0]); 264 // Logger.getLogger("").addHandler(consoleHandler); 265 } 266 // } catch (IOException ex){ 267 // logger.log(Level.SEVERE, "I/O Error while creating log file", ex); 268 } catch (SecurityException ex) { 269 logger.log(Level.SEVERE, "Security error in creating log file", ex); 270 } 271 logger.log(Level.INFO, "Running on {0}", getFullName()); 272 273 if (!lowPermissions) { 274 try { 275 Natives.extractNativeLibs(getPlatform(), settings); 276 } catch (IOException ex) { 277 logger.log(Level.SEVERE, "Error while copying native libraries", ex); 278 } 279 } 280 } 281 } 282