Spec-Zone .ru
спецификации, руководства, описания, API
001/*
002 * Copyright (c) 2010, 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.effect;
027
028import javafx.beans.Observable;
029import javafx.beans.property.DoubleProperty;
030import javafx.beans.property.DoublePropertyBase;
031import javafx.beans.property.ObjectProperty;
032import javafx.beans.property.ObjectPropertyBase;
033import javafx.scene.Node;
034
035import com.sun.javafx.Utils;
036import com.sun.javafx.effect.EffectDirtyBits;
037import com.sun.javafx.effect.EffectUtils;
038import com.sun.javafx.geom.BaseBounds;
039import com.sun.javafx.geom.transform.BaseTransform;
040import com.sun.javafx.scene.BoundsAccessor;
041import com.sun.scenario.effect.PhongLighting;
042
043/**
044 * An effect that simulates a light source shining on the given content,
045 * which can be used to give flat objects a more realistic, three-dimensional
046 * appearance.
047 *
048 * <p>
049 * Example:
050 * <pre><code>
051 * Light.Distant light = new Light.Distant();
052 * light.setAzimuth(-135.0);
053 *
054 * Lighting lighting = new Lighting();
055 * lighting.setLight(light);
056 * lighting.setSurfaceScale(5.0);
057 *
058 * Text text = new Text();
059 * text.setText("JavaFX!");
060 * text.setFill(Color.STEELBLUE);
061 * text.setFont(Font.font(null, FontWeight.BOLD, 60));
062 * text.setX(10.0);
063 * text.setY(10.0);
064 * text.setTextOrigin(VPos.TOP);
065 *
066 * text.setEffect(lighting);
067 * </pre></code>
068 * <p> The code above produces the following: </p>
069 * <p>
070 * <img * src="doc-files/lighting.png"/>
071 * </p>
072 */
073public class Lighting extends Effect {
074    @Override
075    com.sun.scenario.effect.PhongLighting impl_createImpl() {
076        return new PhongLighting(getLightInternal().impl_getImpl());
077    };
078
079    /**
080     * Creates a new instance of Lighting with default parameters.
081     */
082    public Lighting() {
083        Shadow shadow = new Shadow();
084        shadow.setRadius(10.0f);
085        setBumpInput(shadow);
086    }
087
088    /**
089     * Creates a new instance of Lighting with the specified light.
090     * @param light the light source for this {@code Lighting} effect
091     */
092    public Lighting(Light light) {
093        Shadow shadow = new Shadow();
094        shadow.setRadius(10.0f);
095        setBumpInput(shadow);
096        setLight(light);
097    }
098
099    private final Light defaultLight = new Light.Distant();
100
101    /**
102     * The light source for this {@code Lighting} effect.
103     */
104    private ObjectProperty<Light> light = new ObjectPropertyBase<Light>(new Light.Distant()) {
105        @Override
106        public void invalidated() {
107            markDirty(EffectDirtyBits.EFFECT_DIRTY);
108            effectBoundsChanged();
109        }
110
111        @Override
112        public Object getBean() {
113            return Lighting.this;
114        }
115
116        @Override
117        public String getName() {
118            return "light";
119        }
120    };
121
122
123    public final void setLight(Light value) {
124        lightProperty().set(value);
125    }
126
127    public final Light getLight() {
128        return light.get();
129    }
130
131    public final ObjectProperty<Light> lightProperty() {
132        return light;
133    }
134
135    private final LightChangeListener lightChangeListener = new LightChangeListener();
136
137    /**
138     * 
139     * @treatAsPrivate implementation detail
140     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
141     */
142    @Deprecated
143    @Override
144    public Effect impl_copy() {
145        Lighting lighting = new Lighting(this.getLight());
146        lighting.setBumpInput(this.getBumpInput());
147        lighting.setContentInput(this.getContentInput());
148        lighting.setDiffuseConstant(this.getDiffuseConstant());
149        lighting.setSpecularConstant(this.getSpecularConstant());
150        lighting.setSpecularExponent(this.getSpecularExponent());
151        lighting.setSurfaceScale(this.getSurfaceScale());
152        return lighting;
153    }
154    private class LightChangeListener extends EffectChangeListener {
155        Light light;
156
157        public void register(Light value) {
158            light = value;
159            super.register(light == null ? null : light.effectDirtyProperty());
160        }
161
162        @Override
163        public void invalidated(Observable valueModel) {
164            if (light.impl_isEffectDirty()) {
165                markDirty(EffectDirtyBits.EFFECT_DIRTY);
166                effectBoundsChanged();
167            }
168        }
169    };
170    /**
171     * The optional bump map input.
172     * If not specified, a bump map will be automatically generated
173     * from the default input.
174     * If set to {@code null}, or left unspecified, a graphical image of
175     * the {@code Node} to which the {@code Effect} is attached will be
176     * used to generate a default bump map.
177     * @defaultValue a Shadow effect with a radius of 10
178     */
179    private ObjectProperty<Effect> bumpInput;
180
181
182    public final void setBumpInput(Effect value) {
183        bumpInputProperty().set(value);
184    }
185
186    public final Effect getBumpInput() {
187        return bumpInput == null ? null : bumpInput.get();
188    }
189
190    public final ObjectProperty<Effect> bumpInputProperty() {
191        if (bumpInput == null) {
192            bumpInput = new EffectInputProperty("bumpInput");
193        }
194        return bumpInput;
195    }
196
197    /**
198     * The content input for this {@code Effect}.
199     * If set to {@code null}, or left unspecified, a graphical image of
200     * the {@code Node} to which the {@code Effect} is attached will be
201     * used as the input.
202     * @defaultValue null
203     */
204    private ObjectProperty<Effect> contentInput;
205
206
207    public final void setContentInput(Effect value) {
208        contentInputProperty().set(value);
209    }
210
211    public final Effect getContentInput() {
212        return contentInput == null ? null : contentInput.get();
213    }
214
215    public final ObjectProperty<Effect> contentInputProperty() {
216        if (contentInput == null) {
217            contentInput = new EffectInputProperty("contentInput");
218        }
219        return contentInput;
220    }
221
222    @Override
223    boolean impl_checkChainContains(Effect e) {
224        Effect localBumpInput = getBumpInput();
225        Effect localContentInput = getContentInput();
226        if (localContentInput == e || localBumpInput == e)
227            return true;
228        if (localContentInput != null && localContentInput.impl_checkChainContains(e))
229            return true;
230        if (localBumpInput != null && localBumpInput.impl_checkChainContains(e))
231            return true;
232
233        return false;
234    }
235
236    /**
237     * The diffuse constant.
238     * <pre>
239     *       Min: 0.0
240     *       Max: 2.0
241     *   Default: 1.0
242     *  Identity: n/a
243     * </pre>
244     * @defaultValue 1.0
245     */
246    private DoubleProperty diffuseConstant;
247
248
249    public final void setDiffuseConstant(double value) {
250        diffuseConstantProperty().set(value);
251    }
252
253    public final double getDiffuseConstant() {
254        return diffuseConstant == null ? 1 : diffuseConstant.get();
255    }
256
257    public final DoubleProperty diffuseConstantProperty() {
258        if (diffuseConstant == null) {
259            diffuseConstant = new DoublePropertyBase(1) {
260
261                @Override
262                public void invalidated() {
263                    markDirty(EffectDirtyBits.EFFECT_DIRTY);
264                }
265
266                @Override
267                public Object getBean() {
268                    return Lighting.this;
269                }
270
271                @Override
272                public String getName() {
273                    return "diffuseConstant";
274                }
275            };
276        }
277        return diffuseConstant;
278    }
279
280    /**
281     * The specular constant.
282     * <pre>
283     *       Min: 0.0
284     *       Max: 2.0
285     *   Default: 0.3
286     *  Identity: n/a
287     * </pre>
288     * @defaultValue 0.3
289     */
290    private DoubleProperty specularConstant;
291
292
293    public final void setSpecularConstant(double value) {
294        specularConstantProperty().set(value);
295    }
296
297    public final double getSpecularConstant() {
298        return specularConstant == null ? 0.3 : specularConstant.get();
299    }
300
301    public final DoubleProperty specularConstantProperty() {
302        if (specularConstant == null) {
303            specularConstant = new DoublePropertyBase(0.3) {
304
305                @Override
306                public void invalidated() {
307                    markDirty(EffectDirtyBits.EFFECT_DIRTY);
308                }
309
310                @Override
311                public Object getBean() {
312                    return Lighting.this;
313                }
314
315                @Override
316                public String getName() {
317                    return "specularConstant";
318                }
319            };
320        }
321        return specularConstant;
322    }
323
324    /**
325     * The specular exponent.
326     * <pre>
327     *       Min:  0.0
328     *       Max: 40.0
329     *   Default: 20.0
330     *  Identity:  n/a
331     * </pre>
332     * @defaultValue 20.0
333     */
334    private DoubleProperty specularExponent;
335
336
337    public final void setSpecularExponent(double value) {
338        specularExponentProperty().set(value);
339    }
340
341    public final double getSpecularExponent() {
342        return specularExponent == null ? 20 : specularExponent.get();
343    }
344
345    public final DoubleProperty specularExponentProperty() {
346        if (specularExponent == null) {
347            specularExponent = new DoublePropertyBase(20) {
348
349                @Override
350                public void invalidated() {
351                    markDirty(EffectDirtyBits.EFFECT_DIRTY);
352                }
353
354                @Override
355                public Object getBean() {
356                    return Lighting.this;
357                }
358
359                @Override
360                public String getName() {
361                    return "specularExponent";
362                }
363            };
364        }
365        return specularExponent;
366    }
367
368    /**
369     * The surface scale factor.
370     * <pre>
371     *       Min:  0.0
372     *       Max: 10.0
373     *   Default:  1.5
374     *  Identity:  n/a
375     * </pre>
376     * @defaultValue 1.5
377     */
378    private DoubleProperty surfaceScale;
379
380
381    public final void setSurfaceScale(double value) {
382        surfaceScaleProperty().set(value);
383    }
384
385    public final double getSurfaceScale() {
386        return surfaceScale == null ? 1.5 : surfaceScale.get();
387    }
388
389    public final DoubleProperty surfaceScaleProperty() {
390        if (surfaceScale == null) {
391            surfaceScale = new DoublePropertyBase(1.5) {
392
393                @Override
394                public void invalidated() {
395                    markDirty(EffectDirtyBits.EFFECT_DIRTY);
396                }
397
398                @Override
399                public Object getBean() {
400                    return Lighting.this;
401                }
402
403                @Override
404                public String getName() {
405                    return "surfaceScale";
406                }
407            };
408        }
409        return surfaceScale;
410    }
411
412    private Light getLightInternal() {
413        Light localLight = getLight();
414        return localLight == null ? defaultLight : localLight;
415    }
416
417    @Override
418    void impl_update() {
419        Effect localBumpInput = getBumpInput();
420
421        if (localBumpInput != null) {
422            localBumpInput.impl_sync();
423        }
424
425        Effect localContentInput = getContentInput();
426        if (localContentInput != null) {
427            localContentInput.impl_sync();
428        }
429
430        PhongLighting peer = (PhongLighting) impl_getImpl();
431        peer.setBumpInput(localBumpInput == null ? null : localBumpInput.impl_getImpl());
432        peer.setContentInput(localContentInput == null ? null : localContentInput.impl_getImpl());
433        peer.setDiffuseConstant((float)Utils.clamp(0, getDiffuseConstant(), 2));
434        peer.setSpecularConstant((float)Utils.clamp(0, getSpecularConstant(), 2));
435        peer.setSpecularExponent((float)Utils.clamp(0, getSpecularExponent(), 40));
436        peer.setSurfaceScale((float)Utils.clamp(0, getSurfaceScale(), 10));
437        // we don't need to register on default light in case the light is null
438        // because default light never changes
439        lightChangeListener.register(getLight());
440
441        getLightInternal().impl_sync();
442        peer.setLight(getLightInternal().impl_getImpl());
443    }
444
445    /**
446     * @treatAsPrivate implementation detail
447     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
448     */
449    @Deprecated
450    @Override
451    public BaseBounds impl_getBounds(BaseBounds bounds,
452                                     BaseTransform tx,
453                                     Node node,
454                                     BoundsAccessor boundsAccessor) {
455        return EffectUtils.getInputBounds(bounds, tx,
456                                          node, boundsAccessor,
457                                          getContentInput());
458    }
459}