57 * shape or the outline of the shape (see {@link #setMaterial}).
58 * <li>The draw model properties that defines how to render its geometry (see {@link #setDrawMode}).
59 * <li>The face culling properties that defines which face to cull (see {@link #setCullFace}).
60 * </ul>
61 *
62 * Note that this is a conditional feature. See
63 * {@link javafx.application.ConditionalFeature#SCENE3D ConditionalFeature.SCENE3D}
64 * for more information.
65 *
66 * @since JavaFX 8.0
67 */
68 public abstract class Shape3D extends Node {
69 static {
70 // This is used by classes in different packages to get access to
71 // private and package private methods.
72 Shape3DHelper.setShape3DAccessor(new Shape3DHelper.Shape3DAccessor() {
73 @Override
74 public void doUpdatePeer(Node node) {
75 ((Shape3D) node).doUpdatePeer();
76 }
77 });
78 }
79
80 // NOTE: Need a way to specify shape tessellation resolution, may use metric relate to window resolution
81 // Will not support dynamic refinement in FX8
82
83 // TODO: 3D - May provide user convenient utility to compose images in a single image for shapes such as Box or Cylinder
84
85 private static final PhongMaterial DEFAULT_MATERIAL = new PhongMaterial();
86
87 protected Shape3D() {
88 if (!Platform.isSupported(ConditionalFeature.SCENE3D)) {
89 String logname = Shape3D.class.getName();
90 PlatformLogger.getLogger(logname).warning("System can't support "
91 + "ConditionalFeature.SCENE3D");
92 }
93 }
94
95 PredefinedMeshManager manager = PredefinedMeshManager.getInstance();
96 int key = 0;
119
120 private Material old = null;
121 private final ChangeListener<Boolean> materialChangeListener =
122 (observable, oldValue, newValue) -> {
123 if (newValue) {
124 NodeHelper.markDirty(Shape3D.this, DirtyBits.MATERIAL);
125 }
126 };
127 private final WeakChangeListener<Boolean> weakMaterialChangeListener =
128 new WeakChangeListener(materialChangeListener);
129
130 @Override protected void invalidated() {
131 if (old != null) {
132 MaterialHelper.dirtyProperty(old).removeListener(weakMaterialChangeListener);
133 }
134 Material newMaterial = get();
135 if (newMaterial != null) {
136 MaterialHelper.dirtyProperty(newMaterial).addListener(weakMaterialChangeListener);
137 }
138 NodeHelper.markDirty(Shape3D.this, DirtyBits.MATERIAL);
139 impl_geomChanged();
140 old = newMaterial;
141 }
142 };
143 }
144 return material;
145 }
146
147 /**
148 * Defines the draw mode used to render this {@code Shape3D}.
149 * {@link DrawMode.LINE} is not available on embedded platforms.
150 * If {@code drawMode} is set to {@link DrawMode.LINE} on an embedded
151 * platform the default value of {@link DrawMode.FILL} will be used instead.
152 *
153 * @defaultValue DrawMode.FILL
154 */
155 private ObjectProperty<DrawMode> drawMode;
156
157 public final void setDrawMode(DrawMode value) {
158 drawModeProperty().set(value);
159 }
188 }
189
190 public final CullFace getCullFace() {
191 return cullFace == null ? CullFace.BACK : cullFace.get();
192 }
193
194 public final ObjectProperty<CullFace> cullFaceProperty() {
195 if (cullFace == null) {
196 cullFace = new SimpleObjectProperty<CullFace>(Shape3D.this,
197 "cullFace", CullFace.BACK) {
198
199 @Override
200 protected void invalidated() {
201 NodeHelper.markDirty(Shape3D.this, DirtyBits.NODE_CULLFACE);
202 }
203 };
204 }
205 return cullFace;
206 }
207
208 /**
209 * @treatAsPrivate implementation detail
210 * @deprecated This is an internal API that is not intended for use and will be removed in the next version
211 */
212 @Deprecated
213 @Override
214 public BaseBounds impl_computeGeomBounds(BaseBounds bounds, BaseTransform tx) {
215 // TODO: 3D - Evaluate this logic
216 return new BoxBounds(0, 0, 0, 0, 0, 0);
217 }
218
219 /**
220 * @treatAsPrivate implementation detail
221 * @deprecated This is an internal API that is not intended for use and will be removed in the next version
222 */
223 @Deprecated
224 @Override
225 protected boolean impl_computeContains(double localX, double localY) {
226 return false;
227 }
228
229 /*
230 * Note: This method MUST only be called via its accessor method.
231 */
232 private void doUpdatePeer() {
233 final NGShape3D peer = NodeHelper.getPeer(this);
234 if (NodeHelper.isDirty(this, DirtyBits.MATERIAL)) {
235 Material mat = getMaterial() == null ? DEFAULT_MATERIAL : getMaterial();
236 MaterialHelper.updatePG(mat); // new material should be updated
237 peer.setMaterial(MaterialHelper.getNGMaterial(mat));
238 }
239 if (NodeHelper.isDirty(this, DirtyBits.NODE_DRAWMODE)) {
240 peer.setDrawMode(getDrawMode() == null ? DrawMode.FILL : getDrawMode());
241 }
242 if (NodeHelper.isDirty(this, DirtyBits.NODE_CULLFACE)) {
243 peer.setCullFace(getCullFace() == null ? CullFace.BACK : getCullFace());
244 }
245 }
246
247 /**
248 * @treatAsPrivate implementation detail
249 * @deprecated This is an internal API that is not intended for use and will be removed in the next version
250 */
251 @Deprecated
252 @Override
253 public Object impl_processMXNode(MXNodeAlgorithm alg, MXNodeAlgorithmContext ctx) {
254 throw new UnsupportedOperationException("Not supported yet.");
255 }
256
257 }
|
57 * shape or the outline of the shape (see {@link #setMaterial}).
58 * <li>The draw model properties that defines how to render its geometry (see {@link #setDrawMode}).
59 * <li>The face culling properties that defines which face to cull (see {@link #setCullFace}).
60 * </ul>
61 *
62 * Note that this is a conditional feature. See
63 * {@link javafx.application.ConditionalFeature#SCENE3D ConditionalFeature.SCENE3D}
64 * for more information.
65 *
66 * @since JavaFX 8.0
67 */
68 public abstract class Shape3D extends Node {
69 static {
70 // This is used by classes in different packages to get access to
71 // private and package private methods.
72 Shape3DHelper.setShape3DAccessor(new Shape3DHelper.Shape3DAccessor() {
73 @Override
74 public void doUpdatePeer(Node node) {
75 ((Shape3D) node).doUpdatePeer();
76 }
77
78 @Override
79 public BaseBounds doComputeGeomBounds(Node node,
80 BaseBounds bounds, BaseTransform tx) {
81 return ((Shape3D) node).doComputeGeomBounds(bounds, tx);
82 }
83
84 @Override
85 public boolean doComputeContains(Node node, double localX, double localY) {
86 return ((Shape3D) node).doComputeContains(localX, localY);
87 }
88
89 @Override
90 public Object doProcessMXNode(Node node, MXNodeAlgorithm alg, MXNodeAlgorithmContext ctx) {
91 return ((Shape3D) node).doProcessMXNode(alg, ctx);
92 }
93 });
94 }
95
96 // NOTE: Need a way to specify shape tessellation resolution, may use metric relate to window resolution
97 // Will not support dynamic refinement in FX8
98
99 // TODO: 3D - May provide user convenient utility to compose images in a single image for shapes such as Box or Cylinder
100
101 private static final PhongMaterial DEFAULT_MATERIAL = new PhongMaterial();
102
103 protected Shape3D() {
104 if (!Platform.isSupported(ConditionalFeature.SCENE3D)) {
105 String logname = Shape3D.class.getName();
106 PlatformLogger.getLogger(logname).warning("System can't support "
107 + "ConditionalFeature.SCENE3D");
108 }
109 }
110
111 PredefinedMeshManager manager = PredefinedMeshManager.getInstance();
112 int key = 0;
135
136 private Material old = null;
137 private final ChangeListener<Boolean> materialChangeListener =
138 (observable, oldValue, newValue) -> {
139 if (newValue) {
140 NodeHelper.markDirty(Shape3D.this, DirtyBits.MATERIAL);
141 }
142 };
143 private final WeakChangeListener<Boolean> weakMaterialChangeListener =
144 new WeakChangeListener(materialChangeListener);
145
146 @Override protected void invalidated() {
147 if (old != null) {
148 MaterialHelper.dirtyProperty(old).removeListener(weakMaterialChangeListener);
149 }
150 Material newMaterial = get();
151 if (newMaterial != null) {
152 MaterialHelper.dirtyProperty(newMaterial).addListener(weakMaterialChangeListener);
153 }
154 NodeHelper.markDirty(Shape3D.this, DirtyBits.MATERIAL);
155 NodeHelper.geomChanged(Shape3D.this);
156 old = newMaterial;
157 }
158 };
159 }
160 return material;
161 }
162
163 /**
164 * Defines the draw mode used to render this {@code Shape3D}.
165 * {@link DrawMode.LINE} is not available on embedded platforms.
166 * If {@code drawMode} is set to {@link DrawMode.LINE} on an embedded
167 * platform the default value of {@link DrawMode.FILL} will be used instead.
168 *
169 * @defaultValue DrawMode.FILL
170 */
171 private ObjectProperty<DrawMode> drawMode;
172
173 public final void setDrawMode(DrawMode value) {
174 drawModeProperty().set(value);
175 }
204 }
205
206 public final CullFace getCullFace() {
207 return cullFace == null ? CullFace.BACK : cullFace.get();
208 }
209
210 public final ObjectProperty<CullFace> cullFaceProperty() {
211 if (cullFace == null) {
212 cullFace = new SimpleObjectProperty<CullFace>(Shape3D.this,
213 "cullFace", CullFace.BACK) {
214
215 @Override
216 protected void invalidated() {
217 NodeHelper.markDirty(Shape3D.this, DirtyBits.NODE_CULLFACE);
218 }
219 };
220 }
221 return cullFace;
222 }
223
224 /*
225 * Note: This method MUST only be called via its accessor method.
226 */
227 private BaseBounds doComputeGeomBounds(BaseBounds bounds, BaseTransform tx) {
228 // TODO: 3D - Evaluate this logic
229 return new BoxBounds(0, 0, 0, 0, 0, 0);
230 }
231
232 /*
233 * Note: This method MUST only be called via its accessor method.
234 */
235 private boolean doComputeContains(double localX, double localY) {
236 return false;
237 }
238
239 /*
240 * Note: This method MUST only be called via its accessor method.
241 */
242 private void doUpdatePeer() {
243 final NGShape3D peer = NodeHelper.getPeer(this);
244 if (NodeHelper.isDirty(this, DirtyBits.MATERIAL)) {
245 Material mat = getMaterial() == null ? DEFAULT_MATERIAL : getMaterial();
246 MaterialHelper.updatePG(mat); // new material should be updated
247 peer.setMaterial(MaterialHelper.getNGMaterial(mat));
248 }
249 if (NodeHelper.isDirty(this, DirtyBits.NODE_DRAWMODE)) {
250 peer.setDrawMode(getDrawMode() == null ? DrawMode.FILL : getDrawMode());
251 }
252 if (NodeHelper.isDirty(this, DirtyBits.NODE_CULLFACE)) {
253 peer.setCullFace(getCullFace() == null ? CullFace.BACK : getCullFace());
254 }
255 }
256
257 /*
258 * Note: This method MUST only be called via its accessor method.
259 */
260 private Object doProcessMXNode(MXNodeAlgorithm alg, MXNodeAlgorithmContext ctx) {
261 throw new UnsupportedOperationException("Not supported yet.");
262 }
263
264 }
|