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}