com.sun.scenario.effect.PhongLighting Maven / Gradle / Ivy
The newest version!
/*
* Copyright (c) 2008, 2015, 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 com.sun.scenario.effect;
import com.sun.javafx.geom.BaseBounds;
import com.sun.javafx.geom.DirtyRegionContainer;
import com.sun.javafx.geom.DirtyRegionPool;
import com.sun.javafx.geom.Point2D;
import com.sun.javafx.geom.Rectangle;
import com.sun.javafx.geom.transform.BaseTransform;
import com.sun.scenario.effect.impl.state.RenderState;
import com.sun.scenario.effect.light.Light;
/**
* An effect that applies diffuse and specular lighting to an arbitrary
* input using a positionable light source.
*/
public class PhongLighting extends CoreEffect {
private float surfaceScale;
private float diffuseConstant;
private float specularConstant;
private float specularExponent;
private Light light;
/**
* Constructs a new {@code PhongLighting} effect for the given
* {@code Light}, with default values for all other properties,
* using the default input for source data.
* This is a convenience constructor that automatically generates a
* bump map using the default input.
*
* @param light the light source
* @throws IllegalArgumentException if {@code light} is null
*/
public PhongLighting(Light light) {
this(light, new GaussianShadow(10f), DefaultInput);
}
/**
* Constructs a new {@code PhongLighting} effect for the given
* {@code Light} and the given bump and content input {@code Effect}s
* with default values for all other properties.
*
* @param light the light source
* @param bumpInput the input containing the bump map
* @param contentInput the input containing the content data
* @throws IllegalArgumentException if {@code light} is null
*/
public PhongLighting(Light light, Effect bumpInput, Effect contentInput) {
super(bumpInput, contentInput);
this.surfaceScale = 1f;
this.diffuseConstant = 1f;
this.specularConstant = 1f;
this.specularExponent = 1f;
setLight(light);
}
/**
* Returns the bump input for this {@code Effect}.
*
* @return the bump input for this {@code Effect}
*/
public final Effect getBumpInput() {
return getInputs().get(0);
}
/**
* Sets the bump input for this {@code Effect} to a specific
* {@code Effect} or to the default input if {@code input} is
* {@code null}.
*
* @param bumpInput the bump input for this {@code Effect}
*/
public void setBumpInput(Effect bumpInput) {
setInput(0, bumpInput);
}
/**
* Returns the content input for this {@code Effect}.
*
* @return the content input for this {@code Effect}
*/
public final Effect getContentInput() {
return getInputs().get(1);
}
private Effect getContentInput(Effect defaultInput) {
return getDefaultedInput(1, defaultInput);
}
/**
* Sets the content input for this {@code Effect} to a specific
* {@code Effect} or to the default input if {@code input} is
* {@code null}.
*
* @param contentInput the content input for this {@code Effect}
*/
public void setContentInput(Effect contentInput) {
setInput(1, contentInput);
}
/**
* Returns the light source.
*
* @return the light source
*/
public Light getLight() {
return light;
}
/**
* Sets the light source.
*
* @param light the light source
* @throws IllegalArgumentException if {@code light} is null
*/
public void setLight(Light light) {
if (light == null) {
throw new IllegalArgumentException("Light must be non-null");
}
this.light = light;
updatePeerKey("PhongLighting_" + light.getType().name());
}
/**
* Returns the diffuse constant.
*
* @return the diffuse constant value
*/
public float getDiffuseConstant() {
return diffuseConstant;
}
/**
* Sets the diffuse constant.
*
* Min: 0.0
* Max: 2.0
* Default: 1.0
* Identity: n/a
*
*
* @param diffuseConstant the diffuse constant value
* @throws IllegalArgumentException if {@code diffuseConstant} is outside
* the allowable range
*/
public void setDiffuseConstant(float diffuseConstant) {
if (diffuseConstant < 0f || diffuseConstant > 2f) {
throw new IllegalArgumentException("Diffuse constant must be in the range [0,2]");
}
float old = this.diffuseConstant;
this.diffuseConstant = diffuseConstant;
}
/**
* Returns the specular constant.
*
* @return the specular constant value
*/
public float getSpecularConstant() {
return specularConstant;
}
/**
* Sets the specular constant.
*
* Min: 0.0
* Max: 2.0
* Default: 1.0
* Identity: n/a
*
*
* @param specularConstant the specular constant value
* @throws IllegalArgumentException if {@code specularConstant} is outside
* the allowable range
*/
public void setSpecularConstant(float specularConstant) {
if (specularConstant < 0f || specularConstant > 2f) {
throw new IllegalArgumentException("Specular constant must be in the range [0,2]");
}
float old = this.specularConstant;
this.specularConstant = specularConstant;
}
/**
* Returns the specular exponent.
*
* @return the specular exponent value
*/
public float getSpecularExponent() {
return specularExponent;
}
/**
* Sets the specular exponent.
*
* Min: 0.0
* Max: 40.0
* Default: 1.0
* Identity: n/a
*
*
* @param specularExponent the specular exponent value
* @throws IllegalArgumentException if {@code specularExponent} is outside
* the allowable range
*/
public void setSpecularExponent(float specularExponent) {
if (specularExponent < 0f || specularExponent > 40f) {
throw new IllegalArgumentException("Specular exponent must be in the range [0,40]");
}
float old = this.specularExponent;
this.specularExponent = specularExponent;
}
/**
* Returns the surface scale.
*
* @return the surface scale value
*/
public float getSurfaceScale() {
return surfaceScale;
}
/**
* Sets the surface scale.
*
* Min: 0.0
* Max: 10.0
* Default: 1.0
* Identity: n/a
*
*
* @param surfaceScale the surface scale value
* @throws IllegalArgumentException if {@code surfaceScale} is outside
* the allowable range
*/
public void setSurfaceScale(float surfaceScale) {
if (surfaceScale < 0f || surfaceScale > 10f) {
throw new IllegalArgumentException("Surface scale must be in the range [0,10]");
}
float old = this.surfaceScale;
this.surfaceScale = surfaceScale;
}
@Override
public BaseBounds getBounds(BaseTransform transform,
Effect defaultInput)
{
// effect inherits its bounds from the content input
return getContentInput(defaultInput).getBounds(transform, defaultInput);
}
@Override
public Rectangle getResultBounds(BaseTransform transform,
Rectangle outputClip,
ImageData... inputDatas)
{
// result inherits its dimensions from the content input
return super.getResultBounds(transform, outputClip, inputDatas[1]);
}
@Override
public Point2D transform(Point2D p, Effect defaultInput) {
return getContentInput(defaultInput).transform(p, defaultInput);
}
@Override
public Point2D untransform(Point2D p, Effect defaultInput) {
return getContentInput(defaultInput).untransform(p, defaultInput);
}
@Override
public RenderState getRenderState(FilterContext fctx,
BaseTransform transform,
Rectangle outputClip,
Object renderHelper,
Effect defaultInput)
{
// RT-27564
// TODO: Since only the content input is used for the output bounds
// we could attempt to factor the bounds of the content input in our
// answer for the getInputClip() method of the RenderState, but for
// now we will just use (a close copy of) the stock RenderSpaceRenderState object.
return new RenderState() {
@Override
public EffectCoordinateSpace getEffectTransformSpace() {
return EffectCoordinateSpace.RenderSpace;
}
@Override
public BaseTransform getInputTransform(BaseTransform filterTransform) {
return filterTransform;
}
@Override
public BaseTransform getResultTransform(BaseTransform filterTransform) {
return BaseTransform.IDENTITY_TRANSFORM;
}
@Override
public Rectangle getInputClip(int i, Rectangle filterClip) {
if (i == 0 && filterClip != null) {
Rectangle r = new Rectangle(filterClip);
r.grow(1, 1);
return r;
}
return filterClip;
}
};
}
@Override
public boolean reducesOpaquePixels() {
final Effect contentInput = getContentInput();
return contentInput != null && contentInput.reducesOpaquePixels();
}
@Override
public DirtyRegionContainer getDirtyRegions(Effect defaultInput, DirtyRegionPool regionPool) {
Effect bump = getDefaultedInput(0, defaultInput);
DirtyRegionContainer drc1 = bump.getDirtyRegions(defaultInput, regionPool);
drc1.grow(1, 1);
Effect content = getDefaultedInput(1, defaultInput);
DirtyRegionContainer drc2 = content.getDirtyRegions(defaultInput, regionPool);
drc1.merge(drc2);
regionPool.checkIn(drc2);
return drc1;
}
}