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.dummy.DummyKeyInput;
40 import com.jme3.input.dummy.DummyMouseInput;
41 import java.util.concurrent.atomic.AtomicBoolean;
42 import java.util.logging.Level;
43 import java.util.logging.Logger;
44 import org.lwjgl.LWJGLException;
45 import org.lwjgl.Sys;
46 import org.lwjgl.opengl.*;
47 
48 public class LwjglOffscreenBuffer extends LwjglContext implements Runnable {
49 
50     private static final Logger logger = Logger.getLogger(LwjglOffscreenBuffer.class.getName());
51     private Pbuffer pbuffer;
52     protected AtomicBoolean needClose = new AtomicBoolean(false);
53     private int width;
54     private int height;
55     private PixelFormat pixelFormat;
56 
initInThread()57     protected void initInThread(){
58         if ((Pbuffer.getCapabilities() & Pbuffer.PBUFFER_SUPPORTED) == 0){
59             logger.severe("Offscreen surfaces are not supported.");
60             return;
61         }
62 
63 	   int samples = 0;
64          if (settings.getSamples() > 1){
65               samples = settings.getSamples();
66         }
67         pixelFormat = new PixelFormat(settings.getBitsPerPixel(),
68                                       0,
69                                       settings.getDepthBits(),
70                                       settings.getStencilBits(),
71                                       settings.getSamples());
72 
73         width = settings.getWidth();
74         height = settings.getHeight();
75         try{
76             Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
77                 public void uncaughtException(Thread thread, Throwable thrown) {
78                     listener.handleError("Uncaught exception thrown in "+thread.toString(), thrown);
79                 }
80             });
81 
82             pbuffer = new Pbuffer(width, height, pixelFormat, null, null, createContextAttribs());
83             pbuffer.makeCurrent();
84 
85             renderable.set(true);
86 
87             logger.info("Offscreen buffer created.");
88             printContextInitInfo();
89         } catch (LWJGLException ex){
90             listener.handleError("Failed to create display", ex);
91         } finally {
92             // TODO: It is possible to avoid "Failed to find pixel format"
93             // error here by creating a default display.
94         }
95         super.internalCreate();
96         listener.initialize();
97     }
98 
checkGLError()99     protected boolean checkGLError(){
100         try {
101             Util.checkGLError();
102         } catch (OpenGLException ex){
103             listener.handleError("An OpenGL error has occured!", ex);
104         }
105         // NOTE: Always return true since this is used in an "assert" statement
106         return true;
107     }
108 
runLoop()109     protected void runLoop(){
110         if (!created.get())
111             throw new IllegalStateException();
112 
113         if (pbuffer.isBufferLost()){
114             pbuffer.destroy();
115             try{
116                 pbuffer = new Pbuffer(width, height, pixelFormat, null);
117                 pbuffer.makeCurrent();
118             }catch (LWJGLException ex){
119                 listener.handleError("Failed to restore pbuffer content", ex);
120             }
121         }
122 
123         listener.update();
124         assert checkGLError();
125 
126         renderer.onFrame();
127 
128         int frameRate = settings.getFrameRate();
129         if (frameRate >= 1){
130             Display.sync(frameRate);
131         }
132     }
133 
deinitInThread()134     protected void deinitInThread(){
135         renderable.set(false);
136 
137         listener.destroy();
138         renderer.cleanup();
139         pbuffer.destroy();
140         logger.info("Offscreen buffer destroyed.");
141     }
142 
run()143     public void run(){
144         logger.log(Level.INFO, "Using LWJGL {0}", Sys.getVersion());
145         initInThread();
146         while (!needClose.get()){
147             runLoop();
148         }
149         deinitInThread();
150     }
151 
destroy(boolean waitFor)152     public void destroy(boolean waitFor){
153         needClose.set(true);
154         if (waitFor)
155             waitFor(false);
156     }
157 
create(boolean waitFor)158     public void create(boolean waitFor){
159         if (created.get()){
160             logger.warning("create() called when pbuffer is already created!");
161             return;
162         }
163 
164         new Thread(this, "LWJGL Renderer Thread").start();
165         if (waitFor)
166             waitFor(true);
167     }
168 
restart()169     public void restart() {
170     }
171 
setAutoFlushFrames(boolean enabled)172     public void setAutoFlushFrames(boolean enabled){
173     }
174 
getType()175     public Type getType() {
176         return Type.OffscreenSurface;
177     }
178 
getMouseInput()179     public MouseInput getMouseInput() {
180         return new DummyMouseInput();
181     }
182 
getKeyInput()183     public KeyInput getKeyInput() {
184         return new DummyKeyInput();
185     }
186 
getJoyInput()187     public JoyInput getJoyInput() {
188         return null;
189     }
190 
getTouchInput()191     public TouchInput getTouchInput() {
192         return null;
193     }
194 
setTitle(String title)195     public void setTitle(String title) {
196     }
197 
198 }
199