/*
* 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 PhongMaterial
class provides definitions of properties that represent a Phong shaded material. It describes the interaction of light with the surface of the Mesh
it is applied to. The 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:
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 lightColor[i]
is the color of light source i,
L[i]
is the vector from the surface to light source i,
N
is the normal vector (taking into the account the bumpMap if present),
R[i]
is the normalized reflection vector for L[i] about the surface normal,
and V
is the normalized view vector. See Also: Since: JavaFX 8.0
/**
* 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.
* <p>
* The color is computed by the following equation:
*
* <pre>{@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
* }</pre>
* where
* {@code lightColor[i]} is the color of light source i,<br>
* {@code L[i]} is the vector from the surface to light source i,<br>
* {@code N} is the normal vector (taking into the account the bumpMap if present),<br>
* {@code R[i]} is the normalized reflection vector for L[i] about the surface normal,<br>
* 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 PhongMaterial
class with a default Color.WHITE diffuseColor
property. /**
* 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 PhongMaterial
class using the specified color for its diffuseColor
property. Params: - diffuseColor – the color of the diffuseColor property
/**
* 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 PhongMaterial
class using the specified colors and images for its diffuseColor
properties. Params: - diffuseColor – the color of the diffuseColor property
- diffuseMap – the image of the diffuseMap property
- specularMap – the image of the specularMap property
- bumpMap – the image of the bumpMap property
- selfIlluminationMap – the image of the selfIlluminationMap property
/**
* 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 PhongMaterial
. @defaultValue Color.WHITE
/**
* The diffuse color of this {@code PhongMaterial}.
*
* @defaultValue Color.WHITE
*/
private ObjectProperty<Color> diffuseColor;
public final void setDiffuseColor(Color value) {
diffuseColorProperty().set(value);
}
public final Color getDiffuseColor() {
return diffuseColor == null ? null : diffuseColor.get();
}
public final ObjectProperty<Color> diffuseColorProperty() {
if (diffuseColor == null) {
diffuseColor = new SimpleObjectProperty<Color>(PhongMaterial.this,
"diffuseColor") {
@Override
protected void invalidated() {
diffuseColorDirty = true;
setDirty(true);
}
};
}
return diffuseColor;
}
The specular color of this PhongMaterial
. @defaultValue null
/**
* The specular color of this {@code PhongMaterial}.
*
* @defaultValue null
*/
private ObjectProperty<Color> specularColor;
public final void setSpecularColor(Color value) {
specularColorProperty().set(value);
}
public final Color getSpecularColor() {
return specularColor == null ? null : specularColor.get();
}
public final ObjectProperty<Color> specularColorProperty() {
if (specularColor == null) {
specularColor = new SimpleObjectProperty<Color>(PhongMaterial.this,
"specularColor") {
@Override
protected void invalidated() {
specularColorDirty = true;
setDirty(true);
}
};
}
return specularColor;
}
The specular power of this PhongMaterial
. @defaultValue 32.0
/**
* 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 PhongMaterial
. @defaultValue null
/**
* 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<Image> 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<Image> diffuseMapProperty() {
if (diffuseMap == null) {
diffuseMap = new SimpleObjectProperty<Image>(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 PhongMaterial
. @defaultValue null
/**
* 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<Image> 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<Image> specularMapProperty() {
if (specularMap == null) {
specularMap = new SimpleObjectProperty<Image>(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 PhongMaterial
, which is a normal map stored as a RGB Image
. @defaultValue null
/**
* 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<Image> 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<Image> bumpMapProperty() {
if (bumpMap == null) {
bumpMap = new SimpleObjectProperty<Image>(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 PhongMaterial
. @defaultValue null
/**
* 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<Image> 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<Image> selfIlluminationMapProperty() {
if (selfIlluminationMap == null) {
selfIlluminationMap = new SimpleObjectProperty<Image>(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 /** 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() + "]";
}
}