• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2009-2012 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 java.io.IOException;
35 import java.io.InputStream;
36 import java.io.OutputStream;
37 import java.io.UnsupportedEncodingException;
38 import java.util.HashMap;
39 import java.util.Map;
40 import java.util.Properties;
41 import java.util.prefs.BackingStoreException;
42 import java.util.prefs.Preferences;
43 
44 /**
45  * <code>AppSettings</code> provides a store of configuration
46  * to be used by the application.
47  * <p>
48  * By default only the {@link JmeContext context} uses the configuration,
49  * however the user may set and retrieve the settings as well.
50  *
51  * @author Kirill Vainer
52  */
53 public final class AppSettings extends HashMap<String, Object> {
54 
55     private static final AppSettings defaults = new AppSettings(false);
56 
57     /**
58      * Use LWJGL as the display system and force using the OpenGL1.1 renderer.
59      *
60      * @see AppSettings#setRenderer(java.lang.String)
61      */
62     public static final String LWJGL_OPENGL1 = "LWJGL-OPENGL1";
63 
64     /**
65      * Use LWJGL as the display system and force using the OpenGL2.0 renderer.
66      * <p>
67      * If the underlying system does not support OpenGL2.0, then the context
68      * initialization will throw an exception.
69      *
70      * @see AppSettings#setRenderer(java.lang.String)
71      */
72     public static final String LWJGL_OPENGL2 = "LWJGL-OpenGL2";
73 
74     /**
75      * Use LWJGL as the display system and force using the core OpenGL3.3 renderer.
76      * <p>
77      * If the underlying system does not support OpenGL3.3, then the context
78      * initialization will throw an exception. Note that currently jMonkeyEngine
79      * does not have any shaders that support OpenGL3.3 therefore this
80      * option is not useful.
81      *
82      *
83      * @see AppSettings#setRenderer(java.lang.String)
84      */
85     public static final String LWJGL_OPENGL3 = "LWJGL-OpenGL3";
86 
87     /**
88      * Use LWJGL as the display system and allow the context
89      * to choose an appropriate renderer based on system capabilities.
90      * <p>
91      * If the GPU supports OpenGL2 or later, then the OpenGL2.0 renderer will
92      * be used, otherwise, the OpenGL1.1 renderer is used.
93      *
94      * @see AppSettings#setRenderer(java.lang.String)
95      */
96     public static final String LWJGL_OPENGL_ANY = "LWJGL-OpenGL-Any";
97 
98     /**
99      * The JOGL renderer is no longer supported by jME.
100      *
101      * @deprecated Use the LWJGL renderer instead.
102      *
103      * @see AppSettings#setRenderer(java.lang.String)
104      */
105     @Deprecated
106     public static final String JOGL = "JOGL";
107 
108     /**
109      * The "NULL" option is no longer supported
110      *
111      * @deprecated Specify the "null" value instead
112      *
113      * @see AppSettings#setRenderer(java.lang.String)
114      * @see AppSettings#setAudioRenderer(java.lang.String)
115      */
116     @Deprecated
117     public static final String NULL = "NULL";
118 
119     /**
120      * Use the LWJGL OpenAL based renderer for audio capabilities.
121      *
122      * @see AppSettings#setAudioRenderer(java.lang.String)
123      */
124     public static final String LWJGL_OPENAL = "LWJGL";
125 
126     static {
127         defaults.put("Width", 640);
128         defaults.put("Height", 480);
129         defaults.put("BitsPerPixel", 24);
130         defaults.put("Frequency", 60);
131         defaults.put("DepthBits", 24);
132         defaults.put("StencilBits", 0);
133         defaults.put("Samples", 0);
134         defaults.put("Fullscreen", false);
135         defaults.put("Title", "jMonkey Engine 3.0");
136         defaults.put("Renderer", LWJGL_OPENGL2);
137         defaults.put("AudioRenderer", LWJGL_OPENAL);
138         defaults.put("DisableJoysticks", true);
139         defaults.put("UseInput", true);
140         defaults.put("VSync", false);
141         defaults.put("FrameRate", -1);
142         defaults.put("SettingsDialogImage", "/com/jme3/app/Monkey.png");
143       //  defaults.put("Icons", null);
144     }
145 
146     /**
147      * Create a new instance of <code>AppSettings</code>.
148      * <p>
149      * If <code>loadDefaults</code> is true, then the default settings
150      * will be set on the AppSettings.
151      * Use false if you want to change some settings but you would like the
152      * application to load settings from previous launches.
153      *
154      * @param loadDefaults If default settings are to be loaded.
155      */
AppSettings(boolean loadDefaults)156     public AppSettings(boolean loadDefaults) {
157         if (loadDefaults) {
158             putAll(defaults);
159         }
160     }
161 
162     /**
163      * Copies all settings from <code>other</code> to <code>this</code>
164      * AppSettings.
165      * <p>
166      * Any settings that are specified in other will overwrite settings
167      * set on this AppSettings.
168      *
169      * @param other The AppSettings to copy the settings from
170      */
copyFrom(AppSettings other)171     public void copyFrom(AppSettings other) {
172         this.putAll(other);
173     }
174 
175     /**
176      * Same as {@link #copyFrom(com.jme3.system.AppSettings) }, except
177      * doesn't overwrite settings that are already set.
178      *
179      * @param other  The AppSettings to merge the settings from
180      */
mergeFrom(AppSettings other)181     public void mergeFrom(AppSettings other) {
182         for (String key : other.keySet()) {
183             if (get(key) == null) {
184                 put(key, other.get(key));
185             }
186         }
187     }
188 
189     /**
190      * Loads the settings from the given properties input stream.
191      *
192      * @param in The InputStream to load from
193      * @throws IOException If an IOException occurs
194      *
195      * @see #save(java.io.OutputStream)
196      */
load(InputStream in)197     public void load(InputStream in) throws IOException {
198         Properties props = new Properties();
199         props.load(in);
200         for (Map.Entry<Object, Object> entry : props.entrySet()) {
201             String key = (String) entry.getKey();
202             String val = (String) entry.getValue();
203             if (val != null) {
204                 val = val.trim();
205             }
206             if (key.endsWith("(int)")) {
207                 key = key.substring(0, key.length() - 5);
208                 int iVal = Integer.parseInt(val);
209                 putInteger(key, iVal);
210             } else if (key.endsWith("(string)")) {
211                 putString(key.substring(0, key.length() - 8), val);
212             } else if (key.endsWith("(bool)")) {
213                 boolean bVal = Boolean.parseBoolean(val);
214                 putBoolean(key.substring(0, key.length() - 6), bVal);
215             } else {
216                 throw new IOException("Cannot parse key: " + key);
217             }
218         }
219     }
220 
221     /**
222      * Saves all settings to the given properties output stream.
223      *
224      * @param out The OutputStream to write to
225      * @throws IOException If an IOException occurs
226      *
227      * @see #load(java.io.InputStream)
228      */
save(OutputStream out)229     public void save(OutputStream out) throws IOException {
230         Properties props = new Properties();
231         for (Map.Entry<String, Object> entry : entrySet()) {
232             Object val = entry.getValue();
233             String type;
234             if (val instanceof Integer) {
235                 type = "(int)";
236             } else if (val instanceof String) {
237                 type = "(string)";
238             } else if (val instanceof Boolean) {
239                 type = "(bool)";
240             } else {
241                 throw new UnsupportedEncodingException();
242             }
243             props.setProperty(entry.getKey() + type, val.toString());
244         }
245         props.store(out, "jME3 AppSettings");
246     }
247 
248     /**
249      * Loads settings previously saved in the Java preferences.
250      *
251      * @param preferencesKey The preferencesKey previously used to save the settings.
252      * @throws BackingStoreException If an exception occurs with the preferences
253      *
254      * @see #save(java.lang.String)
255      */
load(String preferencesKey)256     public void load(String preferencesKey) throws BackingStoreException {
257         Preferences prefs = Preferences.userRoot().node(preferencesKey);
258         String[] keys = prefs.keys();
259         if (keys != null) {
260             for (String key : keys) {
261                 Object defaultValue = defaults.get(key);
262                 if (defaultValue instanceof Integer) {
263                     put(key, prefs.getInt(key, (Integer) defaultValue));
264                 } else if (defaultValue instanceof String) {
265                     put(key, prefs.get(key, (String) defaultValue));
266                 } else if (defaultValue instanceof Boolean) {
267                     put(key, prefs.getBoolean(key, (Boolean) defaultValue));
268                 }
269             }
270         }
271     }
272 
273     /**
274      * Saves settings into the Java preferences.
275      * <p>
276      * On the Windows operating system, the preferences are saved in the registry
277      * at the following key:<br>
278      * <code>HKEY_CURRENT_USER\Software\JavaSoft\Prefs\[preferencesKey]</code>
279      *
280      * @param preferencesKey The preferences key to save at. Generally the
281      * application's unique name.
282      *
283      * @throws BackingStoreException If an exception occurs with the preferences
284      */
save(String preferencesKey)285     public void save(String preferencesKey) throws BackingStoreException {
286         Preferences prefs = Preferences.userRoot().node(preferencesKey);
287         for (String key : keySet()) {
288             prefs.put(key, get(key).toString());
289         }
290     }
291 
292     /**
293      * Get an integer from the settings.
294      * <p>
295      * If the key is not set, then 0 is returned.
296      */
getInteger(String key)297     public int getInteger(String key) {
298         Integer i = (Integer) get(key);
299         if (i == null) {
300             return 0;
301         }
302 
303         return i.intValue();
304     }
305 
306     /**
307      * Get a boolean from the settings.
308      * <p>
309      * If the key is not set, then false is returned.
310      */
getBoolean(String key)311     public boolean getBoolean(String key) {
312         Boolean b = (Boolean) get(key);
313         if (b == null) {
314             return false;
315         }
316 
317         return b.booleanValue();
318     }
319 
320     /**
321      * Get a string from the settings.
322      * <p>
323      * If the key is not set, then null is returned.
324      */
getString(String key)325     public String getString(String key) {
326         String s = (String) get(key);
327         if (s == null) {
328             return null;
329         }
330 
331         return s;
332     }
333 
334     /**
335      * Set an integer on the settings.
336      */
putInteger(String key, int value)337     public void putInteger(String key, int value) {
338         put(key, Integer.valueOf(value));
339     }
340 
341     /**
342      * Set a boolean on the settings.
343      */
putBoolean(String key, boolean value)344     public void putBoolean(String key, boolean value) {
345         put(key, Boolean.valueOf(value));
346     }
347 
348     /**
349      * Set a string on the settings.
350      */
putString(String key, String value)351     public void putString(String key, String value) {
352         put(key, value);
353     }
354 
355     /**
356      * @param frameRate The frame-rate is the upper limit on how high
357      * the application's frames-per-second can go.
358      * (Default: -1 no frame rate limit imposed)
359      */
setFrameRate(int frameRate)360     public void setFrameRate(int frameRate) {
361         putInteger("FrameRate", frameRate);
362     }
363 
364     /**
365      * @param use If true, the application will initialize and use input.
366      * Set to false for headless applications that do not require keyboard
367      * or mouse input.
368      * (Default: true)
369      */
setUseInput(boolean use)370     public void setUseInput(boolean use) {
371         putBoolean("UseInput", use);
372     }
373 
374     /**
375      * @param use If true, the application will initialize and use joystick
376      * input. Set to false if no joystick input is desired.
377      * (Default: false)
378      */
setUseJoysticks(boolean use)379     public void setUseJoysticks(boolean use) {
380         putBoolean("DisableJoysticks", !use);
381     }
382 
383     /**
384      * Set the graphics renderer to use, one of:<br>
385      * <ul>
386      * <li>AppSettings.LWJGL_OPENGL1 - Force OpenGL1.1 compatability</li>
387      * <li>AppSettings.LWJGL_OPENGL2 - Force OpenGL2 compatability</li>
388      * <li>AppSettings.LWJGL_OPENGL3 - Force OpenGL3.3 compatability</li>
389      * <li>AppSettings.LWJGL_OPENGL_ANY - Choose an appropriate
390      * OpenGL version based on system capabilities</li>
391      * <li>null - Disable graphics rendering</li>
392      * </ul>
393      * @param renderer The renderer to set
394      * (Default: AppSettings.LWJGL_OPENGL2)
395      */
setRenderer(String renderer)396     public void setRenderer(String renderer) {
397         putString("Renderer", renderer);
398     }
399 
400     /**
401      * Set a custom graphics renderer to use. The class should implement
402      * the {@link JmeContext} interface.
403      * @param clazz The custom context class.
404      * (Default: not set)
405      */
setCustomRenderer(Class<? extends JmeContext> clazz)406     public void setCustomRenderer(Class<? extends JmeContext> clazz){
407         put("Renderer", "CUSTOM" + clazz.getName());
408     }
409 
410     /**
411      * Set the audio renderer to use. One of:<br>
412      * <ul>
413      * <li>AppSettings.LWJGL_OPENAL - Default for LWJGL</li>
414      * <li>null - Disable audio</li>
415      * </ul>
416      * @param audioRenderer
417      * (Default: LWJGL)
418      */
setAudioRenderer(String audioRenderer)419     public void setAudioRenderer(String audioRenderer) {
420         putString("AudioRenderer", audioRenderer);
421     }
422 
423     /**
424      * @param value the width for the rendering display.
425      * (Default: 640)
426      */
setWidth(int value)427     public void setWidth(int value) {
428         putInteger("Width", value);
429     }
430 
431     /**
432      * @param value the height for the rendering display.
433      * (Default: 480)
434      */
setHeight(int value)435     public void setHeight(int value) {
436         putInteger("Height", value);
437     }
438 
439     /**
440      * Set the resolution for the rendering display
441      * @param width The width
442      * @param height The height
443      * (Default: 640x480)
444      */
setResolution(int width, int height)445     public void setResolution(int width, int height) {
446         setWidth(width);
447         setHeight(height);
448     }
449 
450     /**
451      * Set the frequency, also known as refresh rate, for the
452      * rendering display.
453      * @param value The frequency
454      * (Default: 60)
455      */
setFrequency(int value)456     public void setFrequency(int value) {
457         putInteger("Frequency", value);
458     }
459 
460     /**
461      * Sets the number of depth bits to use.
462      * <p>
463      * The number of depth bits specifies the precision of the depth buffer.
464      * To increase precision, specify 32 bits. To decrease precision, specify
465      * 16 bits. On some platforms 24 bits might not be supported, in that case,
466      * specify 16 bits.<p>
467      * (Default: 24)
468      *
469      * @param value The depth bits
470      */
setDepthBits(int value)471     public void setDepthBits(int value){
472         putInteger("DepthBits", value);
473     }
474 
475     /**
476      * Set the number of stencil bits.
477      * <p>
478      * This value is only relevant when the stencil buffer is being used.
479      * Specify 8 to indicate an 8-bit stencil buffer, specify 0 to disable
480      * the stencil buffer.
481      * </p>
482      * (Default: 0)
483      *
484      * @param value Number of stencil bits
485      */
setStencilBits(int value)486     public void setStencilBits(int value){
487         putInteger("StencilBits", value);
488     }
489 
490     /**
491      * Set the bits per pixel for the display. Appropriate
492      * values are 16 for RGB565 color format, or 24 for RGB8 color format.
493      *
494      * @param value The bits per pixel to set
495      * (Default: 24)
496      */
setBitsPerPixel(int value)497     public void setBitsPerPixel(int value) {
498         putInteger("BitsPerPixel", value);
499     }
500 
501     /**
502      * Set the number of samples per pixel. A value of 1 indicates
503      * each pixel should be single-sampled, higher values indicate
504      * a pixel should be multi-sampled.
505      *
506      * @param value The number of samples
507      * (Default: 1)
508      */
setSamples(int value)509     public void setSamples(int value) {
510         putInteger("Samples", value);
511     }
512 
513     /**
514      * @param title The title of the rendering display
515      * (Default: jMonkeyEngine 3.0)
516      */
setTitle(String title)517     public void setTitle(String title) {
518         putString("Title", title);
519     }
520 
521     /**
522      * @param value true to enable full-screen rendering, false to render in a window
523      * (Default: false)
524      */
setFullscreen(boolean value)525     public void setFullscreen(boolean value) {
526         putBoolean("Fullscreen", value);
527     }
528 
529     /**
530      * Set to true to enable vertical-synchronization, limiting and synchronizing
531      * every frame rendered to the monitor's refresh rate.
532      * @param value
533      * (Default: false)
534      */
setVSync(boolean value)535     public void setVSync(boolean value) {
536         putBoolean("VSync", value);
537     }
538 
539     /**
540      * Enable 3D stereo.
541      * <p>This feature requires hardware support from the GPU driver.
542      * @see <a href="http://en.wikipedia.org/wiki/Quad_buffering">http://en.wikipedia.org/wiki/Quad_buffering</a><br />
543      * Once enabled, filters or scene processors that handle 3D stereo rendering
544      * could use this feature to render using hardware 3D stereo.</p>
545      * (Default: false)
546      */
setStereo3D(boolean value)547     public void setStereo3D(boolean value){
548         putBoolean("Stereo3D", value);
549     }
550 
551     /**
552      * Sets the application icons to be used, with the most preferred first.
553      * For Windows you should supply at least one 16x16 icon and one 32x32. The former is used for the title/task bar,
554      * the latter for the alt-tab icon.
555      * Linux (and similar platforms) expect one 32x32 icon.
556      * Mac OS X should be supplied one 128x128 icon.
557      * <br/>
558      * The icon is used for the settings window, and the LWJGL render window. Not currently supported for JOGL.
559      * Note that a bug in Java 6 (bug ID 6445278, currently hidden but available in Google cache) currently prevents
560      * the icon working for alt-tab on the settings dialog in Windows.
561      *
562      * @param value An array of BufferedImages to use as icons.
563      * (Default: not set)
564      */
setIcons(Object[] value)565     public void setIcons(Object[] value) {
566         put("Icons", value);
567     }
568 
569     /**
570      * Sets the path of the settings dialog image to use.
571      * <p>
572      * The image will be displayed in the settings dialog when the
573      * application is started.
574      * </p>
575      * (Default: /com/jme3/app/Monkey.png)
576      *
577      * @param path The path to the image in the classpath.
578      */
setSettingsDialogImage(String path)579     public void setSettingsDialogImage(String path) {
580         putString("SettingsDialogImage", path);
581     }
582 
583     /**
584      * Get the framerate.
585      * @see #setFrameRate(int)
586      */
getFrameRate()587     public int getFrameRate() {
588         return getInteger("FrameRate");
589     }
590 
591     /**
592      * Get the use input state.
593      * @see #setUseInput(boolean)
594      */
useInput()595     public boolean useInput() {
596         return getBoolean("UseInput");
597     }
598 
599     /**
600      * Get the renderer
601      * @see #setRenderer(java.lang.String)
602      */
getRenderer()603     public String getRenderer() {
604         return getString("Renderer");
605     }
606 
607     /**
608      * Get the width
609      * @see #setWidth(int)
610      */
getWidth()611     public int getWidth() {
612         return getInteger("Width");
613     }
614 
615     /**
616      * Get the height
617      * @see #setHeight(int)
618      */
getHeight()619     public int getHeight() {
620         return getInteger("Height");
621     }
622 
623     /**
624      * Get the bits per pixel
625      * @see #setBitsPerPixel(int)
626      */
getBitsPerPixel()627     public int getBitsPerPixel() {
628         return getInteger("BitsPerPixel");
629     }
630 
631     /**
632      * Get the frequency
633      * @see #setFrequency(int)
634      */
getFrequency()635     public int getFrequency() {
636         return getInteger("Frequency");
637     }
638 
639     /**
640      * Get the number of depth bits
641      * @see #setDepthBits(int)
642      */
getDepthBits()643     public int getDepthBits() {
644         return getInteger("DepthBits");
645     }
646 
647     /**
648      * Get the number of stencil bits
649      * @see #setStencilBits(int)
650      */
getStencilBits()651     public int getStencilBits() {
652         return getInteger("StencilBits");
653     }
654 
655     /**
656      * Get the number of samples
657      * @see #setSamples(int)
658      */
getSamples()659     public int getSamples() {
660         return getInteger("Samples");
661     }
662 
663     /**
664      * Get the application title
665      * @see #setTitle(java.lang.String)
666      */
getTitle()667     public String getTitle() {
668         return getString("Title");
669     }
670 
671     /**
672      * Get the vsync state
673      * @see #setVSync(boolean)
674      */
isVSync()675     public boolean isVSync() {
676         return getBoolean("VSync");
677     }
678 
679     /**
680      * Get the fullscreen state
681      * @see #setFullscreen(boolean)
682      */
isFullscreen()683     public boolean isFullscreen() {
684         return getBoolean("Fullscreen");
685     }
686 
687     /**
688      * Get the use joysticks state
689      * @see #setUseJoysticks(boolean)
690      */
useJoysticks()691     public boolean useJoysticks() {
692         return !getBoolean("DisableJoysticks");
693     }
694 
695     /**
696      * Get the audio renderer
697      * @see #setAudioRenderer(java.lang.String)
698      */
getAudioRenderer()699     public String getAudioRenderer() {
700         return getString("AudioRenderer");
701     }
702 
703     /**
704      * Get the stereo 3D state
705      * @see #setStereo3D(boolean)
706      */
useStereo3D()707     public boolean useStereo3D(){
708         return getBoolean("Stereo3D");
709     }
710 
711     /**
712      * Get the icon array
713      * @see #setIcons(java.lang.Object[])
714      */
getIcons()715     public Object[] getIcons() {
716         return (Object[]) get("Icons");
717     }
718 
719     /**
720      * Get the settings dialog image
721      * @see #setSettingsDialogImage(java.lang.String)
722      */
getSettingsDialogImage()723     public String getSettingsDialogImage() {
724         return getString("SettingsDialogImage");
725     }
726 }
727