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