parent
bf7643f06a
commit
8f77dca931
@ -0,0 +1,12 @@ |
||||
if (!hasProperty('mainClass')) { |
||||
ext.mainClass = '' |
||||
} |
||||
|
||||
dependencies { |
||||
compile project(':jme3-core') |
||||
compile project(':jme3-desktop') |
||||
compile 'org.lwjgl:lwjgl:3.0.0b-SNAPSHOT' |
||||
compile group: 'org.lwjgl', name: 'lwjgl-platform', version: '3.0.0b-SNAPSHOT', classifier: 'natives-windows' |
||||
compile group: 'org.lwjgl', name: 'lwjgl-platform', version: '3.0.0b-SNAPSHOT', classifier: 'natives-linux' |
||||
compile group: 'org.lwjgl', name: 'lwjgl-platform', version: '3.0.0b-SNAPSHOT', classifier: 'natives-osx' |
||||
} |
@ -0,0 +1,140 @@ |
||||
/* |
||||
* Copyright (c) 2009-2012 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.audio.lwjgl; |
||||
|
||||
import com.jme3.audio.openal.AL; |
||||
import com.jme3.system.NativeLibraryLoader; |
||||
import com.jme3.system.Platform; |
||||
import org.lwjgl.openal.AL10; |
||||
import org.lwjgl.openal.AL11; |
||||
|
||||
import java.nio.ByteBuffer; |
||||
import java.nio.FloatBuffer; |
||||
import java.nio.IntBuffer; |
||||
|
||||
public final class LwjglAL implements AL { |
||||
|
||||
public LwjglAL() { |
||||
} |
||||
|
||||
public String alGetString(int parameter) { |
||||
return AL10.alGetString(parameter); |
||||
} |
||||
|
||||
public int alGenSources() { |
||||
return AL10.alGenSources(); |
||||
} |
||||
|
||||
public int alGetError() { |
||||
return AL10.alGetError(); |
||||
} |
||||
|
||||
public void alDeleteSources(int numSources, IntBuffer sources) { |
||||
if (sources.position() != 0) throw new AssertionError(); |
||||
if (sources.limit() != numSources) throw new AssertionError(); |
||||
AL10.alDeleteSources(sources); |
||||
} |
||||
|
||||
public void alGenBuffers(int numBuffers, IntBuffer buffers) { |
||||
if (buffers.position() != 0) throw new AssertionError(); |
||||
if (buffers.limit() != numBuffers) throw new AssertionError(); |
||||
AL10.alGenBuffers(buffers); |
||||
} |
||||
|
||||
public void alDeleteBuffers(int numBuffers, IntBuffer buffers) { |
||||
if (buffers.position() != 0) throw new AssertionError(); |
||||
if (buffers.limit() != numBuffers) throw new AssertionError(); |
||||
AL10.alDeleteBuffers(buffers); |
||||
} |
||||
|
||||
public void alSourceStop(int source) { |
||||
AL10.alSourceStop(source); |
||||
} |
||||
|
||||
public void alSourcei(int source, int param, int value) { |
||||
AL10.alSourcei(source, param, value); |
||||
} |
||||
|
||||
public void alBufferData(int buffer, int format, ByteBuffer data, int size, int frequency) { |
||||
if (data.position() != 0) throw new AssertionError(); |
||||
if (data.limit() != size) throw new AssertionError(); |
||||
AL10.alBufferData(buffer, format, data, frequency); |
||||
} |
||||
|
||||
public void alSourcePlay(int source) { |
||||
AL10.alSourcePlay(source); |
||||
} |
||||
|
||||
public void alSourcePause(int source) { |
||||
AL10.alSourcePause(source); |
||||
} |
||||
|
||||
public void alSourcef(int source, int param, float value) { |
||||
AL10.alSourcef(source, param, value); |
||||
} |
||||
|
||||
public void alSource3f(int source, int param, float value1, float value2, float value3) { |
||||
AL10.alSource3f(source, param, value1, value2, value3); |
||||
} |
||||
|
||||
public int alGetSourcei(int source, int param) { |
||||
return AL10.alGetSourcei(source, param); |
||||
} |
||||
|
||||
public void alSourceUnqueueBuffers(int source, int numBuffers, IntBuffer buffers) { |
||||
if (buffers.position() != 0) throw new AssertionError(); |
||||
if (buffers.limit() != numBuffers) throw new AssertionError(); |
||||
AL10.alSourceUnqueueBuffers(source, buffers); |
||||
} |
||||
|
||||
public void alSourceQueueBuffers(int source, int numBuffers, IntBuffer buffers) { |
||||
if (buffers.position() != 0) throw new AssertionError(); |
||||
if (buffers.limit() != numBuffers) throw new AssertionError(); |
||||
AL10.alSourceQueueBuffers(source, buffers); |
||||
} |
||||
|
||||
public void alListener(int param, FloatBuffer data) { |
||||
AL10.alListenerfv(param, data); |
||||
} |
||||
|
||||
public void alListenerf(int param, float value) { |
||||
AL10.alListenerf(param, value); |
||||
} |
||||
|
||||
public void alListener3f(int param, float value1, float value2, float value3) { |
||||
AL10.alListener3f(param, value1, value2, value3); |
||||
} |
||||
|
||||
public void alSource3i(int source, int param, int value1, int value2, int value3) { |
||||
AL11.alSource3i(source, param, value1, value2, value3); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,58 @@ |
||||
package com.jme3.audio.lwjgl; |
||||
|
||||
import com.jme3.audio.openal.ALC; |
||||
import org.lwjgl.openal.ALC10; |
||||
import org.lwjgl.openal.ALContext; |
||||
|
||||
import java.nio.IntBuffer; |
||||
|
||||
import static org.lwjgl.openal.ALC10.alcGetContextsDevice; |
||||
import static org.lwjgl.openal.ALC10.alcGetCurrentContext; |
||||
|
||||
public class LwjglALC implements ALC { |
||||
|
||||
private ALContext context; |
||||
|
||||
public void createALC() { |
||||
context = ALContext.create(); |
||||
} |
||||
|
||||
public void destroyALC() { |
||||
if (context != null) { |
||||
context.destroy(); |
||||
} |
||||
} |
||||
|
||||
public boolean isCreated() { |
||||
return context != null; |
||||
} |
||||
|
||||
public String alcGetString(final int parameter) { |
||||
final long context = alcGetCurrentContext(); |
||||
final long device = alcGetContextsDevice(context); |
||||
return ALC10.alcGetString(device, parameter); |
||||
} |
||||
|
||||
public boolean alcIsExtensionPresent(final String extension) { |
||||
final long context = alcGetCurrentContext(); |
||||
final long device = alcGetContextsDevice(context); |
||||
return ALC10.alcIsExtensionPresent(device, extension); |
||||
} |
||||
|
||||
public void alcGetInteger(final int param, final IntBuffer buffer, final int size) { |
||||
if (buffer.position() != 0) throw new AssertionError(); |
||||
if (buffer.limit() != size) throw new AssertionError(); |
||||
|
||||
final long context = alcGetCurrentContext(); |
||||
final long device = alcGetContextsDevice(context); |
||||
final int value = ALC10.alcGetInteger(device, param); |
||||
//buffer.put(value);
|
||||
} |
||||
|
||||
public void alcDevicePauseSOFT() { |
||||
} |
||||
|
||||
public void alcDeviceResumeSOFT() { |
||||
} |
||||
|
||||
} |
@ -0,0 +1,66 @@ |
||||
package com.jme3.audio.lwjgl; |
||||
|
||||
import com.jme3.audio.openal.EFX; |
||||
import org.lwjgl.openal.EXTEfx; |
||||
|
||||
import java.nio.IntBuffer; |
||||
|
||||
public class LwjglEFX implements EFX { |
||||
|
||||
public void alGenAuxiliaryEffectSlots(int numSlots, IntBuffer buffers) { |
||||
if (buffers.position() != 0) throw new AssertionError(); |
||||
if (buffers.limit() != numSlots) throw new AssertionError(); |
||||
EXTEfx.alGenAuxiliaryEffectSlots(buffers); |
||||
} |
||||
|
||||
public void alGenEffects(int numEffects, IntBuffer buffers) { |
||||
if (buffers.position() != 0) throw new AssertionError(); |
||||
if (buffers.limit() != numEffects) throw new AssertionError(); |
||||
EXTEfx.alGenEffects(buffers); |
||||
} |
||||
|
||||
public void alEffecti(int effect, int param, int value) { |
||||
EXTEfx.alEffecti(effect, param, value); |
||||
} |
||||
|
||||
public void alAuxiliaryEffectSloti(int effectSlot, int param, int value) { |
||||
EXTEfx.alAuxiliaryEffectSloti(effectSlot, param, value); |
||||
} |
||||
|
||||
public void alDeleteEffects(int numEffects, IntBuffer buffers) { |
||||
if (buffers.position() != 0) throw new AssertionError(); |
||||
if (buffers.limit() != numEffects) throw new AssertionError(); |
||||
EXTEfx.alDeleteEffects(buffers); |
||||
} |
||||
|
||||
public void alDeleteAuxiliaryEffectSlots(int numEffectSlots, IntBuffer buffers) { |
||||
if (buffers.position() != 0) throw new AssertionError(); |
||||
if (buffers.limit() != numEffectSlots) throw new AssertionError(); |
||||
EXTEfx.alDeleteAuxiliaryEffectSlots(buffers); |
||||
} |
||||
|
||||
public void alGenFilters(int numFilters, IntBuffer buffers) { |
||||
if (buffers.position() != 0) throw new AssertionError(); |
||||
if (buffers.limit() != numFilters) throw new AssertionError(); |
||||
EXTEfx.alGenFilters(buffers); |
||||
} |
||||
|
||||
public void alFilteri(int filter, int param, int value) { |
||||
EXTEfx.alFilteri(filter, param, value); |
||||
} |
||||
|
||||
public void alFilterf(int filter, int param, float value) { |
||||
EXTEfx.alFilterf(filter, param, value); |
||||
} |
||||
|
||||
public void alDeleteFilters(int numFilters, IntBuffer buffers) { |
||||
if (buffers.position() != 0) throw new AssertionError(); |
||||
if (buffers.limit() != numFilters) throw new AssertionError(); |
||||
EXTEfx.alDeleteFilters(buffers); |
||||
} |
||||
|
||||
public void alEffectf(int effect, int param, float value) { |
||||
EXTEfx.alEffectf(effect, param, value); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,213 @@ |
||||
/* |
||||
* Copyright (c) 2009-2012 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.*; |
||||
import com.jme3.input.event.JoyAxisEvent; |
||||
import com.jme3.input.event.JoyButtonEvent; |
||||
import org.lwjgl.opengl.GL11; |
||||
|
||||
import java.nio.ByteBuffer; |
||||
import java.nio.FloatBuffer; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
import java.util.logging.Logger; |
||||
|
||||
import static org.lwjgl.glfw.GLFW.*; |
||||
|
||||
/** |
||||
* @author Daniel Johansson (dannyjo) |
||||
* @since 3.1 |
||||
*/ |
||||
public class GlfwJoystickInput implements JoyInput { |
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(InputManager.class.getName()); |
||||
|
||||
private boolean initialized = false; |
||||
private RawInputListener listener; |
||||
private Map<Integer, GlfwJoystick> joysticks = new HashMap<Integer, GlfwJoystick>(); |
||||
|
||||
public void setJoyRumble(int joyId, float amount) { |
||||
if (joyId >= joysticks.size()) { |
||||
throw new IllegalArgumentException(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public Joystick[] loadJoysticks(final InputManager inputManager) { |
||||
// TODO: Implement
|
||||
|
||||
for (int i = 0; i < GLFW_JOYSTICK_LAST; i++) { |
||||
if (glfwJoystickPresent(i) == GL11.GL_TRUE) { |
||||
final String name = glfwGetJoystickName(i); |
||||
final GlfwJoystick joystick = new GlfwJoystick(inputManager, this, i, name); |
||||
joysticks.put(i, joystick); |
||||
|
||||
final FloatBuffer floatBuffer = glfwGetJoystickAxes(i); |
||||
|
||||
int axisIndex = 0; |
||||
while (floatBuffer.hasRemaining()) { |
||||
floatBuffer.get(); |
||||
|
||||
final String logicalId = JoystickCompatibilityMappings.remapComponent(joystick.getName(), convertAxisIndex(axisIndex)); |
||||
final JoystickAxis joystickAxis = new DefaultJoystickAxis(inputManager, joystick, axisIndex, convertAxisIndex(axisIndex), logicalId, true, false, 0.0f); |
||||
joystick.addAxis(axisIndex, joystickAxis); |
||||
axisIndex++; |
||||
} |
||||
|
||||
final ByteBuffer byteBuffer = glfwGetJoystickButtons(i); |
||||
|
||||
int buttonIndex = 0; |
||||
while (byteBuffer.hasRemaining()) { |
||||
byteBuffer.get(); |
||||
final String logicalId = JoystickCompatibilityMappings.remapComponent(joystick.getName(), String.valueOf(buttonIndex)); |
||||
joystick.addButton(new DefaultJoystickButton(inputManager, joystick, buttonIndex, String.valueOf(buttonIndex), logicalId)); |
||||
buttonIndex++; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return joysticks.values().toArray(new GlfwJoystick[joysticks.size()]); |
||||
} |
||||
|
||||
private String convertAxisIndex(final int index) { |
||||
if (index == 0) { |
||||
return "pov_x"; |
||||
} else if (index == 1) { |
||||
return "pov_y"; |
||||
} else if (index == 2) { |
||||
return "z"; |
||||
} else if (index == 3) { |
||||
return "rz"; |
||||
} |
||||
|
||||
return String.valueOf(index); |
||||
} |
||||
|
||||
public void initialize() { |
||||
initialized = true; |
||||
} |
||||
|
||||
public void update() { |
||||
for (final Map.Entry<Integer, GlfwJoystick> entry : joysticks.entrySet()) { |
||||
// Axes
|
||||
final FloatBuffer axisValues = glfwGetJoystickAxes(entry.getKey()); |
||||
|
||||
for (final JoystickAxis axis : entry.getValue().getAxes()) { |
||||
final float value = axisValues.get(axis.getAxisId()); |
||||
listener.onJoyAxisEvent(new JoyAxisEvent(axis, value)); |
||||
} |
||||
|
||||
// Buttons
|
||||
final ByteBuffer byteBuffer = glfwGetJoystickButtons(entry.getKey()); |
||||
|
||||
for (final JoystickButton button : entry.getValue().getButtons()) { |
||||
final boolean pressed = byteBuffer.get(button.getButtonId()) == GLFW_PRESS; |
||||
listener.onJoyButtonEvent(new JoyButtonEvent(button, pressed)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public void destroy() { |
||||
initialized = false; |
||||
} |
||||
|
||||
public boolean isInitialized() { |
||||
return initialized; |
||||
} |
||||
|
||||
public void setInputListener(RawInputListener listener) { |
||||
this.listener = listener; |
||||
} |
||||
|
||||
public long getInputTimeNanos() { |
||||
return 0; |
||||
} |
||||
|
||||
protected class GlfwJoystick extends AbstractJoystick { |
||||
|
||||
private JoystickAxis povAxisX; |
||||
private JoystickAxis povAxisY; |
||||
|
||||
public GlfwJoystick(InputManager inputManager, JoyInput joyInput, int joyId, String name) { |
||||
super(inputManager, joyInput, joyId, name); |
||||
} |
||||
|
||||
public void addAxis(final int index, final JoystickAxis axis) { |
||||
super.addAxis(axis); |
||||
|
||||
if (index == 0) { |
||||
povAxisX = axis; |
||||
} else if (index == 1) { |
||||
povAxisY = axis; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
protected void addButton(JoystickButton button) { |
||||
super.addButton(button); |
||||
} |
||||
|
||||
@Override |
||||
public JoystickAxis getXAxis() { |
||||
return povAxisX; |
||||
} |
||||
|
||||
@Override |
||||
public JoystickAxis getYAxis() { |
||||
return povAxisY; |
||||
} |
||||
|
||||
@Override |
||||
public JoystickAxis getPovXAxis() { |
||||
return povAxisX; |
||||
} |
||||
|
||||
@Override |
||||
public JoystickAxis getPovYAxis() { |
||||
return povAxisY; |
||||
} |
||||
|
||||
@Override |
||||
public int getXAxisIndex() { |
||||
return povAxisX.getAxisId(); |
||||
} |
||||
|
||||
@Override |
||||
public int getYAxisIndex() { |
||||
return povAxisY.getAxisId(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
|
@ -0,0 +1,116 @@ |
||||
/* |
||||
* Copyright (c) 2009-2012 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.KeyInput; |
||||
import com.jme3.input.RawInputListener; |
||||
import com.jme3.input.event.KeyInputEvent; |
||||
import com.jme3.system.lwjgl.LwjglTimer; |
||||
import com.jme3.system.lwjgl.LwjglWindow; |
||||
import org.lwjgl.glfw.GLFWKeyCallback; |
||||
|
||||
import java.util.LinkedList; |
||||
import java.util.Queue; |
||||
import java.util.logging.Logger; |
||||
|
||||
import static org.lwjgl.glfw.GLFW.*; |
||||
|
||||
public class LwjglKeyInput implements KeyInput { |
||||
|
||||
private static final Logger logger = Logger.getLogger(LwjglKeyInput.class.getName()); |
||||
|
||||
private LwjglWindow context; |
||||
private RawInputListener listener; |
||||
private boolean initialized; |
||||
private GLFWKeyCallback keyCallback; |
||||
private Queue<KeyInputEvent> keyInputEvents = new LinkedList<KeyInputEvent>(); |
||||
|
||||
public LwjglKeyInput(LwjglWindow context) { |
||||
this.context = context; |
||||
} |
||||
|
||||
public void initialize() { |
||||
if (!context.isRenderable()) { |
||||
return; |
||||
} |
||||
|
||||
glfwSetKeyCallback(context.getWindowHandle(), keyCallback = new GLFWKeyCallback() { |
||||
@Override |
||||
public void invoke(long window, int key, int scancode, int action, int mods) { |
||||
final KeyInputEvent evt = new KeyInputEvent(scancode, (char) key, GLFW_PRESS == action, GLFW_REPEAT == action); |
||||
evt.setTime(getInputTimeNanos()); |
||||
keyInputEvents.add(evt); |
||||
} |
||||
}); |
||||
|
||||
glfwSetInputMode(context.getWindowHandle(), GLFW_STICKY_KEYS, 1); |
||||
|
||||
initialized = true; |
||||
logger.fine("Keyboard created."); |
||||
} |
||||
|
||||
public int getKeyCount() { |
||||
return 0; // TODO: How do we figure this out?
|
||||
} |
||||
|
||||
public void update() { |
||||
if (!context.isRenderable()) { |
||||
return; |
||||
} |
||||
|
||||
while (!keyInputEvents.isEmpty()) { |
||||
listener.onKeyEvent(keyInputEvents.poll()); |
||||
} |
||||
} |
||||
|
||||
public void destroy() { |
||||
if (!context.isRenderable()) { |
||||
return; |
||||
} |
||||
|
||||
keyCallback.release(); |
||||
logger.fine("Keyboard destroyed."); |
||||
} |
||||
|
||||
public boolean isInitialized() { |
||||
return initialized; |
||||
} |
||||
|
||||
public void setInputListener(RawInputListener listener) { |
||||
this.listener = listener; |
||||
} |
||||
|
||||
public long getInputTimeNanos() { |
||||
return (long) (glfwGetTime() * LwjglTimer.LWJGL_TIME_TO_NANOS); |
||||
} |
||||
} |
@ -0,0 +1,189 @@ |
||||
/* |
||||
* Copyright (c) 2009-2012 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.cursors.plugins.JmeCursor; |
||||
import com.jme3.input.MouseInput; |
||||
import com.jme3.input.RawInputListener; |
||||
import com.jme3.input.event.MouseButtonEvent; |
||||
import com.jme3.input.event.MouseMotionEvent; |
||||
import com.jme3.system.lwjgl.LwjglTimer; |
||||
import com.jme3.system.lwjgl.LwjglWindow; |
||||
import org.lwjgl.glfw.GLFWCursorPosCallback; |
||||
import org.lwjgl.glfw.GLFWMouseButtonCallback; |
||||
import org.lwjgl.glfw.GLFWScrollCallback; |
||||
|
||||
import java.nio.ByteBuffer; |
||||
import java.util.LinkedList; |
||||
import java.util.Queue; |
||||
import java.util.logging.Logger; |
||||
|
||||
import static org.lwjgl.glfw.GLFW.*; |
||||
|
||||
public class LwjglMouseInput implements MouseInput { |
||||
|
||||
private static final Logger logger = Logger.getLogger(LwjglMouseInput.class.getName()); |
||||
|
||||
private LwjglWindow context; |
||||
private RawInputListener listener; |
||||
private boolean cursorVisible = true; |
||||
private int mouseX; |
||||
private int mouseY; |
||||
private int mouseWheel; |
||||
private boolean initialized; |
||||
private GLFWCursorPosCallback cursorPosCallback; |
||||
private GLFWScrollCallback scrollCallback; |
||||
private GLFWMouseButtonCallback mouseButtonCallback; |
||||
private Queue<MouseMotionEvent> mouseMotionEvents = new LinkedList<MouseMotionEvent>(); |
||||
private Queue<MouseButtonEvent> mouseButtonEvents = new LinkedList<MouseButtonEvent>(); |
||||
|
||||
public LwjglMouseInput(LwjglWindow context) { |
||||
this.context = context; |
||||
} |
||||
|
||||
public void initialize() { |
||||
glfwSetCursorPosCallback(context.getWindowHandle(), cursorPosCallback = new GLFWCursorPosCallback() { |
||||
@Override |
||||
public void invoke(long window, double xpos, double ypos) { |
||||
int xDelta; |
||||
int yDelta; |
||||
int x = (int) Math.round(xpos); |
||||
int y = (int) Math.round(ypos); |
||||
|
||||
if (mouseX == 0) { |
||||
mouseX = x; |
||||
} |
||||
|
||||
if (mouseY == 0) { |
||||
mouseY = y; |
||||
} |
||||
|
||||
xDelta = x - mouseX; |
||||
yDelta = y - mouseY; |
||||
mouseX = x; |
||||
mouseY = y; |
||||
|
||||
if (xDelta != 0 || yDelta != 0) { |
||||
final MouseMotionEvent mouseMotionEvent = new MouseMotionEvent(x, y * -1, xDelta, yDelta * -1, mouseWheel, 0); |
||||
mouseMotionEvent.setTime(getInputTimeNanos()); |
||||
mouseMotionEvents.add(mouseMotionEvent); |
||||
} |
||||
} |
||||
}); |
||||
|
||||
glfwSetScrollCallback(context.getWindowHandle(), scrollCallback = new GLFWScrollCallback() { |
||||
@Override |
||||
public void invoke(final long window, final double xOffset, final double yOffset) { |
||||
mouseWheel += yOffset; |
||||
|
||||
final MouseMotionEvent mouseMotionEvent = new MouseMotionEvent(mouseX, mouseY, 0, 0, mouseWheel, (int) Math.round(yOffset)); |
||||
mouseMotionEvent.setTime(getInputTimeNanos()); |
||||
mouseMotionEvents.add(mouseMotionEvent); |
||||
} |
||||
}); |
||||
|
||||
glfwSetMouseButtonCallback(context.getWindowHandle(), mouseButtonCallback = new GLFWMouseButtonCallback() { |
||||
@Override |
||||
public void invoke(final long window, final int button, final int action, final int mods) { |
||||
final MouseButtonEvent mouseButtonEvent = new MouseButtonEvent(button, action == GLFW_PRESS, mouseX, mouseY); |
||||
mouseButtonEvent.setTime(getInputTimeNanos()); |
||||
mouseButtonEvents.add(mouseButtonEvent); |
||||
} |
||||
}); |
||||
|
||||
setCursorVisible(cursorVisible); |
||||
logger.fine("Mouse created."); |
||||
initialized = true; |
||||
} |
||||
|
||||
public boolean isInitialized() { |
||||
return initialized; |
||||
} |
||||
|
||||
public int getButtonCount() { |
||||
return 2; // TODO: How to determine this?
|
||||
} |
||||
|
||||
public void update() { |
||||
while (!mouseMotionEvents.isEmpty()) { |
||||
listener.onMouseMotionEvent(mouseMotionEvents.poll()); |
||||
} |
||||
|
||||
while (!mouseButtonEvents.isEmpty()) { |
||||
listener.onMouseButtonEvent(mouseButtonEvents.poll()); |
||||
} |
||||
} |
||||
|
||||
public void destroy() { |
||||
if (!context.isRenderable()) { |
||||
return; |
||||
} |
||||
|
||||
cursorPosCallback.release(); |
||||
scrollCallback.release(); |
||||
mouseButtonCallback.release(); |
||||
|
||||
logger.fine("Mouse destroyed."); |
||||
} |
||||
|
||||
public void setCursorVisible(boolean visible) { |
||||
cursorVisible = visible; |
||||
|
||||
if (!context.isRenderable()) { |
||||
return; |
||||
} |
||||
|
||||
if (cursorVisible) { |
||||
glfwSetInputMode(context.getWindowHandle(), GLFW_CURSOR, GLFW_CURSOR_NORMAL); |
||||
} else { |
||||
glfwSetInputMode(context.getWindowHandle(), GLFW_CURSOR, GLFW_CURSOR_DISABLED); |
||||
} |
||||
} |
||||
|
||||
public void setInputListener(RawInputListener listener) { |
||||
this.listener = listener; |
||||
} |
||||
|
||||
public long getInputTimeNanos() { |
||||
return (long) (glfwGetTime() * LwjglTimer.LWJGL_TIME_TO_NANOS); |
||||
} |
||||
|
||||
public void setNativeCursor(final JmeCursor jmeCursor) { |
||||
if (jmeCursor != null) { |
||||
final ByteBuffer byteBuffer = org.lwjgl.BufferUtils.createByteBuffer(jmeCursor.getImagesData().capacity()); |
||||
byteBuffer.asIntBuffer().put(jmeCursor.getImagesData().array()); |
||||
final long cursor = glfwCreateCursor(byteBuffer, jmeCursor.getXHotSpot(), jmeCursor.getYHotSpot()); |
||||
glfwSetCursor(context.getWindowHandle(), cursor); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,458 @@ |
||||
package com.jme3.renderer.lwjgl; |
||||
|
||||
import com.jme3.renderer.RendererException; |
||||
import com.jme3.renderer.opengl.GL; |
||||
import com.jme3.renderer.opengl.GL2; |
||||
import com.jme3.renderer.opengl.GL3; |
||||
import com.jme3.renderer.opengl.GL4; |
||||
import com.jme3.system.NativeLibraryLoader; |
||||
import com.jme3.system.Platform; |
||||
import org.lwjgl.opengl.*; |
||||
|
||||
import java.nio.*; |
||||
|
||||
public class LwjglGL implements GL, GL2, GL3, GL4 { |
||||
|
||||
private static void checkLimit(Buffer buffer) { |
||||
if (buffer == null) { |
||||
return; |
||||
} |
||||
if (buffer.limit() == 0) { |
||||
throw new RendererException("Attempting to upload empty buffer (limit = 0), that's an error"); |
||||
} |
||||
if (buffer.remaining() == 0) { |
||||
throw new RendererException("Attempting to upload empty buffer (remaining = 0), that's an error"); |
||||
} |
||||
} |
||||
|
||||
public void resetStats() { |
||||
} |
||||
|
||||
public void glActiveTexture(int param1) { |
||||
GL13.glActiveTexture(param1); |
||||
} |
||||
|
||||
public void glAlphaFunc(int param1, float param2) { |
||||
GL11.glAlphaFunc(param1, param2); |
||||
} |
||||
|
||||
public void glAttachShader(int param1, int param2) { |
||||
GL20.glAttachShader(param1, param2); |
||||
} |
||||
|
||||
public void glBindBuffer(int param1, int param2) { |
||||
GL15.glBindBuffer(param1, param2); |
||||
} |
||||
|
||||
public void glBindTexture(int param1, int param2) { |
||||
GL11.glBindTexture(param1, param2); |
||||
} |
||||
|
||||
public void glBlendFunc(int param1, int param2) { |
||||
GL11.glBlendFunc(param1, param2); |
||||
} |
||||
|
||||
public void glBufferData(int param1, long param2, int param3) { |
||||
GL15.glBufferData(param1, param2, param3); |
||||
} |
||||
|
||||
public void glBufferData(int param1, FloatBuffer param2, int param3) { |
||||
checkLimit(param2); |
||||
GL15.glBufferData(param1, param2, param3); |
||||
} |
||||
|
||||
public void glBufferData(int param1, ShortBuffer param2, int param3) { |
||||
checkLimit(param2); |
||||
GL15.glBufferData(param1, param2, param3); |
||||
} |
||||
|
||||
public void glBufferData(int param1, ByteBuffer param2, int param3) { |
||||
checkLimit(param2); |
||||
GL15.glBufferData(param1, param2, param3); |
||||
} |
||||
|
||||
public void glBufferSubData(int param1, long param2, FloatBuffer param3) { |
||||
checkLimit(param3); |
||||
GL15.glBufferSubData(param1, param2, param3); |
||||
} |
||||
|
||||
public void glBufferSubData(int param1, long param2, ShortBuffer param3) { |
||||
checkLimit(param3); |
||||
GL15.glBufferSubData(param1, param2, param3); |
||||
} |
||||
|
||||
public void glBufferSubData(int param1, long param2, ByteBuffer param3) { |
||||
checkLimit(param3); |
||||
GL15.glBufferSubData(param1, param2, param3); |
||||
} |
||||
|
||||
public void glClear(int param1) { |
||||
GL11.glClear(param1); |
||||
} |
||||
|
||||
public void glClearColor(float param1, float param2, float param3, float param4) { |
||||
GL11.glClearColor(param1, param2, param3, param4); |
||||
} |
||||
|
||||
public void glColorMask(boolean param1, boolean param2, boolean param3, boolean param4) { |
||||
GL11.glColorMask(param1, param2, param3, param4); |
||||
} |
||||
|
||||
public void glCompileShader(int param1) { |
||||
GL20.glCompileShader(param1); |
||||
} |
||||
|
||||
public void glCompressedTexImage2D(int param1, int param2, int param3, int param4, int param5, int param6, ByteBuffer param7) { |
||||
checkLimit(param7); |
||||
GL13.glCompressedTexImage2D(param1, param2, param3, param4, param5, param6, param7); |
||||
} |
||||
|
||||
public void glCompressedTexImage3D(int param1, int param2, int param3, int param4, int param5, int param6, int param7, ByteBuffer param8) { |
||||
checkLimit(param8); |
||||
GL13.glCompressedTexImage3D(param1, param2, param3, param4, param5, param6, param7, param8); |
||||
} |
||||
|
||||
public void glCompressedTexSubImage2D(int param1, int param2, int param3, int param4, int param5, int param6, int param7, ByteBuffer param8) { |
||||
checkLimit(param8); |
||||
GL13.glCompressedTexSubImage2D(param1, param2, param3, param4, param5, param6, param7, param8); |
||||
} |
||||
|
||||
public void glCompressedTexSubImage3D(int param1, int param2, int param3, int param4, int param5, int param6, int param7, int param8, int param9, ByteBuffer param10) { |
||||
checkLimit(param10); |
||||
GL13.glCompressedTexSubImage3D(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10); |
||||
} |
||||
|
||||
public int glCreateProgram() { |
||||
return GL20.glCreateProgram(); |
||||
} |
||||
|
||||
public int glCreateShader(int param1) { |
||||
return GL20.glCreateShader(param1); |
||||
} |
||||
|
||||
public void glCullFace(int param1) { |
||||
GL11.glCullFace(param1); |
||||
} |
||||
|
||||
public void glDeleteBuffers(IntBuffer param1) { |
||||
checkLimit(param1); |
||||
GL15.glDeleteBuffers(param1); |
||||
} |
||||
|
||||
public void glDeleteProgram(int param1) { |
||||
GL20.glDeleteProgram(param1); |
||||
} |
||||
|
||||
public void glDeleteShader(int param1) { |
||||
GL20.glDeleteShader(param1); |
||||
} |
||||
|
||||
public void glDeleteTextures(IntBuffer param1) { |
||||
checkLimit(param1); |
||||
GL11.glDeleteTextures(param1); |
||||
} |
||||
|
||||
public void glDepthFunc(int param1) { |
||||
GL11.glDepthFunc(param1); |
||||
} |
||||
|
||||
public void glDepthMask(boolean param1) { |
||||
GL11.glDepthMask(param1); |
||||
} |
||||
|
||||
public void glDepthRange(double param1, double param2) { |
||||
GL11.glDepthRange(param1, param2); |
||||
} |
||||
|
||||
public void glDetachShader(int param1, int param2) { |
||||
GL20.glDetachShader(param1, param2); |
||||
} |
||||
|
||||
public void glDisable(int param1) { |
||||
GL11.glDisable(param1); |
||||
} |
||||
|
||||
public void glDisableVertexAttribArray(int param1) { |
||||
GL20.glDisableVertexAttribArray(param1); |
||||
} |
||||
|
||||
public void glDrawArrays(int param1, int param2, int param3) { |
||||
GL11.glDrawArrays(param1, param2, param3); |
||||
} |
||||
|
||||
public void glDrawBuffer(int param1) { |
||||
GL11.glDrawBuffer(param1); |
||||
} |
||||
|
||||
public void glDrawRangeElements(int param1, int param2, int param3, int param4, int param5, long param6) { |
||||
GL12.glDrawRangeElements(param1, param2, param3, param4, param5, param6); |
||||
} |
||||
|
||||
public void glEnable(int param1) { |
||||
GL11.glEnable(param1); |
||||
} |
||||
|
||||
public void glEnableVertexAttribArray(int param1) { |
||||
GL20.glEnableVertexAttribArray(param1); |
||||
} |
||||
|
||||
public void glGenBuffers(IntBuffer param1) { |
||||
checkLimit(param1); |
||||
GL15.glGenBuffers(param1); |
||||
} |
||||
|
||||
public void glGenTextures(IntBuffer param1) { |
||||
checkLimit(param1); |
||||
GL11.glGenTextures(param1); |
||||
} |
||||
|
||||
public void glGetBoolean(int param1, ByteBuffer param2) { |
||||
checkLimit(param2); |
||||
GL11.glGetBooleanv(param1, param2); |
||||
} |
||||
|
||||
public void glGetBufferSubData(int target, long offset, ByteBuffer data) { |
||||
checkLimit(data); |
||||
GL15.glGetBufferSubData(target, offset, data); |
||||
} |
||||
|
||||
public int glGetError() { |
||||
return GL11.glGetError(); |
||||
} |
||||
|
||||
public void glGetInteger(int param1, IntBuffer param2) { |
||||
checkLimit(param2); |
||||
GL11.glGetIntegerv(param1, param2); |
||||
} |
||||
|
||||
public void glGetProgram(int param1, int param2, IntBuffer param3) { |
||||
checkLimit(param3); |
||||
GL20.glGetProgramiv(param1, param2, param3); |
||||
} |
||||
|
||||
public void glGetShader(int param1, int param2, IntBuffer param3) { |
||||
checkLimit(param3); |
||||
GL20.glGetShaderiv(param1, param2, param3); |
||||
} |
||||
|
||||
public String glGetString(int param1) { |
||||
return GL11.glGetString(param1); |
||||
} |
||||
|
||||
public String glGetString(int param1, int param2) { |
||||
return GL30.glGetStringi(param1, param2); |
||||
} |
||||
|
||||
public boolean glIsEnabled(int param1) { |
||||
return GL11.glIsEnabled(param1); |
||||
} |
||||
|
||||
public void glLineWidth(float param1) { |
||||
GL11.glLineWidth(param1); |
||||
} |
||||
|
||||
public void glLinkProgram(int param1) { |
||||
GL20.glLinkProgram(param1); |
||||
} |
||||
|
||||
public void glPixelStorei(int param1, int param2) { |
||||
GL11.glPixelStorei(param1, param2); |
||||
} |
||||
|
||||
public void glPointSize(float param1) { |
||||
GL11.glPointSize(param1); |
||||
} |
||||
|
||||
public void glPolygonMode(int param1, int param2) { |
||||
GL11.glPolygonMode(param1, param2); |
||||
} |
||||
|
||||
public void glPolygonOffset(float param1, float param2) { |
||||
GL11.glPolygonOffset(param1, param2); |
||||
} |
||||
|
||||
public void glReadBuffer(int param1) { |
||||
GL11.glReadBuffer(param1); |
||||
} |
||||
|
||||
public void glReadPixels(int param1, int param2, int param3, int param4, int param5, int param6, ByteBuffer param7) { |
||||
checkLimit(param7); |
||||
GL11.glReadPixels(param1, param2, param3, param4, param5, param6, param7); |
||||
} |
||||
|
||||
public void glReadPixels(int param1, int param2, int param3, int param4, int param5, int param6, long param7) { |
||||
GL11.glReadPixels(param1, param2, param3, param4, param5, param6, param7); |
||||
} |
||||
|
||||
public void glScissor(int param1, int param2, int param3, int param4) { |
||||
GL11.glScissor(param1, param2, param3, param4); |
||||
} |
||||
|
||||
public void glStencilFuncSeparate(int param1, int param2, int param3, int param4) { |
||||
GL20.glStencilFuncSeparate(param1, param2, param3, param4); |
||||
} |
||||
|
||||
public void glStencilOpSeparate(int param1, int param2, int param3, int param4) { |
||||
GL20.glStencilOpSeparate(param1, param2, param3, param4); |
||||
} |
||||
|
||||
public void glTexImage2D(int param1, int param2, int param3, int param4, int param5, int param6, int param7, int param8, ByteBuffer param9) { |
||||
checkLimit(param9); |
||||
GL11.glTexImage2D(param1, param2, param3, param4, param5, param6, param7, param8, param9); |
||||
} |
||||
|
||||
public void glTexImage3D(int param1, int param2, int param3, int param4, int param5, int param6, int param7, int param8, int param9, ByteBuffer param10) { |
||||
checkLimit(param10); |
||||
GL12.glTexImage3D(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10); |
||||
} |
||||
|
||||
public void glTexParameterf(int param1, int param2, float param3) { |
||||
GL11.glTexParameterf(param1, param2, param3); |
||||
} |
||||
|
||||
public void glTexParameteri(int param1, int param2, int param3) { |
||||
GL11.glTexParameteri(param1, param2, param3); |
||||
} |
||||
|
||||
public void glTexSubImage2D(int param1, int param2, int param3, int param4, int param5, int param6, int param7, int param8, ByteBuffer param9) { |
||||
checkLimit(param9); |
||||
GL11.glTexSubImage2D(param1, param2, param3, param4, param5, param6, param7, param8, param9); |
||||
} |
||||
|
||||
public void glTexSubImage3D(int param1, int param2, int param3, int param4, int param5, int param6, int param7, int param8, int param9, int param10, ByteBuffer param11) { |
||||
checkLimit(param11); |
||||
GL12.glTexSubImage3D(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11); |
||||
} |
||||
|
||||
public void glUniform1(int param1, FloatBuffer param2) { |
||||
checkLimit(param2); |
||||
GL20.glUniform1fv(param1, param2); |
||||
} |
||||
|
||||
public void glUniform1(int param1, IntBuffer param2) { |
||||
checkLimit(param2); |
||||
GL20.glUniform1iv(param1, param2); |
||||
} |
||||
|
||||
public void glUniform1f(int param1, float param2) { |
||||
GL20.glUniform1f(param1, param2); |
||||
} |
||||
|
||||
public void glUniform1i(int param1, int param2) { |
||||
GL20.glUniform1i(param1, param2); |
||||
} |
||||
|
||||
public void glUniform2(int param1, IntBuffer param2) { |
||||
checkLimit(param2); |
||||
GL20.glUniform2iv(param1, param2); |
||||
} |
||||
|
||||
public void glUniform2(int param1, FloatBuffer param2) { |
||||
checkLimit(param2); |
||||
GL20.glUniform2fv(param1, param2); |
||||
} |
||||
|
||||
public void glUniform2f(int param1, float param2, float param3) { |
||||
GL20.glUniform2f(param1, param2, param3); |
||||
} |
||||
|
||||
public void glUniform3(int param1, IntBuffer param2) { |
||||
checkLimit(param2); |
||||
GL20.glUniform3iv(param1, param2); |
||||
} |
||||
|
||||
public void glUniform3(int param1, FloatBuffer param2) { |
||||
checkLimit(param2); |
||||
GL20.glUniform3fv(param1, param2); |
||||
} |
||||
|
||||
public void glUniform3f(int param1, float param2, float param3, float param4) { |
||||
GL20.glUniform3f(param1, param2, param3, param4); |
||||
} |
||||
|
||||
public void glUniform4(int param1, FloatBuffer param2) { |
||||
checkLimit(param2); |
||||
GL20.glUniform4fv(param1, param2); |
||||
} |
||||
|
||||
public void glUniform4(int param1, IntBuffer param2) { |
||||
checkLimit(param2); |
||||
GL20.glUniform4iv(param1, param2); |
||||
} |
||||
|
||||
public void glUniform4f(int param1, float param2, float param3, float param4, float param5) { |
||||
GL20.glUniform4f(param1, param2, param3, param4, param5); |
||||
} |
||||
|
||||
public void glUniformMatrix3(int param1, boolean param2, FloatBuffer param3) { |
||||
checkLimit(param3); |
||||
GL20.glUniformMatrix3fv(param1, param2, param3); |
||||
} |
||||
|
||||
public void glUniformMatrix4(int param1, boolean param2, FloatBuffer param3) { |
||||
checkLimit(param3); |
||||
GL20.glUniformMatrix4fv(param1, param2, param3); |
||||
} |
||||
|
||||
public void glUseProgram(int param1) { |
||||
GL20.glUseProgram(param1); |
||||
} |
||||
|
||||
public void glVertexAttribPointer(int param1, int param2, int param3, boolean param4, int param5, long param6) { |
||||
GL20.glVertexAttribPointer(param1, param2, param3, param4, param5, param6); |
||||
} |
||||
|
||||
public void glViewport(int param1, int param2, int param3, int param4) { |
||||
GL11.glViewport(param1, param2, param3, param4); |
||||
} |
||||
|
||||
public int glGetAttribLocation(int param1, String param2) { |
||||
// NOTE: LWJGL requires null-terminated strings
|
||||
return GL20.glGetAttribLocation(param1, param2 + "\0"); |
||||
} |
||||
|
||||
public int glGetUniformLocation(int param1, String param2) { |
||||
// NOTE: LWJGL requires null-terminated strings
|
||||
return GL20.glGetUniformLocation(param1, param2 + "\0"); |
||||
} |
||||
|
||||
public void glShaderSource(int param1, String[] param2, IntBuffer param3) { |
||||
checkLimit(param3); |
||||
GL20.glShaderSource(param1, param2); |
||||
} |
||||
|
||||
public String glGetProgramInfoLog(int program, int maxSize) { |
||||
return GL20.glGetProgramInfoLog(program, maxSize); |
||||
} |
||||
|
||||
public String glGetShaderInfoLog(int shader, int maxSize) { |
||||
return GL20.glGetShaderInfoLog(shader, maxSize); |
||||
} |
||||
|
||||
@Override |
||||
public void glBindFragDataLocation(int param1, int param2, String param3) { |
||||
GL30.glBindFragDataLocation(param1, param2, param3); |
||||
} |
||||
|
||||
@Override |
||||
public void glBindVertexArray(int param1) { |
||||
GL30.glBindVertexArray(param1); |
||||
} |
||||
|
||||
@Override |
||||
public void glGenVertexArrays(IntBuffer param1) { |
||||
checkLimit(param1); |
||||
GL30.glGenVertexArrays(param1); |
||||
} |
||||
|
||||
@Override |
||||
public void glPatchParameter(int count) { |
||||
GL40.glPatchParameteri(GL40.GL_PATCH_VERTICES,count); |
||||
} |
||||
|
||||
@Override |
||||
public void glDeleteVertexArrays(IntBuffer arrays) { |
||||
checkLimit(arrays); |
||||
ARBVertexArrayObject.glDeleteVertexArrays(arrays); |
||||
} |
||||
} |
@ -0,0 +1,83 @@ |
||||
package com.jme3.renderer.lwjgl; |
||||
|
||||
import com.jme3.renderer.RendererException; |
||||
import com.jme3.renderer.opengl.GLExt; |
||||
import org.lwjgl.opengl.*; |
||||
|
||||
import java.nio.Buffer; |
||||
import java.nio.FloatBuffer; |
||||
import java.nio.IntBuffer; |
||||
|
||||
public class LwjglGLExt implements GLExt { |
||||
|
||||
private static void checkLimit(Buffer buffer) { |
||||
if (buffer == null) { |
||||
return; |
||||
} |
||||
if (buffer.limit() == 0) { |
||||
throw new RendererException("Attempting to upload empty buffer (limit = 0), that's an error"); |
||||
} |
||||
if (buffer.remaining() == 0) { |
||||
throw new RendererException("Attempting to upload empty buffer (remaining = 0), that's an error"); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void glBufferData(int target, IntBuffer data, int usage) { |
||||
checkLimit(data); |
||||
GL15.glBufferData(target, data, usage); |
||||
} |
||||
|
||||
@Override |
||||
public void glBufferSubData(int target, long offset, IntBuffer data) { |
||||
checkLimit(data); |
||||
GL15.glBufferSubData(target, offset, data); |
||||
} |
||||
|
||||
@Override |
||||
public void glDrawArraysInstancedARB(int mode, int first, int count, int primcount) { |
||||
ARBDrawInstanced.glDrawArraysInstancedARB(mode, first, count, primcount); |
||||
} |
||||
|
||||
@Override |
||||
public void glDrawBuffers(IntBuffer bufs) { |
||||
checkLimit(bufs); |
||||
GL20.glDrawBuffers(bufs); |
||||
} |
||||
|
||||
@Override |
||||
public void glDrawElementsInstancedARB(int mode, int indices_count, int type, long indices_buffer_offset, int primcount) { |
||||
ARBDrawInstanced.glDrawElementsInstancedARB(mode, indices_count, type, indices_buffer_offset, primcount); |
||||
} |
||||
|
||||
@Override |
||||
public void glGetMultisample(int pname, int index, FloatBuffer val) { |
||||
checkLimit(val); |
||||
ARBTextureMultisample.glGetMultisamplefv(pname, index, val); |
||||
} |
||||
|
||||
@Override |
||||
public void glTexImage2DMultisample(int target, int samples, int internalformat, int width, int height, boolean fixedsamplelocations) { |
||||
ARBTextureMultisample.glTexImage2DMultisample(target, samples, internalformat, width, height, fixedsamplelocations); |
||||
} |
||||
|
||||
@Override |
||||
public void glVertexAttribDivisorARB(int index, int divisor) { |
||||
ARBInstancedArrays.glVertexAttribDivisorARB(index, divisor); |
||||
} |
||||
|
||||
@Override |
||||
public Object glFenceSync(int condition, int flags) { |
||||
return ARBSync.glFenceSync(condition, flags); |
||||
} |
||||
|
||||
@Override |
||||
public int glClientWaitSync(final Object sync, final int flags, final long timeout) { |
||||
return ARBSync.glClientWaitSync((Long) sync, flags, timeout); |
||||
} |
||||
|
||||
@Override |
||||
public void glDeleteSync(final Object sync) { |
||||
ARBSync.glDeleteSync((Long) sync); |
||||
} |
||||
} |
@ -0,0 +1,99 @@ |
||||
package com.jme3.renderer.lwjgl; |
||||
|
||||
import com.jme3.renderer.RendererException; |
||||
import com.jme3.renderer.opengl.GLFbo; |
||||
import org.lwjgl.opengl.EXTFramebufferBlit; |
||||
import org.lwjgl.opengl.EXTFramebufferMultisample; |
||||
import org.lwjgl.opengl.EXTFramebufferObject; |
||||
|
||||
import java.nio.Buffer; |
||||
import java.nio.IntBuffer; |
||||
|
||||
/** |
||||
* Implements GLFbo via GL_EXT_framebuffer_object. |
||||
* |
||||
* @author Kirill Vainer |
||||
*/ |
||||
public class LwjglGLFboEXT implements GLFbo { |
||||
|
||||
private static void checkLimit(Buffer buffer) { |
||||
if (buffer == null) { |
||||
return; |
||||
} |
||||
if (buffer.limit() == 0) { |
||||
throw new RendererException("Attempting to upload empty buffer (limit = 0), that's an error"); |
||||
} |
||||
if (buffer.remaining() == 0) { |
||||
throw new RendererException("Attempting to upload empty buffer (remaining = 0), that's an error"); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void glBlitFramebufferEXT(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, int mask, int filter) { |
||||
EXTFramebufferBlit.glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); |
||||
} |
||||
|
||||
@Override |
||||
public void glRenderbufferStorageMultisampleEXT(int target, int samples, int internalformat, int width, int height) { |
||||
EXTFramebufferMultisample.glRenderbufferStorageMultisampleEXT(target, samples, internalformat, width, height); |
||||
} |
||||
|
||||
@Override |
||||
public void glBindFramebufferEXT(int param1, int param2) { |
||||
EXTFramebufferObject.glBindFramebufferEXT(param1, param2); |
||||
} |
||||
|
||||
@Override |
||||
public void glBindRenderbufferEXT(int param1, int param2) { |
||||
EXTFramebufferObject.glBindRenderbufferEXT(param1, param2); |
||||
} |
||||
|
||||
@Override |
||||
public int glCheckFramebufferStatusEXT(int param1) { |
||||
return EXTFramebufferObject.glCheckFramebufferStatusEXT(param1); |
||||
} |
||||
|
||||
@Override |
||||
public void glDeleteFramebuffersEXT(IntBuffer param1) { |
||||
checkLimit(param1); |
||||
EXTFramebufferObject.glDeleteFramebuffersEXT(param1); |
||||
} |
||||
|
||||
@Override |
||||
public void glDeleteRenderbuffersEXT(IntBuffer param1) { |
||||
checkLimit(param1); |
||||
EXTFramebufferObject.glDeleteRenderbuffersEXT(param1); |
||||
} |
||||
|
||||
@Override |
||||
public void glFramebufferRenderbufferEXT(int param1, int param2, int param3, int param4) { |
||||
EXTFramebufferObject.glFramebufferRenderbufferEXT(param1, param2, param3, param4); |
||||
} |
||||
|
||||
@Override |
||||
public void glFramebufferTexture2DEXT(int param1, int param2, int param3, int param4, int param5) { |
||||
EXTFramebufferObject.glFramebufferTexture2DEXT(param1, param2, param3, param4, param5); |
||||
} |
||||
|
||||
@Override |
||||
public void glGenFramebuffersEXT(IntBuffer param1) { |
||||
checkLimit(param1); |
||||
EXTFramebufferObject.glGenFramebuffersEXT(param1); |
||||
} |
||||
|
||||
@Override |
||||
public void glGenRenderbuffersEXT(IntBuffer param1) { |
||||
checkLimit(param1); |
||||
EXTFramebufferObject.glGenRenderbuffersEXT(param1); |
||||
} |
||||
|
||||
@Override |
||||
public void glGenerateMipmapEXT(int param1) { |
||||
EXTFramebufferObject.glGenerateMipmapEXT(param1); |
||||
} |
||||
|
||||
@Override |
||||
public void glRenderbufferStorageEXT(int param1, int param2, int param3, int param4) { |
||||
EXTFramebufferObject.glRenderbufferStorageEXT(param1, param2, param3, param4); |
||||
} |
||||
} |
@ -0,0 +1,97 @@ |
||||
package com.jme3.renderer.lwjgl; |
||||
|
||||
import com.jme3.renderer.RendererException; |
||||
import com.jme3.renderer.opengl.GLFbo; |
||||
import org.lwjgl.opengl.GL30; |
||||
|
||||
import java.nio.Buffer; |
||||
import java.nio.IntBuffer; |
||||
|
||||
/** |
||||
* Implements GLFbo via OpenGL3+. |
||||
* |
||||
* @author Kirill Vainer |
||||
*/ |
||||
public class LwjglGLFboGL3 implements GLFbo { |
||||
|
||||
private static void checkLimit(Buffer buffer) { |
||||
if (buffer == null) { |
||||
return; |
||||
} |
||||
if (buffer.limit() == 0) { |
||||
throw new RendererException("Attempting to upload empty buffer (limit = 0), that's an error"); |
||||
} |
||||
if (buffer.remaining() == 0) { |
||||
throw new RendererException("Attempting to upload empty buffer (remaining = 0), that's an error"); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void glBlitFramebufferEXT(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, int mask, int filter) { |
||||
GL30.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); |
||||
} |
||||
|
||||
@Override |
||||
public void glRenderbufferStorageMultisampleEXT(int target, int samples, int internalformat, int width, int height) { |
||||
GL30.glRenderbufferStorageMultisample(target, samples, internalformat, width, height); |
||||
} |
||||
|
||||
@Override |
||||
public void glBindFramebufferEXT(int param1, int param2) { |
||||
GL30.glBindFramebuffer(param1, param2); |
||||
} |
||||
|
||||
@Override |
||||
public void glBindRenderbufferEXT(int param1, int param2) { |
||||
GL30.glBindRenderbuffer(param1, param2); |
||||
} |
||||
|
||||
@Override |
||||
public int glCheckFramebufferStatusEXT(int param1) { |
||||
return GL30.glCheckFramebufferStatus(param1); |
||||
} |
||||
|
||||
@Override |
||||
public void glDeleteFramebuffersEXT(IntBuffer param1) { |
||||
checkLimit(param1); |
||||
GL30.glDeleteFramebuffers(param1); |
||||
} |
||||
|
||||
@Override |
||||
public void glDeleteRenderbuffersEXT(IntBuffer param1) { |
||||
checkLimit(param1); |
||||
GL30.glDeleteRenderbuffers(param1); |
||||
} |
||||
|
||||
@Override |
||||
public void glFramebufferRenderbufferEXT(int param1, int param2, int param3, int param4) { |
||||
GL30.glFramebufferRenderbuffer(param1, param2, param3, param4); |
||||
} |
||||
|
||||
@Override |
||||
public void glFramebufferTexture2DEXT(int param1, int param2, int param3, int param4, int param5) { |
||||
GL30.glFramebufferTexture2D(param1, param2, param3, param4, param5); |
||||
} |
||||
|
||||
@Override |
||||
public void glGenFramebuffersEXT(IntBuffer param1) { |
||||
checkLimit(param1); |
||||
GL30.glGenFramebuffers(param1); |
||||
} |
||||
|
||||
@Override |
||||
public void glGenRenderbuffersEXT(IntBuffer param1) { |
||||
checkLimit(param1); |
||||
GL30.glGenRenderbuffers(param1); |
||||
} |
||||
|
||||
@Override |
||||
public void glGenerateMipmapEXT(int param1) { |
||||
GL30.glGenerateMipmap(param1); |
||||
} |
||||
|
||||
@Override |
||||
public void glRenderbufferStorageEXT(int param1, int param2, int param3, int param4) { |
||||
GL30.glRenderbufferStorage(param1, param2, param3, param4); |
||||
} |
||||
} |
@ -0,0 +1,369 @@ |
||||
/* |
||||
* Copyright (c) 2009-2012 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.system.lwjgl; |
||||
|
||||
import com.jme3.system.AppSettings; |
||||
import com.jme3.system.JmeCanvasContext; |
||||
|
||||
import javax.swing.*; |
||||
import java.awt.*; |
||||
import java.util.logging.Level; |
||||
import java.util.logging.Logger; |
||||
|
||||
import static org.lwjgl.glfw.GLFW.glfwDestroyWindow; |
||||
|
||||
public class LwjglCanvas extends LwjglWindow implements JmeCanvasContext { |
||||
|
||||
protected static final int TASK_NOTHING = 0, |
||||
TASK_DESTROY_DISPLAY = 1, |
||||
TASK_CREATE_DISPLAY = 2, |
||||
TASK_COMPLETE = 3; |
||||
|
||||
// protected static final boolean USE_SHARED_CONTEXT =
|
||||
// Boolean.parseBoolean(System.getProperty("jme3.canvas.sharedctx", "true"));
|
||||
|
||||
protected static final boolean USE_SHARED_CONTEXT = false; |
||||
|
||||
private static final Logger logger = Logger.getLogger(LwjglCanvas.class.getName()); |
||||
private Canvas canvas; |
||||
private int width; |
||||
private int height; |
||||
|
||||
private final Object taskLock = new Object(); |
||||
private int desiredTask = TASK_NOTHING; |
||||
|
||||
private Thread renderThread; |
||||
private boolean runningFirstTime = true; |
||||
private boolean mouseWasGrabbed = false; |
||||
|
||||
private boolean mouseWasCreated = false; |
||||
private boolean keyboardWasCreated = false; |
||||
|
||||
private long window; |
||||
|
||||
private class GLCanvas extends Canvas { |
||||
@Override |
||||
public void addNotify(){ |
||||
super.addNotify(); |
||||
|
||||
if (renderThread != null && renderThread.getState() == Thread.State.TERMINATED) { |
||||
return; // already destroyed.
|
||||
} |
||||
|
||||
if (renderThread == null){ |
||||
logger.log(Level.FINE, "EDT: Creating OGL thread."); |
||||
|
||||
// Also set some settings on the canvas here.
|
||||
// So we don't do it outside the AWT thread.
|
||||
canvas.setFocusable(true); |
||||
canvas.setIgnoreRepaint(true); |
||||
|
||||
renderThread = new Thread(LwjglCanvas.this, THREAD_NAME); |
||||
renderThread.start(); |
||||
}else if (needClose.get()){ |
||||
return; |
||||
} |
||||
|
||||
logger.log(Level.FINE, "EDT: Telling OGL to create display .."); |
||||
synchronized (taskLock){ |
||||
desiredTask = TASK_CREATE_DISPLAY; |
||||
// while (desiredTask != TASK_COMPLETE){
|
||||
// try {
|
||||
// taskLock.wait();
|
||||
// } catch (InterruptedException ex) {
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// desiredTask = TASK_NOTHING;
|
||||
} |
||||
// logger.log(Level.FINE, "EDT: OGL has created the display");
|
||||
} |
||||
|
||||
@Override |
||||
public void removeNotify(){ |
||||
if (needClose.get()){ |
||||
logger.log(Level.FINE, "EDT: Application is stopped. Not restoring canvas."); |
||||
super.removeNotify(); |
||||
return; |
||||
} |
||||
|
||||
// We must tell GL context to shutdown and wait for it to
|
||||
// shutdown, otherwise, issues will occur.
|
||||
logger.log(Level.FINE, "EDT: Telling OGL to destroy display .."); |
||||
synchronized (taskLock){ |
||||
desiredTask = TASK_DESTROY_DISPLAY; |
||||
while (desiredTask != TASK_COMPLETE){ |
||||
try { |
||||
taskLock.wait(); |
||||
} catch (InterruptedException ex){ |
||||
super.removeNotify(); |
||||
return; |
||||
} |
||||
} |
||||
desiredTask = TASK_NOTHING; |
||||
} |
||||
|
||||
logger.log(Level.FINE, "EDT: Acknowledged receipt of canvas death"); |
||||
// GL context is dead at this point
|
||||
|
||||
super.removeNotify(); |
||||
} |
||||
} |
||||
|
||||
public LwjglCanvas(){ |
||||
super(Type.Canvas); |
||||
canvas = new GLCanvas(); |
||||
} |
||||
|
||||
public void create(boolean waitFor){ |
||||
if (renderThread == null){ |
||||
logger.log(Level.FINE, "MAIN: Creating OGL thread."); |
||||
|
||||
renderThread = new Thread(LwjglCanvas.this, THREAD_NAME); |
||||
renderThread.start(); |
||||
} |
||||
// do not do anything.
|
||||
// superclass's create() will be called at initInThread()
|
||||
if (waitFor) { |
||||
waitFor(true); |
||||
} |
||||
} |
||||
|
||||
public Canvas getCanvas(){ |
||||
return canvas; |
||||
} |
||||
|
||||
@Override |
||||
protected void runLoop(){ |
||||
if (desiredTask != TASK_NOTHING){ |
||||
synchronized (taskLock){ |
||||
switch (desiredTask){ |
||||
case TASK_CREATE_DISPLAY: |
||||
logger.log(Level.FINE, "OGL: Creating display .."); |
||||
restoreCanvas(); |
||||
listener.gainFocus(); |
||||
desiredTask = TASK_NOTHING; |
||||
break; |
||||
case TASK_DESTROY_DISPLAY: |
||||
logger.log(Level.FINE, "OGL: Destroying display .."); |
||||
listener.loseFocus(); |
||||
pauseCanvas(); |
||||
break; |
||||
} |
||||
desiredTask = TASK_COMPLETE; |
||||
taskLock.notifyAll(); |
||||
} |
||||
} |
||||
|
||||
if (renderable.get()){ |
||||
int newWidth = Math.max(canvas.getWidth(), 1); |
||||
int newHeight = Math.max(canvas.getHeight(), 1); |
||||
|
||||
if (width != newWidth || height != newHeight){ |
||||
width = newWidth; |
||||
height = newHeight; |
||||
if (listener != null){ |
||||
listener.reshape(width, height); |
||||
} |
||||
} |
||||
} |
||||
|
||||
super.runLoop(); |
||||
} |
||||
|
||||
private void pauseCanvas(){ |
||||
if (mouseInput != null) { |
||||
mouseInput.setCursorVisible(true); |
||||
mouseWasCreated = true; |
||||
} |
||||
|
||||
/* |
||||
if (Mouse.isCreated()){ |
||||
if (Mouse.isGrabbed()){ |
||||
Mouse.setGrabbed(false); |
||||
mouseWasGrabbed = true; |
||||
} |
||||
mouseWasCreated = true; |
||||
Mouse.destroy(); |
||||
} |
||||
if (Keyboard.isCreated()){ |
||||
keyboardWasCreated = true; |
||||
Keyboard.destroy(); |
||||
} |
||||
*/ |
||||
|
||||
renderable.set(false); |
||||
destroyContext(); |
||||
} |
||||
|
||||
/** |
||||
* Called to restore the canvas. |
||||
*/ |
||||
private void restoreCanvas(){ |
||||
logger.log(Level.FINE, "OGL: Waiting for canvas to become displayable.."); |
||||
while (!canvas.isDisplayable()){ |
||||
try { |
||||
Thread.sleep(10); |
||||
} catch (InterruptedException ex) { |
||||
logger.log(Level.SEVERE, "OGL: Interrupted! ", ex); |
||||
} |
||||
} |
||||
|
||||
logger.log(Level.FINE, "OGL: Creating display context .."); |
||||
|
||||
// Set renderable to true, since canvas is now displayable.
|
||||
renderable.set(true); |
||||
createContext(settings); |
||||
|
||||
logger.log(Level.FINE, "OGL: Display is active!"); |
||||
|
||||
try { |
||||
if (mouseWasCreated){ |
||||
// Mouse.create();
|
||||
// if (mouseWasGrabbed){
|
||||
// Mouse.setGrabbed(true);
|
||||
// mouseWasGrabbed = false;
|
||||
// }
|
||||
} |
||||
if (keyboardWasCreated){ |
||||
// Keyboard.create();
|
||||
// keyboardWasCreated = false;
|
||||
} |
||||
} catch (Exception ex){ |
||||
logger.log(Level.SEVERE, "Encountered exception when restoring input", ex); |
||||
} |
||||
|
||||
SwingUtilities.invokeLater(new Runnable(){ |
||||
public void run(){ |
||||
canvas.requestFocus(); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
/* |
||||
*/ |
||||
/** |
||||
* Makes sure the pbuffer is available and ready for use |
||||
*//*
|
||||
|
||||
protected void makePbufferAvailable() throws LWJGLException{ |
||||
if (pbuffer != null && pbuffer.isBufferLost()){ |
||||
logger.log(Level.WARNING, "PBuffer was lost!"); |
||||
pbuffer.destroy(); |
||||
pbuffer = null; |
||||
} |
||||
|
||||
if (pbuffer == null) { |
||||
pbuffer = new Pbuffer(1, 1, acquirePixelFormat(true), null); |
||||
pbuffer.makeCurrent(); |
||||
logger.log(Level.FINE, "OGL: Pbuffer has been created"); |
||||
|
||||
// Any created objects are no longer valid
|
||||
if (!runningFirstTime){ |
||||
renderer.resetGLObjects(); |
||||
} |
||||
} |
||||
|
||||
pbuffer.makeCurrent(); |
||||
if (!pbuffer.isCurrent()){ |
||||
throw new LWJGLException("Pbuffer cannot be made current"); |
||||
} |
||||
} |
||||
|
||||
protected void destroyPbuffer(){ |
||||
if (pbuffer != null){ |
||||
if (!pbuffer.isBufferLost()){ |
||||
pbuffer.destroy(); |
||||
} |
||||
pbuffer = null; |
||||
} |
||||
} |
||||
*/ |
||||
|
||||
/** |
||||
* This is called: |
||||
* 1) When the context thread ends |
||||
* 2) Any time the canvas becomes non-displayable |
||||
*/ |
||||
protected void destroyContext(){ |
||||
// invalidate the state so renderer can resume operation
|
||||
if (!USE_SHARED_CONTEXT){ |
||||
renderer.cleanup(); |
||||
} |
||||
|
||||
if (window != 0) { |
||||
glfwDestroyWindow(window); |
||||
} |
||||
|
||||
// TODO: Destroy input
|
||||
|
||||
|
||||
// The canvas is no longer visible,
|
||||
// but the context thread is still running.
|
||||
if (!needClose.get()){ |
||||
renderer.invalidateState(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* This is called: |
||||
* 1) When the context thread starts |
||||
* 2) Any time the canvas becomes displayable again. |
||||
*/ |
||||
@Override |
||||
protected void createContext(final AppSettings settings) { |
||||
// In case canvas is not visible, we still take framerate
|
||||
// from settings to prevent "100% CPU usage"
|
||||
allowSwapBuffers = settings.isSwapBuffers(); |
||||
|
||||
if (renderable.get()){ |
||||
if (!runningFirstTime){ |
||||
// because the display is a different opengl context
|
||||
// must reset the context state.
|
||||
if (!USE_SHARED_CONTEXT){ |
||||
renderer.cleanup(); |
||||
} |
||||
} |
||||
|
||||
super.createContext(settings); |
||||
} |
||||
|
||||
// At this point, the OpenGL context is active.
|
||||
if (runningFirstTime) { |
||||
// THIS is the part that creates the renderer.
|
||||
// It must always be called, now that we have the pbuffer workaround.
|
||||
initContextFirstTime(); |
||||
runningFirstTime = false; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,289 @@ |
||||
/* |
||||
* Copyright (c) 2009-2012 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.system.lwjgl; |
||||
|
||||
import com.jme3.input.lwjgl.GlfwJoystickInput; |
||||
import com.jme3.input.lwjgl.LwjglKeyInput; |
||||
import com.jme3.input.lwjgl.LwjglMouseInput; |
||||
import com.jme3.renderer.Renderer; |
||||
import com.jme3.renderer.RendererException; |
||||
import com.jme3.renderer.lwjgl.LwjglGL; |
||||
import com.jme3.renderer.lwjgl.LwjglGLExt; |
||||
import com.jme3.renderer.lwjgl.LwjglGLFboEXT; |
||||
import com.jme3.renderer.lwjgl.LwjglGLFboGL3; |
||||
import com.jme3.renderer.opengl.*; |
||||
import com.jme3.renderer.opengl.GL; |
||||
import com.jme3.system.*; |
||||
import org.lwjgl.Sys; |
||||
import org.lwjgl.glfw.GLFW; |
||||
import org.lwjgl.opengl.*; |
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean; |
||||
import java.util.logging.Level; |
||||
import java.util.logging.Logger; |
||||
|
||||
import static org.lwjgl.opengl.GL.createCapabilities; |
||||
import static org.lwjgl.opengl.GL11.GL_TRUE; |
||||
import static org.lwjgl.opengl.GL11.glGetInteger; |
||||
|
||||
/** |
||||
* A LWJGL implementation of a graphics context. |
||||
*/ |
||||
public abstract class LwjglContext implements JmeContext { |
||||
|
||||
private static final Logger logger = Logger.getLogger(LwjglContext.class.getName()); |
||||
|
||||
protected static final String THREAD_NAME = "jME3 Main"; |
||||
|
||||
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 GlfwJoystickInput joyInput; |
||||
protected Timer timer; |
||||
protected SystemListener listener; |
||||
|
||||
public void setSystemListener(SystemListener listener) { |
||||
this.listener = listener; |
||||
} |
||||
|
||||
protected void printContextInitInfo() { |
||||
logger.log(Level.INFO, "LWJGL {0} context running on thread {1}\n" + |
||||
" * Graphics Adapter: GLFW {2}", |
||||
new Object[]{Sys.getVersion(), Thread.currentThread().getName(), GLFW.glfwGetVersionString()}); |
||||
} |
||||
|
||||
protected int determineMaxSamples() { |
||||
// If we already have a valid context, determine samples using current context.
|
||||
if (GLFW.glfwExtensionSupported("GL_ARB_framebuffer_object") == GL_TRUE) { |
||||
return glGetInteger(ARBFramebufferObject.GL_MAX_SAMPLES); |
||||
} else if (GLFW.glfwExtensionSupported("GL_EXT_framebuffer_multisample") == GL_TRUE) { |
||||
return glGetInteger(EXTFramebufferMultisample.GL_MAX_SAMPLES_EXT); |
||||
} |
||||
|
||||
return Integer.MAX_VALUE; |
||||
} |
||||
|
||||
protected void registerNatives() { |
||||
// LWJGL
|
||||
NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows32, "native/windows/lwjgl32.dll"); |
||||
NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows64, "native/windows/lwjgl.dll"); |
||||
NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Linux32, "native/linux/liblwjgl32.so"); |
||||
NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Linux64, "native/linux/liblwjgl.so"); |
||||
NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.MacOSX32, "native/macosx/liblwjgl.dylib"); |
||||
NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.MacOSX64, "native/macosx/liblwjgl.dylib"); |
||||
NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows32, "native/windows/jemalloc32.dll"); |
||||
NativeLibraryLoader.registerNativeLibrary("lwjgl", Platform.Windows64, "native/windows/jemalloc.dll"); |
||||
|
||||
// OpenAL
|
||||
// For OSX: Need to add lib prefix when extracting
|
||||
NativeLibraryLoader.registerNativeLibrary("openal", Platform.Windows32, "native/windows/OpenAL32.dll"); |
||||
NativeLibraryLoader.registerNativeLibrary("openal", Platform.Windows64, "native/windows/OpenAL.dll"); |
||||
NativeLibraryLoader.registerNativeLibrary("openal", Platform.Linux32, "native/linux/libopenal32.so"); |
||||
NativeLibraryLoader.registerNativeLibrary("openal", Platform.Linux64, "native/linux/libopenal.so"); |
||||
NativeLibraryLoader.registerNativeLibrary("openal", Platform.MacOSX32, "native/macosx/openal.dylib", "libopenal.dylib"); |
||||
NativeLibraryLoader.registerNativeLibrary("openal", Platform.MacOSX64, "native/macosx/openal.dylib", "libopenal.dylib"); |
||||
} |
||||
|
||||
protected void loadNatives() { |
||||
if (JmeSystem.isLowPermissions()) { |
||||
return; |
||||
} |
||||
if ("LWJGL".equals(settings.getAudioRenderer())) { |
||||
NativeLibraryLoader.loadNativeLibrary("openal", true); |
||||
} |
||||
if (settings.useJoysticks()) { |
||||
//NativeLibraryLoader.loadNativeLibrary("jinput", true);
|
||||
//NativeLibraryLoader.loadNativeLibrary("jinput-dx8", true);
|
||||
} |
||||
if (NativeLibraryLoader.isUsingNativeBullet()) { |
||||
NativeLibraryLoader.loadNativeLibrary("bulletjme", true); |
||||
} |
||||
NativeLibraryLoader.loadNativeLibrary("lwjgl", true); |
||||
} |
||||
|
||||
protected int getNumSamplesToUse() { |
||||
int samples = 0; |
||||
if (settings.getSamples() > 1) { |
||||
samples = settings.getSamples(); |
||||
final int supportedSamples = determineMaxSamples(); |
||||
if (supportedSamples < samples) { |
||||
logger.log(Level.WARNING, |
||||
"Couldn't satisfy antialiasing samples requirement: x{0}. " |
||||
+ "Video hardware only supports: x{1}", |
||||
new Object[]{samples, supportedSamples}); |
||||
|
||||
samples = supportedSamples; |
||||
} |
||||
} |
||||
return samples; |
||||
} |
||||
|
||||
protected void initContextFirstTime() { |
||||
final GLCapabilities capabilities = createCapabilities(settings.getRenderer().equals(AppSettings.LWJGL_OPENGL3)); |
||||
|
||||
if (!capabilities.OpenGL20) { |
||||
throw new RendererException("OpenGL 2.0 or higher is required for jMonkeyEngine"); |
||||
} |
||||
|
||||
if (settings.getRenderer().equals(AppSettings.LWJGL_OPENGL2) |
||||
|| settings.getRenderer().equals(AppSettings.LWJGL_OPENGL3)) { |
||||
GL gl = new LwjglGL(); |
||||
GLExt glext = new LwjglGLExt(); |
||||
GLFbo glfbo; |
||||
|
||||
if (capabilities.OpenGL30) { |
||||
glfbo = new LwjglGLFboGL3(); |
||||
} else { |
||||
glfbo = new LwjglGLFboEXT(); |
||||
} |
||||
|
||||
if (settings.getBoolean("GraphicsDebug")) { |
||||
gl = new GLDebugDesktop(gl, glext, glfbo); |
||||
glext = (GLExt) gl; |
||||
glfbo = (GLFbo) gl; |
||||
} |
||||
|
||||
if (settings.getBoolean("GraphicsTiming")) { |
||||
GLTimingState timingState = new GLTimingState(); |
||||
gl = (GL) GLTiming.createGLTiming(gl, timingState, GL.class, GL2.class, GL3.class, GL4.class); |
||||
glext = (GLExt) GLTiming.createGLTiming(glext, timingState, GLExt.class); |
||||
glfbo = (GLFbo) GLTiming.createGLTiming(glfbo, timingState, GLFbo.class); |
||||
} |
||||
|
||||
if (settings.getBoolean("GraphicsTrace")) { |
||||
gl = (GL) GLTracer.createDesktopGlTracer(gl, GL.class, GL2.class, GL3.class, GL4.class); |
||||
glext = (GLExt) GLTracer.createDesktopGlTracer(glext, GLExt.class); |
||||
glfbo = (GLFbo) GLTracer.createDesktopGlTracer(glfbo, GLFbo.class); |
||||
} |
||||
|
||||
renderer = new GLRenderer(gl, glext, glfbo); |
||||
renderer.initialize(); |
||||
} else { |
||||
throw new UnsupportedOperationException("Unsupported renderer: " + settings.getRenderer()); |
||||
} |
||||
|
||||
if (capabilities.GL_ARB_debug_output && settings.getBoolean("GraphicsDebug")) { |
||||
ARBDebugOutput.glDebugMessageCallbackARB(new LwjglGLDebugOutputHandler(), 0); // User param is zero. Not sure what we could use that for.
|
||||
} |
||||
|
||||
renderer.setMainFrameBufferSrgb(settings.getGammaCorrection()); |
||||
renderer.setLinearizeSrgbImages(settings.getGammaCorrection()); |
||||
|
||||
// Init input
|
||||
if (keyInput != null) { |
||||
keyInput.initialize(); |
||||
} |
||||
|
||||
if (mouseInput != null) { |
||||
mouseInput.initialize(); |
||||
} |
||||
|
||||
if (joyInput != null) { |
||||
joyInput.initialize(); |
||||
} |
||||
|
||||
renderable.set(true); |
||||
} |
||||
|
||||
public void internalDestroy() { |
||||
renderer = null; |
||||
timer = null; |
||||
renderable.set(false); |
||||
synchronized (createdLock) { |
||||
created.set(false); |
||||
createdLock.notifyAll(); |
||||
} |
||||
} |
||||
|
||||
public void internalCreate() { |
||||
synchronized (createdLock) { |
||||
created.set(true); |
||||
createdLock.notifyAll(); |
||||
} |
||||
|
||||
//if (renderable.get()) {
|
||||
initContextFirstTime(); |
||||
//} else {
|
||||
// assert getType() == Type.Canvas;
|
||||
// }
|
||||
} |
||||
|
||||
public void create() { |
||||
create(false); |
||||
} |
||||
|
||||
public void destroy() { |
||||
destroy(false); |
||||
} |
||||
|
||||
protected void waitFor(boolean createdVal) { |
||||
synchronized (createdLock) { |
||||
while (created.get() != createdVal) { |
||||
try { |
||||
createdLock.wait(); |
||||
} catch (InterruptedException ex) { |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
public boolean isCreated() { |
||||
return created.get(); |
||||
} |
||||
|
||||
public boolean isRenderable() { |
||||
return renderable.get(); |
||||
} |
||||
|
||||
public void setSettings(AppSettings settings) { |
||||
this.settings.copyFrom(settings); |
||||
} |
||||
|
||||
public AppSettings getSettings() { |
||||
return settings; |
||||
} |
||||
|
||||
public Renderer getRenderer() { |
||||
return renderer; |
||||
} |
||||
|
||||
public Timer getTimer() { |
||||
return timer; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,12 @@ |
||||
package com.jme3.system.lwjgl; |
||||
|
||||
/** |
||||
* @author Daniel Johansson |
||||
* @since 2015-08-11 |
||||
*/ |
||||
public class LwjglDisplay extends LwjglWindow { |
||||
|
||||
public LwjglDisplay() { |
||||
super(Type.Display); |
||||
} |
||||
} |
@ -0,0 +1,78 @@ |
||||
/* |
||||
* Copyright (c) 2009-2015 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.system.lwjgl; |
||||
|
||||
import org.lwjgl.opengl.ARBDebugOutput; |
||||
import org.lwjgl.opengl.GLDebugMessageARBCallback; |
||||
|
||||
import java.util.HashMap; |
||||
|
||||
class LwjglGLDebugOutputHandler extends GLDebugMessageARBCallback { |
||||
|
||||
private static final HashMap<Integer, String> constMap = new HashMap<Integer, String>(); |
||||
private static final String MESSAGE_FORMAT = |
||||
"[JME3] OpenGL debug message\r\n" + |
||||
" ID: %d\r\n" + |
||||
" Source: %s\r\n" + |
||||
" Type: %s\r\n" + |
||||
" Severity: %s\r\n" + |
||||
" Message: %s"; |
||||
|
||||
static { |
||||
constMap.put(ARBDebugOutput.GL_DEBUG_SOURCE_API_ARB, "API"); |
||||
constMap.put(ARBDebugOutput.GL_DEBUG_SOURCE_APPLICATION_ARB, "APPLICATION"); |
||||
constMap.put(ARBDebugOutput.GL_DEBUG_SOURCE_OTHER_ARB, "OTHER"); |
||||
constMap.put(ARBDebugOutput.GL_DEBUG_SOURCE_SHADER_COMPILER_ARB, "SHADER_COMPILER"); |
||||
constMap.put(ARBDebugOutput.GL_DEBUG_SOURCE_THIRD_PARTY_ARB, "THIRD_PARTY"); |
||||
constMap.put(ARBDebugOutput.GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB, "WINDOW_SYSTEM"); |
||||
|
||||
constMap.put(ARBDebugOutput.GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB, "DEPRECATED_BEHAVIOR"); |
||||
constMap.put(ARBDebugOutput.GL_DEBUG_TYPE_ERROR_ARB, "ERROR"); |
||||
constMap.put(ARBDebugOutput.GL_DEBUG_TYPE_OTHER_ARB, "OTHER"); |
||||
constMap.put(ARBDebugOutput.GL_DEBUG_TYPE_PERFORMANCE_ARB, "PERFORMANCE"); |
||||
constMap.put(ARBDebugOutput.GL_DEBUG_TYPE_PORTABILITY_ARB, "PORTABILITY"); |
||||
constMap.put(ARBDebugOutput.GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB, "UNDEFINED_BEHAVIOR"); |
||||
|
||||
constMap.put(ARBDebugOutput.GL_DEBUG_SEVERITY_HIGH_ARB, "HIGH"); |
||||
constMap.put(ARBDebugOutput.GL_DEBUG_SEVERITY_MEDIUM_ARB, "MEDIUM"); |
||||
constMap.put(ARBDebugOutput.GL_DEBUG_SEVERITY_LOW_ARB, "LOW"); |
||||
} |
||||
|
||||
@Override |
||||
public void invoke(int source, int type, int id, int severity, int length, long message, long userParam) { |
||||
String sourceStr = constMap.get(source); |
||||
String typeStr = constMap.get(type); |
||||
String severityStr = constMap.get(severity); |
||||
|
||||
System.err.println(String.format(MESSAGE_FORMAT, id, sourceStr, typeStr, severityStr, message)); |
||||
} |
||||
} |
@ -0,0 +1,14 @@ |
||||
package com.jme3.system.lwjgl; |
||||
|
||||
import com.jme3.system.JmeContext; |
||||
|
||||
/** |
||||
* @author Daniel Johansson |
||||
* @since 2015-08-11 |
||||
*/ |
||||
public class LwjglOffscreenBuffer extends LwjglWindow { |
||||
|
||||
public LwjglOffscreenBuffer() { |
||||
super(JmeContext.Type.OffscreenSurface); |
||||
} |
||||
} |
@ -0,0 +1,203 @@ |
||||
/* |
||||
* Copyright (c) 2009-2012 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.system.lwjgl; |
||||
|
||||
import com.jme3.math.FastMath; |
||||
import com.jme3.system.Timer; |
||||
import org.lwjgl.glfw.GLFW; |
||||
|
||||
import java.util.logging.Level; |
||||
import java.util.logging.Logger; |
||||
|
||||
/** |
||||
* <code>Timer</code> handles the system's time related functionality. This |
||||
* allows the calculation of the framerate. To keep the framerate calculation |
||||
* accurate, a call to update each frame is required. <code>Timer</code> is a |
||||
* singleton object and must be created via the <code>getTimer</code> method. |
||||
* |
||||
* @author Mark Powell |
||||
* @version $Id: LWJGLTimer.java,v 1.21 2007/09/22 16:46:35 irrisor Exp $ |
||||
*/ |
||||
public class LwjglSmoothingTimer extends LwjglTimer { |
||||
private static final Logger logger = Logger.getLogger(LwjglSmoothingTimer.class |
||||
.getName()); |
||||
|
||||
private long lastFrameDiff; |
||||
|
||||
//frame rate parameters.
|
||||
private long oldTime; |
||||
|
||||
private float lastTPF, lastFPS; |
||||
|
||||
public static int TIMER_SMOOTHNESS = 32; |
||||
|
||||
private long[] tpf; |
||||
|
||||
private int smoothIndex; |
||||
|
||||
private final static long LWJGL_TIMER_RES = 1; |
||||
private final static float INV_LWJGL_TIMER_RES = ( 1f / LWJGL_TIMER_RES ); |
||||
private static float invTimerRezSmooth; |
||||
|
||||
public final static long LWJGL_TIME_TO_NANOS = (1000000000 / LWJGL_TIMER_RES); |
||||
|
||||
private long startTime; |
||||
|
||||
private boolean allSmooth = false; |
||||
|
||||
/** |
||||
* Constructor builds a <code>Timer</code> object. All values will be |
||||
* initialized to it's default values. |
||||
*/ |
||||
public LwjglSmoothingTimer() { |
||||
reset(); |
||||
|
||||
//print timer resolution info
|
||||
logger.log(Level.FINE, "Timer resolution: {0} ticks per second", LWJGL_TIMER_RES); |
||||
} |
||||
|
||||
public void reset() { |
||||
lastFrameDiff = 0; |
||||
lastFPS = 0; |
||||
lastTPF = 0; |
||||
|
||||
// init to -1 to indicate this is a new timer.
|
||||
oldTime = -1; |
||||
//reset time
|
||||
startTime = (long) (GLFW.glfwGetTime() * LWJGL_TIME_TO_NANOS); |
||||
|
||||
tpf = new long[TIMER_SMOOTHNESS]; |
||||
smoothIndex = TIMER_SMOOTHNESS - 1; |
||||
invTimerRezSmooth = ( 1f / (LWJGL_TIMER_RES * TIMER_SMOOTHNESS)); |
||||
|
||||
// set tpf... -1 values will not be used for calculating the average in update()
|
||||
for ( int i = tpf.length; --i >= 0; ) { |
||||
tpf[i] = -1; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @see Timer#getResolution() |
||||
*/ |
||||
public long getResolution() { |
||||
return LWJGL_TIMER_RES; |
||||
} |
||||
|
||||
/** |
||||
* <code>getFrameRate</code> returns the current frame rate since the last |
||||
* call to <code>update</code>. |
||||
* |
||||
* @return the current frame rate. |
||||
*/ |
||||
public float getFrameRate() { |
||||
return lastFPS; |
||||
} |
||||
|
||||
public float getTimePerFrame() { |
||||
return lastTPF; |
||||
} |
||||
|
||||
/** |
||||
* <code>update</code> recalulates the frame rate based on the previous |
||||
* call to update. It is assumed that update is called each frame. |
||||
*/ |
||||
public void update() { |
||||
long newTime = (long) (GLFW.glfwGetTime() * LWJGL_TIME_TO_NANOS); |
||||
long oldTime = this.oldTime; |
||||
this.oldTime = newTime; |
||||
if ( oldTime == -1 ) { |
||||
// For the first frame use 60 fps. This value will not be counted in further averages.
|
||||
// This is done so initialization code between creating the timer and the first
|
||||
// frame is not counted as a single frame on it's own.
|
||||
lastTPF = 1 / 60f; |
||||
lastFPS = 1f / lastTPF; |
||||
return; |
||||
} |
||||
|
||||
long frameDiff = newTime - oldTime; |
||||
long lastFrameDiff = this.lastFrameDiff; |
||||
if ( lastFrameDiff > 0 && frameDiff > lastFrameDiff *100 ) { |
||||
frameDiff = lastFrameDiff *100; |
||||
} |
||||
this.lastFrameDiff = frameDiff; |
||||
tpf[smoothIndex] = frameDiff; |
||||
smoothIndex--; |
||||
if ( smoothIndex < 0 ) { |
||||
smoothIndex = tpf.length - 1; |
||||
} |
||||
|
||||
lastTPF = 0.0f; |
||||
if (!allSmooth) { |
||||
int smoothCount = 0; |
||||
for ( int i = tpf.length; --i >= 0; ) { |
||||
if ( tpf[i] != -1 ) { |
||||
lastTPF += tpf[i]; |
||||
smoothCount++; |
||||
} |
||||
} |
||||
if (smoothCount == tpf.length) |
||||
allSmooth = true; |
||||
lastTPF *= ( INV_LWJGL_TIMER_RES / smoothCount ); |
||||
} else { |
||||
for ( int i = tpf.length; --i >= 0; ) { |
||||
if ( tpf[i] != -1 ) { |
||||
lastTPF += tpf[i]; |
||||
} |
||||
} |
||||
lastTPF *= invTimerRezSmooth; |
||||
} |
||||
if ( lastTPF < FastMath.FLT_EPSILON ) { |
||||
lastTPF = FastMath.FLT_EPSILON; |
||||
} |
||||
|
||||
lastFPS = 1f / lastTPF; |
||||
} |
||||
|
||||
/** |
||||
* <code>toString</code> returns the string representation of this timer |
||||
* in the format: <br> |
||||
* <br> |
||||
* jme.utility.Timer@1db699b <br> |
||||
* Time: {LONG} <br> |
||||
* FPS: {LONG} <br> |
||||
* |
||||
* @return the string representation of this object. |
||||
*/ |
||||
@Override |
||||
public String toString() { |
||||
String string = super.toString(); |
||||
string += "\nTime: " + oldTime; |
||||
string += "\nFPS: " + getFrameRate(); |
||||
return string; |
||||
} |
||||
} |
@ -0,0 +1,139 @@ |
||||
/* |
||||
* Copyright (c) 2009-2012 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.system.lwjgl; |
||||
|
||||
import com.jme3.system.Timer; |
||||
import org.lwjgl.glfw.GLFW; |
||||
|
||||
import java.util.logging.Level; |
||||
import java.util.logging.Logger; |
||||
|
||||
/** |
||||
* <code>Timer</code> handles the system's time related functionality. This |
||||
* allows the calculation of the framerate. To keep the framerate calculation |
||||
* accurate, a call to update each frame is required. <code>Timer</code> is a |
||||
* singleton object and must be created via the <code>getTimer</code> method. |
||||
* |
||||
* @author Mark Powell |
||||
* @version $Id: LWJGLTimer.java,v 1.21 2007/09/22 16:46:35 irrisor Exp $ |
||||
*/ |
||||
public class LwjglTimer extends Timer { |
||||
|
||||
private static final Logger logger = Logger.getLogger(LwjglTimer.class.getName()); |
||||
|
||||
//frame rate parameters.
|
||||
private long oldTime; |
||||
private long startTime; |
||||
|
||||
private float lastTPF, lastFPS; |
||||
|
||||
private final static long LWJGL_TIMER_RES = 1; |
||||
private final static float INV_LWJGL_TIMER_RES = ( 1f / LWJGL_TIMER_RES ); |
||||
public final static long LWJGL_TIME_TO_NANOS = (1000000000 / LWJGL_TIMER_RES); |
||||
|
||||
/** |
||||
* Constructor builds a <code>Timer</code> object. All values will be |
||||
* initialized to it's default values. |
||||
*/ |
||||
public LwjglTimer() { |
||||
reset(); |
||||
logger.log(Level.FINE, "Timer resolution: {0} ticks per second", LWJGL_TIMER_RES); |
||||
} |
||||
|
||||
public void reset() { |
||||
startTime = (long) (GLFW.glfwGetTime() * LWJGL_TIME_TO_NANOS); |
||||
oldTime = getTime(); |
||||
} |
||||
|
||||
@Override |
||||
public float getTimeInSeconds() { |
||||
return getTime() * INV_LWJGL_TIMER_RES; |
||||
} |
||||
|
||||
/** |
||||
* @see Timer#getTime() |
||||
*/ |
||||
public long getTime() { |
||||
return ((long) (GLFW.glfwGetTime() * LWJGL_TIME_TO_NANOS) - startTime); |
||||
} |
||||
|
||||
/** |
||||
* @see Timer#getResolution() |
||||
*/ |
||||
public long getResolution() { |
||||
return LWJGL_TIMER_RES; |
||||
} |
||||
|
||||
/** |
||||
* <code>getFrameRate</code> returns the current frame rate since the last |
||||
* call to <code>update</code>. |
||||
* |
||||
* @return the current frame rate. |
||||
*/ |
||||
public float getFrameRate() { |
||||
return lastFPS; |
||||
} |
||||
|
||||
public float getTimePerFrame() { |
||||
return lastTPF; |
||||
} |
||||
|
||||
/** |
||||
* <code>update</code> recalulates the frame rate based on the previous |
||||
* call to update. It is assumed that update is called each frame. |
||||
*/ |
||||
public void update() { |
||||
long curTime = getTime(); |
||||
lastTPF = (curTime - oldTime) * (1.0f / LWJGL_TIMER_RES); |
||||
lastFPS = 1.0f / lastTPF; |
||||
oldTime = curTime; |
||||
} |
||||
|
||||
/** |
||||
* <code>toString</code> returns the string representation of this timer |
||||
* in the format: <br> |
||||
* <br> |
||||
* jme.utility.Timer@1db699b <br> |
||||
* Time: {LONG} <br> |
||||
* FPS: {LONG} <br> |
||||
* |
||||
* @return the string representation of this object. |
||||
*/ |
||||
@Override |
||||
public String toString() { |
||||
String string = super.toString(); |
||||
string += "\nTime: " + oldTime; |
||||
string += "\nFPS: " + getFrameRate(); |
||||
return string; |
||||
} |
||||
} |
@ -0,0 +1,489 @@ |
||||
/* |
||||
* Copyright (c) 2009-2012 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.system.lwjgl; |
||||
|
||||
import com.jme3.input.JoyInput; |
||||
import com.jme3.input.KeyInput; |
||||
import com.jme3.input.MouseInput; |
||||
import com.jme3.input.TouchInput; |
||||
import com.jme3.input.lwjgl.GlfwJoystickInput; |
||||
import com.jme3.input.lwjgl.LwjglKeyInput; |
||||
import com.jme3.input.lwjgl.LwjglMouseInput; |
||||
import com.jme3.system.AppSettings; |
||||
import com.jme3.system.JmeContext; |
||||
import com.jme3.system.JmeSystem; |
||||
import org.lwjgl.PointerBuffer; |
||||
import org.lwjgl.Sys; |
||||
import org.lwjgl.glfw.*; |
||||
|
||||
import java.awt.*; |
||||
import java.awt.image.BufferedImage; |
||||
import java.nio.ByteBuffer; |
||||
import java.util.concurrent.atomic.AtomicBoolean; |
||||
import java.util.logging.Level; |
||||
import java.util.logging.Logger; |
||||
|
||||
import static org.lwjgl.glfw.GLFW.*; |
||||
import static org.lwjgl.opengl.GL11.GL_FALSE; |
||||
import static org.lwjgl.opengl.GL11.GL_TRUE; |
||||
import static org.lwjgl.system.MemoryUtil.NULL; |
||||
|
||||
/** |
||||
* A wrapper class over the GLFW framework in LWJGL 3. |
||||
* |
||||
* @author Daniel Johansson (dannyjo) |
||||
* @since 3.1 |
||||
*/ |
||||
public abstract class LwjglWindow extends LwjglContext implements Runnable { |
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(LwjglWindow.class.getName()); |
||||
|
||||
protected AtomicBoolean needClose = new AtomicBoolean(false); |
||||
protected final AtomicBoolean needRestart = new AtomicBoolean(false); |
||||
protected boolean wasActive = false; |
||||
protected boolean autoFlush = true; |
||||
protected boolean allowSwapBuffers = false; |
||||
private long window = -1; |
||||
private final JmeContext.Type type; |
||||
|
||||
private GLFWErrorCallback errorCallback; |
||||
private GLFWWindowSizeCallback windowSizeCallback; |
||||
private GLFWWindowFocusCallback windowFocusCallback; |
||||
|
||||
public LwjglWindow(final JmeContext.Type type) { |
||||
if (!JmeContext.Type.Display.equals(type) && !JmeContext.Type.OffscreenSurface.equals(type) && !JmeContext.Type.Canvas.equals(type)) { |
||||
throw new IllegalArgumentException("Unsupported type '" + type.name() + "' provided"); |
||||
} |
||||
|
||||
this.type = type; |
||||
} |
||||
|
||||
/** |
||||
* @return Type.Display or Type.Canvas |
||||
*/ |
||||
public JmeContext.Type getType() { |
||||
return type; |
||||
} |
||||
|
||||
/** |
||||
* Set the title if its a windowed display |
||||
* |
||||
* @param title |
||||
*/ |
||||
public void setTitle(final String title) { |
||||
if (created.get() && window != -1) { |
||||
glfwSetWindowTitle(window, title); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Restart if its a windowed or full-screen display. |
||||
*/ |
||||
public void restart() { |
||||
if (created.get()) { |
||||
needRestart.set(true); |
||||
} else { |
||||
LOGGER.warning("Display is not created, cannot restart window."); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Apply the settings, changing resolution, etc. |
||||
* |
||||
* @param settings |
||||
*/ |
||||
protected void createContext(final AppSettings settings) { |
||||
glfwSetErrorCallback(errorCallback = new GLFWErrorCallback() { |
||||
@Override |
||||
public void invoke(int error, long description) { |
||||
final String message = Callbacks.errorCallbackDescriptionString(description); |
||||
listener.handleError(message, new Exception(message)); |
||||
} |
||||
}); |
||||
|
||||
if (glfwInit() != GL_TRUE) { |
||||
throw new IllegalStateException("Unable to initialize GLFW"); |
||||
} |
||||
|
||||
glfwDefaultWindowHints(); |
||||
glfwWindowHint(GLFW_VISIBLE, GL_FALSE); |
||||
|
||||
// TODO: Add support for monitor selection
|
||||
long monitor = NULL; |
||||
|
||||
if (settings.isFullscreen()) { |
||||
monitor = glfwGetPrimaryMonitor(); |
||||
} |
||||
|
||||
final ByteBuffer videoMode = glfwGetVideoMode(glfwGetPrimaryMonitor()); |
||||
|
||||
if (settings.getWidth() <= 0 || settings.getHeight() <= 0) { |
||||
settings.setResolution(GLFWvidmode.width(videoMode), GLFWvidmode.height(videoMode)); |
||||
} |
||||
|
||||
window = glfwCreateWindow(settings.getWidth(), settings.getHeight(), settings.getTitle(), monitor, NULL); |
||||
|
||||
if (window == NULL) { |
||||
throw new RuntimeException("Failed to create the GLFW window"); |
||||
} |
||||
|
||||
glfwWindowHint(GLFW_RESIZABLE, settings.isResizable() ? GL_TRUE : GL_FALSE); |
||||
glfwWindowHint(GLFW_DEPTH_BITS, settings.getDepthBits()); |
||||
glfwWindowHint(GLFW_STENCIL_BITS, settings.getStencilBits()); |
||||
glfwWindowHint(GLFW_SAMPLES, settings.getSamples()); |
||||
glfwWindowHint(GLFW_STEREO, settings.useStereo3D() ? GL_TRUE : GL_FALSE); |
||||
|
||||
int frameRateCap = settings.getFrameRate(); |
||||
|
||||
if (!autoFlush) { |
||||
frameRateCap = 20; |
||||
} |
||||
|
||||
if (frameRateCap > 0) { |
||||
glfwWindowHint(GLFW_REFRESH_RATE, frameRateCap); |
||||
} |
||||
|
||||
// Not sure how else to support bits per pixel
|
||||
if (settings.getBitsPerPixel() == 24) { |
||||
glfwWindowHint(GLFW_RED_BITS, 8); |
||||
glfwWindowHint(GLFW_GREEN_BITS, 8); |
||||
glfwWindowHint(GLFW_BLUE_BITS, 8); |
||||
} else if (settings.getBitsPerPixel() == 16) { |
||||
glfwWindowHint(GLFW_RED_BITS, 5); |
||||
glfwWindowHint(GLFW_GREEN_BITS, 6); |
||||
glfwWindowHint(GLFW_BLUE_BITS, 5); |
||||
} |
||||
|
||||
glfwWindowHint(GLFW_ALPHA_BITS, settings.getAlphaBits()); |
||||
|
||||
glfwSetWindowFocusCallback(window, windowFocusCallback = new GLFWWindowFocusCallback() { |
||||
@Override |
||||
public void invoke(final long window, final int focused) { |
||||
final boolean focus = (focused == 1); |
||||
|
||||
if (wasActive != focus) { |
||||
if (!wasActive) { |
||||
listener.gainFocus(); |
||||
timer.reset(); |
||||
} else { |
||||
listener.loseFocus(); |
||||
} |
||||
|
||||
wasActive = !wasActive; |
||||
} |
||||
|
||||
} |
||||
}); |
||||
|
||||
// Center the window
|
||||
if (!settings.isFullscreen() && Type.Display.equals(type)) { |
||||
glfwSetWindowPos(window, (GLFWvidmode.width(videoMode) - settings.getWidth()) / 2, (GLFWvidmode.height(videoMode) - settings.getHeight()) / 2); |
||||
} |
||||
|
||||
// Make the OpenGL context current
|
||||
glfwMakeContextCurrent(window); |
||||
|
||||
// Enable vsync
|
||||
if (settings.isVSync()) { |
||||
glfwSwapInterval(1); |
||||
} else { |
||||
glfwSwapInterval(0); |
||||
} |
||||
|
||||
|
||||
// Make the window visible
|
||||
if (Type.Display.equals(type)) { |
||||
glfwShowWindow(window); |
||||
} |
||||
|
||||
// Add a resize callback which delegates to the listener
|
||||
glfwSetWindowSizeCallback(window, windowSizeCallback = new GLFWWindowSizeCallback() { |
||||
@Override |
||||
public void invoke(final long window, final int width, final int height) { |
||||
settings.setResolution(width, height); |
||||
listener.reshape(width, height); |
||||
} |
||||
}); |
||||
|
||||
allowSwapBuffers = settings.isSwapBuffers(); |
||||
|
||||
// TODO: When GLFW 3.2 is released and included in LWJGL 3.x then we should hopefully be able to set the window icon.
|
||||
} |
||||
|
||||
/** |
||||
* Destroy the context. |
||||
*/ |
||||
protected void destroyContext() { |
||||
try { |
||||
if (renderer != null) { |
||||
renderer.cleanup(); |
||||
} |
||||
|
||||
errorCallback.release(); |
||||
windowSizeCallback.release(); |
||||
windowFocusCallback.release(); |
||||
|
||||
if (window != 0) { |
||||
glfwDestroyWindow(window); |
||||
} |
||||
//glfwTerminate();
|
||||
} catch (Exception ex) { |
||||
listener.handleError("Failed to destroy context", ex); |
||||
} |
||||
} |
||||
|
||||
public void create(boolean waitFor) { |
||||
if (created.get()) { |
||||
LOGGER.warning("create() called when display is already created!"); |
||||
return; |
||||
} |
||||
|
||||
new Thread(this, THREAD_NAME).start(); |
||||
if (waitFor) |
||||
waitFor(true); |
||||
} |
||||
|
||||
/** |
||||
* Does LWJGL display initialization in the OpenGL thread |
||||
*/ |
||||
protected boolean initInThread() { |
||||
try { |
||||
if (!JmeSystem.isLowPermissions()) { |
||||
// Enable uncaught exception handler only for current thread
|
||||
Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { |
||||
public void uncaughtException(Thread thread, Throwable thrown) { |
||||
listener.handleError("Uncaught exception thrown in " + thread.toString(), thrown); |
||||
if (needClose.get()) { |
||||
// listener.handleError() has requested the
|
||||
// context to close. Satisfy request.
|
||||
deinitInThread(); |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
|
||||
timer = new LwjglTimer(); |
||||
|
||||
// For canvas, this will create a pbuffer,
|
||||
// allowing us to query information.
|
||||
// When the canvas context becomes available, it will
|
||||
// be replaced seamlessly.
|
||||
createContext(settings); |
||||
printContextInitInfo(); |
||||
|
||||
created.set(true); |
||||
super.internalCreate(); |
||||
} catch (Exception ex) { |
||||
try { |
||||
if (window != -1) { |
||||
//glfwSetWindowShouldClose(window, GL_TRUE);
|
||||
glfwDestroyWindow(window); |
||||
} |
||||
} catch (Exception ex2) { |
||||
LOGGER.log(Level.WARNING, null, ex2); |
||||
} |
||||
|
||||
listener.handleError("Failed to create display", ex); |
||||
return false; // if we failed to create display, do not continue
|
||||
} |
||||
|
||||
listener.initialize(); |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* execute one iteration of the render loop in the OpenGL thread |
||||
*/ |
||||
protected void runLoop() { |
||||
// If a restart is required, lets recreate the context.
|
||||
if (needRestart.getAndSet(false)) { |
||||
try { |
||||
createContext(settings); |
||||
} catch (Exception ex) { |
||||
LOGGER.log(Level.SEVERE, "Failed to set display settings!", ex); |
||||
} |
||||
|
||||
LOGGER.fine("Display restarted."); |
||||
} |
||||
|
||||
if (!created.get()) { |
||||
throw new IllegalStateException(); |
||||
} |
||||
|
||||
listener.update(); |
||||
|
||||
// All this does is call swap buffers
|
||||
// If the canvas is not active, there's no need to waste time
|
||||
// doing that ..
|
||||
if (renderable.get()) { |
||||
// calls swap buffers, etc.
|
||||
try { |
||||
if (allowSwapBuffers && autoFlush) { |
||||
glfwSwapBuffers(window); |
||||
} |
||||
} catch (Throwable ex) { |
||||
listener.handleError("Error while swapping buffers", ex); |
||||
} |
||||
} |
||||
|
||||
if (glfwGetWindowAttrib(window, GLFW_FOCUSED) == GL_TRUE) { |
||||
glfwPollEvents(); |
||||
} |
||||
|
||||
// Subclasses just call GLObjectManager clean up objects here
|
||||
// it is safe .. for now.
|
||||
if (renderer != null) { |
||||
renderer.postFrame(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* De-initialize in the OpenGL thread. |
||||
*/ |
||||
protected void deinitInThread() { |
||||
destroyContext(); |
||||
|
||||
listener.destroy(); |
||||
LOGGER.fine("Display destroyed."); |
||||
super.internalDestroy(); |
||||
} |
||||
|
||||
public void run() { |
||||
if (listener == null) { |
||||
throw new IllegalStateException("SystemListener is not set on context!" |
||||
+ "Must set with JmeContext.setSystemListner()."); |
||||
} |
||||
|
||||
registerNatives(); |
||||
loadNatives(); |
||||
LOGGER.log(Level.FINE, "Using LWJGL {0}", Sys.getVersion()); |
||||
|
||||
if (!initInThread()) { |
||||
LOGGER.log(Level.SEVERE, "Display initialization failed. Cannot continue."); |
||||
return; |
||||
} |
||||
|
||||
while (true) { |
||||
if (glfwWindowShouldClose(window) == GL_TRUE) { |
||||
listener.requestClose(false); |
||||
} |
||||
|
||||
runLoop(); |
||||
|
||||
if (needClose.get()) { |
||||
break; |
||||
} |
||||
} |
||||
|
||||
deinitInThread(); |
||||
} |
||||
|
||||
public JoyInput getJoyInput() { |
||||
if (joyInput == null) { |
||||
joyInput = new GlfwJoystickInput(); |
||||
} |
||||
return joyInput; |
||||
} |
||||
|
||||
public MouseInput getMouseInput() { |
||||
if (mouseInput == null) { |
||||
mouseInput = new LwjglMouseInput(this); |
||||
} |
||||
return mouseInput; |
||||
} |
||||
|
||||
public KeyInput getKeyInput() { |
||||
if (keyInput == null) { |
||||
keyInput = new LwjglKeyInput(this); |
||||
} |
||||
|
||||
return keyInput; |
||||
} |
||||
|
||||
public TouchInput getTouchInput() { |
||||
return null; |
||||
} |
||||
|
||||
public void setAutoFlushFrames(boolean enabled) { |
||||
this.autoFlush = enabled; |
||||
} |
||||
|
||||
public void destroy(boolean waitFor) { |
||||
needClose.set(true); |
||||
|
||||
if (waitFor) { |
||||
waitFor(false); |
||||
} |
||||
} |
||||
|
||||
public long getWindowHandle() { |
||||
return window; |
||||
} |
||||
|
||||
private ByteBuffer[] imagesToByteBuffers(Object[] images) { |
||||
ByteBuffer[] out = new ByteBuffer[images.length]; |
||||
for (int i = 0; i < images.length; i++) { |
||||
BufferedImage image = (BufferedImage) images[i]; |
||||
out[i] = imageToByteBuffer(image); |
||||
} |
||||
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); |
||||
} |
||||
} |
Loading…
Reference in new issue