Spec-Zone .ru
спецификации, руководства, описания, API
001/*
002 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.  Oracle designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Oracle in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
022 * or visit www.oracle.com if you need additional information or have any
023 * questions.
024 */
025
026package javafx.scene;
027
028import com.sun.javafx.collections.TrackableObservableList;
029import com.sun.javafx.geom.BaseBounds;
030import com.sun.javafx.geom.BoxBounds;
031import com.sun.javafx.geom.transform.Affine3D;
032import com.sun.javafx.geom.transform.BaseTransform;
033import com.sun.javafx.jmx.MXNodeAlgorithm;
034import com.sun.javafx.jmx.MXNodeAlgorithmContext;
035import com.sun.javafx.scene.DirtyBits;
036import com.sun.javafx.sg.PGLightBase;
037import com.sun.javafx.tk.Toolkit;
038import javafx.application.ConditionalFeature;
039import javafx.application.Platform;
040import javafx.beans.InvalidationListener;
041import javafx.beans.Observable;
042import javafx.beans.property.BooleanProperty;
043import javafx.beans.property.ObjectProperty;
044import javafx.beans.property.SimpleBooleanProperty;
045import javafx.beans.property.SimpleObjectProperty;
046import javafx.collections.ListChangeListener.Change;
047import javafx.collections.ObservableList;
048import javafx.scene.paint.Color;
049import javafx.scene.shape.Shape3D;
050import sun.util.logging.PlatformLogger;
051
052/**
053 * The {@code LightBase} class provides definitions of common properties for
054 * objects that represent a form of Light source.  These properties
055 * include:
056 * <ul>
057 * <li>The color that defines color of the light source.
058 * </ul>
059 *
060 * Note that this is a conditional feature. See
061 * {@link javafx.application.ConditionalFeature#SCENE3D ConditionalFeature.SCENE3D}
062 * for more information.
063 *
064 * @since JavaFX 8
065 */
066public abstract class LightBase extends Node {
067
068    private Affine3D localToSceneTx = new Affine3D();
069
070    /**
071     * Creates a new instance of {@code LightBase} class with a default Color.WHITE light source.
072     */
073    protected LightBase() {
074        this(Color.WHITE);
075    }
076
077    /**
078     * Creates a new instance of {@code LightBase} class using the specified color.
079     *
080     * @param color the color of the light source
081     */
082    protected LightBase(Color color) {
083        if (!Platform.isSupported(ConditionalFeature.SCENE3D)) {
084            String logname = LightBase.class.getName();
085            PlatformLogger.getLogger(logname).warning("System can't support "
086                                                      + "ConditionalFeature.SCENE3D");
087        }
088        
089        setColor(color);
090        this.localToSceneTransformProperty().addListener(new InvalidationListener() {
091            @Override
092            public void invalidated(Observable observable) {
093                impl_markDirty(DirtyBits.NODE_LIGHT_TRANSFORM);
094            }
095        });
096    }
097
098    /**
099     * Specifies the color of light source.
100     *
101     * @defaultValue null
102     */
103    private ObjectProperty<Color> color;
104
105    public final void setColor(Color value) {
106        colorProperty().set(value);
107    }
108
109    public final Color getColor() {
110        return color == null ? null : color.get();
111    }
112
113    public final ObjectProperty<Color> colorProperty() {
114        if (color == null) {
115            color = new SimpleObjectProperty<Color>(LightBase.this, "color") {
116                @Override
117                protected void invalidated() {
118                    impl_markDirty(DirtyBits.NODE_LIGHT);
119                }
120            };
121        }
122        return color;
123    }
124
125    /**
126     * Defines the light on or off.
127     *
128     * @defaultValue true
129     */
130    private BooleanProperty lightOn;
131
132    public final void setLightOn(boolean value) {
133        lightOnProperty().set(value);
134    }
135
136    public final boolean isLightOn() {
137        return lightOn == null ? true : lightOn.get();
138    }
139
140    public final BooleanProperty lightOnProperty() {
141        if (lightOn == null) {
142            lightOn = new SimpleBooleanProperty(LightBase.this, "lightOn", true) {
143                @Override
144                protected void invalidated() {
145                    impl_markDirty(DirtyBits.NODE_LIGHT);
146                }
147            };
148        }
149        return lightOn;
150    }
151
152    private ObservableList<Node> scope;
153
154    /**
155     * Gets the list of nodes that specifies the
156     * hierarchical scope of this Light. If the scope list is empty,
157     * the Light node has universe scope: all nodes under it's scene
158     * are affected by it. If the scope list is non-empty, only those
159     * 3D Shape nodes in the scope list and under the Group nodes in the
160     * scope list are affected by this Light node.
161     */
162    public ObservableList<Node> getScope() {
163        if (scope == null) {
164            scope = new TrackableObservableList<Node>() {
165
166                @Override
167                protected void onChanged(Change<Node> c) {
168                    impl_markDirty(DirtyBits.NODE_LIGHT);
169                    while (c.next()) {
170                        for (Node node : c.getRemoved()) {
171                            // Update the removed nodes
172                            if (node instanceof Parent || node instanceof Shape3D) {
173                                node.impl_markDirty(DirtyBits.NODE_CONTENTS);
174                            }
175                        }
176                        for (Node node : c.getAddedSubList()) {
177                            if (node instanceof Parent || node instanceof Shape3D) {
178                                node.impl_markDirty(DirtyBits.NODE_CONTENTS);
179                            }
180                        }
181                    }
182                }
183            };
184        }
185        return scope;
186    }
187
188    @Override
189    void scenesChanged(final Scene newScene, final SubScene newSubScene,
190                       final Scene oldScene, final SubScene oldSubScene) {
191        // This light is owned by the Scene/SubScene, and thus must change
192        // accordingly. Note lights can owned by either a Scene or SubScene,
193        // but not both.
194        if (oldSubScene != null) {
195            oldSubScene.removeLight(this);
196        } else if (oldScene != null) {
197            oldScene.removeLight(this);
198        }
199        if (newSubScene != null) {
200            newSubScene.addLight(this);
201        } else if (newScene != null) {
202            newScene.addLight(this);
203        }
204    }
205
206    /**
207     * @treatAsPrivate implementation detail
208     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
209     */
210    @Deprecated
211    @Override
212    public void impl_updatePG() {
213        super.impl_updatePG();
214        PGLightBase pgLightBase = (PGLightBase) impl_getPGNode();
215        if (impl_isDirty(DirtyBits.NODE_LIGHT)) {
216            pgLightBase.setColor((getColor() == null) ? null
217                    : Toolkit.getPaintAccessor().getPlatformPaint(getColor()));
218            pgLightBase.setLightOn(isLightOn());
219
220            if (scope != null) {
221                if (getScope().isEmpty()) {
222                    pgLightBase.setScope(null);
223                } else {
224                    Object ngList[] = new Object[getScope().size()];
225                    for (int i = 0; i < scope.size(); i++) {
226                        Node n = scope.get(i);
227                        ngList[i] = n.impl_getPGNode();
228                    }
229                    pgLightBase.setScope(ngList);
230                }
231            }
232        }
233
234        if (impl_isDirty(DirtyBits.NODE_LIGHT_TRANSFORM)) {
235            localToSceneTx.setToIdentity();
236            getLocalToSceneTransform().impl_apply(localToSceneTx);
237            // TODO: 3D - For now, we are treating the scene as world. This may need to change
238            // for the fixed eye position case.
239            pgLightBase.setWorldTransform(localToSceneTx);
240        }
241    }
242
243     /**
244     * @treatAsPrivate implementation detail
245     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
246     */
247    @Deprecated
248    @Override
249    public BaseBounds impl_computeGeomBounds(BaseBounds bounds, BaseTransform tx) {
250        // TODO: 3D - Check is this the right default
251        return new BoxBounds();
252    }
253
254    /**
255     * @treatAsPrivate implementation detail
256     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
257     */
258    @Deprecated
259    @Override
260    protected boolean impl_computeContains(double localX, double localY) {
261        // TODO: 3D - Check is this the right default
262        return false;
263    }
264
265    /**
266     * @treatAsPrivate implementation detail
267     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
268     */
269    @Deprecated
270    @Override
271    public Object impl_processMXNode(MXNodeAlgorithm alg, MXNodeAlgorithmContext ctx) {
272        throw new UnsupportedOperationException("Not supported yet.");
273    }
274
275}