Home | History | Annotate | Download | only in system
      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 
     33 package com.jme3.system;
     34 
     35 import com.jme3.input.JoyInput;
     36 import com.jme3.input.KeyInput;
     37 import com.jme3.input.MouseInput;
     38 import com.jme3.input.TouchInput;
     39 import com.jme3.input.dummy.DummyKeyInput;
     40 import com.jme3.input.dummy.DummyMouseInput;
     41 import com.jme3.renderer.Renderer;
     42 import java.util.concurrent.atomic.AtomicBoolean;
     43 import java.util.logging.Level;
     44 import java.util.logging.Logger;
     45 
     46 public class NullContext implements JmeContext, Runnable {
     47 
     48     protected static final Logger logger = Logger.getLogger(NullContext.class.getName());
     49 
     50     protected AtomicBoolean created = new AtomicBoolean(false);
     51     protected AtomicBoolean needClose = new AtomicBoolean(false);
     52     protected final Object createdLock = new Object();
     53 
     54     protected int frameRate;
     55     protected AppSettings settings = new AppSettings(true);
     56     protected Timer timer;
     57     protected SystemListener listener;
     58     protected NullRenderer renderer;
     59 
     60     public Type getType() {
     61         return Type.Headless;
     62     }
     63 
     64     public void setSystemListener(SystemListener listener){
     65         this.listener = listener;
     66     }
     67 
     68     protected void initInThread(){
     69         logger.info("NullContext created.");
     70         logger.log(Level.FINE, "Running on thread: {0}", Thread.currentThread().getName());
     71 
     72         Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
     73             public void uncaughtException(Thread thread, Throwable thrown) {
     74                 listener.handleError("Uncaught exception thrown in "+thread.toString(), thrown);
     75             }
     76         });
     77 
     78         timer = new NanoTimer();
     79         renderer = new NullRenderer();
     80         synchronized (createdLock){
     81             created.set(true);
     82             createdLock.notifyAll();
     83         }
     84 
     85         listener.initialize();
     86     }
     87 
     88     protected void deinitInThread(){
     89         listener.destroy();
     90         timer = null;
     91         synchronized (createdLock){
     92             created.set(false);
     93             createdLock.notifyAll();
     94         }
     95     }
     96 
     97     private static long timeThen;
     98     private static long timeLate;
     99 
    100     public void sync(int fps) {
    101         long timeNow;
    102         long gapTo;
    103         long savedTimeLate;
    104 
    105         gapTo = timer.getResolution() / fps + timeThen;
    106         timeNow = timer.getTime();
    107         savedTimeLate = timeLate;
    108 
    109         try {
    110             while (gapTo > timeNow + savedTimeLate) {
    111                 Thread.sleep(1);
    112                 timeNow = timer.getTime();
    113             }
    114         } catch (InterruptedException e) {
    115             Thread.currentThread().interrupt();
    116         }
    117 
    118         if (gapTo < timeNow) {
    119             timeLate = timeNow - gapTo;
    120         } else {
    121             timeLate = 0;
    122         }
    123 
    124         timeThen = timeNow;
    125     }
    126 
    127     public void run(){
    128         initInThread();
    129 
    130         while (!needClose.get()){
    131             listener.update();
    132 
    133             if (frameRate > 0)
    134                 sync(frameRate);
    135         }
    136 
    137         deinitInThread();
    138 
    139         logger.info("NullContext destroyed.");
    140     }
    141 
    142     public void destroy(boolean waitFor){
    143         needClose.set(true);
    144         if (waitFor)
    145             waitFor(false);
    146     }
    147 
    148     public void create(boolean waitFor){
    149         if (created.get()){
    150             logger.warning("create() called when NullContext is already created!");
    151             return;
    152         }
    153 
    154         new Thread(this, "Headless Application Thread").start();
    155         if (waitFor)
    156             waitFor(true);
    157     }
    158 
    159     public void restart() {
    160     }
    161 
    162     public void setAutoFlushFrames(boolean enabled){
    163     }
    164 
    165     public MouseInput getMouseInput() {
    166         return new DummyMouseInput();
    167     }
    168 
    169     public KeyInput getKeyInput() {
    170         return new DummyKeyInput();
    171     }
    172 
    173     public JoyInput getJoyInput() {
    174         return null;
    175     }
    176 
    177     public TouchInput getTouchInput() {
    178         return null;
    179     }
    180 
    181     public void setTitle(String title) {
    182     }
    183 
    184     public void create(){
    185         create(false);
    186     }
    187 
    188     public void destroy(){
    189         destroy(false);
    190     }
    191 
    192     protected void waitFor(boolean createdVal){
    193         synchronized (createdLock){
    194             while (created.get() != createdVal){
    195                 try {
    196                     createdLock.wait();
    197                 } catch (InterruptedException ex) {
    198                 }
    199             }
    200         }
    201     }
    202 
    203     public boolean isCreated(){
    204         return created.get();
    205     }
    206 
    207     public void setSettings(AppSettings settings) {
    208         this.settings.copyFrom(settings);
    209         frameRate = settings.getFrameRate();
    210         if (frameRate <= 0)
    211             frameRate = 60; // use default update rate.
    212     }
    213 
    214     public AppSettings getSettings(){
    215         return settings;
    216     }
    217 
    218     public Renderer getRenderer() {
    219         return renderer;
    220     }
    221 
    222     public Timer getTimer() {
    223         return timer;
    224     }
    225 
    226     public boolean isRenderable() {
    227         return true; // Doesn't really matter if true or false. Either way
    228                      // RenderManager won't render anything.
    229     }
    230 }
    231