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
newAssetManager(URL configFile)55     public AssetManager newAssetManager(URL configFile) {
56         return new DesktopAssetManager(configFile);
57     }
58 
59     @Override
newAssetManager()60     public AssetManager newAssetManager() {
61         return new DesktopAssetManager(null);
62     }
63 
64     @Override
showSettingsDialog(AppSettings sourceSettings, final boolean loadFromRegistry)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 
newContextLwjgl(AppSettings settings, JmeContext.Type type)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 
newContextJogl(AppSettings settings, JmeContext.Type type)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 
newContextCustom(AppSettings settings, JmeContext.Type type)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
newContext(AppSettings settings, Type contextType)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
newAudioRenderer(AppSettings settings)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
initialize(AppSettings settings)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