All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javafx.scene.paint.PhongMaterial Maven / Gradle / Ivy

/*
 * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package javafx.scene.paint;

import com.sun.javafx.beans.event.AbstractNotifyListener;
import com.sun.javafx.scene.paint.MaterialHelper;
import com.sun.javafx.sg.prism.NGPhongMaterial;
import com.sun.javafx.tk.Toolkit;
import javafx.beans.Observable;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.AmbientLight;
import javafx.scene.PointLight;
import javafx.scene.image.Image;

/**
 * The {@code PhongMaterial} class provides definitions of properties that
 * represent a Phong shaded material. It describes the interaction of
 * light with the surface of the {@code Mesh} it is applied to. The {@code PhongMaterial}
 * reflects light in terms of a diffuse and specular component together with
 * an ambient and a self illumination term. The color of a point on a geometric
 * surface is mathematical function of these four components.
 * 

* The color is computed by the following equation: * *

{@code
 * for each ambient light source i {
 *     ambient += lightColor[i]
 * }
 *
 * for each point light source i {
 *     diffuse += (L[i] . N) * lightColor[i]
 *     specular += ((R[i] . V) ^ (specularPower * intensity(specularMap))) * lightColor[i]
 * }
 *
 * color = (ambient + diffuse) * diffuseColor * diffuseMap
 *             + specular * specularColor * specularMap
 *             + selfIlluminationMap
 * }
* where * {@code lightColor[i]} is the color of light source i,
* {@code L[i]} is the vector from the surface to light source i,
* {@code N} is the normal vector (taking into the account the bumpMap if present),
* {@code R[i]} is the normalized reflection vector for L[i] about the surface normal,
* and {@code V} is the normalized view vector. * * @see AmbientLight * @see PointLight * @since JavaFX 8.0 */ public class PhongMaterial extends Material { private boolean diffuseColorDirty = true; private boolean specularColorDirty = true; private boolean specularPowerDirty = true; private boolean diffuseMapDirty = true; private boolean specularMapDirty = true; private boolean bumpMapDirty = true; private boolean selfIlluminationMapDirty = true; /** * Creates a new instance of {@code PhongMaterial} class with a default * Color.WHITE {@code diffuseColor} property. */ public PhongMaterial() { setDiffuseColor(Color.WHITE); } /** * Creates a new instance of {@code PhongMaterial} class using the specified * color for its {@code diffuseColor} property. * * @param diffuseColor the color of the diffuseColor property */ public PhongMaterial(Color diffuseColor) { setDiffuseColor(diffuseColor); } /** * Creates a new instance of {@code PhongMaterial} class using the specified * colors and images for its {@code diffuseColor} properties. * * @param diffuseColor the color of the diffuseColor property * @param diffuseMap the image of the diffuseMap property * @param specularMap the image of the specularMap property * @param bumpMap the image of the bumpMap property * @param selfIlluminationMap the image of the selfIlluminationMap property * */ public PhongMaterial(Color diffuseColor, Image diffuseMap, Image specularMap, Image bumpMap, Image selfIlluminationMap) { setDiffuseColor(diffuseColor); setDiffuseMap(diffuseMap); setSpecularMap(specularMap); setBumpMap(bumpMap); setSelfIlluminationMap(selfIlluminationMap); } /** * The diffuse color of this {@code PhongMaterial}. * * @defaultValue Color.WHITE */ private ObjectProperty diffuseColor; public final void setDiffuseColor(Color value) { diffuseColorProperty().set(value); } public final Color getDiffuseColor() { return diffuseColor == null ? null : diffuseColor.get(); } public final ObjectProperty diffuseColorProperty() { if (diffuseColor == null) { diffuseColor = new SimpleObjectProperty(PhongMaterial.this, "diffuseColor") { @Override protected void invalidated() { diffuseColorDirty = true; setDirty(true); } }; } return diffuseColor; } /** * The specular color of this {@code PhongMaterial}. * * @defaultValue null */ private ObjectProperty specularColor; public final void setSpecularColor(Color value) { specularColorProperty().set(value); } public final Color getSpecularColor() { return specularColor == null ? null : specularColor.get(); } public final ObjectProperty specularColorProperty() { if (specularColor == null) { specularColor = new SimpleObjectProperty(PhongMaterial.this, "specularColor") { @Override protected void invalidated() { specularColorDirty = true; setDirty(true); } }; } return specularColor; } /** * The specular power of this {@code PhongMaterial}. * * @defaultValue 32.0 */ private DoubleProperty specularPower; public final void setSpecularPower(double value) { specularPowerProperty().set(value); } public final double getSpecularPower() { return specularPower == null ? 32 : specularPower.get(); } public final DoubleProperty specularPowerProperty() { if (specularPower == null) { specularPower = new SimpleDoubleProperty(PhongMaterial.this, "specularPower", 32.0) { @Override public void invalidated() { specularPowerDirty = true; setDirty(true); } }; } return specularPower; } private final AbstractNotifyListener platformImageChangeListener = new AbstractNotifyListener() { @Override public void invalidated(Observable valueModel) { if (oldDiffuseMap != null && valueModel == Toolkit.getImageAccessor().getImageProperty(oldDiffuseMap)) { diffuseMapDirty = true; } else if (oldSpecularMap != null && valueModel == Toolkit.getImageAccessor().getImageProperty(oldSpecularMap)) { specularMapDirty = true; } else if (oldBumpMap != null && valueModel == Toolkit.getImageAccessor().getImageProperty(oldBumpMap)) { bumpMapDirty = true; } else if (oldSelfIlluminationMap != null && valueModel == Toolkit.getImageAccessor().getImageProperty(oldSelfIlluminationMap)) { selfIlluminationMapDirty = true; } setDirty(true); } }; /** * The diffuse map of this {@code PhongMaterial}. * * @defaultValue null */ // TODO: 3D - Texture or Image? For Media it might be better to have it as a Texture private ObjectProperty diffuseMap; public final void setDiffuseMap(Image value) { diffuseMapProperty().set(value); } public final Image getDiffuseMap() { return diffuseMap == null ? null : diffuseMap.get(); } private Image oldDiffuseMap; public final ObjectProperty diffuseMapProperty() { if (diffuseMap == null) { diffuseMap = new SimpleObjectProperty(PhongMaterial.this, "diffuseMap") { private boolean needsListeners = false; @Override public void invalidated() { Image _image = get(); if (needsListeners) { Toolkit.getImageAccessor().getImageProperty(oldDiffuseMap). removeListener(platformImageChangeListener.getWeakListener()); } needsListeners = _image != null && (Toolkit.getImageAccessor().isAnimation(_image) || _image.getProgress() < 1); if (needsListeners) { Toolkit.getImageAccessor().getImageProperty(_image). addListener(platformImageChangeListener.getWeakListener()); } oldDiffuseMap = _image; diffuseMapDirty = true; setDirty(true); } }; } return diffuseMap; } /** * The specular map of this {@code PhongMaterial}. * * @defaultValue null */ // TODO: 3D - Texture or Image? For Media it might be better to have it as a Texture private ObjectProperty specularMap; public final void setSpecularMap(Image value) { specularMapProperty().set(value); } public final Image getSpecularMap() { return specularMap == null ? null : specularMap.get(); } private Image oldSpecularMap; public final ObjectProperty specularMapProperty() { if (specularMap == null) { specularMap = new SimpleObjectProperty(PhongMaterial.this, "specularMap") { private boolean needsListeners = false; @Override public void invalidated() { Image _image = get(); if (needsListeners) { Toolkit.getImageAccessor().getImageProperty(oldSpecularMap). removeListener(platformImageChangeListener.getWeakListener()); } needsListeners = _image != null && (Toolkit.getImageAccessor().isAnimation(_image) || _image.getProgress() < 1); if (needsListeners) { Toolkit.getImageAccessor().getImageProperty(_image). addListener(platformImageChangeListener.getWeakListener()); } oldSpecularMap = _image; specularMapDirty = true; setDirty(true); } }; } return specularMap; } /** * The bump map of this {@code PhongMaterial}, which is a normal map stored * as a RGB {@link Image}. * * @defaultValue null */ // TODO: 3D - Texture or Image? For Media it might be better to have it as a Texture private ObjectProperty bumpMap; public final void setBumpMap(Image value) { bumpMapProperty().set(value); } public final Image getBumpMap() { return bumpMap == null ? null : bumpMap.get(); } private Image oldBumpMap; public final ObjectProperty bumpMapProperty() { if (bumpMap == null) { bumpMap = new SimpleObjectProperty(PhongMaterial.this, "bumpMap") { private boolean needsListeners = false; @Override public void invalidated() { Image _image = get(); if (needsListeners) { Toolkit.getImageAccessor().getImageProperty(oldBumpMap). removeListener(platformImageChangeListener.getWeakListener()); } needsListeners = _image != null && (Toolkit.getImageAccessor().isAnimation(_image) || _image.getProgress() < 1); if (needsListeners) { Toolkit.getImageAccessor().getImageProperty(_image). addListener(platformImageChangeListener.getWeakListener()); } oldBumpMap = _image; bumpMapDirty = true; setDirty(true); } }; } return bumpMap; } /** * The self illumination map of this {@code PhongMaterial}. * * @defaultValue null */ // TODO: 3D - Texture or Image? For Media it might be better to have it as a Texture private ObjectProperty selfIlluminationMap; public final void setSelfIlluminationMap(Image value) { selfIlluminationMapProperty().set(value); } public final Image getSelfIlluminationMap() { return selfIlluminationMap == null ? null : selfIlluminationMap.get(); } private Image oldSelfIlluminationMap; public final ObjectProperty selfIlluminationMapProperty() { if (selfIlluminationMap == null) { selfIlluminationMap = new SimpleObjectProperty(PhongMaterial.this, "selfIlluminationMap") { private boolean needsListeners = false; @Override public void invalidated() { Image _image = get(); if (needsListeners) { Toolkit.getImageAccessor().getImageProperty(oldSelfIlluminationMap). removeListener(platformImageChangeListener.getWeakListener()); } needsListeners = _image != null && (Toolkit.getImageAccessor().isAnimation(_image) || _image.getProgress() < 1); if (needsListeners) { Toolkit.getImageAccessor().getImageProperty(_image). addListener(platformImageChangeListener.getWeakListener()); } oldSelfIlluminationMap = _image; selfIlluminationMapDirty = true; setDirty(true); } }; } return selfIlluminationMap; } @Override void setDirty(boolean value) { super.setDirty(value); if (!value) { diffuseColorDirty = false; specularColorDirty = false; specularPowerDirty = false; diffuseMapDirty = false; specularMapDirty = false; bumpMapDirty = false; selfIlluminationMapDirty = false; } } /** The peer node created by the graphics Toolkit/Pipeline implementation */ private NGPhongMaterial peer; @Override NGPhongMaterial getNGMaterial() { if (peer == null) { peer = new NGPhongMaterial(); } return peer; } @Override void updatePG(){ if (!isDirty()) { return; } final NGPhongMaterial pMaterial = MaterialHelper.getNGMaterial(this); if (diffuseColorDirty) { pMaterial.setDiffuseColor(getDiffuseColor() == null ? null : Toolkit.getPaintAccessor().getPlatformPaint(getDiffuseColor())); } if (specularColorDirty) { pMaterial.setSpecularColor(getSpecularColor() == null ? null : Toolkit.getPaintAccessor().getPlatformPaint(getSpecularColor())); } if (specularPowerDirty) { pMaterial.setSpecularPower((float)getSpecularPower()); } if (diffuseMapDirty) { pMaterial.setDiffuseMap(getDiffuseMap() == null ? null : Toolkit.getImageAccessor().getPlatformImage(getDiffuseMap())); } if (specularMapDirty) { pMaterial.setSpecularMap(getSpecularMap() == null ? null : Toolkit.getImageAccessor().getPlatformImage(getSpecularMap())); } if (bumpMapDirty) { pMaterial.setBumpMap(getBumpMap() == null ? null : Toolkit.getImageAccessor().getPlatformImage(getBumpMap())); } if (selfIlluminationMapDirty) { pMaterial.setSelfIllumMap(getSelfIlluminationMap() == null ? null : Toolkit.getImageAccessor().getPlatformImage(getSelfIlluminationMap())); } setDirty(false); } @Override public String toString() { return "PhongMaterial[" + "diffuseColor=" + getDiffuseColor() + ", specularColor=" + getSpecularColor() + ", specularPower=" + getSpecularPower() + ", diffuseMap=" + getDiffuseMap() + ", specularMap=" + getSpecularMap() + ", bumpMap=" + getBumpMap() + ", selfIlluminationMap=" + getSelfIlluminationMap() + "]"; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy