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 }