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

gov.nasa.worldwind.layers.RenderableLayer Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2012 United States Government as represented by the Administrator of the
 * National Aeronautics and Space Administration.
 * All Rights Reserved.
 */
package gov.nasa.worldwind.layers;

import gov.nasa.worldwind.*;
import gov.nasa.worldwind.avlist.AVList;
import gov.nasa.worldwind.event.*;
import gov.nasa.worldwind.pick.PickSupport;
import gov.nasa.worldwind.render.*;
import gov.nasa.worldwind.util.Logging;

import com.jogamp.opengl.GL2;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * The RenderableLayer class manages a collection of {@link gov.nasa.worldwind.render.Renderable} objects
 * for rendering, picking, and disposal.
 *
 * @author tag
 * @version $Id: RenderableLayer.java 3435 2015-10-13 10:32:43Z dcollins $
 * @see gov.nasa.worldwind.render.Renderable
 */
public class RenderableLayer extends AbstractLayer
{
    protected Collection renderables = new ConcurrentLinkedQueue();
    protected Iterable renderablesOverride;
    protected PickSupport pickSupport = new PickSupport();

    /** Creates a new RenderableLayer with a null delegateOwner */
    public RenderableLayer()
    {
    }

    /**
     * Adds the specified renderable to the end of this layer's internal collection. If this layer's
     * internal collection has been overridden with a call to {@link #setRenderables(Iterable)}, this will throw an
     * exception.
     * 

* If the renderable implements {@link gov.nasa.worldwind.avlist.AVList}, the layer forwards its * property change events to the layer's property change listeners. Any property change listeners the layer attaches * to the renderable are removed in {@link #removeRenderable(gov.nasa.worldwind.render.Renderable)}, * {@link #removeAllRenderables()}, or {@link #dispose()}. * * @param renderable Renderable to add. * * @throws IllegalArgumentException If renderable is null. * @throws IllegalStateException If a custom Iterable has been specified by a call to setRenderables. */ public void addRenderable(Renderable renderable) { if (renderable == null) { String msg = Logging.getMessage("nullValue.RenderableIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } if (this.renderablesOverride != null) { String msg = Logging.getMessage("generic.LayerIsUsingCustomIterable"); Logging.logger().severe(msg); throw new IllegalStateException(msg); } this.renderables.add(renderable); // Attach the layer as a property change listener of the renderable. This forwards property change events from // the renderable to the SceneController. if (renderable instanceof AVList) ((AVList) renderable).addPropertyChangeListener(this); } /** * Inserts the specified renderable at the specified index in this layer's internal * collection. If this layer's internal collection has been overridden with a call to {@link * #setRenderables(Iterable)}, this will throw an exception. *

* If the renderable implements {@link gov.nasa.worldwind.avlist.AVList}, the layer forwards its * property change events to the layer's property change listeners. Any property change listeners the layer attaches * to the renderable are removed in {@link #removeRenderable(gov.nasa.worldwind.render.Renderable)}, * {@link #removeAllRenderables()}, or {@link #dispose()}. * * @param index the index at which to insert the specified renderable. * @param renderable Renderable to insert. * * @throws IllegalArgumentException If renderable is null, if the index is less than zero, * or if the index is greater than the number of renderables in this * layer. * @throws IllegalStateException If a custom Iterable has been specified by a call to setRenderables. */ public void addRenderable(int index, Renderable renderable) { if (renderable == null) { String msg = Logging.getMessage("nullValue.RenderableIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } if (this.renderablesOverride != null) { String msg = Logging.getMessage("generic.LayerIsUsingCustomIterable"); Logging.logger().severe(msg); throw new IllegalStateException(msg); } if (index < 0 || index > this.renderables.size()) { String msg = Logging.getMessage("generic.indexOutOfRange", index); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } // The renderables are contained in a ConcurrentLinkedQueue, which does not support element insertion. Make a // shallow copy of the queue, insert into the copy, then replace the queue contents with the copy. This process // maintains the element order, with the new renderabable inserted in the specified index. ArrayList copy = new ArrayList(this.renderables); copy.add(index, renderable); this.renderables.clear(); this.renderables.addAll(copy); // Attach the layer as a property change listener of the renderable. This forwards property change events from // the renderable to the SceneController. if (renderable instanceof AVList) ((AVList) renderable).addPropertyChangeListener(this); } /** * Adds the contents of the specified renderables to this layer's internal collection. If this layer's * internal collection has been overriden with a call to {@link #setRenderables(Iterable)}, this will throw an * exception. *

* If any of the renderables implement {@link gov.nasa.worldwind.avlist.AVList}, the layer forwards * their property change events to the layer's property change listeners. Any property change listeners the layer * attaches to the renderable are removed in {@link #removeRenderable(gov.nasa.worldwind.render.Renderable)}, * {@link #removeAllRenderables()}, or {@link #dispose()}. * * @param renderables Renderables to add. * * @throws IllegalArgumentException If renderables is null. * @throws IllegalStateException If a custom Iterable has been specified by a call to setRenderables. */ public void addRenderables(Iterable renderables) { if (renderables == null) { String msg = Logging.getMessage("nullValue.IterableIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } if (this.renderablesOverride != null) { String msg = Logging.getMessage("generic.LayerIsUsingCustomIterable"); Logging.logger().severe(msg); throw new IllegalStateException(msg); } for (Renderable renderable : renderables) { // Internal list of renderables does not accept null values. if (renderable != null) this.renderables.add(renderable); // Attach the layer as a property change listener of the renderable. This forwards property change events // from the renderable to the SceneController. if (renderable instanceof AVList) ((AVList) renderable).addPropertyChangeListener(this); } } /** * Removes the specified renderable from this layer's internal collection, if it exists. If this * layer's internal collection has been overridden with a call to {@link #setRenderables(Iterable)}, this will throw * an exception. *

* If the renderable implements {@link gov.nasa.worldwind.avlist.AVList}, this stops forwarding the its * property change events to the layer's property change listeners. Any property change listeners the layer attached * to the renderable in {@link #addRenderable(gov.nasa.worldwind.render.Renderable)} or {@link * #addRenderables(Iterable)} are removed. * * @param renderable Renderable to remove. * * @throws IllegalArgumentException If renderable is null. * @throws IllegalStateException If a custom Iterable has been specified by a call to setRenderables. */ public void removeRenderable(Renderable renderable) { if (renderable == null) { String msg = Logging.getMessage("nullValue.RenderableIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } if (this.renderablesOverride != null) { String msg = Logging.getMessage("generic.LayerIsUsingCustomIterable"); Logging.logger().severe(msg); throw new IllegalStateException(msg); } this.renderables.remove(renderable); // Remove the layer as a property change listener of the renderable. This prevents the renderable from keeping a // dangling reference to the layer. if (renderable instanceof AVList) ((AVList) renderable).removePropertyChangeListener(this); } /** * Clears the contents of this layer's internal Renderable collection. If this layer's internal collection has been * overriden with a call to {@link #setRenderables(Iterable)}, this will throw an exception. *

* If any of the renderables implement {@link gov.nasa.worldwind.avlist.AVList}, this stops forwarding * their property change events to the layer's property change listeners. Any property change listeners the layer * attached to the renderables in {@link #addRenderable(gov.nasa.worldwind.render.Renderable)} or * {@link #addRenderables(Iterable)} are removed. * * @throws IllegalStateException If a custom Iterable has been specified by a call to setRenderables. */ public void removeAllRenderables() { if (this.renderablesOverride != null) { String msg = Logging.getMessage("generic.LayerIsUsingCustomIterable"); Logging.logger().severe(msg); throw new IllegalStateException(msg); } this.clearRenderables(); } protected void clearRenderables() { if (this.renderables != null && this.renderables.size() > 0) { // Remove the layer as property change listener of any renderables. This prevents the renderables from // keeping a dangling references to the layer. for (Renderable renderable : this.renderables) { if (renderable instanceof AVList) ((AVList) renderable).removePropertyChangeListener(this); } this.renderables.clear(); } } public int getNumRenderables() { if (this.renderablesOverride != null) { int size = 0; //noinspection UnusedDeclaration for (Renderable r : this.renderablesOverride) { ++size; } return size; } else { return this.renderables.size(); } } /** * Returns the Iterable of Renderables currently in use by this layer. If the caller has specified a custom Iterable * via {@link #setRenderables(Iterable)}, this will returns a reference to that Iterable. If the caller passed * setRenderables a null parameter, or if setRenderables has not been called, this returns * a view of this layer's internal collection of Renderables. * * @return Iterable of currently active Renderables. */ public Iterable getRenderables() { return this.getActiveRenderables(); } /** * Returns the Iterable of currently active Renderables. If the caller has specified a custom Iterable via {@link * #setRenderables(Iterable)}, this will returns a reference to that Iterable. If the caller passed * setRenderables a null parameter, or if setRenderables has not been called, this returns * a view of this layer's internal collection of Renderables. * * @return Iterable of currently active Renderables. */ protected Iterable getActiveRenderables() { if (this.renderablesOverride != null) { return this.renderablesOverride; } else { // Return an unmodifiable reference to the internal list of renderables. // This prevents callers from changing this list and invalidating any invariants we have established. return java.util.Collections.unmodifiableCollection(this.renderables); } } /** * Overrides the collection of currently active Renderables with the specified renderableIterable. This * layer will maintain a reference to renderableIterable strictly for picking and rendering. This layer * will not modify the reference, or dispose of its contents. This will also clear and dispose of the internal * collection of Renderables, and will prevent any modification to its contents via addRenderable, * addRenderables, removeRenderables, or dispose. *

* Unlike {@link #addRenderable(gov.nasa.worldwind.render.Renderable)} or {@link #addRenderables(Iterable)}, this * does not forward any of the renderable's property change events to the layer's property change listeners. Since * the layer is not in control of the iIterable's contents, attaching property change listeners to the renderables * could cause the them to hold dangling references to the layer. If any of the renderables in the Iterable rely on * forwarding property change events for proper operation - such as {@link gov.nasa.worldwind.render.AbstractBrowserBalloon} * - use {@link #addRenderables(Iterable)} instead. *

* If the specified renderableIterable is null, this layer reverts to maintaining its internal * collection. * * @param renderableIterable Iterable to use instead of this layer's internal collection, or null to use this * layer's internal collection. */ public void setRenderables(Iterable renderableIterable) { this.renderablesOverride = renderableIterable; // Dispose of the internal collection of Renderables. this.disposeRenderables(); // Clear the internal collection of Renderables. this.clearRenderables(); } /** * Opacity is not applied to layers of this type because each renderable typically has its own opacity control. * * @param opacity the current opacity value, which is ignored by this layer. */ @Override public void setOpacity(double opacity) { super.setOpacity(opacity); } /** * Returns the layer's opacity value, which is ignored by this layer because each of its renderables typiically has * its own opacity control. * * @return The layer opacity, a value between 0 and 1. */ @Override public double getOpacity() { return super.getOpacity(); } /** * Disposes the contents of this layer's internal Renderable collection, but does not remove any elements from that * collection. *

* If any of layer's internal Renderables implement {@link gov.nasa.worldwind.avlist.AVList}, this stops forwarding * their property change events to the layer's property change listeners. Any property change listeners the layer * attached to the renderables in {@link #addRenderable(gov.nasa.worldwind.render.Renderable)} or * {@link #addRenderables(Iterable)} are removed. * * @throws IllegalStateException If a custom Iterable has been specified by a call to setRenderables. */ public void dispose() { if (this.renderablesOverride != null) { String msg = Logging.getMessage("generic.LayerIsUsingCustomIterable"); Logging.logger().severe(msg); throw new IllegalStateException(msg); } this.disposeRenderables(); } protected void disposeRenderables() { if (this.renderables != null && this.renderables.size() > 0) { for (Renderable renderable : this.renderables) { try { // Remove the layer as a property change listener of the renderable. This prevents the renderable // from keeping a dangling reference to the layer. if (renderable instanceof AVList) ((AVList) renderable).removePropertyChangeListener(this); if (renderable instanceof Disposable) ((Disposable) renderable).dispose(); } catch (Exception e) { String msg = Logging.getMessage("generic.ExceptionAttemptingToDisposeRenderable"); Logging.logger().severe(msg); // continue to next renderable } } } this.renderables.clear(); } protected void doPreRender(DrawContext dc) { this.doPreRender(dc, this.getActiveRenderables()); } protected void doPick(DrawContext dc, java.awt.Point pickPoint) { this.doPick(dc, this.getActiveRenderables(), pickPoint); } protected void doRender(DrawContext dc) { this.doRender(dc, this.getActiveRenderables()); } protected void doPreRender(DrawContext dc, Iterable renderables) { for (Renderable renderable : renderables) { try { // If the caller has specified their own Iterable, // then we cannot make any guarantees about its contents. if (renderable != null && renderable instanceof PreRenderable) ((PreRenderable) renderable).preRender(dc); } catch (Exception e) { String msg = Logging.getMessage("generic.ExceptionWhilePrerenderingRenderable"); Logging.logger().severe(msg); // continue to next renderable } } } protected void doPick(DrawContext dc, Iterable renderables, java.awt.Point pickPoint) { GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility. this.pickSupport.clearPickList(); this.pickSupport.beginPicking(dc); try { for (Renderable renderable : renderables) { // If the caller has specified their own Iterable, // then we cannot make any guarantees about its contents. if (renderable != null) { // float[] inColor = new float[4]; // gl.glGetFloatv(GL.GL_CURRENT_COLOR, inColor, 0); java.awt.Color color = dc.getUniquePickColor(); gl.glColor3ub((byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue()); try { renderable.render(dc); } catch (Exception e) { String msg = Logging.getMessage("generic.ExceptionWhilePickingRenderable"); Logging.logger().severe(msg); Logging.logger().log(java.util.logging.Level.FINER, msg, e); // show exception for this level continue; // go on to next renderable } // // gl.glColor4fv(inColor, 0); if (renderable instanceof Locatable) { this.pickSupport.addPickableObject(color.getRGB(), renderable, ((Locatable) renderable).getPosition(), false); } else { this.pickSupport.addPickableObject(color.getRGB(), renderable); } } } this.pickSupport.resolvePick(dc, pickPoint, this); } finally { this.pickSupport.endPicking(dc); } } protected void doRender(DrawContext dc, Iterable renderables) { for (Renderable renderable : renderables) { try { // If the caller has specified their own Iterable, // then we cannot make any guarantees about its contents. if (renderable != null) renderable.render(dc); } catch (Exception e) { String msg = Logging.getMessage("generic.ExceptionWhileRenderingRenderable"); Logging.logger().log(java.util.logging.Level.SEVERE, msg, e); // continue to next renderable } } } @Override public String toString() { return Logging.getMessage("layers.RenderableLayer.Name"); } /** * {@inheritDoc} *

* This implementation forwards the message to each Renderable that implements {@link MessageListener}. * * @param message The message that was received. */ @Override public void onMessage(Message message) { for (Renderable renderable : this.renderables) { try { if (renderable instanceof MessageListener) ((MessageListener) renderable).onMessage(message); } catch (Exception e) { String msg = Logging.getMessage("generic.ExceptionInvokingMessageListener"); Logging.logger().log(java.util.logging.Level.SEVERE, msg, e); // continue to next renderable } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy