    001//License: GPL. For details, see LICENSE file.
    002package org.openstreetmap.josm.plugins.streetside.gui.imageinfo;
    003
    004import java.awt.image.BufferedImage;
    005
    006import org.openstreetmap.josm.plugins.streetside.cubemap.CameraTransformer;
    007import org.openstreetmap.josm.plugins.streetside.cubemap.GraphicsUtils;
    008import org.openstreetmap.josm.plugins.streetside.utils.CubemapBox;
    009
    010import javafx.application.Platform;
    011import javafx.embed.swing.JFXPanel;
    012import javafx.scene.Group;
    013import javafx.scene.PerspectiveCamera;
    014import javafx.scene.PointLight;
    015import javafx.scene.Scene;
    016import javafx.scene.SceneAntialiasing;
    017import javafx.scene.control.TextArea;
    018import javafx.scene.image.Image;
    019import javafx.scene.input.KeyCode;
    020import javafx.scene.input.MouseEvent;
    021import javafx.scene.layout.VBox;
    022import javafx.scene.paint.Color;
    023import javafx.scene.transform.NonInvertibleTransformException;
    024
    025
    026@SuppressWarnings("restriction")
    027public class ThreeSixtyDegreeViewerPanel extends JFXPanel {
    028
    029        private static final long serialVersionUID = -4940350009018422000L;
    030
    031        private static Scene cubemapScene;
    032
    033        private static Scene defaultScene;
    034
    035        private static Group root;
    036        private static Group subGroup;
    037        private static CubemapBox cubemapBox;
    038        private static PerspectiveCamera camera;
    039        private static CameraTransformer cameraTransform = new CameraTransformer();
    040
    041        private static double mousePosX;
    042        private static double mousePosY;
    043        private static double mouseOldX;
    044        private static double mouseOldY;
    045        private static double mouseDeltaX;
    046        private static double mouseDeltaY;
    047        private static double cameraDistance = 5000;
    048
    049        // Supply Image Paths or a NullPointer will occur
    050        private static Image front;
    051        private static Image right;
    052        private static Image back;
    053        private static Image left;
    054        private static Image up;
    055        private static Image down;
    056
    057        public ThreeSixtyDegreeViewerPanel() {
    058                // constructor
    059        }
    060
    061        public void initialize() {
    062
    063                root = new Group();
    064
    065                camera = new PerspectiveCamera(true);
    066                cameraTransform.setTranslate(0, 0, 0);
    067                cameraTransform.getChildren().addAll(camera);
    068                camera.setNearClip(0.1);
    069                camera.setFarClip(1000000.0);
    070                camera.setFieldOfView(42);
    071                camera.setTranslateZ(-cameraDistance);
    072                // cameraTransform.ry.setAngle(-45.0);
    073                // cameraTransform.rx.setAngle(-10.0);
    074                // add a Point Light for better viewing of the grid coordinate system
    075                final PointLight light = new PointLight(Color.WHITE);
    076
    077                cameraTransform.getChildren().add(light);
    078                light.setTranslateX(camera.getTranslateX());
    079                light.setTranslateY(camera.getTranslateY());
    080                light.setTranslateZ(camera.getTranslateZ());
    081
    082                root.getChildren().add(cameraTransform);
    083
    084                final double size = 100000D;
    085
    086                cubemapBox = new CubemapBox(front, right, back, left, up, down, size, camera);
    087
    088                subGroup = new Group();
    089                subGroup.getChildren().add(cameraTransform);
    090
    091                Platform.runLater(new Runnable() {
    092                        @Override
    093                        public void run() {
    094                                setScene(createDefaultScene());
    095                        }
    096                });
    097        }
    098
    099        public static Scene createScene() /*throws NonInvertibleTransformException*/ {
    100
    101                root = new Group();
    102
    103                camera = new PerspectiveCamera(true);
    104                cameraTransform.setTranslate(0, 0, 0);
    105                cameraTransform.getChildren().addAll(camera);
    106                camera.setNearClip(0.1);
    107                camera.setFarClip(1000000.0);
    108                camera.setFieldOfView(42);
    109                camera.setTranslateZ(-cameraDistance);
    110                final PointLight light = new PointLight(Color.WHITE);
    111
    112                cameraTransform.getChildren().add(light);
    113                light.setTranslateX(camera.getTranslateX());
    114                light.setTranslateY(camera.getTranslateY());
    115                light.setTranslateZ(camera.getTranslateZ());
    116
    117                root.getChildren().add(cameraTransform);
    118
    119                // Load Cubemap box AFTER camera is initialized
    120                final double size = 100000D;
    121
    122                cubemapBox = new CubemapBox(null, null, null, null, null, null, size, camera);
    123
    124                subGroup = new Group();
    125                subGroup.getChildren().add(cameraTransform);
    126
    127                final Scene scene = new Scene(new Group(root), 1024, 668, true, SceneAntialiasing.BALANCED);
    128                scene.setFill(Color.TRANSPARENT);
    129                scene.setCamera(camera);
    130
    131                // First person shooter keyboard movement
    132                scene.setOnKeyPressed(event -> {
    133                        double change = 10.0;
    134                        // Add shift modifier to simulate "Running Speed"
    135                        if (event.isShiftDown()) {
    136                                change = 50.0;
    137                        }
    138                        // What key did the user press?
    139                        final KeyCode keycode = event.getCode();
    140                        // Step 2c: Add Zoom controls
    141                        if (keycode == KeyCode.W) {
    142                                camera.setTranslateZ(camera.getTranslateZ() + change);
    143                        }
    144                        if (keycode == KeyCode.S) {
    145                                camera.setTranslateZ(camera.getTranslateZ() - change);
    146                        }
    147                        // Step 2d: Add Strafe controls
    148                        if (keycode == KeyCode.A) {
    149                                camera.setTranslateX(camera.getTranslateX() - change);
    150                        }
    151                        if (keycode == KeyCode.D) {
    152                                camera.setTranslateX(camera.getTranslateX() + change);
    153                        }
    154                });
    155
    156                scene.setOnMousePressed((MouseEvent me) -> {
    157                        mousePosX = me.getSceneX();
    158                        mousePosY = me.getSceneY();
    159                        mouseOldX = me.getSceneX();
    160                        mouseOldY = me.getSceneY();
    161                });
    162                scene.setOnMouseDragged((MouseEvent me) -> {
    163                        mouseOldX = mousePosX;
    164                        mouseOldY = mousePosY;
    165                        mousePosX = me.getSceneX();
    166                        mousePosY = me.getSceneY();
    167                        mouseDeltaX = mousePosX - mouseOldX;
    168                        mouseDeltaY = mousePosY - mouseOldY;
    169
    170                        double modifier = 10.0;
    171                        final double modifierFactor = 0.1;
    172
    173                        if (me.isControlDown()) {
    174                                modifier = 0.1;
    175                        }
    176                        if (me.isShiftDown()) {
    177                                modifier = 50.0;
    178                        }
    179                        if (me.isPrimaryButtonDown()) {
    180                                cameraTransform.ry.setAngle(
    181                                                ((cameraTransform.ry.getAngle() + mouseDeltaX * modifierFactor * modifier * 2.0) % 360 + 540)
    182                                                                % 360 - 180); // +
    183                                cameraTransform.rx.setAngle(
    184                                                ((cameraTransform.rx.getAngle() - mouseDeltaY * modifierFactor * modifier * 2.0) % 360 + 540)
    185                                                                % 360 - 180); // -
    186
    187                        } else if (me.isSecondaryButtonDown()) {
    188                                final double z = camera.getTranslateZ();
    189                                final double newZ = z + mouseDeltaX * modifierFactor * modifier;
    190                                camera.setTranslateZ(newZ);
    191                        } else if (me.isMiddleButtonDown()) {
    192                                cameraTransform.t.setX(cameraTransform.t.getX() + mouseDeltaX * modifierFactor * modifier * 0.3); // -
    193                                cameraTransform.t.setY(cameraTransform.t.getY() + mouseDeltaY * modifierFactor * modifier * 0.3); // -
    194                        }
    195                });
    196
    197                root.getChildren().addAll(cubemapBox, subGroup);
    198                root.setAutoSizeChildren(true);
    199
    200                subGroup.setAutoSizeChildren(true);
    201
    202                // prevent content from disappearing after resizing
    203                Platform.setImplicitExit(false);
    204
    205                return scene;
    206        }
    207
    208        private static Scene createDefaultScene() {
    209                // Load Cubemap box AFTER camera is initialized
    210
    211                TextArea textArea = new TextArea();
    212                textArea.setText("No Streetside image selected.");
    213
    214                VBox vbox = new VBox(textArea);
    215
    216                root = new Group();
    217
    218    camera = new PerspectiveCamera(true);
    219    cameraTransform.setTranslate(0, 0, 0);
    220    cameraTransform.getChildren().addAll(camera);
    221    camera.setNearClip(0.1);
    222    camera.setFarClip(1000000.0);
    223    camera.setFieldOfView(42);
    224    camera.setTranslateZ(-cameraDistance);
    225    final PointLight light = new PointLight(Color.WHITE);
    226
    227    cameraTransform.getChildren().add(light);
    228    light.setTranslateX(camera.getTranslateX());
    229    light.setTranslateY(camera.getTranslateY());
    230    light.setTranslateZ(camera.getTranslateZ());
    231
    232    root.getChildren().add(cameraTransform);
    233
    234    // Load Cubemap box AFTER camera is initialized
    235    final double size = 100000D;
    236
    237    cubemapBox = new CubemapBox(null, null, null, null, null, null, size, camera);
    238
    239    subGroup = new Group();
    240    subGroup.getChildren().add(cameraTransform);
    241
    242    /*final Scene*/ cubemapScene = new Scene(new Group(root), 1024, 668, true, SceneAntialiasing.BALANCED);
    243    cubemapScene.setFill(Color.TRANSPARENT);
    244    cubemapScene.setCamera(camera);
    245
    246    // First person shooter keyboard movement
    247    cubemapScene.setOnKeyPressed(event -> {
    248      double change = 10.0;
    249      // Add shift modifier to simulate "Running Speed"
    250      if (event.isShiftDown()) {
    251        change = 50.0;
    252      }
    253      // What key did the user press?
    254      final KeyCode keycode = event.getCode();
    255      // Step 2c: Add Zoom controls
    256      if (keycode == KeyCode.W) {
    257        camera.setTranslateZ(camera.getTranslateZ() + change);
    258      }
    259      if (keycode == KeyCode.S) {
    260        camera.setTranslateZ(camera.getTranslateZ() - change);
    261      }
    262      // Step 2d: Add Strafe controls
    263      if (keycode == KeyCode.A) {
    264        camera.setTranslateX(camera.getTranslateX() - change);
    265      }
    266      if (keycode == KeyCode.D) {
    267        camera.setTranslateX(camera.getTranslateX() + change);
    268      }
    269    });
    270
    271    cubemapScene.setOnMousePressed((MouseEvent me) -> {
    272      mousePosX = me.getSceneX();
    273      mousePosY = me.getSceneY();
    274      mouseOldX = me.getSceneX();
    275      mouseOldY = me.getSceneY();
    276    });
    277    cubemapScene.setOnMouseDragged((MouseEvent me) -> {
    278      mouseOldX = mousePosX;
    279      mouseOldY = mousePosY;
    280      mousePosX = me.getSceneX();
    281      mousePosY = me.getSceneY();
    282      mouseDeltaX = mousePosX - mouseOldX;
    283      mouseDeltaY = mousePosY - mouseOldY;
    284
    285      double modifier = 10.0;
    286      final double modifierFactor = 0.1;
    287
    288      if (me.isControlDown()) {
    289        modifier = 0.1;
    290      }
    291      if (me.isShiftDown()) {
    292        modifier = 50.0;
    293      }
    294      if (me.isPrimaryButtonDown()) {
    295        cameraTransform.ry.setAngle(
    296            ((cameraTransform.ry.getAngle() + mouseDeltaX * modifierFactor * modifier * 2.0) % 360 + 540)
    297                % 360 - 180); // +
    298        cameraTransform.rx.setAngle(
    299            ((cameraTransform.rx.getAngle() - mouseDeltaY * modifierFactor * modifier * 2.0) % 360 + 540)
    300                % 360 - 180); // -
    301
    302      } else if (me.isSecondaryButtonDown()) {
    303        final double z = camera.getTranslateZ();
    304        final double newZ = z + mouseDeltaX * modifierFactor * modifier;
    305        camera.setTranslateZ(newZ);
    306      } else if (me.isMiddleButtonDown()) {
    307        cameraTransform.t.setX(cameraTransform.t.getX() + mouseDeltaX * modifierFactor * modifier * 0.3); // -
    308        cameraTransform.t.setY(cameraTransform.t.getY() + mouseDeltaY * modifierFactor * modifier * 0.3); // -
    309      }
    310    });
    311
    312    root.getChildren().addAll(cubemapBox, subGroup);
    313    root.setAutoSizeChildren(true);
    314
    315    subGroup.setAutoSizeChildren(true);
    316
    317    // prevent content from disappearing after resizing
    318    Platform.setImplicitExit(false);
    319
    320    defaultScene = new Scene(vbox, 200, 100);
    321                return defaultScene;
    322        }
    323
    324        public static Scene createScene(BufferedImage img0, BufferedImage img1, BufferedImage img2, BufferedImage img3,
    325                        BufferedImage img4, BufferedImage img5) throws NonInvertibleTransformException {
    326                front = GraphicsUtils.convertBufferedImage2JavaFXImage(img0);
    327                right = GraphicsUtils.convertBufferedImage2JavaFXImage(img1);
    328                back = GraphicsUtils.convertBufferedImage2JavaFXImage(img2);
    329                left = GraphicsUtils.convertBufferedImage2JavaFXImage(img3);
    330                up = GraphicsUtils.convertBufferedImage2JavaFXImage(img4);
    331                down = GraphicsUtils.convertBufferedImage2JavaFXImage(img5);
    332
    333                root = new Group();
    334
    335                camera = new PerspectiveCamera(true);
    336                cameraTransform.setTranslate(0, 0, 0);
    337                cameraTransform.getChildren().addAll(camera);
    338                camera.setNearClip(0.1);
    339                camera.setFarClip(1000000.0);
    340                camera.setFieldOfView(42);
    341                camera.setTranslateZ(-cameraDistance);
    342                final PointLight light = new PointLight(Color.WHITE);
    343
    344                cameraTransform.getChildren().add(light);
    345                light.setTranslateX(camera.getTranslateX());
    346                light.setTranslateY(camera.getTranslateY());
    347                light.setTranslateZ(camera.getTranslateZ());
    348
    349                root.getChildren().add(cameraTransform);
    350
    351                // Load Cubemap box AFTER camera is initialized
    352                final double size = 100000D;
    353
    354                cubemapBox = new CubemapBox(front, right, back, left, up, down, size, camera);
    355
    356                final Group torusGroup = new Group();
    357                torusGroup.getChildren().add(cameraTransform);
    358
    359                final Scene scene = new Scene(new Group(root), 1024, 668, true, SceneAntialiasing.BALANCED);
    360                scene.setFill(Color.TRANSPARENT);
    361                scene.setCamera(camera);
    362
    363                // First person shooter keyboard movement
    364                scene.setOnKeyPressed(event -> {
    365                        double change = 10.0;
    366                        // Add shift modifier to simulate "Running Speed"
    367                        if (event.isShiftDown()) {
    368                                change = 50.0;
    369                        }
    370                        // What key did the user press?
    371                        final KeyCode keycode = event.getCode();
    372                        // Step 2c: Add Zoom controls
    373                        if (keycode == KeyCode.W) {
    374                                camera.setTranslateZ(camera.getTranslateZ() + change);
    375                        }
    376                        if (keycode == KeyCode.S) {
    377                                camera.setTranslateZ(camera.getTranslateZ() - change);
    378                        }
    379                        // Step 2d: Add Strafe controls
    380                        if (keycode == KeyCode.A) {
    381                                camera.setTranslateX(camera.getTranslateX() - change);
    382                        }
    383                        if (keycode == KeyCode.D) {
    384                                camera.setTranslateX(camera.getTranslateX() + change);
    385                        }
    386
    387                });
    388
    389                scene.setOnMousePressed((MouseEvent me) -> {
    390                        mousePosX = me.getSceneX();
    391                        mousePosY = me.getSceneY();
    392                        mouseOldX = me.getSceneX();
    393                        mouseOldY = me.getSceneY();
    394                });
    395                scene.setOnMouseDragged((MouseEvent me) -> {
    396                        mouseOldX = mousePosX;
    397                        mouseOldY = mousePosY;
    398                        mousePosX = me.getSceneX();
    399                        mousePosY = me.getSceneY();
    400                        mouseDeltaX = mousePosX - mouseOldX;
    401                        mouseDeltaY = mousePosY - mouseOldY;
    402
    403                        double modifier = 10.0;
    404                        final double modifierFactor = 0.1;
    405
    406                        if (me.isControlDown()) {
    407                                modifier = 0.1;
    408                        }
    409                        if (me.isShiftDown()) {
    410                                modifier = 50.0;
    411                        }
    412                        if (me.isPrimaryButtonDown()) {
    413                                cameraTransform.ry.setAngle(
    414                                                ((cameraTransform.ry.getAngle() + mouseDeltaX * modifierFactor * modifier * 2.0) % 360 + 540)
    415                                                                % 360 - 180); // +
    416                                cameraTransform.rx.setAngle(
    417                                                ((cameraTransform.rx.getAngle() - mouseDeltaY * modifierFactor * modifier * 2.0) % 360 + 540)
    418                                                                % 360 - 180); // -
    419
    420                        } else if (me.isSecondaryButtonDown()) {
    421                                final double z = camera.getTranslateZ();
    422                                final double newZ = z + mouseDeltaX * modifierFactor * modifier;
    423                                camera.setTranslateZ(newZ);
    424                        } else if (me.isMiddleButtonDown()) {
    425                                cameraTransform.t.setX(cameraTransform.t.getX() + mouseDeltaX * modifierFactor * modifier * 0.3); // -
    426                                cameraTransform.t.setY(cameraTransform.t.getY() + mouseDeltaY * modifierFactor * modifier * 0.3); // -
    427                        }
    428                });
    429
    430                root.getChildren().addAll(cubemapBox, torusGroup);
    431                root.setAutoSizeChildren(true);
    432
    433                return scene;
    434        }
    435
    436        public CubemapBox getCubemapBox() {
    437                if (cubemapBox == null) {
    438                        // shouldn't happen
    439                        initialize();
    440                }
    441                return cubemapBox;
    442        }
    443
    444  public Scene getDefaultScene() {
    445    return defaultScene;
    446  }
    447
    448  public Scene getCubemapScene() {
    449    return cubemapScene;
    450  }
    451}