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