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

com.sun.scenario.effect.impl.EffectPeer Maven / Gradle / Ivy

There is a newer version: 24-ea+15
Show newest version
/*
 * Copyright (c) 2008, 2014, 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.impl;

import com.sun.scenario.effect.Effect;
import com.sun.scenario.effect.Effect.AccelType;
import com.sun.scenario.effect.FilterContext;
import com.sun.scenario.effect.ImageData;
import com.sun.javafx.geom.Rectangle;
import com.sun.javafx.geom.transform.BaseTransform;
import com.sun.javafx.geom.transform.NoninvertibleTransformException;
import com.sun.scenario.effect.impl.state.RenderState;

/**
 * The abstract base class for all {@code Effect} implementation peers.
 *
 * @param  an optional subclass of RenderState that can be assumed as the
 *            return value for the getRenderState() method
 */
public abstract class EffectPeer {

    private final FilterContext fctx;
    private final Renderer renderer;
    private final String uniqueName;
    private Effect effect;
    private T renderState;
    private int pass;

    protected EffectPeer(FilterContext fctx, Renderer renderer, String uniqueName) {
        if (fctx == null) {
            throw new IllegalArgumentException("FilterContext must be non-null");
        }
        this.fctx = fctx;
        this.renderer = renderer;
        this.uniqueName = uniqueName;
    }

    public boolean isImageDataCompatible(ImageData id) {
        return getRenderer().isImageDataCompatible(id);
    }

    public abstract ImageData filter(Effect effect,
                                     T renderState,
                                     BaseTransform transform,
                                     Rectangle outputClip,
                                     ImageData... inputs);

    /**
     * Disposes resources associated with this peer.
     * Warning: may be called from the rendering thread.
     */
    public void dispose() {
    }

    public AccelType getAccelType() {
        return renderer.getAccelType();
    }

    protected final FilterContext getFilterContext() {
        return fctx;
    }

    protected Renderer getRenderer() {
        return renderer;
    }

    /**
     * Returns the unique name of this peer.  This value can be used as
     * the key value in a hashmap of cached peer instances.  In the case
     * of hardware peers, this value is typically the name of the shader that
     * is used by the peer.
     *
     * @return the unique name of this peer
     */
    public String getUniqueName() {
        return uniqueName;
    }

    protected Effect getEffect() {
        return effect;
    }

    protected void setEffect(Effect effect) {
        this.effect = effect;
    }

    protected T getRenderState() {
        return renderState;
    }

    protected void setRenderState(T renderState) {
        this.renderState = renderState;
    }

    public final int getPass() {
        return pass;
    }

    public void setPass(int pass) {
        this.pass = pass;
    }

    // NOTE: this input(Native)Bounds stuff is unpleasant, but we somehow
    // need to provide access to the native surface bounds for various glue
    // methods (e.g. getKvals())

    private final Rectangle[] inputBounds = new Rectangle[2];
    /**
     * Returns the "valid" bounds of the source image for the given input.
     * Since Effect implementations try to recycle temporary Images, it is
     * quite possible that the input bounds returned by this method will
     * differ from the size of the associated input Image.  For example,
     * this method may return (0, 0, 210, 180) even though the associated
     * Image has dimensions of 230x200 pixels.  Pixels in the input Image
     * outside these "valid" bounds are undefined and should be avoided.
     *
     * @param inputIndex the index of the source input
     * @return the valid bounds of the source Image
     */
    protected final Rectangle getInputBounds(int inputIndex) {
        return inputBounds[inputIndex];
    }
    protected final void setInputBounds(int inputIndex, Rectangle r) {
        inputBounds[inputIndex] = r;
    }

    private final BaseTransform[] inputTransforms = new BaseTransform[2];
    protected final BaseTransform getInputTransform(int inputIndex) {
        return inputTransforms[inputIndex];
    }
    protected final void setInputTransform(int inputIndex, BaseTransform tx) {
        inputTransforms[inputIndex] = tx;
    }

    private final Rectangle[] inputNativeBounds = new Rectangle[2];
    /**
     * Returns the bounds of the native surface for the given input.
     * It is quite possible that the input native bounds returned by this
     * method will differ from the size of the associated input (Java-level)
     * Image.  This is common for the OGL and D3D backends of Java 2D,
     * where on older hardware the dimensions of a VRAM surface (e.g. texture)
     * must be a power of two.  For example, this method may return
     * (0, 0, 256, 256) even though the associated (Volatile)Image has
     * dimensions of 230x200 pixels.
     * 

* This method is useful in cases where it is necessary to access * adjacent pixels in a native surface. For example, the horizontal * distance between two texel centers of a native surface can be * calculated as (1f/inputNativeBounds.width); for the vertical distance, * (1f/inputNativeBounds.height). * * @param inputIndex the index of the source input * @return the native surface bounds */ protected final Rectangle getInputNativeBounds(int inputIndex) { return inputNativeBounds[inputIndex]; } protected final void setInputNativeBounds(int inputIndex, Rectangle r) { inputNativeBounds[inputIndex] = r; } public Rectangle getResultBounds(BaseTransform transform, Rectangle outputClip, ImageData... inputDatas) { return getEffect().getResultBounds(transform, outputClip, inputDatas); } /** * Returns an array of four floats that represent the mapping of the * data for the specified input to the given effect area. * The interpretation of the returned values is entirely dependent on * the algorithm of the pixel shader, but typical values are in the * "unit" coordinate space of the destination effect area, where * {@code (0,0)} is at the upper-left corner, and {@code (1,1)} is at * the lower-right corner. * The returned array contains the values in order (x1, y1, x2, y2). *

* The default implementation converts the logical destination effect * region into the coordinate space of the native surface of the * specified source input according to the * {@link getSourceRegion(Rectangle, Rectangle, Rectangle)} method. *

* Subclasses can override this method to provide more sophisticated * positioning behavior. * * @param inputIndex the index of the source input * @return an array of four float values */ protected float[] getSourceRegion(int inputIndex) { return getSourceRegion(getInputBounds(inputIndex), getInputNativeBounds(inputIndex), getDestBounds()); } /** * Returns an array of four floats that represent the mapping of the * specified source region for the specified effect area. * The returned values are in the "unit" coordinate space of the source * native surface, where (0,0) is at the upper-left corner, and (1,1) * is at the lower-right corner. * For example, if the native input surface (i.e. texture) is 256x256 * pixels, and the effect output region is at the same coordinates as * the input region and is 200x200, this method will * return (0, 0, 200/256, 220/256). * The returned array contains the values in order (x1, y1, x2, y2). *

* Subclasses can override this method to provide more sophisticated * positioning behavior. * * @param srcBounds the logical bounds of the input data * @param srcNativeBounds the actual dimensions of the input image * containing the input data in its upper left * @param dstBounds the logical bounds of the resulting effect output * @return an array of four float values */ static float[] getSourceRegion(Rectangle srcBounds, Rectangle srcNativeBounds, Rectangle dstBounds) { float x1 = dstBounds.x - srcBounds.x; float y1 = dstBounds.y - srcBounds.y; float x2 = x1 + dstBounds.width; float y2 = y1 + dstBounds.height; float sw = srcNativeBounds.width; float sh = srcNativeBounds.height; return new float[] {x1 / sw, y1 / sh, x2 / sw, y2 / sh}; } /** * Returns either 4 or 8 source texture coordinates depending on the * transform being applied to the source. *

* If the mapping is rectilinear then 4 floats are returned. The * texture coordinates are thus mapped using the following table: *

     *     dx1,dy1 => ret[0], ret[1]
     *     dx2,dy1 => ret[2], ret[1]
     *     dx1,dy2 => ret[0], ret[3]
     *     dx2,dy2 => ret[2], ret[3]
     * 
* If the mapping is non-rectilinear then 8 floats are returned and * the texture coordinates are mapped using the following table (note * that the dx1,dy1 and dx2,dy2 mappings are still from the same * indices as in the 4 float return value): *
     *     dx1,dy1 => ret[0], ret[1]
     *     dx2,dy1 => ret[4], ret[5]
     *     dx1,dy2 => ret[6], ret[7]
     *     dx2,dy2 => ret[2], ret[3]
     * 
* The default implementation of this method simply calls the static * method {@link getTextureCoordinates(float[],float,float,float,float,Rectangle,BaseTransform)}. * * @param inputIndex the index of the input whose texture coordinates * are being queried * @param coords An array that can hold up to 8 floats for returning * the texture coordinates. * @param srcX The X coordinate of the origin of the source texture * in the untransformed coordinate space. * @param srcY The Y coordinate of the origin of the source texture * in the untransformed coordinate space. * @param srcNativeWidth the native width of the source texture * @param srcNativeHeight the native height of the source texture * @param dstBounds the output bounds that the texture is * being stretched over * @param transform the transform to be implicitly applied to the * source texture as it is mapped onto the destination * @return the number of texture coordinates stored in the {@code coords} * array (either 4 or 8) */ public int getTextureCoordinates(int inputIndex, float coords[], float srcX, float srcY, float srcNativeWidth, float srcNativeHeight, Rectangle dstBounds, BaseTransform transform) { return getTextureCoordinates(coords, srcX, srcY, srcNativeWidth, srcNativeHeight, dstBounds, transform); } /** * Returns either 4 or 8 source texture coordinates depending on the * transform being applied to the source. *

* If the mapping is rectilinear then 4 floats are returned. The * texture coordinates are thus mapped using the following table: *

     *     dx1,dy1 => ret[0], ret[1]
     *     dx2,dy1 => ret[2], ret[1]
     *     dx1,dy2 => ret[0], ret[3]
     *     dx2,dy2 => ret[2], ret[3]
     * 
* If the mapping is non-rectilinear then 8 floats are returned and * the texture coordinates are mapped using the following table (note * that the dx1,dy1 and dx2,dy2 mappings are still from the same * indices as in the 4 float return value): *
     *     dx1,dy1 => ret[0], ret[1]
     *     dx2,dy1 => ret[4], ret[5]
     *     dx1,dy2 => ret[6], ret[7]
     *     dx2,dy2 => ret[2], ret[3]
     * 
* * @param coords An array that can hold up to 8 floats for returning * the texture coordinates. * @param srcX The X coordinate of the origin of the source texture * in the untransformed coordinate space. * @param srcY The Y coordinate of the origin of the source texture * in the untransformed coordinate space. * @param srcNativeWidth the native width of the source texture * @param srcNativeHeight the native height of the source texture * @param dstBounds the output bounds that the texture is * being stretched over * @param transform the transform to be implicitly applied to the * source texture as it is mapped onto the destination * @return the number of texture coordinates stored in the {@code coords} * array (either 4 or 8) */ public static int getTextureCoordinates(float coords[], float srcX, float srcY, float srcNativeWidth, float srcNativeHeight, Rectangle dstBounds, BaseTransform transform) { coords[0] = dstBounds.x; coords[1] = dstBounds.y; coords[2] = coords[0] + dstBounds.width; coords[3] = coords[1] + dstBounds.height; int numCoords; if (transform.isTranslateOrIdentity()) { srcX += (float) transform.getMxt(); srcY += (float) transform.getMyt(); numCoords = 4; } else { coords[4] = coords[2]; coords[5] = coords[1]; coords[6] = coords[0]; coords[7] = coords[3]; numCoords = 8; try { transform.inverseTransform(coords, 0, coords, 0, 4); } catch (NoninvertibleTransformException e) { coords[0] = coords[1] = coords[2] = coords[4] = 0f; return 4; } } for (int i = 0; i < numCoords; i += 2) { coords[i ] = (coords[i ] - srcX) / srcNativeWidth; coords[i+1] = (coords[i+1] - srcY) / srcNativeHeight; } return numCoords; } private Rectangle destBounds; protected final void setDestBounds(Rectangle r) { destBounds = r; } protected final Rectangle getDestBounds() { return destBounds; } private final Rectangle destNativeBounds = new Rectangle(); protected final Rectangle getDestNativeBounds() { return destNativeBounds; } protected final void setDestNativeBounds(int w, int h) { destNativeBounds.width = w; destNativeBounds.height = h; } protected Object getSamplerData(int i) { return null; } /** * Returns true if the native coordinate system has its origin at * the upper-left corner of the destination surface; otherwise, returns * false, indicating that the origin is at the lower-left corner. *

* This method may be useful in determining the direction of adjacent * pixels in an OpenGL surface (since many OpenGL methods take parameters * assuming a lower-left origin). * * @return true if the coordinate system has an upper-left origin */ protected boolean isOriginUpperLeft() { return (getAccelType() != Effect.AccelType.OPENGL); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy