1 /*
   2  * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javafx.scene;
  27 
  28 import com.sun.javafx.geom.Vec3d;
  29 import com.sun.javafx.geom.transform.Affine3D;
  30 import com.sun.javafx.geom.transform.GeneralTransform3D;
  31 import com.sun.javafx.sg.prism.NGNode;
  32 import com.sun.javafx.sg.prism.NGParallelCamera;
  33 import com.sun.javafx.sg.prism.NGPerspectiveCamera;
  34 import com.sun.javafx.test.TransformHelper;
  35 import com.sun.javafx.tk.Toolkit;
  36 import javafx.scene.transform.NonInvertibleTransformException;
  37 import javafx.stage.Stage;
  38 import org.junit.Test;
  39 
  40 import static org.junit.Assert.*;
  41 
  42 public class CameraTest {
  43 
  44     static final GeneralTransform3D DEFAULT_PROJVIEW_TX;
  45     static {
  46         GeneralTransform3D expected = new GeneralTransform3D();
  47         expected.perspective(true, Math.toRadians(30), 1.5, 0.1, 100);
  48         final double tanOfHalfFOV = Math.tan(Math.toRadians(30) / 2.0);
  49         Affine3D view = new Affine3D();
  50         final double scale = 2.0 * tanOfHalfFOV / 200;
  51         view.setToTranslation(-tanOfHalfFOV * 1.5, tanOfHalfFOV, 0.0);
  52         view.translate(0, 0, -1);
  53         view.rotate(Math.PI, 1, 0, 0);
  54         view.scale(scale, scale, scale);
  55         expected.mul(view);
  56         DEFAULT_PROJVIEW_TX = expected;
  57     }
  58 
  59     /**
  60      * Test of setNearClip method, of class Camera.
  61      */
  62     @Test
  63     public void testSetNearClip() {
  64         Camera camera = new PerspectiveCamera();
  65         camera.setTranslateZ(-10);
  66         camera.setNearClip(10);
  67 
  68         assertEquals(10, camera.getNearClip(), 1e-3);
  69         assertEquals(90, camera.getFarClipInScene(), 1e-3);
  70         assertEquals(0, camera.getNearClipInScene(), 1e-3);
  71     }
  72 
  73     /**
  74      * Test of getNearClipInScene method, of class Camera.
  75      */
  76     @Test
  77     public void testGetNearClipInScene() {
  78         Camera camera = new PerspectiveCamera();
  79         camera.setTranslateZ(-10);
  80 
  81         assertEquals(-9.9, camera.getNearClipInScene(), 1e-3);
  82     }
  83 
  84     /**
  85      * Test of setFarClip method, of class Camera.
  86      */
  87     @Test
  88     public void testSetFarClip() {
  89         Camera camera = new PerspectiveCamera();
  90         camera.setTranslateZ(-10);
  91         camera.setFarClip(200);
  92 
  93         assertEquals(200, camera.getFarClip(), 1e-3);
  94         assertEquals(-9.9, camera.getNearClipInScene(), 1e-3);
  95         assertEquals(190, camera.getFarClipInScene(), 1e-3);
  96     }
  97 
  98     /**
  99      * Test of getFarClipInScene method, of class Camera.
 100      */
 101     @Test
 102     public void testGetFarClipInScene() {
 103         Camera camera = new PerspectiveCamera();
 104         camera.setTranslateZ(-10);
 105         camera.setFarClip(60);
 106 
 107         assertEquals(50, camera.getFarClipInScene(), 1e-3);
 108     }
 109 
 110     @Test
 111     public void testLocalToSceneTxChange() {
 112         Camera camera = new PerspectiveCamera();
 113         camera.setTranslateZ(-10);
 114         assertEquals(0.1, camera.getNearClip(), 1e-3);
 115         assertEquals(100, camera.getFarClip(), 1e-3);
 116         assertEquals(-9.9, camera.getNearClipInScene(), 1e-3);
 117         assertEquals(90, camera.getFarClipInScene(), 1e-3);
 118 
 119         camera.setTranslateZ(100);
 120         assertEquals(0.1, camera.getNearClip(), 1e-3);
 121         assertEquals(100, camera.getFarClip(), 1e-3);
 122         assertEquals(100.1, camera.getNearClipInScene(), 1e-3);
 123         assertEquals(200, camera.getFarClipInScene(), 1e-3);
 124     }
 125 
 126     /**
 127      * Test of getSceneToLocalTransform method, of class Camera.
 128      */
 129     @Test
 130     public void testGetSceneToLocalTransform() {
 131         Camera camera = new PerspectiveCamera();
 132         new Scene(new Group(camera));
 133         camera.setTranslateX(300);
 134         camera.getParent().setTranslateY(100);
 135         Affine3D expected = new Affine3D();
 136         try {
 137             camera.getLocalToSceneTransform().createInverse().impl_apply(expected);
 138         } catch (NonInvertibleTransformException ex) {
 139             fail("NonInvertibleTransformException when compute sceneToLocalTx.");
 140         }
 141         assertEquals(expected, camera.getSceneToLocalTransform());
 142 
 143         camera.setTranslateZ(-10);
 144         camera.setScaleX(10);
 145         expected.setToIdentity();
 146         try {
 147             camera.getLocalToSceneTransform().createInverse().impl_apply(expected);
 148         } catch (NonInvertibleTransformException ex) {
 149             fail("NonInvertibleTransformException when compute sceneToLocalTx.");
 150         }
 151         assertEquals(expected, camera.getSceneToLocalTransform());
 152     }
 153 
 154     /**
 155      * Test of getSceneToLocalTransform method when camera is not in scene.
 156      */
 157     @Test
 158     public void testGetSceneToLocalTransformWhenNotInScene() {
 159         Camera camera = new PerspectiveCamera();
 160         Affine3D expected = new Affine3D();
 161         assertEquals(expected, camera.getSceneToLocalTransform());
 162 
 163         try {
 164             camera.getLocalToSceneTransform().createInverse().impl_apply(expected);
 165         } catch (NonInvertibleTransformException ex) {
 166             fail("NonInvertibleTransformException when compute sceneToLocalTx.");
 167         }
 168         assertEquals(expected, camera.getSceneToLocalTransform());
 169 
 170         camera.setTranslateZ(-10);
 171         camera.setScaleX(10);
 172         expected.setToIdentity();
 173         try {
 174             camera.getLocalToSceneTransform().createInverse().impl_apply(expected);
 175         } catch (NonInvertibleTransformException ex) {
 176             fail("NonInvertibleTransformException when compute sceneToLocalTx.");
 177         }
 178         assertEquals(expected, camera.getSceneToLocalTransform());
 179     }
 180 
 181     @Test
 182     public void testViewSize() {
 183         final Scene scene = new Scene(new Group(), 300, 200);
 184         Camera camera = new PerspectiveCamera();
 185         scene.setCamera(camera);
 186         assertEquals(300.0, camera.getViewWidth(), 1.0e-20);
 187         assertEquals(200.0, camera.getViewHeight(), 1.0e-20);
 188     }
 189 
 190     @Test
 191     public void testDefaultCamera() {
 192         final Scene scene = new Scene(new Group(), 300, 200);
 193         Camera camera = scene.getEffectiveCamera();
 194 
 195         assertTrue(camera instanceof ParallelCamera);
 196         assertEquals(300.0, camera.getViewWidth(), 1.0e-20);
 197         assertEquals(200.0, camera.getViewHeight(), 1.0e-20);
 198     }
 199 
 200     @Test
 201     public void testParallelProjViewTx() {
 202         final Scene scene = new Scene(new Group(), 300, 200);
 203         Camera camera = new ParallelCamera();
 204         scene.setCamera(camera);
 205 
 206         GeneralTransform3D expected = new GeneralTransform3D();
 207         expected.ortho(0.0, 300, 200, 0.0, -150, 150);
 208 
 209         TransformHelper.assertMatrix(camera.getProjViewTransform(), expected);
 210     }
 211 
 212     @Test
 213     public void testParallelProjViewTxWithMovedCamera() {
 214         final Scene scene = new Scene(new Group(), 300, 200);
 215         Camera camera = new ParallelCamera();
 216         scene.setCamera(camera);
 217         scene.getRoot().getChildren().add(camera);
 218         scene.getRoot().setTranslateX(50);
 219         camera.setTranslateY(60);
 220 
 221         GeneralTransform3D expected = new GeneralTransform3D();
 222         expected.ortho(0.0, 300, 200, 0.0, -150, 150);
 223         expected.mul(Affine3D.getTranslateInstance(-50, -60));
 224 
 225         TransformHelper.assertMatrix(camera.getProjViewTransform(), expected);
 226     }
 227 
 228     @Test
 229     public void testParallelProjViewTxWithMovedCameraNotInScene() {
 230         final Scene scene = new Scene(new Group(), 300, 200);
 231         Camera camera = new ParallelCamera();
 232         scene.setCamera(camera);
 233         scene.getRoot().setTranslateX(50);
 234         camera.setTranslateX(50);
 235         camera.setTranslateY(60);
 236 
 237         GeneralTransform3D expected = new GeneralTransform3D();
 238         expected.ortho(0.0, 300, 200, 0.0, -150, 150);
 239         expected.mul(Affine3D.getTranslateInstance(-50, -60));
 240 
 241         TransformHelper.assertMatrix(camera.getProjViewTransform(), expected);
 242     }
 243 
 244     @Test
 245     public void testParallelProjViewTxWithMovedCameraNotInScene2() {
 246         final Scene scene = new Scene(new Group(), 300, 200);
 247         Camera camera = new ParallelCamera();
 248         scene.setCamera(camera);
 249         scene.getRoot().setTranslateX(50);
 250         new Group(camera);
 251         camera.getParent().setTranslateX(50);
 252         camera.setTranslateY(60);
 253 
 254         GeneralTransform3D expected = new GeneralTransform3D();
 255         expected.ortho(0.0, 300, 200, 0.0, -150, 150);
 256         expected.mul(Affine3D.getTranslateInstance(-50, -60));
 257 
 258         TransformHelper.assertMatrix(camera.getProjViewTransform(), expected);
 259     }
 260 
 261     @Test
 262     public void testPerspectiveProjViewTx() {
 263         final Scene scene = new Scene(new Group(), 300, 200);
 264         PerspectiveCamera camera = new PerspectiveCamera();
 265         scene.setCamera(camera);
 266 
 267         TransformHelper.assertMatrix(camera.getProjViewTransform(), DEFAULT_PROJVIEW_TX);
 268     }
 269 
 270     @Test
 271     public void testPerspectiveProjViewTxWithModifiedParams() {
 272         final Scene scene = new Scene(new Group(), 300, 200);
 273         PerspectiveCamera camera = new PerspectiveCamera();
 274         camera.setVerticalFieldOfView(false);
 275         camera.setFieldOfView(40);
 276         camera.setNearClip(1);
 277         camera.setFarClip(200);
 278         scene.setCamera(camera);
 279 
 280         GeneralTransform3D expected = new GeneralTransform3D();
 281         expected.perspective(false, Math.toRadians(40), 1.5, 1.0, 200);
 282 
 283         final double tanOfHalfFOV = Math.tan(Math.toRadians(40) / 2.0);
 284 
 285         Affine3D view = new Affine3D();
 286         final double scale = 2.0 * tanOfHalfFOV / 300;
 287 
 288         view.setToTranslation(-tanOfHalfFOV, tanOfHalfFOV / 1.5, 0.0);
 289         view.translate(0, 0, -1);
 290         view.rotate(Math.PI, 1, 0, 0);
 291         view.scale(scale, scale, scale);
 292 
 293         expected.mul(view);
 294 
 295         TransformHelper.assertMatrix(camera.getProjViewTransform(), expected);
 296     }
 297 
 298     @Test
 299     public void testPerspectiveProjViewTxWithMovedCamera() {
 300         final Scene scene = new Scene(new Group(), 300, 200);
 301         PerspectiveCamera camera = new PerspectiveCamera();
 302         scene.setCamera(camera);
 303         scene.getRoot().getChildren().add(camera);
 304         scene.getRoot().setTranslateX(50);
 305         camera.setTranslateY(60);
 306 
 307         GeneralTransform3D expected = new GeneralTransform3D();
 308         expected.perspective(true, Math.toRadians(30), 1.5, 0.1, 100);
 309 
 310         final double tanOfHalfFOV = Math.tan(Math.toRadians(30) / 2.0);
 311 
 312         Affine3D view = new Affine3D();
 313         final double scale = 2.0 * tanOfHalfFOV / 200;
 314 
 315         view.setToTranslation(-tanOfHalfFOV * 1.5, tanOfHalfFOV, 0.0);
 316         view.translate(0, 0, -1);
 317         view.rotate(Math.PI, 1, 0, 0);
 318         view.scale(scale, scale, scale);
 319 
 320         expected.mul(view);
 321         expected.mul(Affine3D.getTranslateInstance(-50, -60));
 322 
 323         TransformHelper.assertMatrix(camera.getProjViewTransform(), expected);
 324     }
 325 
 326     @Test
 327     public void testPerspectiveProjViewTxWithMovedCameraNotInScene() {
 328         final Scene scene = new Scene(new Group(), 300, 200);
 329         PerspectiveCamera camera = new PerspectiveCamera();
 330         scene.setCamera(camera);
 331         scene.getRoot().setTranslateX(50);
 332         camera.setTranslateX(50);
 333         camera.setTranslateY(60);
 334 
 335         GeneralTransform3D expected = new GeneralTransform3D();
 336         expected.perspective(true, Math.toRadians(30), 1.5, 0.1, 100);
 337 
 338         final double tanOfHalfFOV = Math.tan(Math.toRadians(30) / 2.0);
 339 
 340         Affine3D view = new Affine3D();
 341         final double scale = 2.0 * tanOfHalfFOV / 200;
 342 
 343         view.setToTranslation(-tanOfHalfFOV * 1.5, tanOfHalfFOV, 0.0);
 344         view.translate(0, 0, -1);
 345         view.rotate(Math.PI, 1, 0, 0);
 346         view.scale(scale, scale, scale);
 347 
 348         expected.mul(view);
 349         expected.mul(Affine3D.getTranslateInstance(-50, -60));
 350 
 351         TransformHelper.assertMatrix(camera.getProjViewTransform(), expected);
 352     }
 353 
 354     @Test
 355     public void testPerspectiveProjViewTxWithMovedCameraNotInScene2() {
 356         final Scene scene = new Scene(new Group(), 300, 200);
 357         PerspectiveCamera camera = new PerspectiveCamera();
 358         scene.setCamera(camera);
 359         scene.getRoot().setTranslateX(50);
 360         new Group(camera);
 361         camera.getParent().setTranslateX(50);
 362         camera.setTranslateY(60);
 363 
 364         GeneralTransform3D expected = new GeneralTransform3D();
 365         expected.perspective(true, Math.toRadians(30), 1.5, 0.1, 100);
 366 
 367         final double tanOfHalfFOV = Math.tan(Math.toRadians(30) / 2.0);
 368 
 369         Affine3D view = new Affine3D();
 370         final double scale = 2.0 * tanOfHalfFOV / 200;
 371 
 372         view.setToTranslation(-tanOfHalfFOV * 1.5, tanOfHalfFOV, 0.0);
 373         view.translate(0, 0, -1);
 374         view.rotate(Math.PI, 1, 0, 0);
 375         view.scale(scale, scale, scale);
 376 
 377         expected.mul(view);
 378         expected.mul(Affine3D.getTranslateInstance(-50, -60));
 379 
 380         TransformHelper.assertMatrix(camera.getProjViewTransform(), expected);
 381     }
 382 
 383     @Test
 384     public void testPerspectiveProjViewTxWithFixedEye() {
 385         final Scene scene = new Scene(new Group(), 300, 200);
 386         PerspectiveCamera camera = new PerspectiveCamera(true);
 387         scene.setCamera(camera);
 388 
 389         GeneralTransform3D expected = new GeneralTransform3D();
 390         expected.perspective(true, Math.toRadians(30), 1.5, 0.1, 100);
 391 
 392         Affine3D view = new Affine3D();
 393         view.rotate(Math.PI, 1, 0, 0);
 394 
 395         expected.mul(view);
 396 
 397         TransformHelper.assertMatrix(camera.getProjViewTransform(), expected);
 398     }
 399 
 400     @Test
 401     public void testPerspectiveProjViewTxWithFixedEyeAndModifiedParams() {
 402         final Scene scene = new Scene(new Group(), 300, 200);
 403         PerspectiveCamera camera = new PerspectiveCamera(true);
 404         camera.setVerticalFieldOfView(false);
 405         camera.setFieldOfView(40);
 406         camera.setNearClip(1);
 407         camera.setFarClip(200);
 408         scene.setCamera(camera);
 409 
 410         GeneralTransform3D expected = new GeneralTransform3D();
 411         expected.perspective(false, Math.toRadians(40), 1.5, 1.0, 200);
 412 
 413         Affine3D view = new Affine3D();
 414         view.rotate(Math.PI, 1, 0, 0);
 415 
 416         expected.mul(view);
 417 
 418         TransformHelper.assertMatrix(camera.getProjViewTransform(), expected);
 419     }
 420 
 421     @Test
 422     public void testPerspectiveProjViewTxWithFixedEyeAndMovedCamera() {
 423         final Scene scene = new Scene(new Group(), 300, 200);
 424         PerspectiveCamera camera = new PerspectiveCamera(true);
 425         scene.setCamera(camera);
 426         scene.getRoot().getChildren().add(camera);
 427         scene.getRoot().setTranslateX(50);
 428         camera.setTranslateY(60);
 429 
 430         GeneralTransform3D expected = new GeneralTransform3D();
 431         expected.perspective(true, Math.toRadians(30), 1.5, 0.1, 100);
 432 
 433         Affine3D view = new Affine3D();
 434         view.rotate(Math.PI, 1, 0, 0);
 435 
 436         expected.mul(view);
 437         expected.mul(Affine3D.getTranslateInstance(-50, -60));
 438 
 439         TransformHelper.assertMatrix(camera.getProjViewTransform(), expected);
 440     }
 441 
 442     @Test
 443     public void testPerspectiveProjViewTxWithFixedEyeAndMovedCameraNotInScene() {
 444         final Scene scene = new Scene(new Group(), 300, 200);
 445         PerspectiveCamera camera = new PerspectiveCamera(true);
 446         scene.setCamera(camera);
 447         scene.getRoot().setTranslateX(50);
 448         camera.setTranslateX(50);
 449         camera.setTranslateY(60);
 450 
 451         GeneralTransform3D expected = new GeneralTransform3D();
 452         expected.perspective(true, Math.toRadians(30), 1.5, 0.1, 100);
 453 
 454         Affine3D view = new Affine3D();
 455         view.rotate(Math.PI, 1, 0, 0);
 456 
 457         expected.mul(view);
 458         expected.mul(Affine3D.getTranslateInstance(-50, -60));
 459 
 460         TransformHelper.assertMatrix(camera.getProjViewTransform(), expected);
 461     }
 462 
 463     @Test
 464     public void testPerspectiveProjViewTxWithFixedEyeAndMovedCameraNotInScene2() {
 465         final Scene scene = new Scene(new Group(), 300, 200);
 466         PerspectiveCamera camera = new PerspectiveCamera(true);
 467         scene.setCamera(camera);
 468         scene.getRoot().setTranslateX(50);
 469         new Group(camera);
 470         camera.getParent().setTranslateX(50);
 471         camera.setTranslateY(60);
 472 
 473         GeneralTransform3D expected = new GeneralTransform3D();
 474         expected.perspective(true, Math.toRadians(30), 1.5, 0.1, 100);
 475 
 476         Affine3D view = new Affine3D();
 477         view.rotate(Math.PI, 1, 0, 0);
 478 
 479         expected.mul(view);
 480         expected.mul(Affine3D.getTranslateInstance(-50, -60));
 481 
 482         TransformHelper.assertMatrix(camera.getProjViewTransform(), expected);
 483     }
 484 
 485     @Test
 486     public void testParallelCameraPosition() {
 487         Scene scene = new Scene(new Group(), 300, 200);
 488         Camera cam = new ParallelCamera();
 489         scene.setCamera(cam);
 490         Vec3d v = cam.computePosition(null);
 491         assertEquals(150.0, v.x, 0.000001);
 492         assertEquals(100.0, v.y, 0.000001);
 493         assertEquals(-373.205080, v.z, 0.000001);
 494     }
 495 
 496     @Test
 497     public void testPerspectiveCameraPositionWithFixedEye() {
 498         Scene scene = new Scene(new Group(), 300, 200);
 499         Camera cam = new PerspectiveCamera(true);
 500         scene.setCamera(cam);
 501         Vec3d v = cam.computePosition(null);
 502         assertEquals(0.0, v.x, 0.000001);
 503         assertEquals(0.0, v.y, 0.000001);
 504         assertEquals(0.0, v.z, 0.000001);
 505     }
 506 
 507     @Test
 508     public void testPerspectiveCameraPosition() {
 509         Scene scene = new Scene(new Group(), 300, 200);
 510         Camera cam = new PerspectiveCamera();
 511         scene.setCamera(cam);
 512         Vec3d v = cam.computePosition(null);
 513         assertEquals(150.0, v.x, 0.000001);
 514         assertEquals(100.0, v.y, 0.000001);
 515         assertEquals(-373.205080, v.z, 0.000001);
 516     }
 517 
 518     @Test
 519     public void perspectiveCameraShouldSyncWhenAssignedToScene() {
 520         final Scene scene = new Scene(new Group(), 300, 200);
 521         PerspectiveCamera camera = new StubPerspectiveCamera();
 522         scene.setCamera(camera);
 523         Stage stage = new Stage();
 524         stage.setScene(scene);
 525         stage.show();
 526 
 527         Toolkit.getToolkit().firePulse();
 528 
 529         StubNGPerspectiveCamera pc = camera.impl_getPeer();
 530 
 531         assertEquals(300, pc.getViewWidth(), 0.00001);
 532         assertEquals(200, pc.getViewHeight(), 0.00001);
 533 
 534         TransformHelper.assertMatrix(pc.getProjViewTx(), DEFAULT_PROJVIEW_TX);
 535         assertTrue(pc.isVerticalFieldOfView());
 536         assertEquals(30, pc.getFieldOfView(), 0.00001);
 537         assertEquals(150.0, pc.getPosition().x, 0.000001);
 538         assertEquals(100.0, pc.getPosition().y, 0.000001);
 539         assertEquals(-373.205080, pc.getPosition().z, 0.000001);
 540     }
 541 
 542     @Test
 543     public void perspectiveCameraShouldSyncWhenAssignedToSubScene() {
 544         SubScene sub = new SubScene(new Group(), 300, 200);
 545         final Scene scene = new Scene(new Group(sub), 600, 300);
 546         PerspectiveCamera camera = new StubPerspectiveCamera();
 547         sub.setCamera(camera);
 548         Stage stage = new Stage();
 549         stage.setScene(scene);
 550         stage.show();
 551 
 552         Toolkit.getToolkit().firePulse();
 553 
 554         StubNGPerspectiveCamera pc = camera.impl_getPeer();
 555 
 556         assertEquals(300, pc.getViewWidth(), 0.00001);
 557         assertEquals(200, pc.getViewHeight(), 0.00001);
 558 
 559         TransformHelper.assertMatrix(pc.getProjViewTx(), DEFAULT_PROJVIEW_TX);
 560         assertTrue(pc.isVerticalFieldOfView());
 561         assertEquals(30, pc.getFieldOfView(), 0.00001);
 562         assertEquals(150.0, pc.getPosition().x, 0.000001);
 563         assertEquals(100.0, pc.getPosition().y, 0.000001);
 564         assertEquals(-373.205080, pc.getPosition().z, 0.000001);
 565     }
 566 
 567     @Test
 568     public void parallelCameraShouldSyncWhenAssignedToScene() {
 569         final Scene scene = new Scene(new Group(), 300, 200);
 570         ParallelCamera camera = new StubParallelCamera();
 571         scene.setCamera(camera);
 572         Stage stage = new Stage();
 573         stage.setScene(scene);
 574         stage.show();
 575 
 576         Toolkit.getToolkit().firePulse();
 577 
 578         StubNGParallelCamera pc = camera.impl_getPeer();
 579 
 580         assertEquals(300, pc.getViewWidth(), 0.00001);
 581         assertEquals(200, pc.getViewHeight(), 0.00001);
 582 
 583         GeneralTransform3D expected = new GeneralTransform3D();
 584         expected.ortho(0.0, 300, 200, 0.0, -150, 150);
 585 
 586         TransformHelper.assertMatrix(pc.getProjViewTx(), expected);
 587         assertEquals(150.0, pc.getPosition().x, 0.000001);
 588         assertEquals(100.0, pc.getPosition().y, 0.000001);
 589         assertEquals(-373.205080, pc.getPosition().z, 0.000001);
 590     }
 591 
 592     @Test
 593     public void parallelCameraShouldSyncWhenAssignedToSubScene() {
 594         SubScene sub = new SubScene(new Group(), 300, 200);
 595         final Scene scene = new Scene(new Group(sub), 600, 300);
 596         ParallelCamera camera = new StubParallelCamera();
 597         sub.setCamera(camera);
 598         Stage stage = new Stage();
 599         stage.setScene(scene);
 600         stage.show();
 601 
 602         Toolkit.getToolkit().firePulse();
 603 
 604         StubNGParallelCamera pc = camera.impl_getPeer();
 605 
 606         assertEquals(300, pc.getViewWidth(), 0.00001);
 607         assertEquals(200, pc.getViewHeight(), 0.00001);
 608 
 609         GeneralTransform3D expected = new GeneralTransform3D();
 610         expected.ortho(0.0, 300, 200, 0.0, -150, 150);
 611 
 612         TransformHelper.assertMatrix(pc.getProjViewTx(), expected);
 613         assertEquals(150.0, pc.getPosition().x, 0.000001);
 614         assertEquals(100.0, pc.getPosition().y, 0.000001);
 615         assertEquals(-373.205080, pc.getPosition().z, 0.000001);
 616     }
 617 
 618     @Test
 619     public void sceneDefaultCameraShouldSyncInTheBeginning() {
 620         final Scene scene = new Scene(new Group(), 300, 200);
 621         ParallelCamera camera = new StubParallelCamera();
 622         scene.setCamera(camera);
 623         Stage stage = new Stage();
 624         stage.setScene(scene);
 625         stage.show();
 626 
 627         Toolkit.getToolkit().firePulse();
 628 
 629         StubNGParallelCamera pc = scene.getEffectiveCamera().impl_getPeer();
 630 
 631         assertEquals(300, pc.getViewWidth(), 0.00001);
 632         assertEquals(200, pc.getViewHeight(), 0.00001);
 633 
 634         GeneralTransform3D expected = new GeneralTransform3D();
 635         expected.ortho(0.0, 300, 200, 0.0, -150, 150);
 636 
 637         TransformHelper.assertMatrix(pc.getProjViewTx(), expected);
 638         assertEquals(150.0, pc.getPosition().x, 0.000001);
 639         assertEquals(100.0, pc.getPosition().y, 0.000001);
 640         assertEquals(-373.205080, pc.getPosition().z, 0.000001);
 641     }
 642 
 643     @Test
 644     public void subSceneDefaultCameraShouldSyncInTheBeginning() {
 645         SubScene sub = new SubScene(new Group(), 300, 200);
 646         final Scene scene = new Scene(new Group(sub), 600, 300);
 647         ParallelCamera camera = new StubParallelCamera();
 648         sub.setCamera(camera);
 649         Stage stage = new Stage();
 650         stage.setScene(scene);
 651         stage.show();
 652 
 653         Toolkit.getToolkit().firePulse();
 654 
 655         StubNGParallelCamera pc = sub.getEffectiveCamera().impl_getPeer();
 656 
 657         assertEquals(300, pc.getViewWidth(), 0.00001);
 658         assertEquals(200, pc.getViewHeight(), 0.00001);
 659 
 660         GeneralTransform3D expected = new GeneralTransform3D();
 661         expected.ortho(0.0, 300, 200, 0.0, -150, 150);
 662 
 663         TransformHelper.assertMatrix(pc.getProjViewTx(), expected);
 664         assertEquals(150.0, pc.getPosition().x, 0.000001);
 665         assertEquals(100.0, pc.getPosition().y, 0.000001);
 666         assertEquals(-373.205080, pc.getPosition().z, 0.000001);
 667     }
 668 
 669     @Test
 670     public void resizeShouldTriggerSync() {
 671         SubScene sub = new SubScene(new Group(), 400, 300);
 672         final Scene scene = new Scene(new Group(sub), 600, 300);
 673         PerspectiveCamera camera = new StubPerspectiveCamera();
 674         sub.setCamera(camera);
 675         Stage stage = new Stage();
 676         stage.setScene(scene);
 677         stage.show();
 678         Toolkit.getToolkit().firePulse();
 679 
 680         sub.setWidth(300);
 681         sub.setHeight(200);
 682         Toolkit.getToolkit().firePulse();
 683 
 684         StubNGPerspectiveCamera pc = camera.impl_getPeer();
 685 
 686         assertEquals(300, pc.getViewWidth(), 0.00001);
 687         assertEquals(200, pc.getViewHeight(), 0.00001);
 688 
 689         TransformHelper.assertMatrix(pc.getProjViewTx(), DEFAULT_PROJVIEW_TX);
 690         assertEquals(150.0, pc.getPosition().x, 0.000001);
 691         assertEquals(100.0, pc.getPosition().y, 0.000001);
 692         assertEquals(-373.205080, pc.getPosition().z, 0.000001);
 693     }
 694 
 695     @Test
 696     public void clipChangeShouldTriggerSync() {
 697         final Scene scene = new Scene(new Group(), 300, 200);
 698         PerspectiveCamera camera = new StubPerspectiveCamera();
 699         scene.setCamera(camera);
 700         Stage stage = new Stage();
 701         stage.setScene(scene);
 702         stage.show();
 703         Toolkit.getToolkit().firePulse();
 704 
 705         camera.setFarClip(250.0);
 706         Toolkit.getToolkit().firePulse();
 707 
 708         StubNGPerspectiveCamera pc = camera.impl_getPeer();
 709 
 710         GeneralTransform3D expected = new GeneralTransform3D();
 711         expected.perspective(true, Math.toRadians(30), 1.5, 0.1, 250);
 712         final double tanOfHalfFOV = Math.tan(Math.toRadians(30) / 2.0);
 713         Affine3D view = new Affine3D();
 714         final double scale = 2.0 * tanOfHalfFOV / 200;
 715         view.setToTranslation(-tanOfHalfFOV * 1.5, tanOfHalfFOV, 0.0);
 716         view.translate(0, 0, -1);
 717         view.rotate(Math.PI, 1, 0, 0);
 718         view.scale(scale, scale, scale);
 719         expected.mul(view);
 720 
 721         TransformHelper.assertMatrix(pc.getProjViewTx(), expected);
 722     }
 723 
 724     @Test
 725     public void fieldOfViewChangeShouldTriggerSync() {
 726         final Scene scene = new Scene(new Group(), 300, 200);
 727         PerspectiveCamera camera = new StubPerspectiveCamera();
 728         scene.setCamera(camera);
 729         Stage stage = new Stage();
 730         stage.setScene(scene);
 731         stage.show();
 732         Toolkit.getToolkit().firePulse();
 733 
 734         camera.setFieldOfView(45.0);
 735         Toolkit.getToolkit().firePulse();
 736 
 737         StubNGPerspectiveCamera pc = camera.impl_getPeer();
 738 
 739         GeneralTransform3D expected = new GeneralTransform3D();
 740         expected.perspective(true, Math.toRadians(45), 1.5, 0.1, 100);
 741         final double tanOfHalfFOV = Math.tan(Math.toRadians(45) / 2.0);
 742         Affine3D view = new Affine3D();
 743         final double scale = 2.0 * tanOfHalfFOV / 200;
 744         view.setToTranslation(-tanOfHalfFOV * 1.5, tanOfHalfFOV, 0.0);
 745         view.translate(0, 0, -1);
 746         view.rotate(Math.PI, 1, 0, 0);
 747         view.scale(scale, scale, scale);
 748         expected.mul(view);
 749 
 750         TransformHelper.assertMatrix(pc.getProjViewTx(), expected);
 751         assertEquals(150.0, pc.getPosition().x, 0.000001);
 752         assertEquals(100.0, pc.getPosition().y, 0.000001);
 753         assertEquals(-241.421356, pc.getPosition().z, 0.000001);
 754     }
 755 
 756     @Test
 757     public void verticalFOVChangeShouldTriggerSync() {
 758         final Scene scene = new Scene(new Group(), 300, 200);
 759         PerspectiveCamera camera = new StubPerspectiveCamera();
 760         scene.setCamera(camera);
 761         Stage stage = new Stage();
 762         stage.setScene(scene);
 763         stage.show();
 764         Toolkit.getToolkit().firePulse();
 765 
 766         camera.setVerticalFieldOfView(false);
 767         Toolkit.getToolkit().firePulse();
 768 
 769         StubNGPerspectiveCamera pc = camera.impl_getPeer();
 770 
 771         GeneralTransform3D expected = new GeneralTransform3D();
 772         expected.perspective(false, Math.toRadians(30), 1.5, 0.1, 100);
 773         final double tanOfHalfFOV = Math.tan(Math.toRadians(30) / 2.0);
 774         Affine3D view = new Affine3D();
 775         final double scale = 2.0 * tanOfHalfFOV / 300;
 776         view.setToTranslation(-tanOfHalfFOV, tanOfHalfFOV / 1.5, 0.0);
 777         view.translate(0, 0, -1);
 778         view.rotate(Math.PI, 1, 0, 0);
 779         view.scale(scale, scale, scale);
 780         expected.mul(view);
 781 
 782         TransformHelper.assertMatrix(pc.getProjViewTx(), expected);
 783         assertEquals(150.0, pc.getPosition().x, 0.000001);
 784         assertEquals(100.0, pc.getPosition().y, 0.000001);
 785         assertEquals(-559.80762, pc.getPosition().z, 0.00001);
 786     }
 787 
 788     @Test
 789     public void localToSceneChangeShouldTriggerSync() {
 790         PerspectiveCamera camera = new StubPerspectiveCamera();
 791         final Scene scene = new Scene(new Group(new Group(camera)), 300, 200);
 792         scene.setCamera(camera);
 793         Stage stage = new Stage();
 794         stage.setScene(scene);
 795         stage.show();
 796         Toolkit.getToolkit().firePulse();
 797 
 798         camera.getParent().setTranslateX(200);
 799         Toolkit.getToolkit().firePulse();
 800 
 801         StubNGPerspectiveCamera pc = camera.impl_getPeer();
 802 
 803         GeneralTransform3D expected = new GeneralTransform3D();
 804         expected.set(DEFAULT_PROJVIEW_TX);
 805         expected.mul(Affine3D.getTranslateInstance(-200, 0));
 806 
 807         TransformHelper.assertMatrix(pc.getProjViewTx(), expected);
 808         assertEquals(350.0, pc.getPosition().x, 0.000001);
 809         assertEquals(100.0, pc.getPosition().y, 0.000001);
 810         assertEquals(-373.205080, pc.getPosition().z, 0.000001);
 811         TransformHelper.assertMatrix(pc.getWorldTransform(), Affine3D.getTranslateInstance(200, 0));
 812     }
 813 
 814     private class StubPerspectiveCamera extends PerspectiveCamera {
 815         @Override
 816         protected NGNode impl_createPeer() {
 817             return new StubNGPerspectiveCamera(isFixedEyeAtCameraZero());
 818         }
 819     }
 820 
 821     private class StubNGPerspectiveCamera extends NGPerspectiveCamera {
 822         double viewWidth, viewHeight;
 823         Vec3d position;
 824         GeneralTransform3D projViewTx;
 825         Affine3D localToWorldTx;
 826         float fieldOfView;
 827         boolean verticalFieldOfView;
 828 
 829         public StubNGPerspectiveCamera(boolean fixedEyeAtCameraZero) {
 830             super(fixedEyeAtCameraZero);
 831         }
 832 
 833         @Override public void setViewWidth(double viewWidth) { this.viewWidth = viewWidth; }
 834         public double getViewWidth() { return viewWidth; }
 835 
 836         @Override public void setViewHeight(double viewHeight) { this.viewHeight = viewHeight; }
 837         public double getViewHeight() { return viewHeight; }
 838 
 839         @Override public void setPosition(Vec3d position) { this.position = position; }
 840         public Vec3d getPosition() { return position; }
 841 
 842         @Override public void setWorldTransform(Affine3D localToWorldTx) { this.localToWorldTx = localToWorldTx; }
 843         public Affine3D getWorldTransform() { return localToWorldTx; }
 844 
 845         @Override public void setProjViewTransform(GeneralTransform3D projViewTx) { this.projViewTx = projViewTx; }
 846         public GeneralTransform3D getProjViewTx() { return projViewTx; }
 847 
 848         @Override public void setFieldOfView(float fieldOfView) { this.fieldOfView = fieldOfView; }
 849         public double getFieldOfView() { return fieldOfView; }
 850 
 851         @Override public void setVerticalFieldOfView(boolean verticalFieldOfView) { this.verticalFieldOfView = verticalFieldOfView; }
 852         public boolean isVerticalFieldOfView() { return this.verticalFieldOfView; }
 853     }
 854 
 855     private class StubParallelCamera extends ParallelCamera {
 856         @Override
 857         protected NGNode impl_createPeer() {
 858             return new StubNGParallelCamera();
 859         }
 860     }
 861 
 862     private class StubNGParallelCamera extends NGParallelCamera {
 863         double viewWidth, viewHeight;
 864         Vec3d position;
 865         GeneralTransform3D projViewTx;
 866         Affine3D localToWorldTx;
 867 
 868         @Override public void setViewWidth(double viewWidth) { this.viewWidth = viewWidth; }
 869         public double getViewWidth() { return viewWidth; }
 870 
 871         @Override public void setViewHeight(double viewHeight) { this.viewHeight = viewHeight; }
 872         public double getViewHeight() { return viewHeight; }
 873 
 874         @Override public void setPosition(Vec3d position) { this.position = position; }
 875         public Vec3d getPosition() { return position; }
 876 
 877         @Override public void setWorldTransform(Affine3D localToWorldTx) { this.localToWorldTx = localToWorldTx; }
 878         public Affine3D getWorldTransform() { return localToWorldTx; }
 879 
 880         @Override public void setProjViewTransform(GeneralTransform3D projViewTx) { this.projViewTx = projViewTx; }
 881         public GeneralTransform3D getProjViewTx() { return projViewTx; }
 882     }
 883 }