diff --git a/jme3-core/src/main/java/com/jme3/input/KeyInput.java b/jme3-core/src/main/java/com/jme3/input/KeyInput.java index f9191c6a7..9ad78ed7b 100644 --- a/jme3-core/src/main/java/com/jme3/input/KeyInput.java +++ b/jme3-core/src/main/java/com/jme3/input/KeyInput.java @@ -36,6 +36,11 @@ package com.jme3.input; */ public interface KeyInput extends Input { + /** + * unmapped key. + */ + public static final int KEY_UNKNOWN = 0x00; + /** * escape key. */ @@ -518,17 +523,17 @@ public interface KeyInput extends Input { * delete key. */ public static final int KEY_DELETE = 0xD3; - + /** * Left "Windows" key on PC keyboards, left "Option" key on Mac keyboards. */ public static final int KEY_LMETA = 0xDB; - + /** * Right "Windows" key on PC keyboards, right "Option" key on Mac keyboards. */ public static final int KEY_RMETA = 0xDC; - + public static final int KEY_APPS = 0xDD; /** * power key. @@ -539,4 +544,8 @@ public interface KeyInput extends Input { */ public static final int KEY_SLEEP = 0xDF; + /** + * the last key. + */ + public static final int KEY_LAST = 0xE0; } diff --git a/jme3-core/src/main/java/com/jme3/input/KeyNames.java b/jme3-core/src/main/java/com/jme3/input/KeyNames.java index a1e1a41a8..563c3a5f8 100644 --- a/jme3-core/src/main/java/com/jme3/input/KeyNames.java +++ b/jme3-core/src/main/java/com/jme3/input/KeyNames.java @@ -34,10 +34,11 @@ package com.jme3.input; import static com.jme3.input.KeyInput.*; public class KeyNames { - + private static final String[] KEY_NAMES = new String[0xFF]; - + static { + KEY_NAMES[KEY_UNKNOWN] = "Unknown"; KEY_NAMES[KEY_0] = "0"; KEY_NAMES[KEY_1] = "1"; KEY_NAMES[KEY_2] = "2"; @@ -48,7 +49,7 @@ public class KeyNames { KEY_NAMES[KEY_7] = "7"; KEY_NAMES[KEY_8] = "8"; KEY_NAMES[KEY_9] = "9"; - + KEY_NAMES[KEY_Q] = "Q"; KEY_NAMES[KEY_W] = "W"; KEY_NAMES[KEY_E] = "E"; @@ -75,7 +76,7 @@ public class KeyNames { KEY_NAMES[KEY_B] = "B"; KEY_NAMES[KEY_N] = "N"; KEY_NAMES[KEY_M] = "M"; - + KEY_NAMES[KEY_F1] = "F1"; KEY_NAMES[KEY_F2] = "F2"; KEY_NAMES[KEY_F3] = "F3"; @@ -91,7 +92,7 @@ public class KeyNames { KEY_NAMES[KEY_F13] = "F13"; KEY_NAMES[KEY_F14] = "F14"; KEY_NAMES[KEY_F15] = "F15"; - + KEY_NAMES[KEY_NUMPAD0] = "Numpad 0"; KEY_NAMES[KEY_NUMPAD1] = "Numpad 1"; KEY_NAMES[KEY_NUMPAD2] = "Numpad 2"; @@ -102,25 +103,26 @@ public class KeyNames { KEY_NAMES[KEY_NUMPAD7] = "Numpad 7"; KEY_NAMES[KEY_NUMPAD8] = "Numpad 8"; KEY_NAMES[KEY_NUMPAD9] = "Numpad 9"; - + KEY_NAMES[KEY_NUMPADEQUALS] = "Numpad ="; KEY_NAMES[KEY_NUMPADENTER] = "Numpad Enter"; - KEY_NAMES[KEY_NUMPADCOMMA] = "Numpad ."; + KEY_NAMES[KEY_NUMPADCOMMA] = "Numpad ,"; KEY_NAMES[KEY_DIVIDE] = "Numpad /"; - - + KEY_NAMES[KEY_SUBTRACT] = "Numpad -"; + KEY_NAMES[KEY_DECIMAL] = "Numpad ."; + KEY_NAMES[KEY_LMENU] = "Left Alt"; KEY_NAMES[KEY_RMENU] = "Right Alt"; - + KEY_NAMES[KEY_LCONTROL] = "Left Ctrl"; KEY_NAMES[KEY_RCONTROL] = "Right Ctrl"; - + KEY_NAMES[KEY_LSHIFT] = "Left Shift"; KEY_NAMES[KEY_RSHIFT] = "Right Shift"; - + KEY_NAMES[KEY_LMETA] = "Left Option"; KEY_NAMES[KEY_RMETA] = "Right Option"; - + KEY_NAMES[KEY_MINUS] = "-"; KEY_NAMES[KEY_EQUALS] = "="; KEY_NAMES[KEY_LBRACKET] = "["; @@ -137,37 +139,37 @@ public class KeyNames { KEY_NAMES[KEY_COLON] = ":"; KEY_NAMES[KEY_UNDERLINE] = "_"; KEY_NAMES[KEY_AT] = "@"; - + KEY_NAMES[KEY_APPS] = "Apps"; KEY_NAMES[KEY_POWER] = "Power"; KEY_NAMES[KEY_SLEEP] = "Sleep"; - + KEY_NAMES[KEY_STOP] = "Stop"; KEY_NAMES[KEY_ESCAPE] = "Esc"; KEY_NAMES[KEY_RETURN] = "Enter"; KEY_NAMES[KEY_SPACE] = "Space"; KEY_NAMES[KEY_BACK] = "Backspace"; KEY_NAMES[KEY_TAB] = "Tab"; - + KEY_NAMES[KEY_SYSRQ] = "SysRq"; KEY_NAMES[KEY_PAUSE] = "Pause"; - + KEY_NAMES[KEY_HOME] = "Home"; KEY_NAMES[KEY_PGUP] = "Page Up"; KEY_NAMES[KEY_PGDN] = "Page Down"; KEY_NAMES[KEY_END] = "End"; KEY_NAMES[KEY_INSERT] = "Insert"; KEY_NAMES[KEY_DELETE] = "Delete"; - + KEY_NAMES[KEY_UP] = "Up"; KEY_NAMES[KEY_LEFT] = "Left"; KEY_NAMES[KEY_RIGHT] = "Right"; KEY_NAMES[KEY_DOWN] = "Down"; - + KEY_NAMES[KEY_NUMLOCK] = "Num Lock"; KEY_NAMES[KEY_CAPITAL] = "Caps Lock"; KEY_NAMES[KEY_SCROLL] = "Scroll Lock"; - + KEY_NAMES[KEY_KANA] = "Kana"; KEY_NAMES[KEY_CONVERT] = "Convert"; KEY_NAMES[KEY_NOCONVERT] = "No Convert"; @@ -177,8 +179,8 @@ public class KeyNames { KEY_NAMES[KEY_AX] = "Ax"; KEY_NAMES[KEY_UNLABELED] = "Unlabeled"; } - - public String getName(int keyId){ + + public static String getName(int keyId) { return KEY_NAMES[keyId]; } } diff --git a/jme3-core/src/main/java/com/jme3/system/AppSettings.java b/jme3-core/src/main/java/com/jme3/system/AppSettings.java index 2d7071c9c..05ee2b4bd 100644 --- a/jme3-core/src/main/java/com/jme3/system/AppSettings.java +++ b/jme3-core/src/main/java/com/jme3/system/AppSettings.java @@ -963,7 +963,7 @@ public final class AppSettings extends HashMap { return getString("SettingsDialogImage"); } - public boolean getGammaCorrection() { + public boolean isGammaCorrection() { return getBoolean("GammaCorrection"); } diff --git a/jme3-desktop/src/main/java/com/jme3/app/SettingsDialog.java b/jme3-desktop/src/main/java/com/jme3/app/SettingsDialog.java index 69f2c18ac..e2d64c8b9 100644 --- a/jme3-desktop/src/main/java/com/jme3/app/SettingsDialog.java +++ b/jme3-desktop/src/main/java/com/jme3/app/SettingsDialog.java @@ -360,7 +360,7 @@ public final class SettingsDialog extends JFrame { vsyncBox.setSelected(source.isVSync()); gammaBox = new JCheckBox(resourceBundle.getString("checkbox.gamma")); - gammaBox.setSelected(source.getGammaCorrection()); + gammaBox.setSelected(source.isGammaCorrection()); gbc = new GridBagConstraints(); gbc.weightx = 0.5; diff --git a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java index 936cab616..3ed543bc9 100644 --- a/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java +++ b/jme3-jogl/src/main/java/com/jme3/system/jogl/JoglContext.java @@ -203,8 +203,8 @@ public abstract class JoglContext implements JmeContext { GLContext.getCurrent().addGLDebugListener(new JoglGLDebugOutputHandler()); } - renderer.setMainFrameBufferSrgb(settings.getGammaCorrection()); - renderer.setLinearizeSrgbImages(settings.getGammaCorrection()); + renderer.setMainFrameBufferSrgb(settings.isGammaCorrection()); + renderer.setLinearizeSrgbImages(settings.isGammaCorrection()); // Init input if (keyInput != null) { diff --git a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java index 9f23f8814..354910bbc 100644 --- a/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java +++ b/jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglContext.java @@ -250,8 +250,8 @@ public abstract class LwjglContext implements JmeContext { ARBDebugOutput.glDebugMessageCallbackARB(new ARBDebugOutputCallback(new LwjglGLDebugOutputHandler())); } - renderer.setMainFrameBufferSrgb(settings.getGammaCorrection()); - renderer.setLinearizeSrgbImages(settings.getGammaCorrection()); + renderer.setMainFrameBufferSrgb(settings.isGammaCorrection()); + renderer.setLinearizeSrgbImages(settings.isGammaCorrection()); // Init input if (keyInput != null) { diff --git a/jme3-lwjgl3/build.gradle b/jme3-lwjgl3/build.gradle index 3ee3b0f65..b70cd4303 100644 --- a/jme3-lwjgl3/build.gradle +++ b/jme3-lwjgl3/build.gradle @@ -2,14 +2,14 @@ if (!hasProperty('mainClass')) { ext.mainClass = '' } -repositories { - maven { - url "https://oss.sonatype.org/content/repositories/snapshots" - } -} +def lwjglVersion = '3.0.0b' dependencies { compile project(':jme3-core') compile project(':jme3-desktop') - compile files('lib/lwjgl-3.0.0b-35.jar', 'lib/lwjgl-3.0.0b-35-natives.jar') -} + + compile "org.lwjgl:lwjgl:${lwjglVersion}" + compile "org.lwjgl:lwjgl-platform:${lwjglVersion}:natives-windows" + compile "org.lwjgl:lwjgl-platform:${lwjglVersion}:natives-linux" + compile "org.lwjgl:lwjgl-platform:${lwjglVersion}:natives-osx" +} \ No newline at end of file diff --git a/jme3-lwjgl3/lib/lwjgl-3.0.0b-35-natives.jar b/jme3-lwjgl3/lib/lwjgl-3.0.0b-35-natives.jar deleted file mode 100644 index 79b12bc5d..000000000 Binary files a/jme3-lwjgl3/lib/lwjgl-3.0.0b-35-natives.jar and /dev/null differ diff --git a/jme3-lwjgl3/lib/lwjgl-3.0.0b-35.jar b/jme3-lwjgl3/lib/lwjgl-3.0.0b-35.jar deleted file mode 100644 index d1466e8aa..000000000 Binary files a/jme3-lwjgl3/lib/lwjgl-3.0.0b-35.jar and /dev/null differ diff --git a/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglALC.java b/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglALC.java index b99a939b8..c9812d7df 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglALC.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/audio/lwjgl/LwjglALC.java @@ -32,32 +32,38 @@ package com.jme3.audio.lwjgl; import com.jme3.audio.openal.ALC; +import java.nio.IntBuffer; import org.lwjgl.openal.ALC10; import org.lwjgl.openal.ALContext; import org.lwjgl.openal.ALDevice; - -import java.nio.IntBuffer; - -import static org.lwjgl.openal.ALC10.alcGetContextsDevice; -import static org.lwjgl.openal.ALC10.alcGetCurrentContext; +import org.lwjgl.openal.SOFTPauseDevice; public class LwjglALC implements ALC { private ALDevice device; private ALContext context; + private long contextId; + private long deviceId; + public void createALC() { device = ALDevice.create(); context = ALContext.create(device); + context.makeCurrent(); + + contextId = ALC10.alcGetCurrentContext(); + deviceId = ALC10.alcGetContextsDevice(contextId); } public void destroyALC() { if (context != null) { context.destroy(); + context = null; } if (device != null) { device.destroy(); + device = null; } } @@ -66,31 +72,29 @@ public class LwjglALC implements ALC { } public String alcGetString(final int parameter) { - final long context = alcGetCurrentContext(); - final long device = alcGetContextsDevice(context); - return ALC10.alcGetString(device, parameter); + return ALC10.alcGetString(deviceId, parameter); } public boolean alcIsExtensionPresent(final String extension) { - final long context = alcGetCurrentContext(); - final long device = alcGetContextsDevice(context); - return ALC10.alcIsExtensionPresent(device, extension); + return ALC10.alcIsExtensionPresent(deviceId, 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); + if (buffer.position() != 0) { + throw new AssertionError(); + } + if (buffer.limit() != size) { + throw new AssertionError(); + } + ALC10.alcGetIntegerv(deviceId, param, buffer); } public void alcDevicePauseSOFT() { + SOFTPauseDevice.alcDevicePauseSOFT(deviceId); } public void alcDeviceResumeSOFT() { + SOFTPauseDevice.alcDeviceResumeSOFT(deviceId); } } diff --git a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyInput.java b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyInput.java index 20cd07672..cd87cc70a 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyInput.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyInput.java @@ -66,7 +66,8 @@ public class GlfwKeyInput implements KeyInput { 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); + int jmeKey = GlfwKeyMap.toJmeKeyCode(key); + final KeyInputEvent evt = new KeyInputEvent(jmeKey, (char) key, GLFW_PRESS == action, GLFW_REPEAT == action); evt.setTime(getInputTimeNanos()); keyInputEvents.add(evt); } diff --git a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyMap.java b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyMap.java new file mode 100644 index 000000000..39592fe60 --- /dev/null +++ b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyMap.java @@ -0,0 +1,171 @@ +/* + * 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.input.lwjgl; + +import static org.lwjgl.glfw.GLFW.*; +import static com.jme3.input.KeyInput.*; + +public class GlfwKeyMap { + + private static final int[] glfwToJmeKeyMap = new int[GLFW_KEY_LAST + 1]; + + private static void reg(int jmeKey, int glfwKey) { + glfwToJmeKeyMap[glfwKey] = jmeKey; + } + + static { + reg(KEY_ESCAPE, GLFW_KEY_ESCAPE); + reg(KEY_1, GLFW_KEY_1); + reg(KEY_2, GLFW_KEY_2); + reg(KEY_3, GLFW_KEY_3); + reg(KEY_4, GLFW_KEY_4); + reg(KEY_5, GLFW_KEY_5); + reg(KEY_6, GLFW_KEY_6); + reg(KEY_7, GLFW_KEY_7); + reg(KEY_8, GLFW_KEY_8); + reg(KEY_9, GLFW_KEY_9); + reg(KEY_0, GLFW_KEY_0); + reg(KEY_MINUS, GLFW_KEY_MINUS); + reg(KEY_EQUALS, GLFW_KEY_EQUAL); + reg(KEY_BACK, GLFW_KEY_BACKSPACE); + reg(KEY_TAB, GLFW_KEY_TAB); + reg(KEY_Q, GLFW_KEY_Q); + reg(KEY_W, GLFW_KEY_W); + reg(KEY_E, GLFW_KEY_E); + reg(KEY_R, GLFW_KEY_R); + reg(KEY_T, GLFW_KEY_T); + reg(KEY_Y, GLFW_KEY_Y); + reg(KEY_U, GLFW_KEY_U); + reg(KEY_I, GLFW_KEY_I); + reg(KEY_O, GLFW_KEY_O); + reg(KEY_P, GLFW_KEY_P); + reg(KEY_LBRACKET, GLFW_KEY_LEFT_BRACKET); + reg(KEY_RBRACKET, GLFW_KEY_RIGHT_BRACKET); + reg(KEY_RETURN, GLFW_KEY_ENTER); + reg(KEY_LCONTROL, GLFW_KEY_LEFT_CONTROL); + reg(KEY_A, GLFW_KEY_A); + reg(KEY_S, GLFW_KEY_S); + reg(KEY_D, GLFW_KEY_D); + reg(KEY_F, GLFW_KEY_F); + reg(KEY_G, GLFW_KEY_G); + reg(KEY_H, GLFW_KEY_H); + reg(KEY_J, GLFW_KEY_J); + reg(KEY_K, GLFW_KEY_K); + reg(KEY_L, GLFW_KEY_L); + reg(KEY_SEMICOLON, GLFW_KEY_SEMICOLON); + reg(KEY_APOSTROPHE, GLFW_KEY_APOSTROPHE); + reg(KEY_GRAVE, GLFW_KEY_GRAVE_ACCENT); + reg(KEY_LSHIFT, GLFW_KEY_LEFT_SHIFT); + reg(KEY_BACKSLASH, GLFW_KEY_BACKSLASH); + reg(KEY_Z, GLFW_KEY_Z); + reg(KEY_X, GLFW_KEY_X); + reg(KEY_C, GLFW_KEY_C); + reg(KEY_V, GLFW_KEY_V); + reg(KEY_B, GLFW_KEY_B); + reg(KEY_N, GLFW_KEY_N); + reg(KEY_M, GLFW_KEY_M); + reg(KEY_COMMA, GLFW_KEY_COMMA); + reg(KEY_PERIOD, GLFW_KEY_PERIOD); + reg(KEY_SLASH, GLFW_KEY_SLASH); + reg(KEY_RSHIFT, GLFW_KEY_RIGHT_SHIFT); + reg(KEY_MULTIPLY, GLFW_KEY_KP_MULTIPLY); + reg(KEY_LMENU, GLFW_KEY_LEFT_ALT); + reg(KEY_SPACE, GLFW_KEY_SPACE); + reg(KEY_CAPITAL, GLFW_KEY_CAPS_LOCK); + reg(KEY_F1, GLFW_KEY_F1); + reg(KEY_F2, GLFW_KEY_F2); + reg(KEY_F3, GLFW_KEY_F3); + reg(KEY_F4, GLFW_KEY_F4); + reg(KEY_F5, GLFW_KEY_F5); + reg(KEY_F6, GLFW_KEY_F6); + reg(KEY_F7, GLFW_KEY_F7); + reg(KEY_F8, GLFW_KEY_F8); + reg(KEY_F9, GLFW_KEY_F9); + reg(KEY_F10, GLFW_KEY_F10); + reg(KEY_NUMLOCK, GLFW_KEY_NUM_LOCK); + reg(KEY_SCROLL, GLFW_KEY_SCROLL_LOCK); + reg(KEY_NUMPAD7, GLFW_KEY_KP_7); + reg(KEY_NUMPAD8, GLFW_KEY_KP_8); + reg(KEY_NUMPAD9, GLFW_KEY_KP_9); + reg(KEY_SUBTRACT, GLFW_KEY_KP_SUBTRACT); + reg(KEY_NUMPAD4, GLFW_KEY_KP_4); + reg(KEY_NUMPAD5, GLFW_KEY_KP_5); + reg(KEY_NUMPAD6, GLFW_KEY_KP_6); + reg(KEY_ADD, GLFW_KEY_KP_ADD); + reg(KEY_NUMPAD1, GLFW_KEY_KP_1); + reg(KEY_NUMPAD2, GLFW_KEY_KP_2); + reg(KEY_NUMPAD3, GLFW_KEY_KP_3); + reg(KEY_NUMPAD0, GLFW_KEY_KP_0); + reg(KEY_DECIMAL, GLFW_KEY_KP_DECIMAL); + reg(KEY_F11, GLFW_KEY_F11); + reg(KEY_F12, GLFW_KEY_F12); + reg(KEY_F13, GLFW_KEY_F13); + reg(KEY_F14, GLFW_KEY_F14); + reg(KEY_F15, GLFW_KEY_F15); + //reg(KEY_KANA, GLFW_KEY_); + //reg(KEY_CONVERT, GLFW_KEY_); + //reg(KEY_NOCONVERT, GLFW_KEY_); + //reg(KEY_YEN, GLFW_KEY_); + //reg(KEY_NUMPADEQUALS, GLFW_KEY_); + //reg(KEY_CIRCUMFLEX, GLFW_KEY_); + //reg(KEY_AT, GLFW_KEY_); + //reg(KEY_COLON, GLFW_KEY_); + //reg(KEY_UNDERLINE, GLFW_KEY_); + //reg(KEY_KANJI, GLFW_KEY_); + //reg(KEY_STOP, GLFW_KEY_); + //reg(KEY_AX, GLFW_KEY_); + //reg(KEY_UNLABELED, GLFW_KEY_); + reg(KEY_NUMPADENTER, GLFW_KEY_KP_ENTER); + reg(KEY_RCONTROL, GLFW_KEY_RIGHT_CONTROL); + //reg(KEY_NUMPADCOMMA, GLFW_KEY_); + reg(KEY_DIVIDE, GLFW_KEY_KP_DIVIDE); + reg(KEY_SYSRQ, GLFW_KEY_PRINT_SCREEN); + reg(KEY_RMENU, GLFW_KEY_RIGHT_ALT); + reg(KEY_PAUSE, GLFW_KEY_PAUSE); + reg(KEY_HOME, GLFW_KEY_HOME); + reg(KEY_UP, GLFW_KEY_UP); + reg(KEY_PRIOR, GLFW_KEY_PAGE_UP); + reg(KEY_LEFT, GLFW_KEY_LEFT); + reg(KEY_RIGHT, GLFW_KEY_RIGHT); + reg(KEY_END, GLFW_KEY_END); + reg(KEY_DOWN, GLFW_KEY_DOWN); + reg(KEY_NEXT, GLFW_KEY_PAGE_DOWN); + reg(KEY_INSERT, GLFW_KEY_INSERT); + reg(KEY_DELETE, GLFW_KEY_DELETE); + reg(KEY_LMETA, GLFW_KEY_LEFT_SUPER); + reg(KEY_RMETA, GLFW_KEY_RIGHT_SUPER); + } + + public static int toJmeKeyCode(int glfwKey) { + return glfwToJmeKeyMap[glfwKey]; + } +} diff --git a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwMouseInput.java b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwMouseInput.java index 05a2df5db..bf5478cba 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwMouseInput.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwMouseInput.java @@ -38,16 +38,22 @@ import com.jme3.input.RawInputListener; import com.jme3.input.event.MouseButtonEvent; import com.jme3.input.event.MouseMotionEvent; import com.jme3.system.lwjgl.LwjglWindow; +import com.jme3.util.BufferUtils; import org.lwjgl.glfw.GLFWCursorPosCallback; import org.lwjgl.glfw.GLFWMouseButtonCallback; import org.lwjgl.glfw.GLFWScrollCallback; import java.nio.ByteBuffer; +import java.nio.IntBuffer; +import java.util.HashMap; import java.util.LinkedList; +import java.util.Map; import java.util.Queue; import java.util.logging.Logger; import static org.lwjgl.glfw.GLFW.*; +import org.lwjgl.glfw.GLFWImage; +import org.lwjgl.system.MemoryUtil; /** * Captures mouse input using GLFW callbacks. It then temporarily stores these in event queues which are processed in the @@ -74,57 +80,70 @@ public class GlfwMouseInput implements MouseInput { private Queue mouseMotionEvents = new LinkedList(); private Queue mouseButtonEvents = new LinkedList(); - public GlfwMouseInput(final LwjglWindow context) { + private Map jmeToGlfwCursorMap = new HashMap(); + + public GlfwMouseInput(LwjglWindow context) { this.context = context; } + private void onCursorPos(long window, double xpos, double ypos) { + int xDelta; + int yDelta; + int x = (int) Math.round(xpos); + int y = context.getSettings().getHeight() - (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, xDelta, yDelta, mouseWheel, 0); + mouseMotionEvent.setTime(getInputTimeNanos()); + mouseMotionEvents.add(mouseMotionEvent); + } + } + + private void onWheelScroll(long window, double xOffset, double yOffset) { + mouseWheel += yOffset; + final MouseMotionEvent mouseMotionEvent = new MouseMotionEvent(mouseX, mouseY, 0, 0, mouseWheel, (int) Math.round(yOffset)); + mouseMotionEvent.setTime(getInputTimeNanos()); + mouseMotionEvents.add(mouseMotionEvent); + } + + private void onMouseButton(final long window, final int button, final int action, final int mods) { + final MouseButtonEvent mouseButtonEvent = new MouseButtonEvent(convertButton(button), action == GLFW_PRESS, mouseX, mouseY); + mouseButtonEvent.setTime(getInputTimeNanos()); + mouseButtonEvents.add(mouseButtonEvent); + } + 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 = context.getSettings().getHeight() - (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, xDelta, yDelta, mouseWheel, 0); - mouseMotionEvent.setTime(getInputTimeNanos()); - mouseMotionEvents.add(mouseMotionEvent); - } + onCursorPos(window, xpos, ypos); } }); 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); + onWheelScroll(window, xOffset, yOffset); } }); 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(convertButton(button), action == GLFW_PRESS, mouseX, mouseY); - mouseButtonEvent.setTime(getInputTimeNanos()); - mouseButtonEvents.add(mouseButtonEvent); + onMouseButton(window, button, action, mods); } }); @@ -160,6 +179,10 @@ public class GlfwMouseInput implements MouseInput { scrollCallback.release(); mouseButtonCallback.release(); + for (long glfwCursor : jmeToGlfwCursorMap.values()) { + glfwDestroyCursor(glfwCursor); + } + logger.fine("Mouse destroyed."); } @@ -185,31 +208,52 @@ public class GlfwMouseInput implements MouseInput { return (long) (glfwGetTime() * 1000000000); } - public void setNativeCursor(final JmeCursor jmeCursor) { + private long createGlfwCursor(JmeCursor jmeCursor) { + GLFWImage glfwImage = new GLFWImage(BufferUtils.createByteBuffer(GLFWImage.SIZEOF)); + + // TODO: currently animated cursors are not supported + IntBuffer imageData = jmeCursor.getImagesData(); + ByteBuffer buf = BufferUtils.createByteBuffer(imageData.capacity()); + buf.asIntBuffer().put(imageData); + + glfwImage.set(jmeCursor.getWidth(), jmeCursor.getHeight(), buf); + + return glfwCreateCursor(glfwImage, jmeCursor.getXHotSpot(), jmeCursor.getYHotSpot()); + } + + public void setNativeCursor(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); + Long glfwCursor = jmeToGlfwCursorMap.get(jmeCursor); + + if (glfwCursor == null) { + glfwCursor = createGlfwCursor(jmeCursor); + jmeToGlfwCursorMap.put(jmeCursor, glfwCursor); + } + + glfwSetCursor(context.getWindowHandle(), glfwCursor); + } else { + glfwSetCursor(context.getWindowHandle(), MemoryUtil.NULL); } } /** - * Simply converts the GLFW button code to a JME button code. If there is no match it just returns the GLFW button - * code. Bare in mind GLFW supports 8 different mouse buttons. + * Simply converts the GLFW button code to a JME button code. If there is no + * match it just returns the GLFW button code. Bear in mind GLFW supports 8 + * different mouse buttons. * * @param glfwButton the raw GLFW button index. * @return the mapped {@link MouseInput} button id. */ private int convertButton(final int glfwButton) { - if (glfwButton == GLFW_MOUSE_BUTTON_LEFT) { - return MouseInput.BUTTON_LEFT; - } else if(glfwButton == GLFW_MOUSE_BUTTON_MIDDLE) { - return MouseInput.BUTTON_MIDDLE; - } else if(glfwButton == GLFW_MOUSE_BUTTON_RIGHT) { - return MouseInput.BUTTON_RIGHT; + switch (glfwButton) { + case GLFW_MOUSE_BUTTON_LEFT: + return MouseInput.BUTTON_LEFT; + case GLFW_MOUSE_BUTTON_MIDDLE: + return MouseInput.BUTTON_MIDDLE; + case GLFW_MOUSE_BUTTON_RIGHT: + return MouseInput.BUTTON_RIGHT; + default: + return glfwButton; } - - return glfwButton; } } diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java index 61ea20b71..a74b19cdb 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglContext.java @@ -43,9 +43,7 @@ import com.jme3.renderer.lwjgl.LwjglGLFboEXT; import com.jme3.renderer.lwjgl.LwjglGLFboGL3; import com.jme3.renderer.opengl.*; import com.jme3.system.*; -import org.lwjgl.Sys; import org.lwjgl.glfw.GLFW; -import org.lwjgl.opengl.ARBDebugOutput; import org.lwjgl.opengl.ARBFramebufferObject; import org.lwjgl.opengl.EXTFramebufferMultisample; import org.lwjgl.opengl.GLCapabilities; @@ -53,9 +51,10 @@ import org.lwjgl.opengl.GLCapabilities; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; +import static org.lwjgl.glfw.GLFW.GLFW_TRUE; +import org.lwjgl.opengl.ARBDebugOutput; import static org.lwjgl.opengl.GL.createCapabilities; -import static org.lwjgl.opengl.GL11.GL_TRUE; import static org.lwjgl.opengl.GL11.glGetInteger; /** @@ -84,16 +83,16 @@ public abstract class LwjglContext implements JmeContext { } 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()}); + logger.log(Level.INFO, "LWJGL {0} context running on thread {1}\n" + + " * Graphics Adapter: GLFW {2}", + new Object[]{org.lwjgl.Version.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) { + if (GLFW.glfwExtensionSupported("GL_ARB_framebuffer_object") == GLFW_TRUE) { return glGetInteger(ARBFramebufferObject.GL_MAX_SAMPLES); - } else if (GLFW.glfwExtensionSupported("GL_EXT_framebuffer_multisample") == GL_TRUE) { + } else if (GLFW.glfwExtensionSupported("GL_EXT_framebuffer_multisample") == GLFW_TRUE) { return glGetInteger(EXTFramebufferMultisample.GL_MAX_SAMPLES_EXT); } @@ -180,11 +179,11 @@ public abstract class LwjglContext implements JmeContext { } 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. + ARBDebugOutput.glDebugMessageCallbackARB(new LwjglGLDebugOutputHandler(), 0); } - renderer.setMainFrameBufferSrgb(settings.getGammaCorrection()); - renderer.setLinearizeSrgbImages(settings.getGammaCorrection()); + renderer.setMainFrameBufferSrgb(settings.isGammaCorrection()); + renderer.setLinearizeSrgbImages(settings.isGammaCorrection()); // Init input if (keyInput != null) { @@ -198,7 +197,6 @@ public abstract class LwjglContext implements JmeContext { if (joyInput != null) { joyInput.initialize(); } - renderable.set(true); } @@ -240,26 +238,32 @@ public abstract class LwjglContext implements JmeContext { } } + @Override public boolean isCreated() { return created.get(); } + @Override public boolean isRenderable() { return renderable.get(); } + @Override public void setSettings(AppSettings settings) { this.settings.copyFrom(settings); } + @Override public AppSettings getSettings() { return settings; } + @Override public Renderer getRenderer() { return renderer; } + @Override public Timer getTimer() { return timer; } diff --git a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java index e1f4dcf73..48cdd1cab 100644 --- a/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java +++ b/jme3-lwjgl3/src/main/java/com/jme3/system/lwjgl/LwjglWindow.java @@ -43,7 +43,6 @@ import com.jme3.system.AppSettings; import com.jme3.system.JmeContext; import com.jme3.system.JmeSystem; import com.jme3.system.NanoTimer; -import org.lwjgl.Sys; import org.lwjgl.glfw.*; import java.awt.*; @@ -52,6 +51,7 @@ import java.nio.ByteBuffer; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; +import org.lwjgl.Version; import static org.lwjgl.glfw.GLFW.*; import static org.lwjgl.opengl.GL11.GL_FALSE; @@ -72,7 +72,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { protected boolean wasActive = false; protected boolean autoFlush = true; protected boolean allowSwapBuffers = false; - private long window = -1; + private long window = NULL; private final JmeContext.Type type; private int frameRateLimit = -1; private double frameSleepTime; @@ -102,7 +102,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { * @param title the title to set */ public void setTitle(final String title) { - if (created.get() && window != -1) { + if (created.get() && window != NULL) { glfwSetWindowTitle(window, title); } } @@ -127,45 +127,45 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { glfwSetErrorCallback(errorCallback = new GLFWErrorCallback() { @Override public void invoke(int error, long description) { - final String message = Callbacks.errorCallbackDescriptionString(description); + final String message = GLFWErrorCallback.getDescription(description); listener.handleError(message, new Exception(message)); } }); - if (glfwInit() != GL_TRUE) { + if (glfwInit() != GLFW_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(); + if (settings.getRenderer().equals(AppSettings.LWJGL_OPENGL3)) { + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); + } else { + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); } - final ByteBuffer videoMode = glfwGetVideoMode(glfwGetPrimaryMonitor()); - - if (settings.getWidth() <= 0 || settings.getHeight() <= 0) { - settings.setResolution(GLFWvidmode.width(videoMode), GLFWvidmode.height(videoMode)); + if (settings.getBoolean("RendererDebug")) { + glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); } - window = glfwCreateWindow(settings.getWidth(), settings.getHeight(), settings.getTitle(), monitor, NULL); - - if (window == NULL) { - throw new RuntimeException("Failed to create the GLFW window"); + if (settings.isGammaCorrection()) { + glfwWindowHint(GLFW_SRGB_CAPABLE, GLFW_TRUE); } - glfwWindowHint(GLFW_RESIZABLE, settings.isResizable() ? GL_TRUE : GL_FALSE); + glfwWindowHint(GLFW_VISIBLE, GL_FALSE); + glfwWindowHint(GLFW_RESIZABLE, settings.isResizable() ? GLFW_TRUE : GLFW_FALSE); + + glfwWindowHint(GLFW_DOUBLE_BUFFER, GLFW_TRUE); 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); + glfwWindowHint(GLFW_STEREO, settings.useStereo3D() ? GLFW_TRUE : GLFW_FALSE); glfwWindowHint(GLFW_REFRESH_RATE, settings.getFrequency()); - // Not sure how else to support bits per pixel if (settings.getBitsPerPixel() == 24) { glfwWindowHint(GLFW_RED_BITS, 8); glfwWindowHint(GLFW_GREEN_BITS, 8); @@ -178,6 +178,34 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { glfwWindowHint(GLFW_ALPHA_BITS, settings.getAlphaBits()); + // TODO: Add support for monitor selection + long monitor = NULL; + + if (settings.isFullscreen()) { + monitor = glfwGetPrimaryMonitor(); + } + + final GLFWVidMode videoMode = glfwGetVideoMode(glfwGetPrimaryMonitor()); + + if (settings.getWidth() <= 0 || settings.getHeight() <= 0) { + settings.setResolution(videoMode.width(), videoMode.height()); + } + + window = glfwCreateWindow(settings.getWidth(), settings.getHeight(), settings.getTitle(), monitor, NULL); + + if (window == NULL) { + throw new RuntimeException("Failed to create the GLFW 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); + } + }); + glfwSetWindowFocusCallback(window, windowFocusCallback = new GLFWWindowFocusCallback() { @Override public void invoke(final long window, final int focused) { @@ -197,8 +225,10 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { }); // Center the window - if (!settings.isFullscreen() && Type.Display.equals(type)) { - glfwSetWindowPos(window, (GLFWvidmode.width(videoMode) - settings.getWidth()) / 2, (GLFWvidmode.height(videoMode) - settings.getHeight()) / 2); + if (!settings.isFullscreen()) { + glfwSetWindowPos(window, + (videoMode.width() - settings.getWidth()) / 2, + (videoMode.height() - settings.getHeight()) / 2); } // Make the OpenGL context current @@ -216,14 +246,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { 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); - } - }); + glfwShowWindow(window); allowSwapBuffers = settings.isSwapBuffers(); @@ -239,12 +262,24 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { renderer.cleanup(); } - errorCallback.release(); - windowSizeCallback.release(); - windowFocusCallback.release(); + if (errorCallback != null) { + errorCallback.release(); + errorCallback = null; + } + + if (windowSizeCallback != null) { + windowSizeCallback.release(); + windowSizeCallback = null; + } - if (window != 0) { + if (windowFocusCallback != null) { + windowFocusCallback.release(); + windowFocusCallback = null; + } + + if (window != NULL) { glfwDestroyWindow(window); + window = NULL; } } catch (Exception ex) { listener.handleError("Failed to destroy context", ex); @@ -296,8 +331,9 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { super.internalCreate(); } catch (Exception ex) { try { - if (window != -1) { + if (window != NULL) { glfwDestroyWindow(window); + window = NULL; } } catch (Exception ex2) { LOGGER.log(Level.WARNING, null, ex2); @@ -318,6 +354,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { // If a restart is required, lets recreate the context. if (needRestart.getAndSet(false)) { try { + destroyContext(); createContext(settings); } catch (Exception ex) { LOGGER.log(Level.SEVERE, "Failed to set display settings!", ex); @@ -346,8 +383,6 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { } } - glfwPollEvents(); - // Subclasses just call GLObjectManager clean up objects here // it is safe .. for now. if (renderer != null) { @@ -377,6 +412,8 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { } } } + + glfwPollEvents(); } private void setFrameRateLimit(int frameRateLimit) { @@ -389,11 +426,12 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { */ protected void deinitInThread() { + listener.destroy(); + destroyContext(); + super.internalDestroy(); - listener.destroy(); LOGGER.fine("Display destroyed."); - super.internalDestroy(); } public void run() { @@ -403,7 +441,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { } loadNatives(); - LOGGER.log(Level.FINE, "Using LWJGL {0}", Sys.getVersion()); + LOGGER.log(Level.FINE, "Using LWJGL {0}", Version.getVersion()); if (!initInThread()) { LOGGER.log(Level.SEVERE, "Display initialization failed. Cannot continue."); @@ -411,15 +449,16 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { } while (true) { - if (glfwWindowShouldClose(window) == GL_TRUE) { - listener.requestClose(false); - } runLoop(); if (needClose.get()) { break; } + + if (glfwWindowShouldClose(window) == GL_TRUE) { + listener.requestClose(false); + } } deinitInThread();