1 /* 2 * Copyright (c) 2013, 2016, 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.shape; 27 28 import com.sun.javafx.geom.BaseBounds; 29 import com.sun.javafx.geom.PickRay; 30 import com.sun.javafx.geom.transform.BaseTransform; 31 import com.sun.javafx.scene.DirtyBits; 32 import com.sun.javafx.scene.NodeHelper; 33 import com.sun.javafx.scene.input.PickResultChooser; 34 import com.sun.javafx.scene.shape.MeshHelper; 35 import com.sun.javafx.scene.shape.MeshViewHelper; 36 import com.sun.javafx.sg.prism.NGMeshView; 37 import com.sun.javafx.sg.prism.NGNode; 38 import javafx.beans.property.ObjectProperty; 39 import javafx.beans.property.SimpleObjectProperty; 40 import javafx.beans.value.ChangeListener; 41 import javafx.beans.value.ObservableValue; 42 import javafx.beans.value.WeakChangeListener; 43 import javafx.scene.Node; 44 45 /** 46 * The {@code MeshView} class defines a surface with the specified 3D 47 * mesh data. 48 * 49 * @since JavaFX 8.0 50 */ 51 public class MeshView extends Shape3D { 52 static { 53 // This is used by classes in different packages to get access to 54 // private and package private methods. 55 MeshViewHelper.setMeshViewAccessor(new MeshViewHelper.MeshViewAccessor() { 56 @Override 57 public NGNode doCreatePeer(Node node) { 58 return ((MeshView) node).doCreatePeer(); 59 } 60 61 @Override 62 public void doUpdatePeer(Node node) { 63 ((MeshView) node).doUpdatePeer(); 64 } 65 66 @Override 67 public BaseBounds doComputeGeomBounds(Node node, 68 BaseBounds bounds, BaseTransform tx) { 69 return ((MeshView) node).doComputeGeomBounds(bounds, tx); 70 } 71 72 @Override 73 public boolean doComputeContains(Node node, double localX, double localY) { 74 return ((MeshView) node).doComputeContains(localX, localY); 75 } 76 77 @Override 78 public boolean doComputeIntersects(Node node, PickRay pickRay, 79 PickResultChooser pickResult) { 80 return ((MeshView) node).doComputeIntersects(pickRay, pickResult); 81 } 82 }); 83 } 84 85 { 86 // To initialize the class helper at the begining each constructor of this class 87 MeshViewHelper.initHelper(this); 88 } 89 90 /** 91 * Creates a new instance of {@code MeshView} class. 92 */ 93 public MeshView() { 94 } 95 96 /** 97 * Creates a new instance of {@code MeshView} class with the specified {@code Mesh} 98 * surface. 99 */ 100 public MeshView(Mesh mesh) { 101 setMesh(mesh); 102 } 103 104 /** 105 * Specifies the 3D mesh data of this {@code MeshView}. 106 * 107 * @defaultValue null 108 */ 109 private ObjectProperty<Mesh> mesh; 110 111 public final void setMesh(Mesh value) { 112 meshProperty().set(value); 113 } 114 115 public final Mesh getMesh() { 116 return mesh == null ? null : mesh.get(); 117 } 118 119 public final ObjectProperty<Mesh> meshProperty() { 120 if (mesh == null) { 121 mesh = new SimpleObjectProperty<Mesh>(MeshView.this, "mesh") { 122 123 private Mesh old = null; 124 private final ChangeListener<Boolean> meshChangeListener = 125 (observable, oldValue, newValue) -> { 126 if (newValue) { 127 NodeHelper.markDirty(MeshView.this, DirtyBits.MESH_GEOM); 128 NodeHelper.geomChanged(MeshView.this); 129 } 130 }; 131 private final WeakChangeListener<Boolean> weakMeshChangeListener = 132 new WeakChangeListener(meshChangeListener); 133 134 @Override 135 protected void invalidated() { 136 if (old != null) { 137 old.dirtyProperty().removeListener(weakMeshChangeListener); 138 } 139 Mesh newMesh = get(); 140 if (newMesh != null) { 141 newMesh.dirtyProperty().addListener(weakMeshChangeListener); 142 } 143 NodeHelper.markDirty(MeshView.this, DirtyBits.MESH); 144 NodeHelper.markDirty(MeshView.this, DirtyBits.MESH_GEOM); 145 NodeHelper.geomChanged(MeshView.this); 146 old = newMesh; 147 } 148 }; 149 } 150 return mesh; 151 } 152 153 /* 154 * Note: This method MUST only be called via its accessor method. 155 */ 156 private void doUpdatePeer() { 157 NGMeshView peer = NodeHelper.getPeer(this); 158 if (NodeHelper.isDirty(this, DirtyBits.MESH_GEOM) && getMesh() != null) { 159 getMesh().updatePG(); 160 } 161 if (NodeHelper.isDirty(this, DirtyBits.MESH)) { 162 peer.setMesh((getMesh() == null) ? null : getMesh().getPGMesh()); 163 } 164 } 165 166 /* 167 * Note: This method MUST only be called via its accessor method. 168 */ 169 private NGNode doCreatePeer() { 170 return new NGMeshView(); 171 } 172 173 /* 174 * Note: This method MUST only be called via its accessor method. 175 */ 176 private BaseBounds doComputeGeomBounds(BaseBounds bounds, BaseTransform tx) { 177 if (getMesh() != null) { 178 bounds = getMesh().computeBounds(bounds); 179 bounds = tx.transform(bounds, bounds); 180 } else { 181 bounds.makeEmpty(); 182 } 183 return bounds; 184 } 185 186 /* 187 * Note: This method MUST only be called via its accessor method. 188 */ 189 private boolean doComputeContains(double localX, double localY) { 190 throw new UnsupportedOperationException("Not supported yet."); 191 } 192 193 /* 194 * Note: This method MUST only be called via its accessor method. 195 */ 196 private boolean doComputeIntersects(PickRay pickRay, PickResultChooser pickResult) { 197 return MeshHelper.computeIntersects(getMesh(), pickRay, pickResult, this, getCullFace(), true); 198 } 199 200 }