Home | History | Annotate | Download | only in system
      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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    579     public void setSettingsDialogImage(String path) {
    580         putString("SettingsDialogImage", path);
    581     }
    582 
    583     /**
    584      * Get the framerate.
    585      * @see #setFrameRate(int)
    586      */
    587     public int getFrameRate() {
    588         return getInteger("FrameRate");
    589     }
    590 
    591     /**
    592      * Get the use input state.
    593      * @see #setUseInput(boolean)
    594      */
    595     public boolean useInput() {
    596         return getBoolean("UseInput");
    597     }
    598 
    599     /**
    600      * Get the renderer
    601      * @see #setRenderer(java.lang.String)
    602      */
    603     public String getRenderer() {
    604         return getString("Renderer");
    605     }
    606 
    607     /**
    608      * Get the width
    609      * @see #setWidth(int)
    610      */
    611     public int getWidth() {
    612         return getInteger("Width");
    613     }
    614 
    615     /**
    616      * Get the height
    617      * @see #setHeight(int)
    618      */
    619     public int getHeight() {
    620         return getInteger("Height");
    621     }
    622 
    623     /**
    624      * Get the bits per pixel
    625      * @see #setBitsPerPixel(int)
    626      */
    627     public int getBitsPerPixel() {
    628         return getInteger("BitsPerPixel");
    629     }
    630 
    631     /**
    632      * Get the frequency
    633      * @see #setFrequency(int)
    634      */
    635     public int getFrequency() {
    636         return getInteger("Frequency");
    637     }
    638 
    639     /**
    640      * Get the number of depth bits
    641      * @see #setDepthBits(int)
    642      */
    643     public int getDepthBits() {
    644         return getInteger("DepthBits");
    645     }
    646 
    647     /**
    648      * Get the number of stencil bits
    649      * @see #setStencilBits(int)
    650      */
    651     public int getStencilBits() {
    652         return getInteger("StencilBits");
    653     }
    654 
    655     /**
    656      * Get the number of samples
    657      * @see #setSamples(int)
    658      */
    659     public int getSamples() {
    660         return getInteger("Samples");
    661     }
    662 
    663     /**
    664      * Get the application title
    665      * @see #setTitle(java.lang.String)
    666      */
    667     public String getTitle() {
    668         return getString("Title");
    669     }
    670 
    671     /**
    672      * Get the vsync state
    673      * @see #setVSync(boolean)
    674      */
    675     public boolean isVSync() {
    676         return getBoolean("VSync");
    677     }
    678 
    679     /**
    680      * Get the fullscreen state
    681      * @see #setFullscreen(boolean)
    682      */
    683     public boolean isFullscreen() {
    684         return getBoolean("Fullscreen");
    685     }
    686 
    687     /**
    688      * Get the use joysticks state
    689      * @see #setUseJoysticks(boolean)
    690      */
    691     public boolean useJoysticks() {
    692         return !getBoolean("DisableJoysticks");
    693     }
    694 
    695     /**
    696      * Get the audio renderer
    697      * @see #setAudioRenderer(java.lang.String)
    698      */
    699     public String getAudioRenderer() {
    700         return getString("AudioRenderer");
    701     }
    702 
    703     /**
    704      * Get the stereo 3D state
    705      * @see #setStereo3D(boolean)
    706      */
    707     public boolean useStereo3D(){
    708         return getBoolean("Stereo3D");
    709     }
    710 
    711     /**
    712      * Get the icon array
    713      * @see #setIcons(java.lang.Object[])
    714      */
    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      */
    723     public String getSettingsDialogImage() {
    724         return getString("SettingsDialogImage");
    725     }
    726 }
    727