* Big refactoring of LWJGL display system, mainly to support updating the main loop without a render context or input devices being available.
* Added test that demonstrates above functionality, by starting Application without attaching the canvas, and then constantly attaching and detaching canvas from a frame. * Deleted deprecated methods in JmeContext * Deleted deprecated class LwjglJoyInput * Audio renderer will not attempt to initialize OpenAL twice if already initialized git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7078 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
eaeb1de436
commit
61aea1e2c5
@ -299,13 +299,17 @@ public class Application implements SystemListener {
|
||||
public Camera getCamera(){
|
||||
return cam;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Starts the application as a display.
|
||||
*/
|
||||
public void start(){
|
||||
start(JmeContext.Type.Display);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the application. Creating a display and running the main loop.
|
||||
* Starts the application. Creating a rendering context and executing
|
||||
* the main loop in a separate thread.
|
||||
*/
|
||||
public void start(JmeContext.Type contextType){
|
||||
if (context != null && context.isCreated()){
|
||||
@ -423,6 +427,10 @@ public class Application implements SystemListener {
|
||||
context.destroy(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues a task/callable object to execute in the jME3
|
||||
* rendering thread.
|
||||
*/
|
||||
public <V> Future<V> enqueue(Callable<V> callable) {
|
||||
AppTask<V> task = new AppTask<V>(callable);
|
||||
taskQueue.add(task);
|
||||
@ -495,6 +503,4 @@ public class Application implements SystemListener {
|
||||
return viewPort;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -249,7 +249,9 @@ public abstract class SimpleApplication extends Application {
|
||||
|
||||
// render states
|
||||
stateManager.render(renderManager);
|
||||
renderManager.render(tpf);
|
||||
if (context.isRenderable()){
|
||||
renderManager.render(tpf);
|
||||
}
|
||||
simpleRender(renderManager);
|
||||
stateManager.postRender();
|
||||
}
|
||||
@ -257,7 +259,6 @@ public abstract class SimpleApplication extends Application {
|
||||
public void setDisplayFps(boolean show) {
|
||||
showFps = show;
|
||||
fpsText.setCullHint(show ? CullHint.Never : CullHint.Always);
|
||||
|
||||
}
|
||||
|
||||
public void setDisplayStatView(boolean show) {
|
||||
|
||||
@ -108,7 +108,6 @@ public class RenderManager {
|
||||
public RenderManager(Renderer renderer) {
|
||||
this.renderer = renderer;
|
||||
this.shader = renderer.getCaps().contains(Caps.GLSL100);
|
||||
|
||||
}
|
||||
|
||||
public ViewPort getPreView(String viewName) {
|
||||
|
||||
@ -48,16 +48,19 @@ public interface JmeContext {
|
||||
public enum Type {
|
||||
/**
|
||||
* A display can represent a windowed or a fullscreen-exclusive display.
|
||||
* If windowed, the graphics are rendered to a new onscreen surface
|
||||
* enclosed in a system defined by the operating system. Implementations
|
||||
* are encourged to not use AWT or Swing to create the OpenGL display
|
||||
* If windowed, the graphics are rendered to a new on-screen surface
|
||||
* enclosed in a window defined by the operating system. Implementations
|
||||
* are encouraged to not use AWT or Swing to create the OpenGL display
|
||||
* but rather use native operating system functions to set up a native
|
||||
* display with the windowing system.
|
||||
*/
|
||||
Display,
|
||||
|
||||
/**
|
||||
*
|
||||
* A canvas type context makes a rendering surface available as an
|
||||
* AWT {@link java.awt.Canvas} object that can be embedded in a Swing/AWT
|
||||
* frame. To retrieve the Canvas object, you should cast the context
|
||||
* to {@link JmeCanvasContext}.
|
||||
*/
|
||||
Canvas,
|
||||
|
||||
@ -139,18 +142,19 @@ public interface JmeContext {
|
||||
*/
|
||||
public boolean isCreated();
|
||||
|
||||
/**
|
||||
* @return True if the context contains a valid render surface,
|
||||
* if any of the rendering methods in {@link Renderer} are called
|
||||
* while this is <code>false</code>, then the result is undefined.
|
||||
*/
|
||||
public boolean isRenderable();
|
||||
|
||||
/**
|
||||
* @param enabled If enabled, the context will automatically flush
|
||||
* frames to the video card (swap buffers) after an update cycle.
|
||||
*/
|
||||
public void setAutoFlushFrames(boolean enabled);
|
||||
|
||||
/**
|
||||
* Creates the context and makes it active.
|
||||
*/
|
||||
@Deprecated
|
||||
public void create();
|
||||
|
||||
/**
|
||||
* Creates the context and makes it active.
|
||||
*
|
||||
@ -164,12 +168,6 @@ public interface JmeContext {
|
||||
*/
|
||||
public void restart();
|
||||
|
||||
/**
|
||||
* Destroys the context completely, making it inactive.
|
||||
*/
|
||||
@Deprecated
|
||||
public void destroy();
|
||||
|
||||
/**
|
||||
* Destroys the context completely, making it inactive.
|
||||
*
|
||||
|
||||
@ -218,4 +218,9 @@ public class NullContext implements JmeContext, Runnable {
|
||||
return timer;
|
||||
}
|
||||
|
||||
public boolean isRenderable() {
|
||||
return true; // Doesn't really matter if true or false. Either way
|
||||
// RenderManager won't render anything.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -154,7 +154,9 @@ public class LwjglAudioRenderer implements AudioRenderer, Runnable {
|
||||
|
||||
public void initInThread(){
|
||||
try{
|
||||
AL.create();
|
||||
if (!AL.isCreated()){
|
||||
AL.create();
|
||||
}
|
||||
}catch (OpenALException ex){
|
||||
logger.log(Level.SEVERE, "Failed to load audio library", ex);
|
||||
audioDisabled = true;
|
||||
|
||||
@ -1,181 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2010 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.jme3.input.lwjgl;
|
||||
|
||||
import com.jme3.input.InputManager;
|
||||
import com.jme3.input.JoyInput;
|
||||
import com.jme3.input.Joystick;
|
||||
import com.jme3.input.RawInputListener;
|
||||
import com.jme3.input.event.JoyAxisEvent;
|
||||
import com.jme3.input.event.JoyButtonEvent;
|
||||
import com.jme3.system.lwjgl.LwjglTimer;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.lwjgl.LWJGLException;
|
||||
import org.lwjgl.Sys;
|
||||
import org.lwjgl.input.Controller;
|
||||
import org.lwjgl.input.Controllers;
|
||||
|
||||
@Deprecated
|
||||
class LwjglJoyInput implements JoyInput {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(LwjglKeyInput.class.getName());
|
||||
|
||||
private RawInputListener listener;
|
||||
private boolean enabled = false;
|
||||
|
||||
public void initialize() {
|
||||
try {
|
||||
Controllers.create();
|
||||
if (Controllers.getControllerCount() == 0 || !Controllers.isCreated()){
|
||||
logger.warning("Joysticks disabled.");
|
||||
return;
|
||||
}
|
||||
logger.info("Joysticks created.");
|
||||
enabled = true;
|
||||
} catch (LWJGLException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to create joysticks", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public int getJoyCount() {
|
||||
return Controllers.getControllerCount();
|
||||
}
|
||||
|
||||
public String getJoyName(int joyIndex) {
|
||||
return Controllers.getController(joyIndex).getName();
|
||||
}
|
||||
|
||||
public int getAxesCount(int joyIndex) {
|
||||
return Controllers.getController(joyIndex).getAxisCount();
|
||||
}
|
||||
|
||||
public int getButtonCount(int joyIndex) {
|
||||
return Controllers.getController(joyIndex).getButtonCount();
|
||||
}
|
||||
|
||||
private void printController(Controller c){
|
||||
System.out.println("Name: "+c.getName());
|
||||
System.out.println("Index: "+c.getIndex());
|
||||
System.out.println("Button Count: "+c.getButtonCount());
|
||||
System.out.println("Axis Count: "+c.getAxisCount());
|
||||
|
||||
int buttons = c.getButtonCount();
|
||||
for (int b = 0; b < buttons; b++) {
|
||||
System.out.println("Button " + b + " = " + c.getButtonName(b));
|
||||
}
|
||||
|
||||
int axis = c.getAxisCount();
|
||||
for (int b = 0; b < axis; b++) {
|
||||
System.out.println("Axis " + b + " = " + c.getAxisName(b));
|
||||
}
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
Controllers.poll();
|
||||
while (Controllers.next()){
|
||||
Controller c = Controllers.getEventSource();
|
||||
if (Controllers.isEventAxis()){
|
||||
int realAxis = Controllers.getEventControlIndex();
|
||||
JoyAxisEvent evt = new JoyAxisEvent(c.getIndex(),
|
||||
realAxis,
|
||||
c.getAxisValue(realAxis));
|
||||
listener.onJoyAxisEvent(evt);
|
||||
}else if (Controllers.isEventPovX()){
|
||||
JoyAxisEvent evt = new JoyAxisEvent(c.getIndex(),
|
||||
JoyInput.AXIS_POV_X,
|
||||
c.getPovX());
|
||||
listener.onJoyAxisEvent(evt);
|
||||
}else if (Controllers.isEventPovY()){
|
||||
JoyAxisEvent evt = new JoyAxisEvent(c.getIndex(),
|
||||
JoyInput.AXIS_POV_Y,
|
||||
c.getPovY());
|
||||
listener.onJoyAxisEvent(evt);
|
||||
}else if (Controllers.isEventButton()){
|
||||
int btn = Controllers.getEventControlIndex();
|
||||
JoyButtonEvent evt = new JoyButtonEvent(c.getIndex(),
|
||||
btn,
|
||||
c.isButtonPressed(btn));
|
||||
listener.onJoyButtonEvent(evt);
|
||||
}
|
||||
}
|
||||
Controllers.clearEvents();
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
Controllers.destroy();
|
||||
logger.info("Joysticks destroyed.");
|
||||
}
|
||||
|
||||
public boolean isInitialized() {
|
||||
if (!enabled)
|
||||
return false;
|
||||
|
||||
return Controllers.isCreated();
|
||||
}
|
||||
|
||||
public void setInputListener(RawInputListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public long getInputTimeNanos() {
|
||||
return Sys.getTime() * LwjglTimer.LWJGL_TIME_TO_NANOS;
|
||||
}
|
||||
|
||||
public void setJoyRumble(int joyId, float amount){
|
||||
}
|
||||
|
||||
public Joystick[] loadJoysticks(InputManager inputManager) {
|
||||
int count = Controllers.getControllerCount();
|
||||
Joystick[] joysticks = new Joystick[count];
|
||||
for (int i = 0; i < count; i++){
|
||||
Controller c = Controllers.getController(i);
|
||||
Joystick j = new Joystick(inputManager,
|
||||
this,
|
||||
i,
|
||||
c.getName(),
|
||||
c.getButtonCount(),
|
||||
c.getAxisCount(),
|
||||
-1,-1);
|
||||
joysticks[i] = j;
|
||||
}
|
||||
return joysticks;
|
||||
}
|
||||
|
||||
}
|
||||
@ -35,6 +35,7 @@ package com.jme3.input.lwjgl;
|
||||
import com.jme3.input.KeyInput;
|
||||
import com.jme3.input.event.KeyInputEvent;
|
||||
import com.jme3.input.RawInputListener;
|
||||
import com.jme3.system.lwjgl.LwjglAbstractDisplay;
|
||||
import com.jme3.system.lwjgl.LwjglTimer;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@ -46,9 +47,18 @@ public class LwjglKeyInput implements KeyInput {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(LwjglKeyInput.class.getName());
|
||||
|
||||
private LwjglAbstractDisplay context;
|
||||
|
||||
private RawInputListener listener;
|
||||
|
||||
public LwjglKeyInput(LwjglAbstractDisplay context){
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
if (!context.isRenderable())
|
||||
return;
|
||||
|
||||
try {
|
||||
Keyboard.create();
|
||||
Keyboard.enableRepeatEvents(true);
|
||||
@ -58,15 +68,14 @@ public class LwjglKeyInput implements KeyInput {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isKeyDown(int key){
|
||||
return Keyboard.isKeyDown(key);
|
||||
}
|
||||
|
||||
public int getKeyCount(){
|
||||
return Keyboard.KEYBOARD_SIZE;
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if (!context.isRenderable())
|
||||
return;
|
||||
|
||||
Keyboard.poll();
|
||||
while (Keyboard.next()){
|
||||
int keyCode = Keyboard.getEventKey();
|
||||
@ -81,6 +90,9 @@ public class LwjglKeyInput implements KeyInput {
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
if (!context.isRenderable())
|
||||
return;
|
||||
|
||||
Keyboard.destroy();
|
||||
logger.info("Keyboard destroyed.");
|
||||
}
|
||||
|
||||
@ -36,6 +36,7 @@ import com.jme3.input.event.MouseButtonEvent;
|
||||
import com.jme3.input.event.MouseMotionEvent;
|
||||
import com.jme3.input.MouseInput;
|
||||
import com.jme3.input.RawInputListener;
|
||||
import com.jme3.system.lwjgl.LwjglAbstractDisplay;
|
||||
import com.jme3.system.lwjgl.LwjglTimer;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@ -48,6 +49,8 @@ public class LwjglMouseInput implements MouseInput {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(LwjglMouseInput.class.getName());
|
||||
|
||||
private LwjglAbstractDisplay context;
|
||||
|
||||
private RawInputListener listener;
|
||||
|
||||
private boolean supportHardwareCursor = false;
|
||||
@ -55,11 +58,21 @@ public class LwjglMouseInput implements MouseInput {
|
||||
|
||||
private int curX, curY, curWheel;
|
||||
|
||||
public LwjglMouseInput(LwjglAbstractDisplay context){
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
if (!context.isRenderable())
|
||||
return;
|
||||
|
||||
try {
|
||||
Mouse.create();
|
||||
logger.info("Mouse created.");
|
||||
supportHardwareCursor = (Cursor.getCapabilities() & Cursor.CURSOR_ONE_BIT_TRANSPARENCY) != 0;
|
||||
|
||||
// Recall state that was set before initialization
|
||||
Mouse.setGrabbed(!cursorVisible);
|
||||
} catch (LWJGLException ex) {
|
||||
logger.log(Level.SEVERE, "Error while creating mouse", ex);
|
||||
}
|
||||
@ -74,6 +87,9 @@ public class LwjglMouseInput implements MouseInput {
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if (!context.isRenderable())
|
||||
return;
|
||||
|
||||
while (Mouse.next()){
|
||||
int btn = Mouse.getEventButton();
|
||||
|
||||
@ -109,13 +125,19 @@ public class LwjglMouseInput implements MouseInput {
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
if (!context.isRenderable())
|
||||
return;
|
||||
|
||||
Mouse.destroy();
|
||||
logger.info("Mouse destroyed.");
|
||||
}
|
||||
|
||||
public void setCursorVisible(boolean visible){
|
||||
Mouse.setGrabbed(!visible);
|
||||
cursorVisible = visible;
|
||||
if (!context.isRenderable())
|
||||
return;
|
||||
|
||||
Mouse.setGrabbed(!visible);
|
||||
}
|
||||
|
||||
public void setInputListener(RawInputListener listener) {
|
||||
|
||||
@ -47,16 +47,13 @@ import java.util.logging.Logger;
|
||||
import org.lwjgl.LWJGLException;
|
||||
import org.lwjgl.Sys;
|
||||
import org.lwjgl.opengl.Display;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.opengl.GLContext;
|
||||
import org.lwjgl.opengl.OpenGLException;
|
||||
import org.lwjgl.opengl.Util;
|
||||
|
||||
|
||||
public abstract class LwjglAbstractDisplay extends LwjglContext implements Runnable {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(LwjglDisplay.class.getName());
|
||||
private static final Logger logger = Logger.getLogger(LwjglAbstractDisplay.class.getName());
|
||||
|
||||
protected AtomicBoolean needClose = new AtomicBoolean(false);
|
||||
protected boolean wasActive = false;
|
||||
protected int frameRate = 0;
|
||||
@ -84,6 +81,8 @@ public abstract class LwjglAbstractDisplay extends LwjglContext implements Runna
|
||||
*/
|
||||
protected abstract void createContext(AppSettings settings) throws LWJGLException;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Does LWJGL display initialization in the OpenGL thread
|
||||
*/
|
||||
@ -97,42 +96,22 @@ public abstract class LwjglAbstractDisplay extends LwjglContext implements Runna
|
||||
});
|
||||
}
|
||||
|
||||
// For canvas, this wont happen until its initialized.
|
||||
createContext(settings);
|
||||
// String rendererStr = settings.getString("Renderer");
|
||||
if (renderable.get()) // assumes createContext will set this flag
|
||||
printContextInitInfo();
|
||||
|
||||
logger.info("Display created.");
|
||||
logger.log(Level.FINE, "Running on thread: {0}", Thread.currentThread().getName());
|
||||
|
||||
logger.log(Level.INFO, "Adapter: {0}", Display.getAdapter());
|
||||
logger.log(Level.INFO, "Driver Version: {0}", Display.getVersion());
|
||||
|
||||
String vendor = GL11.glGetString(GL11.GL_VENDOR);
|
||||
logger.log(Level.INFO, "Vendor: {0}", vendor);
|
||||
|
||||
String version = GL11.glGetString(GL11.GL_VERSION);
|
||||
logger.log(Level.INFO, "OpenGL Version: {0}", version);
|
||||
|
||||
String renderer = GL11.glGetString(GL11.GL_RENDERER);
|
||||
logger.log(Level.INFO, "Renderer: {0}", renderer);
|
||||
|
||||
if (GLContext.getCapabilities().OpenGL20){
|
||||
String shadingLang = GL11.glGetString(GL20.GL_SHADING_LANGUAGE_VERSION);
|
||||
logger.log(Level.INFO, "GLSL Ver: {0}", shadingLang);
|
||||
}
|
||||
|
||||
created.set(true);
|
||||
} catch (Exception ex){
|
||||
listener.handleError("Failed to create display", ex);
|
||||
} finally {
|
||||
// TODO: It is possible to avoid "Failed to find pixel format"
|
||||
// error here by creating a default display.
|
||||
|
||||
if (!created.get()){
|
||||
try {
|
||||
if (Display.isCreated())
|
||||
Display.destroy();
|
||||
|
||||
return; // if we failed to create display, do not continue
|
||||
} catch (Exception ex2){
|
||||
logger.log(Level.WARNING, null, ex2);
|
||||
}
|
||||
|
||||
listener.handleError("Failed to create display", ex);
|
||||
return; // if we failed to create display, do not continue
|
||||
}
|
||||
super.internalCreate();
|
||||
listener.initialize();
|
||||
@ -156,26 +135,29 @@ public abstract class LwjglAbstractDisplay extends LwjglContext implements Runna
|
||||
throw new IllegalStateException();
|
||||
|
||||
listener.update();
|
||||
assert checkGLError();
|
||||
|
||||
// calls swap buffers, etc.
|
||||
try {
|
||||
if (autoFlush){
|
||||
Display.update();
|
||||
}else{
|
||||
Display.processMessages();
|
||||
Thread.sleep(50);
|
||||
// add a small wait
|
||||
// to reduce CPU usage
|
||||
if (renderable.get()){
|
||||
assert checkGLError();
|
||||
|
||||
// calls swap buffers, etc.
|
||||
try {
|
||||
if (autoFlush){
|
||||
Display.update();
|
||||
}else{
|
||||
Display.processMessages();
|
||||
Thread.sleep(50);
|
||||
// add a small wait
|
||||
// to reduce CPU usage
|
||||
}
|
||||
} catch (Throwable ex){
|
||||
listener.handleError("Error while swapping buffers", ex);
|
||||
}
|
||||
} catch (Throwable ex){
|
||||
listener.handleError("Error while swapping buffers", ex);
|
||||
}
|
||||
|
||||
if (frameRate > 0)
|
||||
Display.sync(frameRate);
|
||||
|
||||
if (autoFlush)
|
||||
if (renderable.get() && autoFlush)
|
||||
renderer.onFrame();
|
||||
}
|
||||
|
||||
@ -205,16 +187,18 @@ public abstract class LwjglAbstractDisplay extends LwjglContext implements Runna
|
||||
logger.log(Level.INFO, "Using LWJGL {0}", Sys.getVersion());
|
||||
initInThread();
|
||||
while (true){
|
||||
if (Display.isCloseRequested())
|
||||
listener.requestClose(false);
|
||||
if (renderable.get()){
|
||||
if (Display.isCloseRequested())
|
||||
listener.requestClose(false);
|
||||
|
||||
if (wasActive != Display.isActive()){
|
||||
if (!wasActive){
|
||||
listener.gainFocus();
|
||||
wasActive = true;
|
||||
}else{
|
||||
listener.loseFocus();
|
||||
wasActive = false;
|
||||
if (wasActive != Display.isActive()) {
|
||||
if (!wasActive) {
|
||||
listener.gainFocus();
|
||||
wasActive = true;
|
||||
} else {
|
||||
listener.loseFocus();
|
||||
wasActive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -227,15 +211,24 @@ public abstract class LwjglAbstractDisplay extends LwjglContext implements Runna
|
||||
}
|
||||
|
||||
public JoyInput getJoyInput() {
|
||||
return new JInputJoyInput();
|
||||
if (joyInput == null){
|
||||
joyInput = new JInputJoyInput();
|
||||
}
|
||||
return joyInput;
|
||||
}
|
||||
|
||||
public MouseInput getMouseInput() {
|
||||
return new LwjglMouseInput();
|
||||
if (mouseInput == null){
|
||||
mouseInput = new LwjglMouseInput(this);
|
||||
}
|
||||
return mouseInput;
|
||||
}
|
||||
|
||||
public KeyInput getKeyInput() {
|
||||
return new LwjglKeyInput();
|
||||
if (keyInput == null){
|
||||
keyInput = new LwjglKeyInput(this);
|
||||
}
|
||||
return keyInput;
|
||||
}
|
||||
|
||||
public void setAutoFlushFrames(boolean enabled){
|
||||
|
||||
@ -36,6 +36,8 @@ import com.jme3.system.AppSettings;
|
||||
import com.jme3.system.JmeCanvasContext;
|
||||
import com.jme3.system.JmeContext.Type;
|
||||
import java.awt.Canvas;
|
||||
import java.util.concurrent.BrokenBarrierException;
|
||||
import java.util.concurrent.CyclicBarrier;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@ -54,69 +56,68 @@ public class LwjglCanvas extends LwjglAbstractDisplay implements JmeCanvasContex
|
||||
private int width;
|
||||
private int height;
|
||||
|
||||
private AtomicBoolean reinitReq = new AtomicBoolean(false);
|
||||
private final Object reinitReqLock = new Object();
|
||||
|
||||
private AtomicBoolean reinitAuth = new AtomicBoolean(false);
|
||||
private final Object reinitAuthLock = new Object();
|
||||
private final AtomicBoolean needRestoreCanvas = new AtomicBoolean(false);
|
||||
private final AtomicBoolean needDestroyCanvas = new AtomicBoolean(false);
|
||||
private final CyclicBarrier actionRequiredBarrier = new CyclicBarrier(2);
|
||||
|
||||
private Thread renderThread;
|
||||
private boolean runningFirstTime = true;
|
||||
private boolean mouseWasGrabbed = false;
|
||||
// private Pbuffer dummyCtx;
|
||||
private boolean mouseActive, keyboardActive, joyActive;
|
||||
|
||||
public LwjglCanvas(){
|
||||
super();
|
||||
|
||||
canvas = new Canvas(){
|
||||
|
||||
@Override
|
||||
public void addNotify(){
|
||||
super.addNotify();
|
||||
if (renderThread == null || renderThread.getState() == Thread.State.TERMINATED){
|
||||
if (renderThread != null && renderThread.getState() == Thread.State.TERMINATED){
|
||||
logger.log(Level.INFO, "EDT: Creating OGL thread. Was terminated.");
|
||||
}else{
|
||||
logger.log(Level.INFO, "EDT: Creating OGL thread.");
|
||||
}
|
||||
|
||||
if (renderThread != null && renderThread.getState() == Thread.State.TERMINATED)
|
||||
return; // already destroyed.
|
||||
|
||||
if (renderThread == null){
|
||||
logger.log(Level.INFO, "EDT: Creating OGL thread.");
|
||||
|
||||
renderThread = new Thread(LwjglCanvas.this, "LWJGL Renderer Thread");
|
||||
renderThread.start();
|
||||
}else{
|
||||
if (needClose.get())
|
||||
return;
|
||||
|
||||
logger.log(Level.INFO, "EDT: Sending re-init authorization..");
|
||||
|
||||
// reinitializing canvas
|
||||
synchronized (reinitAuthLock){
|
||||
reinitAuth.set(true);
|
||||
reinitAuthLock.notifyAll();
|
||||
}
|
||||
}else if (needClose.get()){
|
||||
return;
|
||||
}
|
||||
|
||||
logger.log(Level.INFO, "EDT: Notifying OGL that canvas is visible..");
|
||||
needRestoreCanvas.set(true);
|
||||
|
||||
// NOTE: no need to wait for OGL to initialize the canvas,
|
||||
// it can happen at any time.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotify(){
|
||||
if (needClose.get()){
|
||||
logger.log(Level.INFO, "EDT: Close requested. Not re-initing.");
|
||||
logger.log(Level.INFO, "EDT: Application is stopped. Not restoring canvas.");
|
||||
super.removeNotify();
|
||||
return;
|
||||
}
|
||||
|
||||
// request to put context into reinit mode
|
||||
// this waits until reinit is authorized
|
||||
logger.log(Level.INFO, "EDT: Sending re-init request..");
|
||||
synchronized (reinitReqLock){
|
||||
reinitReq.set(true);
|
||||
while (reinitReq.get()){
|
||||
try {
|
||||
reinitReqLock.wait();
|
||||
} catch (InterruptedException ex) {
|
||||
logger.log(Level.SEVERE, "EDT: Interrupted! ", ex);
|
||||
}
|
||||
}
|
||||
// NOTE: reinitReq is now false.
|
||||
// We must tell GL context to shutdown and wait for it to
|
||||
// shutdown, otherwise, issues will occur.
|
||||
logger.log(Level.INFO, "EDT: Sending destroy request..");
|
||||
needDestroyCanvas.set(true);
|
||||
try {
|
||||
actionRequiredBarrier.await();
|
||||
} catch (InterruptedException ex) {
|
||||
logger.log(Level.SEVERE, "EDT: Interrupted! ", ex);
|
||||
} catch (BrokenBarrierException ex){
|
||||
logger.log(Level.SEVERE, "EDT: Broken barrier! ", ex);
|
||||
}
|
||||
logger.log(Level.INFO, "EDT: Acknowledged receipt of re-init request!");
|
||||
|
||||
logger.log(Level.INFO, "EDT: Acknowledged receipt of destroy request!");
|
||||
// GL context is dead at this point
|
||||
|
||||
// Reset barrier for future use
|
||||
actionRequiredBarrier.reset();
|
||||
|
||||
super.removeNotify();
|
||||
}
|
||||
};
|
||||
@ -131,6 +132,12 @@ public class LwjglCanvas extends LwjglAbstractDisplay implements JmeCanvasContex
|
||||
}
|
||||
|
||||
public void create(boolean waitFor){
|
||||
if (renderThread == null){
|
||||
logger.log(Level.INFO, "MAIN: Creating OGL thread.");
|
||||
|
||||
renderThread = new Thread(LwjglCanvas.this, "LWJGL Renderer Thread");
|
||||
renderThread.start();
|
||||
}
|
||||
// do not do anything.
|
||||
// superclass's create() will be called at initInThread()
|
||||
if (waitFor)
|
||||
@ -151,106 +158,64 @@ public class LwjglCanvas extends LwjglAbstractDisplay implements JmeCanvasContex
|
||||
|
||||
@Override
|
||||
protected void runLoop(){
|
||||
boolean reinitNeeded;
|
||||
synchronized (reinitReqLock){
|
||||
reinitNeeded = reinitReq.get();
|
||||
if (needDestroyCanvas.getAndSet(false)){
|
||||
// Destroy canvas
|
||||
logger.log(Level.INFO, "OGL: Received destroy request! Complying..");
|
||||
try {
|
||||
listener.loseFocus();
|
||||
pauseCanvas();
|
||||
} finally {
|
||||
try {
|
||||
// Required to avoid deadlock if an exception occurs
|
||||
actionRequiredBarrier.await();
|
||||
} catch (InterruptedException ex) {
|
||||
logger.log(Level.SEVERE, "OGL: Interrupted! ", ex);
|
||||
} catch (BrokenBarrierException ex) {
|
||||
logger.log(Level.SEVERE, "OGL: Broken barrier! ", ex);
|
||||
}
|
||||
}
|
||||
}else if (needRestoreCanvas.getAndSet(false)){
|
||||
// Put canvas back online
|
||||
logger.log(Level.INFO, "OGL: Canvas is now visible! Re-initializing..");
|
||||
restoreCanvas();
|
||||
listener.gainFocus();
|
||||
}
|
||||
|
||||
if (reinitNeeded){
|
||||
logger.log(Level.INFO, "OGL: Re-init request received!");
|
||||
listener.loseFocus();
|
||||
|
||||
boolean mouseActive = Mouse.isCreated();
|
||||
boolean keyboardActive = Keyboard.isCreated();
|
||||
boolean joyActive = Controllers.isCreated();
|
||||
|
||||
if (mouseActive)
|
||||
Mouse.destroy();
|
||||
if (keyboardActive)
|
||||
Keyboard.destroy();
|
||||
if (joyActive)
|
||||
Controllers.destroy();
|
||||
|
||||
pauseCanvas();
|
||||
|
||||
synchronized (reinitReqLock){
|
||||
reinitReq.set(false);
|
||||
reinitReqLock.notifyAll();
|
||||
}
|
||||
|
||||
// we got the reinit request, now we wait for reinit to happen..
|
||||
logger.log(Level.INFO, "OGL: Waiting for re-init authorization..");
|
||||
synchronized (reinitAuthLock){
|
||||
while (!reinitAuth.get()){
|
||||
try {
|
||||
reinitAuthLock.wait();
|
||||
if (Thread.interrupted())
|
||||
throw new InterruptedException();
|
||||
} catch (InterruptedException ex) {
|
||||
if (needClose.get()){
|
||||
logger.log(Level.INFO, "OGL: Re-init aborted. Closing display..");
|
||||
return;
|
||||
}
|
||||
|
||||
logger.log(Level.SEVERE, "OGL: Interrupted! ", ex);
|
||||
}
|
||||
}
|
||||
// NOTE: reinitAuth becamse true, now set it to false.
|
||||
reinitAuth.set(false);
|
||||
}
|
||||
|
||||
logger.log(Level.INFO, "OGL: Re-init authorization received. Re-initializing..");
|
||||
restoreCanvas();
|
||||
|
||||
try {
|
||||
if (mouseActive){
|
||||
Mouse.create();
|
||||
}
|
||||
if (keyboardActive){
|
||||
Keyboard.create();
|
||||
}
|
||||
if (joyActive){
|
||||
Controllers.create();
|
||||
}
|
||||
} catch (LWJGLException ex){
|
||||
listener.handleError("Failed to re-init input", ex);
|
||||
}
|
||||
}
|
||||
if (width != canvas.getWidth() || height != canvas.getHeight()){
|
||||
width = canvas.getWidth();
|
||||
height = canvas.getHeight();
|
||||
if (listener != null)
|
||||
listener.reshape(width, height);
|
||||
}
|
||||
|
||||
super.runLoop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy(boolean waitFor){
|
||||
needClose.set(true);
|
||||
if (renderThread != null && renderThread.isAlive()){
|
||||
renderThread.interrupt();
|
||||
// make sure it really does get interrupted
|
||||
synchronized(reinitAuthLock){
|
||||
reinitAuthLock.notifyAll();
|
||||
}
|
||||
}
|
||||
if (waitFor)
|
||||
waitFor(false);
|
||||
}
|
||||
|
||||
private void pauseCanvas(){
|
||||
if (Mouse.isCreated() && Mouse.isGrabbed()){
|
||||
mouseActive = Mouse.isCreated();
|
||||
keyboardActive = Keyboard.isCreated();
|
||||
joyActive = Controllers.isCreated();
|
||||
|
||||
if (mouseActive && Mouse.isGrabbed()){
|
||||
Mouse.setGrabbed(false);
|
||||
mouseWasGrabbed = true;
|
||||
}
|
||||
|
||||
if (mouseActive)
|
||||
Mouse.destroy();
|
||||
if (keyboardActive)
|
||||
Keyboard.destroy();
|
||||
if (joyActive)
|
||||
Controllers.destroy();
|
||||
|
||||
logger.log(Level.INFO, "OGL: Destroying display (temporarily)");
|
||||
Display.destroy();
|
||||
|
||||
renderable.set(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called if canvas was removed and then restored unexpectedly
|
||||
* Called to restore the canvas.
|
||||
*/
|
||||
private void restoreCanvas(){
|
||||
logger.log(Level.INFO, "OGL: Waiting for canvas to become displayable..");
|
||||
@ -261,8 +226,12 @@ public class LwjglCanvas extends LwjglAbstractDisplay implements JmeCanvasContex
|
||||
logger.log(Level.SEVERE, "OGL: Interrupted! ", ex);
|
||||
}
|
||||
}
|
||||
|
||||
renderer.resetGLObjects();
|
||||
logger.log(Level.INFO, "OGL: Creating display..");
|
||||
|
||||
// Set renderable to true, since canvas is now displayable.
|
||||
renderable.set(true);
|
||||
createContext(settings);
|
||||
|
||||
logger.log(Level.INFO, "OGL: Waiting for display to become active..");
|
||||
@ -276,26 +245,33 @@ public class LwjglCanvas extends LwjglAbstractDisplay implements JmeCanvasContex
|
||||
logger.log(Level.INFO, "OGL: Display is active!");
|
||||
|
||||
try {
|
||||
if (mouseWasGrabbed){
|
||||
if (mouseActive){
|
||||
Mouse.create();
|
||||
Mouse.setGrabbed(true);
|
||||
mouseWasGrabbed = false;
|
||||
}
|
||||
|
||||
SwingUtilities.invokeLater(new Runnable(){
|
||||
public void run(){
|
||||
canvas.requestFocus();
|
||||
if (mouseWasGrabbed){
|
||||
Mouse.setGrabbed(true);
|
||||
mouseWasGrabbed = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (keyboardActive){
|
||||
Keyboard.create();
|
||||
}
|
||||
logger.log(Level.INFO, "OGL: Input has been reinitialized");
|
||||
} catch (LWJGLException ex) {
|
||||
logger.log(Level.SEVERE, "restoreCanvas()", ex);
|
||||
logger.log(Level.SEVERE, "Failed to re-init input", ex);
|
||||
}
|
||||
|
||||
listener.gainFocus();
|
||||
SwingUtilities.invokeLater(new Runnable(){
|
||||
public void run(){
|
||||
canvas.requestFocus();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createContext(AppSettings settings) {
|
||||
if (!renderable.get())
|
||||
return;
|
||||
|
||||
frameRate = settings.getFrameRate();
|
||||
Display.setVSyncEnabled(settings.isVSync());
|
||||
|
||||
@ -308,6 +284,11 @@ public class LwjglCanvas extends LwjglAbstractDisplay implements JmeCanvasContex
|
||||
settings.getSamples());
|
||||
Display.create(pf);
|
||||
Display.makeCurrent();
|
||||
|
||||
if (runningFirstTime){
|
||||
initContextFirstTime();
|
||||
runningFirstTime = false;
|
||||
}
|
||||
}catch (LWJGLException ex){
|
||||
listener.handleError("Failed to parent canvas to display", ex);
|
||||
}
|
||||
|
||||
@ -32,6 +32,9 @@
|
||||
|
||||
package com.jme3.system.lwjgl;
|
||||
|
||||
import com.jme3.input.lwjgl.JInputJoyInput;
|
||||
import com.jme3.input.lwjgl.LwjglKeyInput;
|
||||
import com.jme3.input.lwjgl.LwjglMouseInput;
|
||||
import com.jme3.renderer.Renderer;
|
||||
import com.jme3.renderer.lwjgl.LwjglGL1Renderer;
|
||||
import com.jme3.renderer.lwjgl.LwjglRenderer;
|
||||
@ -40,6 +43,12 @@ import com.jme3.system.SystemListener;
|
||||
import com.jme3.system.JmeContext;
|
||||
import com.jme3.system.Timer;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.lwjgl.opengl.ContextAttribs;
|
||||
import org.lwjgl.opengl.Display;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.opengl.GLContext;
|
||||
|
||||
/**
|
||||
@ -47,11 +56,17 @@ import org.lwjgl.opengl.GLContext;
|
||||
*/
|
||||
public abstract class LwjglContext implements JmeContext {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(LwjglContext.class.getName());
|
||||
|
||||
protected AtomicBoolean created = new AtomicBoolean(false);
|
||||
protected AtomicBoolean renderable = new AtomicBoolean(false);
|
||||
protected final Object createdLock = new Object();
|
||||
|
||||
protected AppSettings settings = new AppSettings(true);
|
||||
protected Renderer renderer;
|
||||
protected LwjglKeyInput keyInput;
|
||||
protected LwjglMouseInput mouseInput;
|
||||
protected JInputJoyInput joyInput;
|
||||
protected Timer timer;
|
||||
protected SystemListener listener;
|
||||
|
||||
@ -59,9 +74,72 @@ public abstract class LwjglContext implements JmeContext {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
protected void printContextInitInfo(){
|
||||
logger.log(Level.FINE, "Running on thread: {0}", Thread.currentThread().getName());
|
||||
|
||||
logger.log(Level.INFO, "Adapter: {0}", Display.getAdapter());
|
||||
logger.log(Level.INFO, "Driver Version: {0}", Display.getVersion());
|
||||
|
||||
String vendor = GL11.glGetString(GL11.GL_VENDOR);
|
||||
logger.log(Level.INFO, "Vendor: {0}", vendor);
|
||||
|
||||
String version = GL11.glGetString(GL11.GL_VERSION);
|
||||
logger.log(Level.INFO, "OpenGL Version: {0}", version);
|
||||
|
||||
String renderGl = GL11.glGetString(GL11.GL_RENDERER);
|
||||
logger.log(Level.INFO, "Renderer: {0}", renderGl);
|
||||
|
||||
if (GLContext.getCapabilities().OpenGL20){
|
||||
String shadingLang = GL11.glGetString(GL20.GL_SHADING_LANGUAGE_VERSION);
|
||||
logger.log(Level.INFO, "GLSL Ver: {0}", shadingLang);
|
||||
}
|
||||
}
|
||||
|
||||
protected ContextAttribs createContextAttribs(){
|
||||
if (settings.getBoolean("GraphicsDebug") || settings.getRenderer().equals(AppSettings.LWJGL_OPENGL3)){
|
||||
ContextAttribs attr;
|
||||
if (settings.getRenderer().equals(AppSettings.LWJGL_OPENGL3)){
|
||||
attr = new ContextAttribs(3, 3);
|
||||
attr = attr.withProfileCore(true).withForwardCompatible(true).withProfileCompatibility(false);
|
||||
}else{
|
||||
attr = new ContextAttribs();
|
||||
}
|
||||
if (settings.getBoolean("GraphicsDebug")){
|
||||
attr = attr.withDebug(true);
|
||||
}
|
||||
return attr;
|
||||
}else{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void initContextFirstTime(){
|
||||
assert renderable.get();
|
||||
|
||||
// Init renderer
|
||||
if (renderer instanceof LwjglRenderer){
|
||||
((LwjglRenderer)renderer).initialize();
|
||||
}else if (renderer instanceof LwjglGL1Renderer){
|
||||
((LwjglGL1Renderer)renderer).initialize();
|
||||
}else{
|
||||
assert false;
|
||||
}
|
||||
|
||||
// Init input
|
||||
if (keyInput != null)
|
||||
keyInput.initialize();
|
||||
|
||||
if (mouseInput != null)
|
||||
mouseInput.initialize();
|
||||
|
||||
if (joyInput != null)
|
||||
joyInput.initialize();
|
||||
}
|
||||
|
||||
public void internalDestroy(){
|
||||
renderer = null;
|
||||
timer = null;
|
||||
renderable.set(false);
|
||||
synchronized (createdLock){
|
||||
created.set(false);
|
||||
createdLock.notifyAll();
|
||||
@ -73,10 +151,8 @@ public abstract class LwjglContext implements JmeContext {
|
||||
if (settings.getRenderer().equals(AppSettings.LWJGL_OPENGL2)
|
||||
|| settings.getRenderer().equals(AppSettings.LWJGL_OPENGL3)){
|
||||
renderer = new LwjglRenderer();
|
||||
((LwjglRenderer)renderer).initialize();
|
||||
}else if (settings.getRenderer().equals(AppSettings.LWJGL_OPENGL1)){
|
||||
renderer = new LwjglGL1Renderer();
|
||||
((LwjglGL1Renderer)renderer).initialize();
|
||||
}else{
|
||||
throw new UnsupportedOperationException("Unsupported renderer: " + settings.getRenderer());
|
||||
}
|
||||
@ -84,6 +160,10 @@ public abstract class LwjglContext implements JmeContext {
|
||||
created.set(true);
|
||||
createdLock.notifyAll();
|
||||
}
|
||||
if (renderable.get())
|
||||
initContextFirstTime();
|
||||
else
|
||||
assert getType() == Type.Canvas;
|
||||
}
|
||||
|
||||
public void create(){
|
||||
@ -108,6 +188,10 @@ public abstract class LwjglContext implements JmeContext {
|
||||
public boolean isCreated(){
|
||||
return created.get();
|
||||
}
|
||||
|
||||
public boolean isRenderable(){
|
||||
return renderable.get();
|
||||
}
|
||||
|
||||
public void setSettings(AppSettings settings) {
|
||||
this.settings.copyFrom(settings);
|
||||
|
||||
@ -47,6 +47,7 @@ import java.util.logging.Logger;
|
||||
import org.lwjgl.opengl.ARBMultisample;
|
||||
import org.lwjgl.opengl.ContextAttribs;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GLContext;
|
||||
import org.lwjgl.opengl.PixelFormat;
|
||||
|
||||
public class LwjglDisplay extends LwjglAbstractDisplay {
|
||||
@ -118,65 +119,21 @@ public class LwjglDisplay extends LwjglAbstractDisplay {
|
||||
Display.setVSyncEnabled(settings.isVSync());
|
||||
|
||||
if (!created.get() || pixelFormatChanged){
|
||||
if (settings.getBoolean("GraphicsDebug") || settings.getRenderer().equals(AppSettings.LWJGL_OPENGL3)){
|
||||
ContextAttribs attr;
|
||||
if (settings.getRenderer().equals(AppSettings.LWJGL_OPENGL3)){
|
||||
attr = new ContextAttribs(3, 3);
|
||||
attr = attr.withProfileCore(true).withForwardCompatible(true).withProfileCompatibility(false);
|
||||
}else{
|
||||
attr = new ContextAttribs();
|
||||
}
|
||||
if (settings.getBoolean("GraphicsDebug")){
|
||||
attr = attr.withDebug(true);
|
||||
}
|
||||
ContextAttribs attr = createContextAttribs();
|
||||
if (attr != null){
|
||||
Display.create(pixelFormat, attr);
|
||||
}else{
|
||||
Display.create(pixelFormat);
|
||||
}
|
||||
renderable.set(true);
|
||||
|
||||
if (pixelFormatChanged && pixelFormat.getSamples() > 1){
|
||||
if (pixelFormatChanged && pixelFormat.getSamples() > 1
|
||||
&& GLContext.getCapabilities().GL_ARB_multisample){
|
||||
GL11.glEnable(ARBMultisample.GL_MULTISAMPLE_ARB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ByteBuffer[] imagesToByteBuffers(BufferedImage[] images) {
|
||||
ByteBuffer[] out = new ByteBuffer[images.length];
|
||||
for (int i = 0; i < images.length; i++) {
|
||||
out[i] = imageToByteBuffer(images[i]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
private ByteBuffer imageToByteBuffer(BufferedImage image) {
|
||||
if (image.getType() != BufferedImage.TYPE_INT_ARGB_PRE) {
|
||||
BufferedImage convertedImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB_PRE);
|
||||
Graphics2D g = convertedImage.createGraphics();
|
||||
double width = image.getWidth() * (double) 1;
|
||||
double height = image.getHeight() * (double) 1;
|
||||
g.drawImage(image, (int) ((convertedImage.getWidth() - width) / 2),
|
||||
(int) ((convertedImage.getHeight() - height) / 2),
|
||||
(int) (width), (int) (height), null);
|
||||
g.dispose();
|
||||
image = convertedImage;
|
||||
}
|
||||
|
||||
byte[] imageBuffer = new byte[image.getWidth() * image.getHeight() * 4];
|
||||
int counter = 0;
|
||||
for (int i = 0; i < image.getHeight(); i++) {
|
||||
for (int j = 0; j < image.getWidth(); j++) {
|
||||
int colorSpace = image.getRGB(j, i);
|
||||
imageBuffer[counter + 0] = (byte) ((colorSpace << 8) >> 24);
|
||||
imageBuffer[counter + 1] = (byte) ((colorSpace << 16) >> 24);
|
||||
imageBuffer[counter + 2] = (byte) ((colorSpace << 24) >> 24);
|
||||
imageBuffer[counter + 3] = (byte) (colorSpace >> 24);
|
||||
counter += 4;
|
||||
}
|
||||
}
|
||||
return ByteBuffer.wrap(imageBuffer);
|
||||
}
|
||||
|
||||
|
||||
public void create(boolean waitFor){
|
||||
if (created.get()){
|
||||
logger.warning("create() called when display is already created!");
|
||||
@ -190,6 +147,7 @@ public class LwjglDisplay extends LwjglAbstractDisplay {
|
||||
|
||||
@Override
|
||||
public void runLoop(){
|
||||
// This method is overriden to do restart
|
||||
if (needRestart.getAndSet(false)){
|
||||
try{
|
||||
createContext(settings);
|
||||
@ -220,5 +178,41 @@ public class LwjglDisplay extends LwjglAbstractDisplay {
|
||||
if (created.get())
|
||||
Display.setTitle(title);
|
||||
}
|
||||
|
||||
private ByteBuffer[] imagesToByteBuffers(BufferedImage[] images) {
|
||||
ByteBuffer[] out = new ByteBuffer[images.length];
|
||||
for (int i = 0; i < images.length; i++) {
|
||||
out[i] = imageToByteBuffer(images[i]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
private ByteBuffer imageToByteBuffer(BufferedImage image) {
|
||||
if (image.getType() != BufferedImage.TYPE_INT_ARGB_PRE) {
|
||||
BufferedImage convertedImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB_PRE);
|
||||
Graphics2D g = convertedImage.createGraphics();
|
||||
double width = image.getWidth() * (double) 1;
|
||||
double height = image.getHeight() * (double) 1;
|
||||
g.drawImage(image, (int) ((convertedImage.getWidth() - width) / 2),
|
||||
(int) ((convertedImage.getHeight() - height) / 2),
|
||||
(int) (width), (int) (height), null);
|
||||
g.dispose();
|
||||
image = convertedImage;
|
||||
}
|
||||
|
||||
byte[] imageBuffer = new byte[image.getWidth() * image.getHeight() * 4];
|
||||
int counter = 0;
|
||||
for (int i = 0; i < image.getHeight(); i++) {
|
||||
for (int j = 0; j < image.getWidth(); j++) {
|
||||
int colorSpace = image.getRGB(j, i);
|
||||
imageBuffer[counter + 0] = (byte) ((colorSpace << 8) >> 24);
|
||||
imageBuffer[counter + 1] = (byte) ((colorSpace << 16) >> 24);
|
||||
imageBuffer[counter + 2] = (byte) ((colorSpace << 24) >> 24);
|
||||
imageBuffer[counter + 3] = (byte) (colorSpace >> 24);
|
||||
counter += 4;
|
||||
}
|
||||
}
|
||||
return ByteBuffer.wrap(imageBuffer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -42,15 +42,11 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.lwjgl.LWJGLException;
|
||||
import org.lwjgl.Sys;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.opengl.GLContext;
|
||||
import org.lwjgl.opengl.OpenGLException;
|
||||
import org.lwjgl.opengl.Pbuffer;
|
||||
import org.lwjgl.opengl.PixelFormat;
|
||||
import org.lwjgl.opengl.Util;
|
||||
|
||||
|
||||
public class LwjglOffscreenBuffer extends LwjglContext implements Runnable {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(LwjglOffscreenBuffer.class.getName());
|
||||
@ -74,6 +70,12 @@ public class LwjglOffscreenBuffer extends LwjglContext implements Runnable {
|
||||
width = settings.getWidth();
|
||||
height = settings.getHeight();
|
||||
try{
|
||||
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
|
||||
public void uncaughtException(Thread thread, Throwable thrown) {
|
||||
listener.handleError("Uncaught exception thrown in "+thread.toString(), thrown);
|
||||
}
|
||||
});
|
||||
|
||||
//String rendererStr = settings.getString("Renderer");
|
||||
// if (rendererStr.startsWith("LWJGL-OpenGL3")){
|
||||
// ContextAttribs attribs;
|
||||
@ -86,35 +88,15 @@ public class LwjglOffscreenBuffer extends LwjglContext implements Runnable {
|
||||
// attribs.withDebug(false);
|
||||
// Display.create(pf, attribs);
|
||||
// }else{
|
||||
pbuffer = new Pbuffer(width, height, pixelFormat, null);
|
||||
pbuffer = new Pbuffer(width, height, pixelFormat, null, null, createContextAttribs());
|
||||
// }
|
||||
|
||||
pbuffer.makeCurrent();
|
||||
|
||||
renderable.set(true);
|
||||
|
||||
logger.info("Offscreen buffer created.");
|
||||
logger.log(Level.FINE, "Running on thread: {0}", Thread.currentThread().getName());
|
||||
|
||||
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
|
||||
public void uncaughtException(Thread thread, Throwable thrown) {
|
||||
listener.handleError("Uncaught exception thrown in "+thread.toString(), thrown);
|
||||
}
|
||||
});
|
||||
|
||||
String vendor = GL11.glGetString(GL11.GL_VENDOR);
|
||||
logger.log(Level.INFO, "Vendor: {0}", vendor);
|
||||
|
||||
String version = GL11.glGetString(GL11.GL_VERSION);
|
||||
logger.log(Level.INFO, "OpenGL Version: {0}", version);
|
||||
|
||||
String renderer = GL11.glGetString(GL11.GL_RENDERER);
|
||||
logger.log(Level.INFO, "Renderer: {0}", renderer);
|
||||
|
||||
if (GLContext.getCapabilities().OpenGL20){
|
||||
String shadingLang = GL11.glGetString(GL20.GL_SHADING_LANGUAGE_VERSION);
|
||||
logger.log(Level.INFO, "GLSL Ver: {0}", shadingLang);
|
||||
}
|
||||
|
||||
created.set(true);
|
||||
printContextInitInfo();
|
||||
} catch (LWJGLException ex){
|
||||
listener.handleError("Failed to create display", ex);
|
||||
} finally {
|
||||
|
||||
@ -14,7 +14,7 @@ import javax.swing.JFrame;
|
||||
|
||||
public class TestSafeCanvas extends SimpleApplication {
|
||||
|
||||
public static void main(String[] args){
|
||||
public static void main(String[] args) throws InterruptedException{
|
||||
AppSettings settings = new AppSettings(true);
|
||||
settings.setWidth(640);
|
||||
settings.setHeight(480);
|
||||
@ -28,6 +28,10 @@ public class TestSafeCanvas extends SimpleApplication {
|
||||
Canvas canvas = context.getCanvas();
|
||||
canvas.setSize(settings.getWidth(), settings.getHeight());
|
||||
|
||||
app.startCanvas(true);
|
||||
|
||||
Thread.sleep(3000);
|
||||
|
||||
JFrame frame = new JFrame("Test");
|
||||
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
|
||||
frame.addWindowListener(new WindowAdapter() {
|
||||
@ -40,6 +44,14 @@ public class TestSafeCanvas extends SimpleApplication {
|
||||
frame.pack();
|
||||
frame.setLocationRelativeTo(null);
|
||||
frame.setVisible(true);
|
||||
|
||||
Thread.sleep(3000);
|
||||
|
||||
frame.getContentPane().remove(canvas);
|
||||
|
||||
Thread.sleep(3000);
|
||||
|
||||
frame.getContentPane().add(canvas);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user