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

javax.media.j3d.ShaderProgramRetained Maven / Gradle / Ivy

/*
 * Copyright 2005-2008 Sun Microsystems, Inc.  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.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 *
 */

package javax.media.j3d;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;

/**
 * The ShaderProgramRetained object is a component object of an AppearanceRetained
 * object that defines the shader properties used when programmable shader is
 * enabled. ShaderProgramRetained object is an abstract class. All shader program
 * objects must be created as either a GLSLShaderProgramRetained object or a
 * CgShaderProgramRetained object.
 */
abstract class ShaderProgramRetained extends NodeComponentRetained {

    // Each element in the array corresponds to a unique renderer if shared
    // context or a unique canvas otherwise.
    protected ShaderProgramData shaderProgramData[];

    // Flag indicating whether an UNSUPPORTED_LANGUAGE_ERROR has
    // already been reported for this shader program object.  It is
    // set in verifyShaderProgram and cleared in setLive or clearLive.
    // TODO KCR: Add code to clear this in setLive or clearLive
    private boolean unsupportedErrorReported = false;

    // Flag indicating whether a LINK_ERROR has occurred for this shader program
    // object.  It is set in updateNative to indicate that the linkShaderProgram
    // operation failed. It is cleared in setLive or clearLive.
    // TODO KCR: Add code to clear this in setLive or clearLive
    private boolean linkErrorOccurred = false;

    // an array of shaders used by this shader program
    protected ShaderRetained[] shaders;

    // an array of vertex attribute names
    protected String[] vertexAttrNames;

    // an array of (uniform) shader attribute names
    protected String[] shaderAttrNames;

// Set of ShaderAttribute objects for which we have already reported an error
private HashSet shaderAttrErrorSet = null;

    // need to synchronize access from multiple rendering threads
    Object resourceLock = new Object();

    // Package-scope default constructor
    ShaderProgramRetained() {
    }

    /**
     * Sets the vertex attribute names array for this ShaderProgram
     * object. Each element in the array specifies the shader
     * attribute name that is bound to the corresponding numbered
     * vertex attribute within a GeometryArray object that uses this
     * shader program. Array element 0 specifies the name of
     * GeometryArray vertex attribute 0, array element 1 specifies the
     * name of GeometryArray vertex attribute 1, and so forth.
     * The array of names may be null or empty (0 length), but the
     * elements of the array must be non-null.
     *
     * @param vertexAttrNames array of vertex attribute names for this
     * shader program. A copy of this array is made.
     */
    void setVertexAttrNames(String[] vertexAttrNames) {
        if (vertexAttrNames == null) {
            this.vertexAttrNames = null;
        }
        else {
		this.vertexAttrNames = vertexAttrNames.clone();
        }
    }


    /**
     * Retrieves the vertex attribute names array from this
     * ShaderProgram object.
     *
     * @return a copy of this ShaderProgram's array of vertex attribute names.
     */
    String[] getVertexAttrNames() {

        if (vertexAttrNames == null) {
	    return null;
	}

	return vertexAttrNames.clone();

    }


    /**
     * Sets the shader attribute names array for this ShaderProgram
     * object. Each element in the array specifies a shader
     * attribute name that may be set via a ShaderAttribute object.
     * Only those attributes whose names that appear in the shader
     * attribute names array can be set for a given shader program.
     * The array of names may be null or empty (0 length), but the
     * elements of the array must be non-null.
     *
     * @param shaderAttrNames array of shader attribute names for this
     * shader program. A copy of this array is made.
     */
    void setShaderAttrNames(String[] shaderAttrNames) {
        if (shaderAttrNames == null) {
            this.shaderAttrNames = null;
        }
        else {
		this.shaderAttrNames = shaderAttrNames.clone();
        }
    }


    /**
     * Retrieves the shader attribute names array from this
     * ShaderProgram object.
     *
     * @return a copy of this ShaderProgram's array of shader attribute names.
     */

    String[] getShaderAttrNames() {

        if (shaderAttrNames == null) {
	    return null;
	}

	return shaderAttrNames.clone();

    }



    /**
     * Copies the specified array of shaders into this shader
     * program. This method makes a shallow copy of the array. The
     * array of shaders may be null or empty (0 length), but the
     * elements of the array must be non-null. The shading
     * language of each shader in the array must match the
     * subclass. Subclasses may impose additional restrictions.
     *
     * @param shaders array of Shader objects to be copied into this
     * ShaderProgram
     *
     * @exception CapabilityNotSetException if appropriate capability is
     * not set and this object is part of live or compiled scene graph
     *
     * @exception IllegalArgumentException if the shading language of
     * any shader in the shaders array doesn't match the type of the
     * subclass.
     */
    void setShaders(Shader[] shaders) {

	if (shaders == null) {
	    this.shaders = null;
	    return;
	}

	this.shaders = new ShaderRetained[shaders.length];

	// Copy vertex and fragment shader
	for (int i = 0; i < shaders.length; i++) {
	    this.shaders[i] = (ShaderRetained)shaders[i].retained;
	}

    }

    /**
     * Retrieves the array of shaders from this shader program. A
     * shallow copy of the array is returned. The return value may
     * be null.
     *
     * @return a copy of this ShaderProgram's array of Shader objects
     *
     */
    Shader[] getShaders() {

	if (shaders == null) {
	    return null;
	} else {
	    Shader shads[] =
		new Shader[shaders.length];
	    for (int i = 0; i < shaders.length; i++) {
		if (shaders[i] != null) {
		    shads[i] = (Shader) shaders[i].source;
		} else {
		    shads[i] = null;
		}
	    }
	    return shads;
	}
    }

    /**
     * Method to create the native shader.
     */
    abstract ShaderError createShader(Context ctx, ShaderRetained shader, ShaderId[] shaderIdArr);

    /**
     * Method to destroy the native shader.
     */
    abstract ShaderError destroyShader(Context ctx, ShaderId shaderId);

    /**
     * Method to compile the native shader.
     */
    abstract ShaderError compileShader(Context ctx, ShaderId shaderId, String source);

    /**
     * Method to create the native shader program.
     */
    abstract ShaderError createShaderProgram(Context ctx, ShaderProgramId[] shaderProgramIdArr);

    /**
     * Method to destroy the native shader program.
     */
    abstract ShaderError destroyShaderProgram(Context ctx, ShaderProgramId shaderProgramId);

    /**
     * Method to link the native shader program.
     */
    abstract ShaderError linkShaderProgram(Context ctx, ShaderProgramId shaderProgramId, ShaderId[] shaderIds);

    /**
     * Method to bind a vertex attribute name to the specified index.
     */
    abstract ShaderError bindVertexAttrName(Context ctx, ShaderProgramId shaderProgramId, String attrName, int attrIndex);

    /**
     * Method to lookup a list of (uniform) shader attribute names and return
     * information about the attributes.
     */
    abstract void lookupShaderAttrNames(Context ctx, ShaderProgramId shaderProgramId, String[] attrNames, AttrNameInfo[] attrNameInfoArr);

    /*
     * Method to lookup a list of vertex attribute names.
     */
    abstract void lookupVertexAttrNames(Context ctx, ShaderProgramId shaderProgramId, String[] attrNames, boolean[] errArr);

    /**
     * Method to use the native shader program.
     */
    abstract ShaderError enableShaderProgram(Context ctx, ShaderProgramId shaderProgramId);

    /**
     * Method to disable the native shader program.
     */
    abstract ShaderError disableShaderProgram(Context ctx);

    // ShaderAttributeValue methods

    abstract ShaderError setUniform1i(Context ctx,
					    ShaderProgramId shaderProgramId,
					    ShaderAttrLoc uniformLocation,
					    int value);

    abstract ShaderError setUniform1f(Context ctx,
					    ShaderProgramId shaderProgramId,
					    ShaderAttrLoc uniformLocation,
					    float value);

    abstract ShaderError setUniform2i(Context ctx,
					    ShaderProgramId shaderProgramId,
					    ShaderAttrLoc uniformLocation,
					    int[] value);

    abstract ShaderError setUniform2f(Context ctx,
					    ShaderProgramId shaderProgramId,
					    ShaderAttrLoc uniformLocation,
					    float[] value);

    abstract ShaderError setUniform3i(Context ctx,
					    ShaderProgramId shaderProgramId,
					    ShaderAttrLoc uniformLocation,
					    int[] value);

    abstract ShaderError setUniform3f(Context ctx,
					    ShaderProgramId shaderProgramId,
					    ShaderAttrLoc uniformLocation,
					    float[] value);

    abstract ShaderError setUniform4i(Context ctx,
					    ShaderProgramId shaderProgramId,
					    ShaderAttrLoc uniformLocation,
					    int[] value);

    abstract ShaderError setUniform4f(Context ctx,
					    ShaderProgramId shaderProgramId,
					    ShaderAttrLoc uniformLocation,
					    float[] value);

    abstract ShaderError setUniformMatrix3f(Context ctx,
					   ShaderProgramId shaderProgramId,
				           ShaderAttrLoc uniformLocation,
					   float[] value);

    abstract ShaderError setUniformMatrix4f(Context ctx,
					   ShaderProgramId shaderProgramId,
			         	   ShaderAttrLoc uniformLocation,
					   float[] value);


    // ShaderAttributeArray methods

    abstract ShaderError setUniform1iArray(Context ctx,
				      ShaderProgramId shaderProgramId,
				      ShaderAttrLoc uniformLocation,
				      int numElements,
				      int[] value);

    abstract ShaderError setUniform1fArray(Context ctx,
				      ShaderProgramId shaderProgramId,
				      ShaderAttrLoc uniformLocation,
				      int numElements,
				      float[] value);

    abstract ShaderError setUniform2iArray(Context ctx,
				      ShaderProgramId shaderProgramId,
				      ShaderAttrLoc uniformLocation,
				      int numElements,
				      int[] value);

    abstract ShaderError setUniform2fArray(Context ctx,
				      ShaderProgramId shaderProgramId,
				      ShaderAttrLoc uniformLocation,
				      int numElements,
				      float[] value);

    abstract ShaderError setUniform3iArray(Context ctx,
				      ShaderProgramId shaderProgramId,
				      ShaderAttrLoc uniformLocation,
				      int numElements,
				      int[] value);

    abstract ShaderError setUniform3fArray(Context ctx,
				      ShaderProgramId shaderProgramId,
				      ShaderAttrLoc uniformLocation,
				      int numElements,
				      float[] value);

    abstract ShaderError setUniform4iArray(Context ctx,
				      ShaderProgramId shaderProgramId,
				      ShaderAttrLoc uniformLocation,
				      int numElements,
				      int[] value);

    abstract ShaderError setUniform4fArray(Context ctx,
				      ShaderProgramId shaderProgramId,
				      ShaderAttrLoc uniformLocation,
				      int numElements,
				      float[] value);

    abstract ShaderError setUniformMatrix3fArray(Context ctx,
					    ShaderProgramId shaderProgramId,
					    ShaderAttrLoc uniformLocation,
					    int numElements,
					    float[] value);

    abstract ShaderError setUniformMatrix4fArray(Context ctx,
					    ShaderProgramId shaderProgramId,
					    ShaderAttrLoc uniformLocation,
					    int numElements,
					    float[] value);


    /**
     * Method to return a flag indicating whether this
     * ShaderProgram is supported on the specified Canvas.
     */
    abstract boolean isSupported(Canvas3D cv);


    @Override
    void setLive(boolean backgroundGroup, int refCount) {

	// System.err.println("ShaderProgramRetained.setLive()");

	if (shaders != null) {
	    for (int i = 0; i < shaders.length; i++){
		shaders[i].setLive(backgroundGroup, refCount);
	    }
	}

	super.doSetLive(backgroundGroup, refCount);
        super.markAsLive();

    }

    @Override
    void clearLive(int refCount) {

        // System.err.println("ShaderProgramRetained.clearLive()");

	super.clearLive(refCount);

	if (shaders != null) {
	    for (int i = 0; i < shaders.length; i++) {
		shaders[i].clearLive(refCount);
	    }
	}
    }

    /**
     * Method to enable the native shader program.
     */
    private ShaderError enableShaderProgram(Canvas3D cv, int cvRdrIndex) {
        assert(cvRdrIndex >= 0);
	synchronized(resourceLock) {
            return enableShaderProgram(cv.ctx,
				       shaderProgramData[cvRdrIndex].getShaderProgramId());
	}

    }

    /**
     * Method to disable the native shader program.
     */
    private ShaderError disableShaderProgram(Canvas3D cv) {
        return disableShaderProgram(cv.ctx);
    }

    /**
     * Initializes a mirror object.
     */
    @Override
    synchronized void initMirrorObject() {

        // Create mirror copy of shaders
        if (this.shaders == null) {
            ((ShaderProgramRetained)mirror).shaders = null;
        }
        else {
            ((ShaderProgramRetained)mirror).shaders = new ShaderRetained[this.shaders.length];
            // Copy vertex and fragment shader
            for (int i = 0; i < this.shaders.length; i++) {
                ((ShaderProgramRetained)mirror).shaders[i] =
                        (ShaderRetained)this.shaders[i].mirror;
            }
        }
        ((ShaderProgramRetained)mirror).shaderProgramData = null;

        // Create mirror copy of vertex attribute names
        if (this.vertexAttrNames == null) {
            ((ShaderProgramRetained)mirror).vertexAttrNames = null;
        }
        else {
		((ShaderProgramRetained)mirror).vertexAttrNames = this.vertexAttrNames.clone();
        }

        // Create mirror copy of shader attribute names
        if (this.shaderAttrNames == null) {
            ((ShaderProgramRetained)mirror).shaderAttrNames = null;
        }
        else {
		((ShaderProgramRetained)mirror).shaderAttrNames = this.shaderAttrNames.clone();
        }

        // Clear shader attribute error set
        ((ShaderProgramRetained)mirror).shaderAttrErrorSet = null;
    }

    /**
     * Update the "component" field of the mirror object with the  given "value"
     */
    @Override
    synchronized void updateMirrorObject(int component, Object value) {

	// ShaderProgram can't be modified once it is live.
	assert(false);
	System.err.println("ShaderProgramRetained : updateMirrorObject NOT IMPLEMENTED YET");
    }

    /**
     * Method to create a ShaderProgramData object for the specified
     * canvas/renderer if it doesn't already exist.
     *
     * Issue 378 : reset the ShaderProgramData object if the context
     * has been recreated for the particular canvas / renderer.
     */
    private void createShaderProgramData(int cvRdrIndex, long ctxTimeStamp) {
        // Create shaderProgram resources if it has not been done.
        synchronized(resourceLock) {
	    if(shaderProgramData == null) {
                // We rely on Java to initial the array elements to null.
                shaderProgramData = new ShaderProgramData[cvRdrIndex+1];
	    }
	    else if(shaderProgramData.length <= cvRdrIndex) {
                // We rely on Java to initial the array elements to null.
		ShaderProgramData[] tempSPData = new ShaderProgramData[cvRdrIndex+1];
                System.arraycopy(shaderProgramData, 0,
                        tempSPData, 0,
                        shaderProgramData.length);
                shaderProgramData = tempSPData;
	    }

            if(shaderProgramData[cvRdrIndex] == null) {
                shaderProgramData[cvRdrIndex] = new ShaderProgramData();
            } else if (shaderProgramData[cvRdrIndex].getCtxTimeStamp() != ctxTimeStamp) {
                // Issue 378 - reset the shader program data for this canvas / renderer
                // if the context has been recreated
                shaderProgramData[cvRdrIndex].reset();
            }
            shaderProgramData[cvRdrIndex].setCtxTimeStamp(ctxTimeStamp);
        }
    }

    /**
     * Method to create the native shader program. We must already have
     * called createShaderProgramData for this cvRdrIndex.
     */
    private ShaderError createShaderProgram(Canvas3D cv, int cvRdrIndex) {
        // Create shaderProgram resources if it has not been done.
        synchronized(resourceLock) {
            assert shaderProgramData[cvRdrIndex].getShaderProgramId() == null;

            ShaderProgramId[] spIdArr = new ShaderProgramId[1];
            ShaderError err = createShaderProgram(cv.ctx, spIdArr);
            if(err != null) {
                return err;
            }
            shaderProgramData[cvRdrIndex].setShaderProgramId(spIdArr[0]);
        }

        return null;
    }

    /**
     * Method to link the native shader program.
     */
    private ShaderError linkShaderProgram(Canvas3D cv, int cvRdrIndex,
					  ShaderRetained[] shaders) {
	synchronized(resourceLock) {
            ShaderId[] shaderIds = new ShaderId[shaders.length];
	    for(int i=0; i cvRdrIndex &&
                   shaderProgramData[cvRdrIndex] != null);

//            // Check whether an entry in the shaderProgramData array has been allocated
//            if (shaderProgramData == null ||
//                    shaderProgramData.length <= cvRdrIndex ||
//                    shaderProgramData[cvRdrIndex] == null) {
//                return;
//            }

	    ShaderProgramId shaderProgramId = shaderProgramData[cvRdrIndex].getShaderProgramId();
            // Nothing to do if the shaderProgramId is null
            if (shaderProgramId == null) {
                return;
            }

            // Destroy the native resource, set the ID to null for this canvas/renderer,
            // and clear the bit in the resourceCreationMask
            // Ignore any possible shader error, because there is no meaningful way to report it
            destroyShaderProgram(cv.ctx, shaderProgramId);
            // Reset this ShaderProgramData object.
	    shaderProgramData[cvRdrIndex].reset();
        }
    }


    /**
     * updateNative is called while traversing the RenderBin to
     * update the shader program state
     */
    void updateNative(Canvas3D cv, boolean enable) {
	// System.err.println("ShaderProgramRetained.updateNative : ");

        final boolean useSharedCtx = cv.useSharedCtx && cv.screen.renderer.sharedCtx != null;
        int cvRdrIndex;
        long ctxTimeStamp;

        if (useSharedCtx) {
            cvRdrIndex = cv.screen.renderer.rendererId;
            ctxTimeStamp = cv.screen.renderer.sharedCtxTimeStamp;
        } else {
            cvRdrIndex = cv.canvasId;
            ctxTimeStamp = cv.ctxTimeStamp;
        }

        // Create ShaderProgramData object for this canvas/renderer if it doesn't already exist
        createShaderProgramData(cvRdrIndex, ctxTimeStamp);

        // Check whether this shader program type is supported for this canvas
        if (!verifyShaderProgramSupported(cv)) {
            return;
        }

        // Just disable shader program and return if enable parameter is set to false
        if (!enable) {
            // Given the current design, disableShaderProgram cannot return a non-null value,
            // so no need to check it
            disableShaderProgram(cv);
            return;
        }

        // Just disable shader program and return if array of shaders is empty,
        // or if a previous attempt to link resulted in an error
        if (shaders == null || shaders.length == 0 || linkErrorOccurred) {
            disableShaderProgram(cv);
            return;
        }

	boolean loadShaderProgram = false; // flag indicating whether to reload all shaderProgram states
        if (getShaderProgramData(cvRdrIndex).getShaderProgramId() == null) {
            loadShaderProgram = true;
        }

	//System.err.println(".... loadShaderProgram = " + loadShaderProgram);
	//System.err.println(".... resourceCreationMask= " + resourceCreationMask);

        ShaderError err = null;
        boolean errorOccurred = false;
	if (loadShaderProgram) {
            if (useSharedCtx) {
	    // TODO : Need to test useSharedCtx case. ** Untested case **
		cv.makeCtxCurrent(cv.screen.renderer.sharedCtx);
            }

            // Create shader resources if not already done
            for(int i=0; i < shaders.length; i++) {
                // Create ShaderProgramData object for this canvas/renderer if it doesn't already exist
                shaders[i].createShaderData(cvRdrIndex, ctxTimeStamp);

                if (shaders[i].compileErrorOccurred) {
                    errorOccurred = true;
                }
                else {
                    err = createShader(cv, cvRdrIndex, shaders[i]);
                    if (err != null) {
                        err.setShaderProgram((ShaderProgram)this.source);
                        err.setShader((Shader)shaders[i].source);
                        err.setCanvas3D(cv);
                        notifyErrorListeners(cv, err);
                        errorOccurred = true;
                    }
                    else {
                        err = compileShader(cv, cvRdrIndex, shaders[i]);
                        if (err != null) {
                            err.setShaderProgram((ShaderProgram)this.source);
                            err.setShader((Shader)shaders[i].source);
                            err.setCanvas3D(cv);
                            notifyErrorListeners(cv, err);
                            destroyShader(cv, cvRdrIndex, shaders[i]);
                            shaders[i].compileErrorOccurred = true;
                            errorOccurred = true;
                        }
                    }
                }
            }

            // Create shader program
            if (!errorOccurred) {
                err = createShaderProgram(cv, cvRdrIndex);
                if (err != null) {
                    err.setShaderProgram((ShaderProgram)this.source);
                    err.setCanvas3D(cv);
                    notifyErrorListeners(cv, err);
                    errorOccurred = true;
                }
            }

            boolean linked = getShaderProgramData(cvRdrIndex).isLinked();
            if (!linked) {
                // Bind vertex attribute names
                if (!errorOccurred) {
                    if (vertexAttrNames != null) {
//                        System.err.println("vertexAttrNames.length = " + vertexAttrNames.length);
                        for (int i = 0; i < vertexAttrNames.length; i++) {
                            err = bindVertexAttrName(cv, cvRdrIndex, vertexAttrNames[i], i);
                            // Report non-fatal error, if one was detected
                            if (err != null) {
                                err.setShaderProgram((ShaderProgram)this.source);
                                err.setCanvas3D(cv);
                                notifyErrorListeners(cv, err);
                            }
                        }
                    }
                }

                // Link shader program
                if (!errorOccurred) {
                    err = linkShaderProgram(cv, cvRdrIndex, shaders);
                    if (err != null) {
                        err.setShaderProgram((ShaderProgram)this.source);
                        err.setCanvas3D(cv);
                        notifyErrorListeners(cv, err);
                        destroyShaderProgram(cv, cvRdrIndex);
                        linkErrorOccurred = true;
                        errorOccurred = true;
                    }
                }

                // lookup vertex attribute names
                if (!errorOccurred) {
                    if (vertexAttrNames != null) {
                        lookupVertexAttrNames(cv, cvRdrIndex, vertexAttrNames);
                    }
                }

                // Lookup shader attribute names
                if (!errorOccurred) {
                    if (shaderAttrNames != null) {
//                        System.err.println("shaderAttrNames.length = " + shaderAttrNames.length);
                        lookupShaderAttrNames(cv, cvRdrIndex, shaderAttrNames);
                    }
                }
            }

            // Restore current context if we changed it to the shareCtx
            if (useSharedCtx) {
                cv.makeCtxCurrent(cv.ctx);
            }

            // If compilation or link error occured, disable shader program and return
            if (errorOccurred) {
                disableShaderProgram(cv);
                return;
            }
        }

        // Now we can enable the shader program
	enableShaderProgram(cv, cvRdrIndex);
    }

    /**
     * Update native value for ShaderAttributeValue class
     */
    ShaderError setUniformAttrValue(Context ctx, ShaderProgramId shaderProgramId,
            ShaderAttrLoc loc, ShaderAttributeValueRetained sav) {

	switch (sav.getClassType()) {
	case ShaderAttributeObjectRetained.TYPE_INTEGER:
	    return setUniform1i(ctx, shaderProgramId, loc,
				((int[])sav.attrWrapper.getRef())[0]);

	case ShaderAttributeObjectRetained.TYPE_FLOAT:
	    return setUniform1f(ctx, shaderProgramId, loc,
				((float[])sav.attrWrapper.getRef())[0]);

	case ShaderAttributeObjectRetained.TYPE_TUPLE2I:
	    return setUniform2i(ctx, shaderProgramId, loc,
				(int[])sav.attrWrapper.getRef());

	case ShaderAttributeObjectRetained.TYPE_TUPLE2F:
	    return setUniform2f(ctx, shaderProgramId, loc,
				(float[])sav.attrWrapper.getRef());

	case ShaderAttributeObjectRetained.TYPE_TUPLE3I:
	    return setUniform3i(ctx, shaderProgramId, loc,
				(int[])sav.attrWrapper.getRef());

	case ShaderAttributeObjectRetained.TYPE_TUPLE3F:
	    return setUniform3f(ctx, shaderProgramId, loc,
				(float[])sav.attrWrapper.getRef());

	case ShaderAttributeObjectRetained.TYPE_TUPLE4I:
	    return setUniform4i(ctx, shaderProgramId, loc,
				(int[])sav.attrWrapper.getRef());

	case ShaderAttributeObjectRetained.TYPE_TUPLE4F:
	    return setUniform4f(ctx, shaderProgramId, loc,
				(float[])sav.attrWrapper.getRef());

	case ShaderAttributeObjectRetained.TYPE_MATRIX3F:
	    return setUniformMatrix3f(ctx, shaderProgramId, loc,
				      (float[])sav.attrWrapper.getRef());

	case ShaderAttributeObjectRetained.TYPE_MATRIX4F:
	    return setUniformMatrix4f(ctx, shaderProgramId, loc,
				      (float[])sav.attrWrapper.getRef());

	default:
	    // Should never get here
	    assert false : "Unrecognized ShaderAttributeValue classType";
	    return null;
	}
    }

     /**
     * Update native value for ShaderAttributeArray class
     */
    ShaderError setUniformAttrArray(Context ctx, ShaderProgramId shaderProgramId,
            ShaderAttrLoc loc, ShaderAttributeArrayRetained saa) {

        switch (saa.getClassType()) {
            case ShaderAttributeObjectRetained.TYPE_INTEGER:
                return  setUniform1iArray(ctx, shaderProgramId, loc, saa.length(),
                        ((int[])saa.attrWrapper.getRef()));

            case ShaderAttributeObjectRetained.TYPE_FLOAT:
                return setUniform1fArray(ctx, shaderProgramId, loc, saa.length(),
                        ((float[])saa.attrWrapper.getRef()));

            case ShaderAttributeObjectRetained.TYPE_TUPLE2I:
                return setUniform2iArray(ctx, shaderProgramId, loc, saa.length(),
                        (int[])saa.attrWrapper.getRef());

            case ShaderAttributeObjectRetained.TYPE_TUPLE2F:
                return setUniform2fArray(ctx, shaderProgramId, loc, saa.length(),
                        (float[])saa.attrWrapper.getRef());

            case ShaderAttributeObjectRetained.TYPE_TUPLE3I:
                return setUniform3iArray(ctx, shaderProgramId, loc, saa.length(),
                        (int[])saa.attrWrapper.getRef());

            case ShaderAttributeObjectRetained.TYPE_TUPLE3F:
                return setUniform3fArray(ctx, shaderProgramId, loc, saa.length(),
                        (float[])saa.attrWrapper.getRef());

            case ShaderAttributeObjectRetained.TYPE_TUPLE4I:
                return setUniform4iArray(ctx, shaderProgramId, loc, saa.length(),
                        (int[])saa.attrWrapper.getRef());

            case ShaderAttributeObjectRetained.TYPE_TUPLE4F:
                return setUniform4fArray(ctx, shaderProgramId, loc, saa.length(),
                        (float[])saa.attrWrapper.getRef());

            case ShaderAttributeObjectRetained.TYPE_MATRIX3F:
                return setUniformMatrix3fArray(ctx, shaderProgramId, loc, saa.length(),
                        (float[])saa.attrWrapper.getRef());

            case ShaderAttributeObjectRetained.TYPE_MATRIX4F:
                return setUniformMatrix4fArray(ctx, shaderProgramId, loc, saa.length(),
                        (float[])saa.attrWrapper.getRef());

            default:
                // Should never get here
                assert false : "Unrecognized ShaderAttributeArray classType";
                return null;
        }

    }


    void setShaderAttributes(Canvas3D cv, ShaderAttributeSetRetained attributeSet) {
        final boolean useSharedCtx = cv.useSharedCtx && cv.screen.renderer.sharedCtx != null;
        final int cvRdrIndex = useSharedCtx ? cv.screen.renderer.rendererId : cv.canvasId;
        ShaderProgramData spData = getShaderProgramData(cvRdrIndex);

        // Just return if shader program wasn't linked successfully
        if (!spData.isLinked()) {
            return;
        }

        ShaderProgramId shaderProgramId = spData.getShaderProgramId();

	Iterator attrs = attributeSet.getAttrs().values().iterator();
        while (attrs.hasNext()) {
            ShaderError err = null;
		ShaderAttributeRetained saRetained = attrs.next();

            // Lookup attribute info for the specified attrName; null means
            // that the name does not appear in the ShaderProgram, so we will
            // report an error.
            AttrNameInfo attrNameInfo = spData.getAttrNameInfo(saRetained.getAttributeName());
            if(attrNameInfo == null) {
//                System.err.println("ShaderProgramRetained : attrLocation (" + saRetained.getAttributeName() + ") is null.");
                String errMsg = "Attribute name not set in ShaderProgram: " + saRetained.getAttributeName(); // TODO: I18N
                err = new ShaderError(ShaderError.SHADER_ATTRIBUTE_NAME_NOT_SET_ERROR, errMsg);
            } else {
                ShaderAttrLoc loc = attrNameInfo.getLocation();
                if (loc != null) {
                    if (saRetained instanceof ShaderAttributeValueRetained) {
                        ShaderAttributeValueRetained savRetained = (ShaderAttributeValueRetained)saRetained;
                        if (attrNameInfo.isArray() ||
                                (savRetained.getClassType() != attrNameInfo.getType())) {
                            String errMsg = "Attribute type mismatch: " + savRetained.getAttributeName(); // TODO: I18N
                            err = new ShaderError(ShaderError.SHADER_ATTRIBUTE_TYPE_ERROR, errMsg);
                        }
                        else {
                            err = setUniformAttrValue(cv.ctx, shaderProgramId, loc, savRetained);
                        }
                    } else if (saRetained instanceof ShaderAttributeArrayRetained) {
                        ShaderAttributeArrayRetained saaRetained = (ShaderAttributeArrayRetained)saRetained;
                        if (!attrNameInfo.isArray() ||
                                (saaRetained.getClassType() != attrNameInfo.getType())) {
                            String errMsg = "Attribute type mismatch: " + saaRetained.getAttributeName(); // TODO: I18N
                            err = new ShaderError(ShaderError.SHADER_ATTRIBUTE_TYPE_ERROR, errMsg);
                        }
                        else {
                            err = setUniformAttrArray(cv.ctx, shaderProgramId, loc, saaRetained);
                        }
                    } else if (saRetained instanceof ShaderAttributeBindingRetained) {
                        assert false;
                        throw new RuntimeException("not implemented");
                    } else {
                        assert false;
                    }
                }
            }

            if (err != null) {
                // Before reporting the ShaderAttribute error, check
                // whether it has already been reported for this ShaderProgram
                if (shaderAttrErrorSet == null) {
				shaderAttrErrorSet = new HashSet();
                }
			if (shaderAttrErrorSet.add((ShaderAttribute) saRetained.source)) {
                    err.setShaderProgram((ShaderProgram)this.source);
                    err.setShaderAttributeSet((ShaderAttributeSet)attributeSet.source);
                    err.setShaderAttribute((ShaderAttribute)saRetained.source);
                    err.setCanvas3D(cv);
                    notifyErrorListeners(cv, err);
                }
            }
        }
    }

    class ShaderProgramData extends Object {

        // issue 378 - time stamp of context creation for this Canvas
        private long ctxTimeStamp;

	// shaderProgramId use by native code.
	private ShaderProgramId shaderProgramId = null;

	// linked flag for native.
	private boolean linked = false;

	// A map of locations for ShaderAttributes.
private HashMap attrNameInfoMap = new HashMap();

	/** ShaderProgramData Constructor */
	ShaderProgramData() {
	}

        void reset() {
            ctxTimeStamp = 0L;
            shaderProgramId = null;
            linked = false;
            attrNameInfoMap.clear();
        }

        long getCtxTimeStamp() {
            return ctxTimeStamp;
        }

        void setCtxTimeStamp(long ctxTimeStamp) {
            this.ctxTimeStamp = ctxTimeStamp;
        }

	void setShaderProgramId(ShaderProgramId shaderProgramId) {
	    this.shaderProgramId = shaderProgramId;
	}

	ShaderProgramId getShaderProgramId() {
	    return this.shaderProgramId;
	}

	void setLinked(boolean linked) {
	    this.linked = linked;
	}

	boolean isLinked() {
	    return linked;
	}

void setAttrNameInfo(String shaderAttribute, AttrNameInfo attrNameInfo) {
	assert (shaderAttribute != null);
	attrNameInfoMap.put(shaderAttribute, attrNameInfo);
}

AttrNameInfo getAttrNameInfo(String shaderAttribute) {
	return attrNameInfoMap.get(shaderAttribute);
}

    }

    // Data associated with an attribute name
    class AttrNameInfo {
        void setLocation(ShaderAttrLoc loc) {
            this.loc = loc;
        }

        ShaderAttrLoc getLocation() {
            return loc;
        }

        void setType(int type) {
            this.type = type;
        }

        int getType() {
            return type;
        }

        boolean isArray() {
            return isArray;
        }

        void setArray(boolean isArray) {
            this.isArray = isArray;
        }

        // Location of attribute name in linked shader program
        private ShaderAttrLoc loc;

        // boolean indicating whether the attribute is an array
        private boolean isArray;

        // type of shader attribute
        private int type;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy