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

org.scijava.java3d.BackgroundRetained Maven / Gradle / Ivy

/*
 * Copyright 1997-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 org.scijava.java3d;

import java.util.ArrayList;

import org.scijava.vecmath.Color3f;


/**
 * The Background leaf node defines either a solid background color
 * or a background image that is used to fill the window at the
 * beginning of each new frame.  It also specifies an application
 * region in which this background is active.
 */
class BackgroundRetained extends LeafRetained {

    static final int COLOR_CHANGED		= 0x00001;
    static final int IMAGE_CHANGED		= 0x00002;
    static final int GEOMETRY_CHANGED		= 0x00004;
    static final int BOUNDS_CHANGED		= 0x00008;
    static final int BOUNDINGLEAF_CHANGED	= 0x00010;
    static final int IMAGE_SCALE_CHANGED        = 0x00020;
    // Background color or image.  If non-null, the image overrides the
    // color.
    Color3f		color = new Color3f(0.0f, 0.0f, 0.0f);
    ImageComponent2DRetained	image = null;
    Texture2DRetained           texture = null;

    // the image scale mode if image is used.
    int imageScaleMode = Background.SCALE_NONE;

    /**
     * The Boundary object defining the lights's application region.
     */
    Bounds applicationRegion = null;

    /**
     * The bounding leaf reference
     */
    BoundingLeafRetained boundingLeaf = null;

    /**
     * Background geometry branch group
     */
    BranchGroup geometryBranch = null;

    /**
     * The transformed value of the applicationRegion.
     */
    Bounds transformedRegion = null;

    /**
     * The state structure used for Background Geometry
     */
    SetLiveState setLiveState = null;

    /**
     * The locale of this Background node since we don't have mirror object
     *  when clearLive is called
     * locale is set to null, we still want locale to have a
     * non-null value, since renderingEnv structure may be using the
     * locale
     */
    Locale cachedLocale = null;

    // This is true when this background is referenced in an immediate mode context
    boolean inImmCtx = false;

// list of light nodes for background geometry
ArrayList lights = new ArrayList();

// list of fog nodes for background geometry
ArrayList fogs = new ArrayList();

// a list of background geometry atoms
ArrayList bgGeometryAtomList = new ArrayList();

// false is background geometry atoms list has changed
boolean bgGeometryAtomListDirty = true;

// an array of background geometry atoms
GeometryAtom[] bgGeometryAtoms = null;

    // Target threads to be notified when light changes
    // Note, the rendering env structure only get notified
    // when there is a bounds related change
    final static int targetThreads = J3dThread.UPDATE_RENDERING_ENVIRONMENT |
                                     J3dThread.UPDATE_RENDER;

    // Is true, if the background is viewScoped
    boolean isViewScoped = false;

    BackgroundRetained () {
        this.nodeType = NodeRetained.BACKGROUND;
	localBounds = new BoundingBox((Bounds)null);
    }

    /**
     * Initializes the background color to the specified color.
     * This color is used
     * if the image is null.
     * @param color the new background color
     */
    final void initColor(Color3f color) {
	this.color.set(color);
    }


    /**
     * Sets the background color to the specified color.  This color is used
     * if the image is null.
     * @param color the new background color
     */
    final void setColor(Color3f color) {
	initColor(color);
	if (source.isLive()) {
	    sendMessage(COLOR_CHANGED, new Color3f(color));
	}
    }

    /**
     * Initializes the background color to the specified color.
     * This color is used
     * if the image is null.
     * @param r the red component of the background color
     * @param g the green component of the background color
     * @param b the blue component of the background color
     */
    final void initColor(float r, float g, float b) {
	this.color.x = r;
	this.color.y = g;
	this.color.z = b;
    }



    /**
     * Sets the background color to the specified color.  This color is used
     * if the image is null.
     * @param r the red component of the background color
     * @param g the green component of the background color
     * @param b the blue component of the background color
     */
    final void setColor(float r, float g, float b) {
	setColor(new Color3f(r, g, b));
    }


    /**
     * Retrieves the background color.
     * @param color the vector that will receive the current background color
     */
    final void getColor(Color3f color) {
	color.set(this.color);
    }

    /**
     * Initialize the image scale mode to the specified mode
     * @imageScaleMode the image scale mode to the used
     */
    final void initImageScaleMode(int imageScaleMode){
	this.imageScaleMode = imageScaleMode;
    }

    /**
     * Sets the image scale mode for this Background node.
     * @param imageScaleMode the image scale mode
     */
    final void setImageScaleMode(int imageScaleMode){
	initImageScaleMode(imageScaleMode);
	if(source.isLive()){
	    sendMessage(IMAGE_SCALE_CHANGED, new Integer(imageScaleMode));
	}
    }

    /**
     * gets the image scale mode for this Background node.
     */
    final int getImageScaleMode(){
	return imageScaleMode;
    }

    /**
     * Initializes the background image to the specified image.
     * @param image new ImageCompoent2D object used as the background image
     */
    final void initImage(ImageComponent2D img) {
        int texFormat;

        if (img == null) {
            image = null;
            texture = null;
            return;
        }

        if (img.retained != image ) {
            image = (ImageComponent2DRetained) img.retained;
            image.setEnforceNonPowerOfTwoSupport(true);
            switch(image.getNumberOfComponents()) {
                case 1:
                    texFormat = Texture.INTENSITY;
                    break;
                case 2:
                    texFormat = Texture.LUMINANCE_ALPHA;
                    break;
                case 3:
                    texFormat = Texture.RGB;
                    break;
                case 4:
                    texFormat = Texture.RGBA;
                    break;
                default:
                    assert false;
                    return;
            }

            Texture2D tex2D = new Texture2D(Texture.BASE_LEVEL, texFormat,
                    img.getWidth(), img.getHeight());
            texture = (Texture2DRetained) tex2D.retained;
            // Background is special case of Raster.
            texture.setUseAsRaster(true);
            // Fix to issue 373 : ImageComponent.set(BufferedImage) ignored when used by Background
            image.addUser(texture);
            texture.initImage(0,img);
        }
    }

    /**
     * Sets the background image to the specified image.
     * @param image new ImageCompoent3D object used as the background image
     */
    final void setImage(ImageComponent2D img) {
	if (source.isLive()) {
	    if (texture != null) {
		texture.clearLive(refCount);
	    }
	}
	initImage(img);
        if (source.isLive()) {
            if (texture != null) {
                texture.setLive(inBackgroundGroup, refCount);
            }

            sendMessage(IMAGE_CHANGED,
                    (texture != null ? texture.mirror : null));

        }
    }

    /**
     * Retrieves the background image.
     * @return the current background image
     */
    final ImageComponent2D getImage() {
        return (image == null ? null :
		(ImageComponent2D)image.source);
    }

    /**
     * Initializes the background geometry branch group to the specified branch.
     * @param branch new branch group object used for background geometry
     */
    final void initGeometry(BranchGroup branch) {
        geometryBranch = branch;
    }


    /**
     * Sets the background geometry branch group to the specified branch.
     * @param branch new branch group object used for background geometry
     */
    final void setGeometry(BranchGroup branch) {
        int numMessages = 0;
        int i;

        if (source.isLive()) {
	    J3dMessage m[];
            if (geometryBranch != null)
                numMessages+=2; // REMOVE_NODES, ORDERED_GROUP_REMOVED
            if (branch != null)
                numMessages+=2; // INSERT_NODES, ORDERED_GROUP_INSERTED
            m = new J3dMessage[numMessages];
            for (i=0; i();
	setLiveState.branchGroupPaths.add(new BranchGroupRetained[0]);

	setLiveState.orderedPaths = new ArrayList(1);
	setLiveState.orderedPaths.add(new OrderedPath());

	setLiveState.switchStates = new ArrayList(1);
	setLiveState.switchStates.add(new SwitchState(false));

	branch.setLive(setLiveState);


    }

    void clearGeometryBranch(BranchGroupRetained branch) {
        setLiveState.reset(locale);
        setLiveState.inBackgroundGroup = true;
        setLiveState.geometryBackground = this;
        branch.clearLive(setLiveState);
        branch.setParent(null);
        branch.setLocale(null);

    }

    /**
     * This setLive routine first calls the superclass's method, then
     * it adds itself to the list of lights
     */
    @Override
    void setLive(SetLiveState s) {
	super.doSetLive(s);

        if (inImmCtx) {
           throw new IllegalSharingException(
				J3dI18N.getString("BackgroundRetained1"));
        }
        if (inBackgroundGroup) {
            throw new
              IllegalSceneGraphException(J3dI18N.getString("BackgroundRetained5"));
        }

	if (inSharedGroup) {
	    throw new
		IllegalSharingException(J3dI18N.getString("BackgroundRetained6"));
	}


        if (geometryBranch != null) {
            BranchGroupRetained branch =
                (BranchGroupRetained)geometryBranch.retained;
            if (branch.inBackgroundGroup == true)
               throw new IllegalSharingException(
				J3dI18N.getString("BackgroundRetained0"));

            if (branch.parent != null)
               throw new IllegalSharingException(
				J3dI18N.getString("BackgroundRetained3"));

            if (branch.locale != null)
               throw new IllegalSharingException(
				J3dI18N.getString("BackgroundRetained4"));

	    if (setLiveState == null) {
	   	setLiveState = new SetLiveState(universe);
		setLiveState.universe = universe;
	    }
            setGeometryBranch((BranchGroupRetained)geometryBranch.retained);
	    // add background geometry nodes to setLiveState's nodeList
            s.nodeList.addAll(setLiveState.nodeList);
	    s.notifyThreads |= setLiveState.notifyThreads;
	    s.ogList.addAll(setLiveState.ogList);
	    s.ogChildIdList.addAll(setLiveState.ogChildIdList);
	    s.ogOrderedIdList.addAll(setLiveState.ogOrderedIdList);
	    // Free up memory.
            setLiveState.reset(null);
        }

	if ((s.viewScopedNodeList != null) && (s.viewLists != null)) {
	    s.viewScopedNodeList.add(this);
	    s.scopedNodesViewList.add(s.viewLists.get(0));
	} else {
	    s.nodeList.add(this);
	}
	// System.err.println("bkg.setlive nodeList " + s.nodeList);

        // process switch leaf
        if (s.switchTargets != null && s.switchTargets[0] != null) {
            s.switchTargets[0].addNode(this, Targets.ENV_TARGETS);
        }
	switchState = s.switchStates.get(0);

	// Initialize some mirror values
	if (boundingLeaf != null) {
	    transformedRegion = boundingLeaf.mirrorBoundingLeaf.transformedRegion;
	}
	else { // Evaluate applicationRegion if not null
	    if (applicationRegion != null) {
		transformedRegion = (Bounds)applicationRegion.clone();
		transformedRegion.transform(
					applicationRegion,
					getLastLocalToVworld());
	    }
	    else {
		transformedRegion = null;
	    }

	}
	cachedLocale = s.locale;

        // add this node to the transform target
        if (s.transformTargets != null && s.transformTargets[0] != null) {
            s.transformTargets[0].addNode(this, Targets.ENV_TARGETS);
	    s.notifyThreads |= J3dThread.UPDATE_TRANSFORM;
        }

	s.notifyThreads |= J3dThread.UPDATE_RENDERING_ENVIRONMENT|
	    J3dThread.UPDATE_RENDER;

	if (texture != null) {
	    texture.setLive(inBackgroundGroup, refCount);
	}
	super.markAsLive();

    }

    /**
     * This clearLive routine first calls the superclass's method, then
     * it removes itself to the list of lights
     */
    @Override
    void clearLive(SetLiveState s) {
        super.clearLive(s);
	if ((s.viewScopedNodeList != null) && (s.viewLists != null)) {
	    s.viewScopedNodeList.add(this);
	    s.scopedNodesViewList.add(s.viewLists.get(0));
	} else {
	    s.nodeList.add(this);
	}
        if (s.transformTargets != null && s.transformTargets[0] != null) {
            s.transformTargets[0].addNode(this, Targets.ENV_TARGETS);
	    s.notifyThreads |= J3dThread.UPDATE_TRANSFORM;
        }

        if (s.switchTargets != null && s.switchTargets[0] != null) {
            s.switchTargets[0].addNode(this, Targets.ENV_TARGETS);
        }

        if (geometryBranch != null) {
            BranchGroupRetained branch = (BranchGroupRetained)geometryBranch.retained;
            clearGeometryBranch(branch);
            // add background geometry nodes to setLiveState's nodeList
            s.nodeList.addAll(setLiveState.nodeList);
            s.ogList.addAll(setLiveState.ogList);
            s.ogChildIdList.addAll(setLiveState.ogChildIdList);
	    s.notifyThreads |= setLiveState.notifyThreads;
	    // Free up memory.
	    setLiveState.reset(null);
            lights.clear();
            fogs.clear();
        }

	if (texture != null) {
	    texture.clearLive(refCount);
	}

	s.notifyThreads |= J3dThread.UPDATE_RENDERING_ENVIRONMENT|
	    J3dThread.UPDATE_RENDER;
    }

    // The update Object function.
    synchronized void updateImmediateMirrorObject(Object[] objs) {
	int component = ((Integer)objs[1]).intValue();
	// If initialization

	// Bounds message only sent when boundingleaf is null
	if  ((component & BOUNDS_CHANGED) != 0) {
	    if (objs[2] != null) {
		transformedRegion = ((Bounds) objs[2]).copy(transformedRegion);
		transformedRegion.transform(
			(Bounds) objs[2], getCurrentLocalToVworld());
	    }
	    else {
		transformedRegion = null;
	    }
	}
	else if  ((component & BOUNDINGLEAF_CHANGED) != 0) {
	    if (objs[2] != null) {
		transformedRegion = ((BoundingLeafRetained)objs[2]).transformedRegion;
	    }
	    else { // Evaluate applicationRegion if not null
		Bounds appRegion = (Bounds)objs[3];
		if (appRegion != null) {
		    transformedRegion = appRegion.copy(transformedRegion);
		    transformedRegion.transform(
			appRegion, getCurrentLocalToVworld());
		}
		else {
		    transformedRegion = null;
		}

	    }
	}

    }

    /** Note: This routine will only be called
     * to  update the object's
     * transformed region
     */
    @Override
    void updateBoundingLeaf() {
        if (boundingLeaf != null &&
		boundingLeaf.mirrorBoundingLeaf.switchState.currentSwitchOn) {
            transformedRegion =
                        boundingLeaf.mirrorBoundingLeaf.transformedRegion;
        } else { // Evaluate applicationRegion if not null
            if (applicationRegion != null) {
		transformedRegion = applicationRegion.copy(transformedRegion);
                transformedRegion.transform(
			applicationRegion, getCurrentLocalToVworld());
            } else {
                transformedRegion = null;
            }
        }
    }

    void updateImmediateTransformChange() {
        // If bounding leaf is null, tranform the bounds object
        if (boundingLeaf == null) {
            if (applicationRegion != null) {
		transformedRegion = applicationRegion.copy(transformedRegion);
                transformedRegion.transform(
			applicationRegion, getCurrentLocalToVworld());
            }
        }
    }


    final void sendMessage(int attrMask, Object attr) {
	J3dMessage createMessage = new J3dMessage();
	createMessage.threads = targetThreads;
	createMessage.universe = universe;
	createMessage.type = J3dMessage.BACKGROUND_CHANGED;
	createMessage.args[0] = this;
	createMessage.args[1]= new Integer(attrMask);
	createMessage.args[2] = attr;
	VirtualUniverse.mc.processMessage(createMessage);
    }

void addBgGeometryAtomList(GeometryAtom geomAtom) {
	bgGeometryAtomList.add(geomAtom);
	bgGeometryAtomListDirty = true;
}

void removeBgGeometryAtomList(GeometryAtom geomAtom) {
	bgGeometryAtomList.remove(geomAtom);
	bgGeometryAtomListDirty = true;
}

GeometryAtom[] getBackgroundGeometryAtoms() {
	if (bgGeometryAtomListDirty) {
		int nAtoms = bgGeometryAtomList.size();
		if (nAtoms == 0) {
			bgGeometryAtoms = null;
		}
		else {
			bgGeometryAtoms = bgGeometryAtomList.toArray(new GeometryAtom[nAtoms]);
			bgGeometryAtomListDirty = false;
		}
	}
	return bgGeometryAtoms;
}

    @Override
    void mergeTransform(TransformGroupRetained xform) {
	super.mergeTransform(xform);
        if (applicationRegion != null) {
            applicationRegion.transform(xform.transform);
        }
    }

    // notifies the Background object that the image data in a referenced
    // ImageComponent object is changed.
    // Currently we are not making use of this information.

    void notifyImageComponentImageChanged(ImageComponentRetained image,
                                        ImageComponentUpdateInfo value) {
    }
    @Override
    void getMirrorObjects(ArrayList leafList, HashKey key) {
	leafList.add(this); // No Mirror in this case
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy