├── .classpath ├── .gitignore ├── .project ├── .settings └── org.eclipse.jdt.core.prefs └── src ├── LwjglJavaFX.java ├── TestApp.java ├── com └── badlogic │ └── gdx │ └── backends │ └── lwjgl │ ├── LwjglFXApplication.java │ ├── LwjglFXGraphics.java │ ├── LwjglFXInput.java │ └── LwjglToJavaFX.java ├── mapeditor.fxml └── org └── lwjgl └── util └── stream ├── RenderStream.java ├── RenderStreamINTEL.java ├── RenderStreamPBO.java ├── RenderStreamPBOAMD.java ├── RenderStreamPBOCopy.java ├── RenderStreamPBODefault.java ├── StreamBuffered.java ├── StreamBufferedPBO.java ├── StreamHandler.java ├── StreamUtil.java ├── TextureStream.java ├── TextureStreamINTEL.java ├── TextureStreamPBO.java ├── TextureStreamPBODefault.java └── TextureStreamPBORange.java /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /.settings/ -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | LibGdx-FX 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 5 | org.eclipse.jdt.core.compiler.compliance=1.8 6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 11 | org.eclipse.jdt.core.compiler.source=1.8 12 | -------------------------------------------------------------------------------- /src/LwjglJavaFX.java: -------------------------------------------------------------------------------- 1 | import java.net.URL; 2 | 3 | import com.badlogic.gdx.backends.lwjgl.LwjglFXApplication; 4 | 5 | import javafx.application.Application; 6 | import javafx.fxml.FXMLLoader; 7 | import javafx.geometry.Rectangle2D; 8 | import javafx.scene.Scene; 9 | import javafx.scene.image.ImageView; 10 | import javafx.scene.layout.AnchorPane; 11 | import javafx.scene.layout.BorderPane; 12 | import javafx.stage.Screen; 13 | import javafx.stage.Stage; 14 | 15 | 16 | public class LwjglJavaFX extends Application{ 17 | public static void main(String[] args) { 18 | Application.launch(args); 19 | } 20 | 21 | @Override 22 | public void start(Stage stage) { 23 | stage.setTitle("JavaFX Window"); 24 | 25 | stage.setMinWidth(640); 26 | stage.setMinHeight(480); 27 | 28 | final Screen screen = Screen.getPrimary(); 29 | final Rectangle2D screenBounds = screen.getVisualBounds(); 30 | 31 | if ( screenBounds.getWidth() < stage.getWidth() || screenBounds.getHeight() < stage.getHeight() ) { 32 | stage.setX(screenBounds.getMinX()); 33 | stage.setY(screenBounds.getMinY()); 34 | 35 | stage.setWidth(screenBounds.getWidth()); 36 | stage.setHeight(screenBounds.getHeight()); 37 | } 38 | 39 | BorderPane pane = new BorderPane(); 40 | final URL fxmlURL = getClass().getClassLoader().getResource("mapeditor.fxml"); 41 | final FXMLLoader fxmlLoader = new FXMLLoader(fxmlURL); 42 | fxmlLoader.setRoot(pane); 43 | 44 | try { 45 | pane = (BorderPane)fxmlLoader.load(); 46 | } catch (Exception e) { 47 | e.printStackTrace(); 48 | System.exit(-1); 49 | return; 50 | } 51 | 52 | final Scene scene = new Scene(pane); 53 | 54 | stage.setScene(scene); 55 | stage.show(); 56 | ImageView glArea = (ImageView) pane.lookup("#glTarget"); 57 | glArea.fitWidthProperty().bind(((AnchorPane)glArea.getParent()).widthProperty()); 58 | glArea.fitHeightProperty().bind(((AnchorPane)glArea.getParent()).heightProperty()); 59 | 60 | //LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration(); 61 | //cfg.vSyncEnabled = true; 62 | new LwjglFXApplication(new TestApp(), glArea); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/TestApp.java: -------------------------------------------------------------------------------- 1 | import com.badlogic.gdx.ApplicationListener; 2 | import com.badlogic.gdx.Gdx; 3 | import com.badlogic.gdx.graphics.Color; 4 | import com.badlogic.gdx.graphics.GL20; 5 | import com.badlogic.gdx.graphics.OrthographicCamera; 6 | import com.badlogic.gdx.graphics.glutils.ShapeRenderer; 7 | import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType; 8 | import com.badlogic.gdx.math.MathUtils; 9 | 10 | public class TestApp implements ApplicationListener { 11 | 12 | private OrthographicCamera camera; 13 | private ShapeRenderer renderer; 14 | float deg = 0, x = 0, y = 0; 15 | 16 | @Override 17 | public void create() { 18 | float w = Gdx.graphics.getWidth(); 19 | float h = Gdx.graphics.getHeight(); 20 | 21 | camera = new OrthographicCamera(w, h); 22 | renderer = new ShapeRenderer(); 23 | } 24 | 25 | @Override 26 | public void resize(int width, int height) { 27 | if(camera != null) camera.setToOrtho(false, width, height); 28 | x = camera.position.x; 29 | y = camera.position.y; 30 | } 31 | @Override 32 | public void render() { 33 | Gdx.gl.glClearColor(0, 0, 0, 1); 34 | Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT); 35 | 36 | camera.update(); 37 | renderer.setProjectionMatrix(camera.combined); 38 | renderer.setColor(Color.RED); 39 | renderer.begin(ShapeType.Line); 40 | renderer.line(x, y, x+100f*MathUtils.cos(-deg/10f), y+100f*MathUtils.sin(-deg/10f)); 41 | renderer.end(); 42 | deg++; 43 | 44 | Gdx.graphics.setTitle("Fps: "+ Gdx.graphics.getFramesPerSecond()); 45 | } 46 | 47 | @Override 48 | public void pause() { 49 | } 50 | 51 | @Override 52 | public void resume() { 53 | } 54 | 55 | @Override 56 | public void dispose() { 57 | renderer.dispose(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/com/badlogic/gdx/backends/lwjgl/LwjglFXApplication.java: -------------------------------------------------------------------------------- 1 | package com.badlogic.gdx.backends.lwjgl; 2 | 3 | import javafx.application.Platform; 4 | import javafx.scene.image.ImageView; 5 | import javafx.stage.Stage; 6 | 7 | import org.lwjgl.LWJGLException; 8 | import org.lwjgl.opengl.Display; 9 | import org.lwjgl.util.stream.StreamUtil; 10 | 11 | import com.badlogic.gdx.ApplicationListener; 12 | import com.badlogic.gdx.Gdx; 13 | import com.badlogic.gdx.LifecycleListener; 14 | import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration; 15 | import com.badlogic.gdx.backends.lwjgl.LwjglFXGraphics; 16 | import com.badlogic.gdx.utils.Array; 17 | import com.badlogic.gdx.utils.GdxRuntimeException; 18 | 19 | 20 | public class LwjglFXApplication extends LwjglApplication{ 21 | 22 | private boolean shouldRender, isActive = true; 23 | LwjglFXInput input; 24 | 25 | public LwjglFXApplication (ApplicationListener listener, ImageView target) { 26 | this(listener, target, new LwjglApplicationConfiguration()); 27 | } 28 | 29 | public LwjglFXApplication (ApplicationListener listener, ImageView target, LwjglApplicationConfiguration config) { 30 | this(listener, config, new LwjglFXGraphics(config, target)); 31 | } 32 | 33 | public LwjglFXApplication (ApplicationListener listener, LwjglApplicationConfiguration config, LwjglFXGraphics graphics) { 34 | super(listener, config, graphics); 35 | input = new LwjglFXInput(graphics.target); 36 | Gdx.input = input; 37 | } 38 | 39 | private void resize(){ 40 | Platform.runLater(() -> { 41 | Gdx.app.postRunnable(() -> { 42 | ImageView target = ((LwjglFXGraphics)graphics).target; 43 | int width = (int)target.fitWidthProperty().get(); 44 | int height = (int)target.fitHeightProperty().get(); 45 | graphics.resize = false; 46 | graphics.config.width = width; 47 | graphics.config.height = height; 48 | if (listener != null) listener.resize(width, height); 49 | shouldRender = true; 50 | graphics.requestRendering(); 51 | }); 52 | }); 53 | } 54 | 55 | @Override 56 | void mainLoop () { 57 | Array lifecycleListeners = this.lifecycleListeners; 58 | ImageView target = ((LwjglFXGraphics)graphics).target; 59 | Stage stage = (Stage)target.getScene().getWindow(); 60 | target.fitWidthProperty().addListener(e -> resize()); 61 | target.fitHeightProperty().addListener(e -> resize()); 62 | stage.setOnCloseRequest(e -> exit()); 63 | LwjglToJavaFX toFX; 64 | try { 65 | graphics.setupDisplay(); 66 | toFX = ((LwjglFXGraphics)graphics).toFX; 67 | toFX.setRenderStreamFactory(StreamUtil.getRenderStreamImplementations().get(1)); 68 | } catch (LWJGLException e) { 69 | throw new GdxRuntimeException(e); 70 | } 71 | 72 | listener.create(); 73 | graphics.resize = true; 74 | 75 | graphics.lastTime = System.nanoTime(); 76 | boolean wasActive = true; 77 | while (running) { 78 | isActive = stage.isFocused(); 79 | if (wasActive && !isActive) { // if it's just recently minimized from active state 80 | wasActive = false; 81 | synchronized (lifecycleListeners) { 82 | for (LifecycleListener listener : lifecycleListeners) 83 | listener.pause(); 84 | } 85 | listener.pause(); 86 | } 87 | if (!wasActive && isActive) { // if it's just recently focused from minimized state 88 | wasActive = true; 89 | listener.resume(); 90 | synchronized (lifecycleListeners) { 91 | for (LifecycleListener listener : lifecycleListeners) 92 | listener.resume(); 93 | } 94 | } 95 | 96 | shouldRender = false; 97 | graphics.config.x = (int) ((LwjglFXGraphics)graphics).target.getLayoutX(); 98 | graphics.config.y = (int) ((LwjglFXGraphics)graphics).target.getLayoutY(); 99 | 100 | if (executeRunnables()) shouldRender = true; 101 | 102 | // If one of the runnables set running to false, for example after an exit(). 103 | if (!running) break; 104 | shouldRender |= graphics.shouldRender(); 105 | input.processEvents(); 106 | if (audio != null) audio.update(); 107 | 108 | if (!isActive && graphics.config.backgroundFPS == -1) shouldRender = false; 109 | int frameRate = isActive ? graphics.config.foregroundFPS : graphics.config.backgroundFPS; 110 | if (shouldRender) { 111 | graphics.updateTime(); 112 | toFX.begin(); 113 | listener.render(); 114 | toFX.end(); 115 | } else { 116 | // Sleeps to avoid wasting CPU in an empty loop. 117 | if (frameRate == -1) frameRate = 10; 118 | if (frameRate == 0) frameRate = graphics.config.backgroundFPS; 119 | if (frameRate == 0) frameRate = 30; 120 | } 121 | if (frameRate > 0 && graphics.vsync) Display.sync(frameRate); 122 | } 123 | 124 | synchronized (lifecycleListeners) { 125 | for (LifecycleListener listener : lifecycleListeners) { 126 | listener.pause(); 127 | listener.dispose(); 128 | } 129 | } 130 | listener.pause(); 131 | listener.dispose(); 132 | toFX.dispose(); 133 | if (audio != null) audio.dispose(); 134 | if (graphics.config.forceExit) System.exit(-1); 135 | } 136 | 137 | } 138 | -------------------------------------------------------------------------------- /src/com/badlogic/gdx/backends/lwjgl/LwjglFXGraphics.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.gdx.backends.lwjgl; 18 | 19 | import com.badlogic.gdx.Gdx; 20 | import com.badlogic.gdx.graphics.Pixmap; 21 | import com.badlogic.gdx.graphics.Pixmap.Format; 22 | import com.badlogic.gdx.utils.GdxRuntimeException; 23 | 24 | import java.nio.ByteBuffer; 25 | 26 | import javafx.application.Platform; 27 | import javafx.scene.image.ImageView; 28 | import javafx.stage.Stage; 29 | 30 | import org.lwjgl.LWJGLException; 31 | import org.lwjgl.opengl.Display; 32 | 33 | 34 | public class LwjglFXGraphics extends LwjglGraphics { 35 | ImageView target; 36 | LwjglToJavaFX toFX; 37 | 38 | LwjglFXGraphics (LwjglApplicationConfiguration config, ImageView target) { 39 | super(config); 40 | this.target = target; 41 | } 42 | 43 | LwjglFXGraphics (ImageView target) { 44 | this(new LwjglApplicationConfiguration(), target); 45 | } 46 | 47 | @Override 48 | public int getHeight () { 49 | return (int) target.getLayoutBounds().getHeight(); 50 | } 51 | 52 | @Override 53 | public int getWidth () { 54 | return (int) target.getLayoutBounds().getWidth(); 55 | } 56 | 57 | @Override 58 | void setupDisplay () throws LWJGLException { 59 | if (canvas != null) { 60 | Display.setParent(canvas); 61 | } else { 62 | if (!setDisplayMode(config.width, config.height, config.fullscreen)) 63 | throw new GdxRuntimeException("Couldn't set display mode " + config.width + "x" + config.height + ", fullscreen: " 64 | + config.fullscreen); 65 | 66 | if (config.iconPaths.size > 0) { 67 | ByteBuffer[] icons = new ByteBuffer[config.iconPaths.size]; 68 | for (int i = 0, n = config.iconPaths.size; i < n; i++) { 69 | Pixmap pixmap = new Pixmap(Gdx.files.getFileHandle(config.iconPaths.get(i), config.iconFileTypes.get(i))); 70 | if (pixmap.getFormat() != Format.RGBA8888) { 71 | Pixmap rgba = new Pixmap(pixmap.getWidth(), pixmap.getHeight(), Format.RGBA8888); 72 | rgba.drawPixmap(pixmap, 0, 0); 73 | pixmap = rgba; 74 | } 75 | icons[i] = ByteBuffer.allocateDirect(pixmap.getPixels().limit()); 76 | icons[i].put(pixmap.getPixels()).flip(); 77 | pixmap.dispose(); 78 | } 79 | } 80 | } 81 | Display.setInitialBackground(config.initialBackgroundColor.r, config.initialBackgroundColor.g, 82 | config.initialBackgroundColor.b); 83 | 84 | if (config.x != -1 && config.y != -1) Display.setLocation(config.x, config.y); 85 | createDisplayPixelFormat(); 86 | config.x = Display.getX(); 87 | config.y = Display.getY(); 88 | initiateGLInstances(); 89 | } 90 | 91 | private void createDisplayPixelFormat () { 92 | bufferFormat = new BufferFormat(config.r, config.g, config.b, config.a, config.depth, config.stencil, config.samples, false); 93 | this.toFX = new LwjglToJavaFX(target); 94 | } 95 | 96 | @Override 97 | public void setTitle(String title){ 98 | Platform.runLater(() -> ((Stage)target.getScene().getWindow()).setTitle(title)); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/com/badlogic/gdx/backends/lwjgl/LwjglFXInput.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011 See AUTHORS file. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | ******************************************************************************/ 16 | 17 | package com.badlogic.gdx.backends.lwjgl; 18 | 19 | import java.util.ArrayList; 20 | import java.util.HashSet; 21 | import java.util.List; 22 | import java.util.Set; 23 | 24 | import javafx.application.Platform; 25 | import javafx.scene.image.ImageView; 26 | import javafx.scene.input.KeyCode; 27 | import javafx.scene.input.MouseButton; 28 | import javafx.scene.input.MouseEvent; 29 | import javafx.scene.input.ScrollEvent; 30 | 31 | import com.badlogic.gdx.graphics.Pixmap; 32 | import com.badlogic.gdx.utils.GdxRuntimeException; 33 | import com.badlogic.gdx.Input; 34 | import com.badlogic.gdx.InputProcessor; 35 | import com.badlogic.gdx.utils.Pool; 36 | 37 | /** An implementation of the {@link Input} interface hooking a JavaFX ImageView for input. 38 | * 39 | * @author Trixt0r */ 40 | final public class LwjglFXInput implements Input { 41 | static public float keyRepeatInitialTime = 0.4f; 42 | static public float keyRepeatTime = 0.1f; 43 | 44 | List keyEvents = new ArrayList(); 45 | List touchEvents = new ArrayList(); 46 | boolean mousePressed = false; 47 | int mouseX, mouseY; 48 | int deltaX, deltaY; 49 | int pressedKeys = 0; 50 | boolean justTouched = false; 51 | Set pressedButtons = new HashSet(); 52 | InputProcessor processor; 53 | char lastKeyCharPressed; 54 | float keyRepeatTimer; 55 | long currentEventTimeStamp; 56 | ImageView target; 57 | int x,y, lastX, lastY; 58 | KeyCode lastKeyCode; 59 | MouseButton lastButton; 60 | boolean isPressed, hasFocus = false; 61 | 62 | Pool usedKeyEvents = new Pool(16, 1000) { 63 | protected KeyEvent newObject () { 64 | return new KeyEvent(); 65 | } 66 | }; 67 | 68 | Pool usedTouchEvents = new Pool(16, 1000) { 69 | protected TouchEvent newObject () { 70 | return new TouchEvent(); 71 | } 72 | }; 73 | 74 | public LwjglFXInput (ImageView target) { 75 | this.target = target; 76 | this.target.addEventHandler(MouseEvent.MOUSE_PRESSED, e -> lastButton = e.getButton()); 77 | this.target.getScene().addEventHandler(javafx.scene.input.KeyEvent.KEY_PRESSED, e ->{ 78 | if(!hasFocus) return; 79 | lastKeyCode = e.getCode(); 80 | int keyCode = getGdxKeyCode(lastKeyCode); 81 | char keyChar = e.getText().charAt(0); 82 | long timeStamp = System.nanoTime(); 83 | KeyEvent event = usedKeyEvents.obtain(); 84 | event.keyCode = keyCode; 85 | event.keyChar = 0; 86 | event.type = KeyEvent.KEY_DOWN; 87 | event.timeStamp = timeStamp; 88 | keyEvents.add(event); 89 | 90 | event = usedKeyEvents.obtain(); 91 | event.keyCode = 0; 92 | event.keyChar = keyChar; 93 | event.type = KeyEvent.KEY_TYPED; 94 | event.timeStamp = timeStamp; 95 | keyEvents.add(event); 96 | 97 | pressedKeys++; 98 | lastKeyCharPressed = keyChar; 99 | keyRepeatTimer = keyRepeatInitialTime; 100 | }); 101 | this.target.getScene().addEventHandler(javafx.scene.input.KeyEvent.KEY_RELEASED, e ->{ 102 | if(!hasFocus) return; 103 | lastKeyCode = null; 104 | int keyCode = getGdxKeyCode(e.getCode()); 105 | KeyEvent event = usedKeyEvents.obtain(); 106 | event.keyCode = keyCode; 107 | event.keyChar = 0; 108 | event.type = KeyEvent.KEY_UP; 109 | event.timeStamp = System.nanoTime(); 110 | keyEvents.add(event); 111 | pressedKeys--; 112 | lastKeyCharPressed = 0; 113 | }); 114 | 115 | 116 | this.target.addEventHandler(MouseEvent.ANY, e -> { 117 | TouchEvent event = usedTouchEvents.obtain(); 118 | event.x = (int) e.getX(); 119 | event.y = (int) e.getY(); 120 | event.button = toGdxButton(e.getButton()); 121 | event.pointer = 0; 122 | event.timeStamp = System.nanoTime(); 123 | deltaX = 0; deltaY = 0; 124 | if (e.getEventType() == MouseEvent.MOUSE_DRAGGED) 125 | event.type = TouchEvent.TOUCH_DRAGGED; 126 | else if(e.getEventType() == MouseEvent.MOUSE_MOVED) 127 | event.type = TouchEvent.TOUCH_MOVED; 128 | else if (e.getEventType() == MouseEvent.MOUSE_PRESSED) { 129 | event.type = TouchEvent.TOUCH_DOWN; 130 | pressedButtons.add(event.button); 131 | justTouched = true; 132 | } else if (e.getEventType() == MouseEvent.MOUSE_RELEASED) { 133 | event.type = TouchEvent.TOUCH_UP; 134 | pressedButtons.remove(event.button); 135 | } else return; 136 | touchEvents.add(event); 137 | lastX = mouseX; 138 | lastY = mouseY; 139 | mouseX = event.x; 140 | mouseY = event.y; 141 | }); 142 | 143 | 144 | this.target.addEventHandler(ScrollEvent.SCROLL, e -> { 145 | TouchEvent event = usedTouchEvents.obtain(); 146 | event.x = (int) e.getX(); 147 | event.y = (int) e.getY(); 148 | event.timeStamp = System.nanoTime(); 149 | event.type = TouchEvent.TOUCH_SCROLLED; 150 | event.scrollAmount = (int)-Math.signum(e.getDeltaY()); 151 | touchEvents.add(event); 152 | }); 153 | } 154 | 155 | public float getAccelerometerX () { 156 | return 0; 157 | } 158 | 159 | public float getAccelerometerY () { 160 | return 0; 161 | } 162 | 163 | public float getAccelerometerZ () { 164 | return 0; 165 | } 166 | 167 | public void getTextInput (final TextInputListener listener, final String title, final String text) { 168 | throw new GdxRuntimeException("Not supported"); 169 | } 170 | 171 | public void getPlaceholderTextInput (final TextInputListener listener, final String title, final String placeholder) { 172 | throw new GdxRuntimeException("Not supported"); 173 | } 174 | 175 | public int getX () { 176 | return mouseX; 177 | } 178 | 179 | public int getY () { 180 | return mouseY; 181 | } 182 | 183 | public boolean isAccelerometerAvailable () { 184 | return false; 185 | } 186 | 187 | public boolean isKeyPressed (int key) { 188 | if (key == Input.Keys.ANY_KEY) 189 | return pressedKeys > 0; 190 | else 191 | return getGdxKeyCode(lastKeyCode) == key; 192 | } 193 | 194 | public boolean isTouched () { 195 | return target.isPressed(); 196 | } 197 | 198 | public int getX (int pointer) { 199 | if (pointer > 0) 200 | return 0; 201 | else 202 | return getX(); 203 | } 204 | 205 | public int getY (int pointer) { 206 | if (pointer > 0) 207 | return 0; 208 | else 209 | return getY(); 210 | } 211 | 212 | public boolean isTouched (int pointer) { 213 | if (pointer > 0) 214 | return false; 215 | else 216 | return isTouched(); 217 | } 218 | 219 | public boolean supportsMultitouch () { 220 | return false; 221 | } 222 | 223 | @Override 224 | public void setOnscreenKeyboardVisible (boolean visible) { 225 | 226 | } 227 | 228 | @Override 229 | public void setCatchBackKey (boolean catchBack) { 230 | 231 | } 232 | void processEvents () { 233 | isPressed = target.isPressed(); 234 | if(isPressed && !hasFocus){ 235 | hasFocus = true; 236 | Platform.runLater(() -> { 237 | target.requestFocus(); 238 | }); 239 | } 240 | if(!isPressed && hasFocus && target.getScene().getRoot().isPressed()) hasFocus = false; 241 | synchronized (this) { 242 | if (processor != null) { 243 | InputProcessor processor = this.processor; 244 | int len = keyEvents.size(); 245 | for (int i = 0; i < len; i++) { 246 | KeyEvent e = keyEvents.get(i); 247 | currentEventTimeStamp = e.timeStamp; 248 | switch (e.type) { 249 | case KeyEvent.KEY_DOWN: 250 | processor.keyDown(e.keyCode); 251 | break; 252 | case KeyEvent.KEY_UP: 253 | processor.keyUp(e.keyCode); 254 | break; 255 | case KeyEvent.KEY_TYPED: 256 | processor.keyTyped(e.keyChar); 257 | } 258 | usedKeyEvents.free(e); 259 | } 260 | 261 | len = touchEvents.size(); 262 | for (int i = 0; i < len; i++) { 263 | TouchEvent e = touchEvents.get(i); 264 | currentEventTimeStamp = e.timeStamp; 265 | switch (e.type) { 266 | case TouchEvent.TOUCH_DOWN: 267 | processor.touchDown(e.x, e.y, e.pointer, e.button); 268 | break; 269 | case TouchEvent.TOUCH_UP: 270 | processor.touchUp(e.x, e.y, e.pointer, e.button); 271 | break; 272 | case TouchEvent.TOUCH_DRAGGED: 273 | processor.touchDragged(e.x, e.y, e.pointer); 274 | break; 275 | case TouchEvent.TOUCH_MOVED: 276 | processor.mouseMoved(e.x, e.y); 277 | break; 278 | case TouchEvent.TOUCH_SCROLLED: 279 | processor.scrolled(e.scrollAmount); 280 | } 281 | usedTouchEvents.free(e); 282 | } 283 | } else { 284 | int len = touchEvents.size(); 285 | for (int i = 0; i < len; i++) { 286 | usedTouchEvents.free(touchEvents.get(i)); 287 | } 288 | 289 | len = keyEvents.size(); 290 | for (int i = 0; i < len; i++) { 291 | usedKeyEvents.free(keyEvents.get(i)); 292 | } 293 | } 294 | 295 | keyEvents.clear(); 296 | touchEvents.clear(); 297 | deltaX = mouseX - lastX; 298 | deltaY = mouseY - lastY; 299 | lastX = mouseX; 300 | lastY = mouseY; 301 | 302 | } 303 | } 304 | 305 | public static int getGdxKeyCode (KeyCode code) { 306 | if(code == null) return Keys.UNKNOWN; 307 | switch (code) { 308 | case LEFT_PARENTHESIS: 309 | return Input.Keys.LEFT_BRACKET; 310 | case RIGHT_PARENTHESIS: 311 | return Input.Keys.RIGHT_BRACKET; 312 | case DEAD_GRAVE: 313 | return Input.Keys.GRAVE; 314 | case MULTIPLY: 315 | return Input.Keys.STAR; 316 | case NUM_LOCK: 317 | return Input.Keys.NUM; 318 | case DECIMAL: 319 | return Input.Keys.PERIOD; 320 | case DIVIDE: 321 | return Input.Keys.SLASH; 322 | case META: 323 | return Input.Keys.SYM; 324 | case AT: 325 | return Input.Keys.AT; 326 | case EQUALS: 327 | return Input.Keys.EQUALS; 328 | case DIGIT0: 329 | return Input.Keys.NUM_0; 330 | case DIGIT1: 331 | return Input.Keys.NUM_1; 332 | case DIGIT2: 333 | return Input.Keys.NUM_2; 334 | case DIGIT3: 335 | return Input.Keys.NUM_3; 336 | case DIGIT4: 337 | return Input.Keys.NUM_4; 338 | case DIGIT5: 339 | return Input.Keys.NUM_5; 340 | case DIGIT6: 341 | return Input.Keys.NUM_6; 342 | case DIGIT7: 343 | return Input.Keys.NUM_7; 344 | case DIGIT8: 345 | return Input.Keys.NUM_8; 346 | case DIGIT9: 347 | return Input.Keys.NUM_9; 348 | case A: 349 | return Input.Keys.A; 350 | case B: 351 | return Input.Keys.B; 352 | case C: 353 | return Input.Keys.C; 354 | case D: 355 | return Input.Keys.D; 356 | case E: 357 | return Input.Keys.E; 358 | case F: 359 | return Input.Keys.F; 360 | case G: 361 | return Input.Keys.G; 362 | case H: 363 | return Input.Keys.H; 364 | case I: 365 | return Input.Keys.I; 366 | case J: 367 | return Input.Keys.J; 368 | case K: 369 | return Input.Keys.K; 370 | case L: 371 | return Input.Keys.L; 372 | case M: 373 | return Input.Keys.M; 374 | case N: 375 | return Input.Keys.N; 376 | case O: 377 | return Input.Keys.O; 378 | case P: 379 | return Input.Keys.P; 380 | case Q: 381 | return Input.Keys.Q; 382 | case R: 383 | return Input.Keys.R; 384 | case S: 385 | return Input.Keys.S; 386 | case T: 387 | return Input.Keys.T; 388 | case U: 389 | return Input.Keys.U; 390 | case V: 391 | return Input.Keys.V; 392 | case W: 393 | return Input.Keys.W; 394 | case X: 395 | return Input.Keys.X; 396 | case Y: 397 | return Input.Keys.Y; 398 | case Z: 399 | return Input.Keys.Z; 400 | case ALT: 401 | return Input.Keys.ALT_LEFT; 402 | case BACK_SLASH: 403 | return Input.Keys.BACKSLASH; 404 | case COMMA: 405 | return Input.Keys.COMMA; 406 | case LEFT: 407 | return Input.Keys.DPAD_LEFT; 408 | case RIGHT: 409 | return Input.Keys.DPAD_RIGHT; 410 | case UP: 411 | return Input.Keys.DPAD_UP; 412 | case DOWN: 413 | return Input.Keys.DPAD_DOWN; 414 | case ENTER: 415 | return Input.Keys.ENTER; 416 | case HOME: 417 | return Input.Keys.HOME; 418 | case MINUS: 419 | return Input.Keys.MINUS; 420 | case PERIOD: 421 | return Input.Keys.PERIOD; 422 | case ADD: 423 | return Input.Keys.PLUS; 424 | case SEMICOLON: 425 | return Input.Keys.SEMICOLON; 426 | case SHIFT: 427 | return Input.Keys.SHIFT_LEFT; 428 | case SLASH: 429 | return Input.Keys.SLASH; 430 | case SPACE: 431 | return Input.Keys.SPACE; 432 | case TAB: 433 | return Input.Keys.TAB; 434 | case CONTROL: 435 | return Input.Keys.CONTROL_LEFT; 436 | case PAGE_DOWN: 437 | return Input.Keys.PAGE_DOWN; 438 | case PAGE_UP: 439 | return Input.Keys.PAGE_UP; 440 | case ESCAPE: 441 | return Input.Keys.ESCAPE; 442 | case END: 443 | return Input.Keys.END; 444 | case INSERT: 445 | return Input.Keys.INSERT; 446 | case DELETE: 447 | return Input.Keys.DEL; 448 | case SUBTRACT: 449 | return Input.Keys.MINUS; 450 | case QUOTE: 451 | return Input.Keys.APOSTROPHE; 452 | case F1: 453 | return Input.Keys.F1; 454 | case F2: 455 | return Input.Keys.F2; 456 | case F3: 457 | return Input.Keys.F3; 458 | case F4: 459 | return Input.Keys.F4; 460 | case F5: 461 | return Input.Keys.F5; 462 | case F6: 463 | return Input.Keys.F6; 464 | case F7: 465 | return Input.Keys.F7; 466 | case F8: 467 | return Input.Keys.F8; 468 | case F9: 469 | return Input.Keys.F9; 470 | case F10: 471 | return Input.Keys.F10; 472 | case F11: 473 | return Input.Keys.F11; 474 | case F12: 475 | return Input.Keys.F12; 476 | case COLON: 477 | return Input.Keys.COLON; 478 | case NUMPAD0: 479 | return Input.Keys.NUMPAD_0; 480 | case NUMPAD1: 481 | return Input.Keys.NUMPAD_1; 482 | case NUMPAD2: 483 | return Input.Keys.NUMPAD_2; 484 | case NUMPAD3: 485 | return Input.Keys.NUMPAD_3; 486 | case NUMPAD4: 487 | return Input.Keys.NUMPAD_4; 488 | case NUMPAD5: 489 | return Input.Keys.NUMPAD_5; 490 | case NUMPAD6: 491 | return Input.Keys.NUMPAD_6; 492 | case NUMPAD7: 493 | return Input.Keys.NUMPAD_7; 494 | case NUMPAD8: 495 | return Input.Keys.NUMPAD_8; 496 | case NUMPAD9: 497 | return Input.Keys.NUMPAD_9; 498 | default: 499 | return Input.Keys.UNKNOWN; 500 | } 501 | } 502 | 503 | public static KeyCode getFXKeyCode (int gdxKeyCode) { 504 | switch (gdxKeyCode) { 505 | case Input.Keys.APOSTROPHE: 506 | return KeyCode.QUOTE; 507 | case Input.Keys.LEFT_BRACKET: 508 | return KeyCode.LEFT_PARENTHESIS; 509 | case Input.Keys.RIGHT_BRACKET: 510 | return KeyCode.RIGHT_PARENTHESIS; 511 | case Input.Keys.GRAVE: 512 | return KeyCode.DEAD_GRAVE; 513 | case Input.Keys.STAR: 514 | return KeyCode.MULTIPLY; 515 | case Input.Keys.NUM: 516 | return KeyCode.NUM_LOCK; 517 | case Input.Keys.AT: 518 | return KeyCode.AT; 519 | case Input.Keys.EQUALS: 520 | return KeyCode.EQUALS; 521 | case Input.Keys.SYM: 522 | return KeyCode.META; 523 | case Input.Keys.NUM_0: 524 | return KeyCode.DIGIT0; 525 | case Input.Keys.NUM_1: 526 | return KeyCode.DIGIT1; 527 | case Input.Keys.NUM_2: 528 | return KeyCode.DIGIT2; 529 | case Input.Keys.NUM_3: 530 | return KeyCode.DIGIT3; 531 | case Input.Keys.NUM_4: 532 | return KeyCode.DIGIT4; 533 | case Input.Keys.NUM_5: 534 | return KeyCode.DIGIT5; 535 | case Input.Keys.NUM_6: 536 | return KeyCode.DIGIT6; 537 | case Input.Keys.NUM_7: 538 | return KeyCode.DIGIT7; 539 | case Input.Keys.NUM_8: 540 | return KeyCode.DIGIT8; 541 | case Input.Keys.NUM_9: 542 | return KeyCode.DIGIT9; 543 | case Input.Keys.A: 544 | return KeyCode.A; 545 | case Input.Keys.B: 546 | return KeyCode.B; 547 | case Input.Keys.C: 548 | return KeyCode.C; 549 | case Input.Keys.D: 550 | return KeyCode.D; 551 | case Input.Keys.E: 552 | return KeyCode.E; 553 | case Input.Keys.F: 554 | return KeyCode.F; 555 | case Input.Keys.G: 556 | return KeyCode.G; 557 | case Input.Keys.H: 558 | return KeyCode.H; 559 | case Input.Keys.I: 560 | return KeyCode.I; 561 | case Input.Keys.J: 562 | return KeyCode.J; 563 | case Input.Keys.K: 564 | return KeyCode.K; 565 | case Input.Keys.L: 566 | return KeyCode.L; 567 | case Input.Keys.M: 568 | return KeyCode.M; 569 | case Input.Keys.N: 570 | return KeyCode.N; 571 | case Input.Keys.O: 572 | return KeyCode.O; 573 | case Input.Keys.P: 574 | return KeyCode.P; 575 | case Input.Keys.Q: 576 | return KeyCode.Q; 577 | case Input.Keys.R: 578 | return KeyCode.R; 579 | case Input.Keys.S: 580 | return KeyCode.S; 581 | case Input.Keys.T: 582 | return KeyCode.T; 583 | case Input.Keys.U: 584 | return KeyCode.U; 585 | case Input.Keys.V: 586 | return KeyCode.V; 587 | case Input.Keys.W: 588 | return KeyCode.W; 589 | case Input.Keys.X: 590 | return KeyCode.X; 591 | case Input.Keys.Y: 592 | return KeyCode.Y; 593 | case Input.Keys.Z: 594 | return KeyCode.Z; 595 | case Input.Keys.ALT_LEFT: 596 | return KeyCode.ALT; 597 | case Input.Keys.ALT_RIGHT: 598 | return KeyCode.ALT; 599 | case Input.Keys.BACKSLASH: 600 | return KeyCode.BACK_SLASH; 601 | case Input.Keys.COMMA: 602 | return KeyCode.COMMA; 603 | case Input.Keys.FORWARD_DEL: 604 | return KeyCode.DELETE; 605 | case Input.Keys.DPAD_LEFT: 606 | return KeyCode.LEFT; 607 | case Input.Keys.DPAD_RIGHT: 608 | return KeyCode.RIGHT; 609 | case Input.Keys.DPAD_UP: 610 | return KeyCode.UP; 611 | case Input.Keys.DPAD_DOWN: 612 | return KeyCode.DOWN; 613 | case Input.Keys.ENTER: 614 | return KeyCode.ENTER; 615 | case Input.Keys.HOME: 616 | return KeyCode.HOME; 617 | case Input.Keys.END: 618 | return KeyCode.END; 619 | case Input.Keys.PAGE_DOWN: 620 | return KeyCode.PAGE_DOWN; 621 | case Input.Keys.PAGE_UP: 622 | return KeyCode.PAGE_UP; 623 | case Input.Keys.INSERT: 624 | return KeyCode.INSERT; 625 | case Input.Keys.MINUS: 626 | return KeyCode.MINUS; 627 | case Input.Keys.PERIOD: 628 | return KeyCode.PERIOD; 629 | case Input.Keys.PLUS: 630 | return KeyCode.ADD; 631 | case Input.Keys.SEMICOLON: 632 | return KeyCode.SEMICOLON; 633 | case Input.Keys.SHIFT_LEFT: 634 | return KeyCode.SHIFT; 635 | case Input.Keys.SHIFT_RIGHT: 636 | return KeyCode.SHIFT; 637 | case Input.Keys.SLASH: 638 | return KeyCode.SLASH; 639 | case Input.Keys.SPACE: 640 | return KeyCode.SPACE; 641 | case Input.Keys.TAB: 642 | return KeyCode.TAB; 643 | case Input.Keys.DEL: 644 | return KeyCode.DELETE; 645 | case Input.Keys.CONTROL_LEFT: 646 | return KeyCode.CONTROL; 647 | case Input.Keys.CONTROL_RIGHT: 648 | return KeyCode.CONTROL; 649 | case Input.Keys.ESCAPE: 650 | return KeyCode.ESCAPE; 651 | case Input.Keys.F1: 652 | return KeyCode.F1; 653 | case Input.Keys.F2: 654 | return KeyCode.F2; 655 | case Input.Keys.F3: 656 | return KeyCode.F3; 657 | case Input.Keys.F4: 658 | return KeyCode.F4; 659 | case Input.Keys.F5: 660 | return KeyCode.F5; 661 | case Input.Keys.F6: 662 | return KeyCode.F6; 663 | case Input.Keys.F7: 664 | return KeyCode.F7; 665 | case Input.Keys.F8: 666 | return KeyCode.F8; 667 | case Input.Keys.F9: 668 | return KeyCode.F9; 669 | case Input.Keys.F10: 670 | return KeyCode.F10; 671 | case Input.Keys.F11: 672 | return KeyCode.F11; 673 | case Input.Keys.F12: 674 | return KeyCode.F12; 675 | case Input.Keys.COLON: 676 | return KeyCode.COLON; 677 | case Input.Keys.NUMPAD_0: 678 | return KeyCode.NUMPAD0; 679 | case Input.Keys.NUMPAD_1: 680 | return KeyCode.NUMPAD1; 681 | case Input.Keys.NUMPAD_2: 682 | return KeyCode.NUMPAD2; 683 | case Input.Keys.NUMPAD_3: 684 | return KeyCode.NUMPAD3; 685 | case Input.Keys.NUMPAD_4: 686 | return KeyCode.NUMPAD4; 687 | case Input.Keys.NUMPAD_5: 688 | return KeyCode.NUMPAD5; 689 | case Input.Keys.NUMPAD_6: 690 | return KeyCode.NUMPAD6; 691 | case Input.Keys.NUMPAD_7: 692 | return KeyCode.NUMPAD7; 693 | case Input.Keys.NUMPAD_8: 694 | return KeyCode.NUMPAD8; 695 | case Input.Keys.NUMPAD_9: 696 | return KeyCode.NUMPAD9; 697 | default: 698 | return KeyCode.ACCEPT; 699 | } 700 | } 701 | 702 | 703 | public static int toGdxButton (MouseButton button) { 704 | if (button == MouseButton.PRIMARY) return Buttons.LEFT; 705 | if (button == MouseButton.SECONDARY) return Buttons.RIGHT; 706 | if (button == MouseButton.MIDDLE) return Buttons.MIDDLE; 707 | return Buttons.LEFT; 708 | } 709 | 710 | @Override 711 | public void setInputProcessor (InputProcessor processor) { 712 | this.processor = processor; 713 | } 714 | 715 | @Override 716 | public InputProcessor getInputProcessor () { 717 | return this.processor; 718 | } 719 | 720 | @Override 721 | public void vibrate (int milliseconds) { 722 | } 723 | 724 | @Override 725 | public boolean justTouched () { 726 | return justTouched; 727 | } 728 | 729 | public static MouseButton toLwjglButton (int button) { 730 | switch (button) { 731 | case Buttons.LEFT: 732 | return MouseButton.PRIMARY; 733 | case Buttons.RIGHT: 734 | return MouseButton.SECONDARY; 735 | case Buttons.MIDDLE: 736 | return MouseButton.MIDDLE; 737 | } 738 | return MouseButton.NONE; 739 | } 740 | 741 | @Override 742 | public boolean isButtonPressed (int button) { 743 | return target.isPressed() && lastButton == toLwjglButton(button); 744 | } 745 | 746 | @Override 747 | public void vibrate (long[] pattern, int repeat) { 748 | } 749 | 750 | @Override 751 | public void cancelVibrate () { 752 | } 753 | 754 | @Override 755 | public float getAzimuth () { 756 | return 0; 757 | } 758 | 759 | @Override 760 | public float getPitch () { 761 | return 0; 762 | } 763 | 764 | @Override 765 | public float getRoll () { 766 | return 0; 767 | } 768 | 769 | @Override 770 | public boolean isPeripheralAvailable (Peripheral peripheral) { 771 | if (peripheral == Peripheral.HardwareKeyboard) return true; 772 | return false; 773 | } 774 | 775 | @Override 776 | public int getRotation () { 777 | return 0; 778 | } 779 | 780 | @Override 781 | public Orientation getNativeOrientation () { 782 | return Orientation.Landscape; 783 | } 784 | 785 | @Override 786 | public void setCursorCatched (boolean catched) { 787 | //Mouse.setGrabbed(catched); 788 | } 789 | 790 | @Override 791 | public boolean isCursorCatched () { 792 | return false; 793 | } 794 | 795 | @Override 796 | public int getDeltaX () { 797 | return deltaX; 798 | } 799 | 800 | @Override 801 | public int getDeltaX (int pointer) { 802 | if (pointer == 0) 803 | return deltaX; 804 | else 805 | return 0; 806 | } 807 | 808 | @Override 809 | public int getDeltaY () { 810 | return -deltaY; 811 | } 812 | 813 | @Override 814 | public int getDeltaY (int pointer) { 815 | if (pointer == 0) 816 | return -deltaY; 817 | else 818 | return 0; 819 | } 820 | 821 | @Override 822 | public void setCursorPosition (int x, int y) { 823 | //TODO 824 | } 825 | 826 | @Override 827 | public void setCursorImage(Pixmap pixmap, int xHotspot, int yHotspot) { 828 | throw new GdxRuntimeException("Not supported yet!"); 829 | } 830 | 831 | @Override 832 | public void setCatchMenuKey (boolean catchMenu) { 833 | } 834 | 835 | @Override 836 | public long getCurrentEventTime () { 837 | return currentEventTimeStamp; 838 | } 839 | 840 | @Override 841 | public void getRotationMatrix (float[] matrix) { 842 | // TODO Auto-generated method stub 843 | 844 | } 845 | 846 | class KeyEvent { 847 | static final int KEY_DOWN = 0; 848 | static final int KEY_UP = 1; 849 | static final int KEY_TYPED = 2; 850 | 851 | long timeStamp; 852 | int type; 853 | int keyCode; 854 | char keyChar; 855 | } 856 | 857 | class TouchEvent { 858 | static final int TOUCH_DOWN = 0; 859 | static final int TOUCH_UP = 1; 860 | static final int TOUCH_DRAGGED = 2; 861 | static final int TOUCH_SCROLLED = 3; 862 | static final int TOUCH_MOVED = 4; 863 | 864 | long timeStamp; 865 | int type; 866 | int x; 867 | int y; 868 | int scrollAmount; 869 | int button; 870 | int pointer; 871 | } 872 | } 873 | -------------------------------------------------------------------------------- /src/com/badlogic/gdx/backends/lwjgl/LwjglToJavaFX.java: -------------------------------------------------------------------------------- 1 | package com.badlogic.gdx.backends.lwjgl; 2 | import static org.lwjgl.opengl.AMDDebugOutput.glDebugMessageCallbackAMD; 3 | import static org.lwjgl.opengl.ARBDebugOutput.glDebugMessageCallbackARB; 4 | import static org.lwjgl.opengl.GL11.glGetInteger; 5 | import static org.lwjgl.opengl.GL30.GL_MAX_SAMPLES; 6 | 7 | import java.nio.ByteBuffer; 8 | import java.util.concurrent.ConcurrentLinkedQueue; 9 | import java.util.concurrent.Semaphore; 10 | import java.util.concurrent.atomic.AtomicLong; 11 | 12 | import javafx.application.Platform; 13 | import javafx.scene.image.ImageView; 14 | import javafx.scene.image.WritableImage; 15 | 16 | import org.lwjgl.LWJGLException; 17 | import org.lwjgl.opengl.AMDDebugOutputCallback; 18 | import org.lwjgl.opengl.ARBDebugOutputCallback; 19 | import org.lwjgl.opengl.ContextAttribs; 20 | import org.lwjgl.opengl.ContextCapabilities; 21 | import org.lwjgl.opengl.Drawable; 22 | import org.lwjgl.opengl.GLContext; 23 | import org.lwjgl.opengl.Pbuffer; 24 | import org.lwjgl.opengl.PixelFormat; 25 | import org.lwjgl.util.stream.RenderStream; 26 | import org.lwjgl.util.stream.StreamHandler; 27 | import org.lwjgl.util.stream.StreamUtil; 28 | import org.lwjgl.util.stream.StreamUtil.RenderStreamFactory; 29 | 30 | 31 | public class LwjglToJavaFX { 32 | 33 | static Drawable drawable; 34 | 35 | private final ConcurrentLinkedQueue pendingRunnables; 36 | 37 | private final Pbuffer pbuffer; 38 | private final int maxSamples; 39 | 40 | private RenderStreamFactory renderStreamFactory; 41 | private RenderStream renderStream; 42 | 43 | private ImageView targetView; 44 | private WritableImage renderImage; 45 | 46 | private int transfersToBuffer = 3; 47 | private int samples = 1; 48 | 49 | private final AtomicLong snapshotRequest; 50 | 51 | LwjglToJavaFX(final ImageView target) { 52 | targetView = target; 53 | target.setScaleY(-1); 54 | this.pendingRunnables = new ConcurrentLinkedQueue(); 55 | 56 | if ( (Pbuffer.getCapabilities() & Pbuffer.PBUFFER_SUPPORTED) == 0 ) 57 | throw new UnsupportedOperationException("Support for pbuffers is required."); 58 | 59 | try { 60 | pbuffer = new Pbuffer(1, 1, new PixelFormat(), null, null, new ContextAttribs().withDebug(true)); 61 | pbuffer.makeCurrent(); 62 | } catch (LWJGLException e) { 63 | throw new RuntimeException(e); 64 | } 65 | 66 | drawable = pbuffer; 67 | 68 | final ContextCapabilities caps = GLContext.getCapabilities(); 69 | 70 | if ( caps.OpenGL30 || (caps.GL_EXT_framebuffer_multisample && caps.GL_EXT_framebuffer_blit) ) 71 | maxSamples = glGetInteger(GL_MAX_SAMPLES); 72 | else 73 | maxSamples = 1; 74 | 75 | if ( caps.GL_ARB_debug_output ) 76 | glDebugMessageCallbackARB(new ARBDebugOutputCallback()); 77 | else if ( caps.GL_AMD_debug_output ) 78 | glDebugMessageCallbackAMD(new AMDDebugOutputCallback()); 79 | 80 | this.renderStreamFactory = StreamUtil.getRenderStreamImplementation(); 81 | this.renderStream = renderStreamFactory.create(getReadHandler(), 1, transfersToBuffer); 82 | 83 | this.snapshotRequest = new AtomicLong(); 84 | } 85 | 86 | public int getMaxSamples() { 87 | return maxSamples; 88 | } 89 | 90 | public RenderStreamFactory getRenderStreamFactory() { 91 | return renderStreamFactory; 92 | } 93 | 94 | public void setRenderStreamFactory(final RenderStreamFactory renderStreamFactory) { 95 | pendingRunnables.offer(new Runnable() { 96 | public void run() { 97 | if ( renderStream != null ) 98 | renderStream.destroy(); 99 | 100 | LwjglToJavaFX.this.renderStreamFactory = renderStreamFactory; 101 | 102 | renderStream = renderStreamFactory.create(renderStream.getHandler(), samples, transfersToBuffer); 103 | } 104 | }); 105 | } 106 | 107 | void dispose() { 108 | renderStream.destroy(); 109 | pbuffer.destroy(); 110 | } 111 | 112 | public void updateSnapshot() { 113 | snapshotRequest.incrementAndGet(); 114 | } 115 | 116 | public int getTransfersToBuffer() { 117 | return transfersToBuffer; 118 | } 119 | 120 | public void setTransfersToBuffer(final int transfersToBuffer) { 121 | if ( this.transfersToBuffer == transfersToBuffer ) 122 | return; 123 | 124 | this.transfersToBuffer = transfersToBuffer; 125 | resetStreams(); 126 | } 127 | 128 | public void setSamples(final int samples) { 129 | if ( this.samples == samples ) 130 | return; 131 | 132 | this.samples = samples; 133 | resetStreams(); 134 | } 135 | 136 | private void resetStreams() { 137 | pendingRunnables.offer(new Runnable() { 138 | public void run() { 139 | renderStream.destroy(); 140 | renderStream = renderStreamFactory.create(renderStream.getHandler(), samples, transfersToBuffer); 141 | updateSnapshot(); 142 | } 143 | }); 144 | } 145 | 146 | private void drainPendingActionsQueue() { 147 | Runnable runnable; 148 | while ( (runnable = pendingRunnables.poll()) != null ) 149 | runnable.run(); 150 | } 151 | 152 | void begin(){ 153 | drainPendingActionsQueue(); 154 | renderStream.bind(); 155 | } 156 | 157 | void end(){ 158 | renderStream.swapBuffers(); 159 | } 160 | 161 | private StreamHandler getReadHandler() { 162 | return new StreamHandler() { 163 | 164 | public int getWidth() { 165 | return (int)targetView.getFitWidth(); 166 | } 167 | 168 | public int getHeight() { 169 | return (int)targetView.getFitHeight(); 170 | } 171 | 172 | public void process(final int width, final int height, final ByteBuffer data, final int stride, final Semaphore signal) { 173 | // This method runs in the background rendering thread 174 | // TODO: Run setPixels on the PlatformImage in this thread, run pixelsDirty on JFX application thread with runLater. 175 | Platform.runLater(new Runnable() { 176 | public void run() { 177 | try { 178 | // If we're quitting, discard update 179 | if ( !targetView.isVisible() ) 180 | return; 181 | // Detect resize and recreate the image 182 | if ( renderImage == null || (int)renderImage.getWidth() != width || (int)renderImage.getHeight() != height ) { 183 | renderImage = new WritableImage(width, height); 184 | targetView.setImage(renderImage); 185 | } 186 | 187 | // Upload the image to JavaFX 188 | renderImage.getPixelWriter().setPixels(0, 0, width, height, javafx.scene.image.PixelFormat.getByteBgraPreInstance(), data, stride); 189 | } finally { 190 | // Notify the render thread that we're done processing 191 | signal.release(); 192 | } 193 | } 194 | }); 195 | } 196 | }; 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /src/mapeditor.fxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 |
43 |
44 |
46 |
47 |
48 |
49 |
50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 |