/* * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package meshviewer; import java.util.LinkedList; import java.util.List; import javafx.application.Application; import javafx.beans.InvalidationListener; import javafx.beans.Observable; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.*; import javafx.scene.control.Button; import javafx.scene.control.CheckBox; import javafx.scene.control.ToggleButton; import javafx.scene.input.MouseButton; import javafx.scene.input.MouseEvent; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.scene.paint.PhongMaterial; import javafx.scene.shape.*; import javafx.scene.text.Font; import javafx.scene.text.FontWeight; import javafx.scene.text.Text; import javafx.scene.text.TextAlignment; import javafx.stage.Stage; public class Shapes3DSubSceneLightTester extends Application { private static final int SS_STATUS_WIDTH = 300; private static final int SS_STATUS_HIGHT = 700; private static final int SS_MODEL_WIDTH = 800; private Group build3DScene(double x, double y, double z, double dx) { PhongMaterial material = new PhongMaterial(); material.setDiffuseColor(Color.LIGHTGRAY); material.setSpecularColor(Color.rgb(30, 30, 30)); Shape3D meshView[] = new Shape3D[] { new Box(200, 200, 200), new Sphere(100), new Cylinder(100, 200), }; for (int i=0; i!=3; ++i) { meshView[i].setMaterial(material); meshView[i].setTranslateX(x + (i) * dx); meshView[i].setTranslateY(y); meshView[i].setTranslateZ(z); meshView[i].setDrawMode(DrawMode.FILL); meshView[i].setCullFace(CullFace.BACK); } PointLight pointLight = new PointLight(Color.rgb(128, 255, 128)); pointLight.setTranslateX(800); pointLight.setTranslateY(-100); pointLight.setTranslateZ(-1000); Group grp = new Group(); PointLight redLight = new PointLight(Color.rgb(255, 0, 0)); redLight.setTranslateZ(-400); grp.getChildren().add(redLight); redLight.getScope().addAll(meshView[1], meshView[0]); AmbientLight ambient = new AmbientLight(Color.rgb(10, 10, 10)); Group root = new Group(meshView); root.getChildren().add(grp); root.getChildren().add(pointLight); root.getChildren().add(ambient); return root; } private PerspectiveCamera addCamera(Scene scene) { PerspectiveCamera perspectiveCamera = new PerspectiveCamera(false); scene.setCamera(perspectiveCamera); return perspectiveCamera; } private Font titleFont; private List selectedNodes = new LinkedList<>(); private HBox subSceneListTopHBox = new HBox(); private int lightCounter = 0; private VBox addRemButtonVBox = new VBox(); private int addRemButtonCount = 0; private Node createControls(Node sgRoot, VBox vbox) { if (vbox == null) { vbox = new VBox(); } Text titleText = new Text("Controls For Model View Scene\n"); titleText.setFont(titleFont); vbox.getChildren().add(titleText); Text lightScopeText = new Text("Light Scope\nToggle ON one of the lights you would like to change scope. Then pick all the shapes you would like to add to scope. Toggle OFF to see the change in scope. Note light scope is replaced with new selection.\n"); lightScopeText.setWrappingWidth(SS_STATUS_WIDTH*0.9); vbox.getChildren().add(lightScopeText); vbox.getChildren().add(subSceneListTopHBox); vbox.getChildren().add(new Rectangle(SS_STATUS_WIDTH, 2)); Text lightInfoText = new Text("\nNode Information\nCheck box turns lights on/off, and for none lights nodes changes visibility on/off.\n"); lightInfoText.setWrappingWidth(SS_STATUS_WIDTH*0.9); vbox.getChildren().add(lightInfoText); lightCounter = 0; createControlsR(sgRoot, 0, vbox); vbox.getChildren().add(new Rectangle(SS_STATUS_WIDTH, 2)); Text removeNodesText = new Text("\nToggle Remove/Add Nodes from the graph\n"); vbox.getChildren().add(removeNodesText); vbox.getChildren().add(addRemButtonVBox); return vbox; } /** * Recursive traversal of graph, adding controls to vboxOut * @param n traverse to control * @param lvl level in tree where root is 0 * @param vboxOut location for to place controls */ private void createControlsR(final Node n, int lvl, VBox vboxOut) { String spaces = ""; for (int i = 0; i < lvl; i++) { spaces += " "; } final CheckBox cb = new CheckBox(spaces + n.toString()); vboxOut.getChildren().add(cb); if (n instanceof LightBase) { cb.setSelected(((LightBase)n).isLightOn()); lightCounter++; cb.setText(cb.getText() + " (L" + lightCounter+")"); final LightBase light = ((LightBase)n); final ToggleButton toggleButton = new ToggleButton("L" + lightCounter); toggleButton.selectedProperty().addListener(new ChangeListener() { @Override public void changed(ObservableValue ov, Boolean t, Boolean t1) { if (t1 != null) { if (t1) { // TODO selection of nodes to zero selectedNodes.clear(); // TODO all other toggle buttons off } else { light.getScope().clear(); light.getScope().addAll(selectedNodes); } } } }); subSceneListTopHBox.getChildren().add(toggleButton); final Text scopeText = new Text("scope: " + light.getScope().toString()); scopeText.setTranslateX(20); vboxOut.getChildren().add(scopeText); light.getScope().addListener(new InvalidationListener() { @Override public void invalidated(Observable v) { scopeText.setText(light.getScope().toString()); } }); } else { if (n.getParent() != null) { addRemButtonCount++; Button button = new Button(n.toString() + addRemButtonCount); addRemButtonVBox.getChildren().add(button); button.setOnAction(new EventHandler() { Parent lastParent; @Override public void handle(ActionEvent e) { Parent p = n.getParent(); boolean add = false; if (p == null) { p = lastParent; add = true; } if (p instanceof Group) { lastParent = p; if (!add) { ((Group)p).getChildren().remove(n); System.out.println("remove " + n); } else { ((Group)p).getChildren().add(n); System.out.println("add " + n); } } } }); } cb.setSelected(true); n.setOnMouseClicked(new EventHandler() { @Override public void handle(MouseEvent event) { if (event.getButton() == MouseButton.PRIMARY) { if (!(n instanceof Parent)) { selectedNodes.add(n); } } } }); } cb.selectedProperty().addListener(new InvalidationListener() { @Override public void invalidated(Observable v) { if (n instanceof LightBase) { ((LightBase)n).setLightOn(cb.isSelected()); } else { n.setVisible(cb.isSelected()); } } }); if (n instanceof Parent) { Object nodes[] = ((Parent)n).getChildrenUnmodifiable().toArray(); for (Object node: nodes) { createControlsR((Node)node, lvl + 1, vboxOut); } } } private SubScene createSubScene3D() { Group root = build3DScene(220.0, 250.0, 20.0, 220); Text titleText = new Text(0.0, 20, "Model View SubScene"); titleFont = Font.font(titleText.getFont().getFamily(),FontWeight.BOLD, 14); titleText.setFont(titleFont); titleText.setWrappingWidth(SS_MODEL_WIDTH); titleText.setTextAlignment(TextAlignment.CENTER); titleText.setFill(Color.WHITESMOKE); root.getChildren().add(titleText); SubScene subScene = new SubScene(root, SS_MODEL_WIDTH, 400, true, true); subScene.setTranslateY(20); subScene.setFill(Color.rgb(20, 20, 100)); PerspectiveCamera camera = new PerspectiveCamera(false); subScene.setCamera(camera); return subScene; } Scene initScene() { return initScene(false); } private Scene initScene(boolean subSceneModelView) { Group sceneRoot = new Group(); Scene scene = new Scene(sceneRoot, SS_MODEL_WIDTH + SS_STATUS_WIDTH, 800, true); VBox vbSSRoot = new VBox(); SubScene subSceneListView = new SubScene(vbSSRoot, SS_STATUS_WIDTH, SS_STATUS_HIGHT); subSceneListView.setFill(Color.LIGHTGRAY); Group group3DModel; if (subSceneModelView) { SubScene subScene3D = createSubScene3D(); HBox hbox = new HBox(); hbox.getChildren().addAll(subSceneListView, subScene3D); sceneRoot.getChildren().add(hbox); group3DModel = (Group)subScene3D.getRoot(); } else { // TODO: Problem with picking subSceneListView when hbox is used in place of sceneRoot group3DModel = build3DScene(220.0, 500.0, 20.0, 220); sceneRoot.getChildren().addAll(subSceneListView, group3DModel); } createControls(group3DModel, vbSSRoot); scene.setFill(Color.rgb(10, 10, 40)); addCamera(scene); return scene; } @Override public void start(Stage stage) { Scene scene = initScene(true); stage.setTitle("SubScene Light Tester"); stage.setScene(scene); stage.show(); } public static void main(String[] args) { System.setProperty("prism.dirtyopts", "false"); launch(args); } }