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         });
  67     }
  68 
  69     {
  70         // To initialize the class helper at the begining each constructor of this class
  71         MeshViewHelper.initHelper(this);
  72     }
  73 
  74     /**
  75      * Creates a new instance of {@code MeshView} class.
  76      */
  77     public MeshView() {
  78     }
  79 
  80     /**
  81      * Creates a new instance of {@code MeshView} class with the specified {@code Mesh}
  82      * surface.
  83      */
  84     public MeshView(Mesh mesh) {
  85         setMesh(mesh);
  86     }
  87 
  88     /**
  89      * Specifies the 3D mesh data of this {@code MeshView}.
  90      *
  91      * @defaultValue null
  92      */
  93     private ObjectProperty<Mesh> mesh;
  94 
  95     public final void setMesh(Mesh value) {
  96         meshProperty().set(value);
  97     }
  98 
  99     public final Mesh getMesh() {
 100         return mesh == null ? null : mesh.get();
 101     }
 102 
 103     public final ObjectProperty<Mesh> meshProperty() {
 104         if (mesh == null) {
 105             mesh = new SimpleObjectProperty<Mesh>(MeshView.this, "mesh") {
 106 
 107                 private Mesh old = null;
 108                 private final ChangeListener<Boolean> meshChangeListener =
 109                         (observable, oldValue, newValue) -> {
 110                             if (newValue) {
 111                                 NodeHelper.markDirty(MeshView.this, DirtyBits.MESH_GEOM);
 112                                 impl_geomChanged();
 113                             }
 114                         };
 115                 private final WeakChangeListener<Boolean> weakMeshChangeListener =
 116                         new WeakChangeListener(meshChangeListener);
 117 
 118                 @Override
 119                 protected void invalidated() {
 120                     if (old != null) {
 121                         old.dirtyProperty().removeListener(weakMeshChangeListener);
 122                     }
 123                     Mesh newMesh = get();
 124                     if (newMesh != null) {
 125                         newMesh.dirtyProperty().addListener(weakMeshChangeListener);
 126                     }
 127                     NodeHelper.markDirty(MeshView.this, DirtyBits.MESH);
 128                     NodeHelper.markDirty(MeshView.this, DirtyBits.MESH_GEOM);
 129                     impl_geomChanged();
 130                     old = newMesh;
 131                 }
 132             };
 133         }
 134         return mesh;
 135     }
 136 
 137     /*
 138      * Note: This method MUST only be called via its accessor method.
 139      */
 140     private void doUpdatePeer() {
 141         NGMeshView peer = NodeHelper.getPeer(this);
 142         if (NodeHelper.isDirty(this, DirtyBits.MESH_GEOM) && getMesh() != null) {
 143             getMesh().updatePG();
 144         }
 145         if (NodeHelper.isDirty(this, DirtyBits.MESH)) {
 146             peer.setMesh((getMesh() == null) ? null : getMesh().getPGMesh());
 147         }
 148     }
 149 
 150     /*
 151      * Note: This method MUST only be called via its accessor method.
 152      */
 153     private NGNode doCreatePeer() {
 154         return new NGMeshView();
 155     }
 156 
 157     /**
 158      * @treatAsPrivate implementation detail
 159      * @deprecated This is an internal API that is not intended for use and will be removed in the next version
 160      */
 161     @Deprecated
 162     @Override
 163     public BaseBounds impl_computeGeomBounds(BaseBounds bounds, BaseTransform tx) {
 164         if (getMesh() != null) {
 165             bounds = getMesh().computeBounds(bounds);
 166             bounds = tx.transform(bounds, bounds);
 167         } else {
 168             bounds.makeEmpty();
 169         }
 170         return bounds;
 171     }
 172 
 173     /**
 174      * @treatAsPrivate implementation detail
 175      * @deprecated This is an internal API that is not intended for use and will be removed in the next version
 176      */
 177     @Deprecated
 178     @Override
 179     protected boolean impl_computeContains(double localX, double localY) {
 180         throw new UnsupportedOperationException("Not supported yet.");
 181     }
 182 
 183     /**
 184      * @treatAsPrivate implementation detail
 185      * @deprecated This is an internal API that is not intended for use and will be removed in the next version
 186      */
 187     @Override
 188     @Deprecated
 189     protected boolean impl_computeIntersects(PickRay pickRay, PickResultChooser pickResult) {
 190         return MeshHelper.computeIntersects(getMesh(), pickRay, pickResult, this, getCullFace(), true);
 191     }
 192 
 193 }