• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.lwjgl;
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.lwjgl.JInputJoyInput;
40 import com.jme3.input.lwjgl.LwjglKeyInput;
41 import com.jme3.input.lwjgl.LwjglMouseInput;
42 import com.jme3.system.AppSettings;
43 import com.jme3.system.JmeContext.Type;
44 import com.jme3.system.JmeSystem;
45 import java.util.concurrent.atomic.AtomicBoolean;
46 import java.util.logging.Level;
47 import java.util.logging.Logger;
48 import org.lwjgl.LWJGLException;
49 import org.lwjgl.Sys;
50 import org.lwjgl.opengl.Display;
51 import org.lwjgl.opengl.OpenGLException;
52 import org.lwjgl.opengl.Util;
53 
54 public abstract class LwjglAbstractDisplay extends LwjglContext implements Runnable {
55 
56     private static final Logger logger = Logger.getLogger(LwjglAbstractDisplay.class.getName());
57 
58     protected AtomicBoolean needClose = new AtomicBoolean(false);
59     protected boolean wasActive = false;
60     protected int frameRate = 0;
61     protected boolean autoFlush = true;
62 
63     /**
64      * @return Type.Display or Type.Canvas
65      */
getType()66     public abstract Type getType();
67 
68     /**
69      * Set the title if its a windowed display
70      * @param title
71      */
setTitle(String title)72     public abstract void setTitle(String title);
73 
74     /**
75      * Restart if its a windowed or full-screen display.
76      */
restart()77     public abstract void restart();
78 
79     /**
80      * Apply the settings, changing resolution, etc.
81      * @param settings
82      */
createContext(AppSettings settings)83     protected abstract void createContext(AppSettings settings) throws LWJGLException;
84 
85     /**
86      * Destroy the context.
87      */
destroyContext()88     protected abstract void destroyContext();
89 
90     /**
91      * Does LWJGL display initialization in the OpenGL thread
92      */
initInThread()93     protected void initInThread(){
94         try{
95             if (!JmeSystem.isLowPermissions()){
96                 // Enable uncaught exception handler only for current thread
97                 Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
98                     public void uncaughtException(Thread thread, Throwable thrown) {
99                         listener.handleError("Uncaught exception thrown in "+thread.toString(), thrown);
100                         if (needClose.get()){
101                             // listener.handleError() has requested the
102                             // context to close. Satisfy request.
103                             deinitInThread();
104                         }
105                     }
106                 });
107             }
108 
109             // For canvas, this will create a pbuffer,
110             // allowing us to query information.
111             // When the canvas context becomes available, it will
112             // be replaced seamlessly.
113             createContext(settings);
114             printContextInitInfo();
115 
116             created.set(true);
117         } catch (Exception ex){
118             try {
119                 if (Display.isCreated())
120                     Display.destroy();
121             } catch (Exception ex2){
122                 logger.log(Level.WARNING, null, ex2);
123             }
124 
125             listener.handleError("Failed to create display", ex);
126             return; // if we failed to create display, do not continue
127         }
128         super.internalCreate();
129         listener.initialize();
130     }
131 
checkGLError()132     protected boolean checkGLError(){
133         try {
134             Util.checkGLError();
135         } catch (OpenGLException ex){
136             listener.handleError("An OpenGL error has occured!", ex);
137         }
138         // NOTE: Always return true since this is used in an "assert" statement
139         return true;
140     }
141 
142     /**
143      * execute one iteration of the render loop in the OpenGL thread
144      */
runLoop()145     protected void runLoop(){
146         if (!created.get())
147             throw new IllegalStateException();
148 
149         listener.update();
150 
151         // All this does is call swap buffers
152         // If the canvas is not active, there's no need to waste time
153         // doing that ..
154         if (renderable.get()){
155             assert checkGLError();
156 
157             // calls swap buffers, etc.
158             try {
159                 if (autoFlush){
160                     Display.update(false);
161                 }else{
162                     Display.processMessages();
163                     Thread.sleep(50);
164                     // add a small wait
165                     // to reduce CPU usage
166                 }
167             } catch (Throwable ex){
168                 listener.handleError("Error while swapping buffers", ex);
169             }
170         }
171 
172         if (frameRate > 0)
173             Display.sync(frameRate);
174 
175         if (renderable.get()){
176             if (autoFlush){
177                 // check input after we synchronize with framerate.
178                 // this reduces input lag.
179                 Display.processMessages();
180             }
181         }
182 
183         // Subclasses just call GLObjectManager clean up objects here
184         // it is safe .. for now.
185         renderer.onFrame();
186     }
187 
188     /**
189      * De-initialize in the OpenGL thread.
190      */
deinitInThread()191     protected void deinitInThread(){
192         destroyContext();
193 
194         listener.destroy();
195         logger.info("Display destroyed.");
196         super.internalDestroy();
197     }
198 
run()199     public void run(){
200         if (listener == null)
201             throw new IllegalStateException("SystemListener is not set on context!"
202                                           + "Must set with JmeContext.setSystemListner().");
203 
204         logger.log(Level.INFO, "Using LWJGL {0}", Sys.getVersion());
205         initInThread();
206         while (true){
207             if (renderable.get()){
208                 if (Display.isCloseRequested())
209                     listener.requestClose(false);
210 
211                 if (wasActive != Display.isActive()) {
212                     if (!wasActive) {
213                         listener.gainFocus();
214                         timer.reset();
215                         wasActive = true;
216                     } else {
217                         listener.loseFocus();
218                         wasActive = false;
219                     }
220                 }
221             }
222 
223             runLoop();
224 
225             if (needClose.get())
226                 break;
227         }
228         deinitInThread();
229     }
230 
getJoyInput()231     public JoyInput getJoyInput() {
232         if (joyInput == null){
233             joyInput = new JInputJoyInput();
234         }
235         return joyInput;
236     }
237 
getMouseInput()238     public MouseInput getMouseInput() {
239         if (mouseInput == null){
240             mouseInput = new LwjglMouseInput(this);
241         }
242         return mouseInput;
243     }
244 
getKeyInput()245     public KeyInput getKeyInput() {
246         if (keyInput == null){
247             keyInput = new LwjglKeyInput(this);
248         }
249         return keyInput;
250     }
251 
getTouchInput()252     public TouchInput getTouchInput() {
253         return null;
254     }
255 
setAutoFlushFrames(boolean enabled)256     public void setAutoFlushFrames(boolean enabled){
257         this.autoFlush = enabled;
258     }
259 
destroy(boolean waitFor)260     public void destroy(boolean waitFor){
261         needClose.set(true);
262         if (waitFor)
263             waitFor(false);
264     }
265 
266 }
267