mainstringargs
mainstringargs

Reputation: 14381

Flickering Annotations in WorldWind Java

I'm trying to implement my own clutter filter in NASA Worldwind for Java and its causing a weird problem -- the clutter filter isn't doing much yet, but I will use it to move things around when I get passed the "flickering" issue. Whenever the mouse is moved the GlobeAnnotation renderables are flickering. When I have the clutter filter set to null, the flickering does not seem to occur.

Here is a GIF that shows what I mean: https://media.giphy.com/media/xT9IgFiZwYZ3VJHQU8/giphy.gif

I've cloned the NASA worldwind code from here: https://github.com/NASAWorldWind/WorldWindJava. I've made a couple of changes to make things work for my eventual filter. One note is that I want the GlobeAnnotations to appear as Always On Top of everything else.

How can I make the GlobeAnnotations not fight with each other and flicker, but still appear on top of everything else -- while having the Clutter Filter turned on?

Note that the following code is just an example I put together to show the issue that I'm seeing in my "real" application. I want the GlobeAnnotations to always be on top of everything else -- but not flickering and fighting with each other.

Here is my test driver:

package gov.nasa.worldwindx.examples;

import java.awt.Color;

import gov.nasa.worldwind.geom.LatLon;
import gov.nasa.worldwind.geom.Position;
import gov.nasa.worldwind.layers.AnnotationLayer;
import gov.nasa.worldwind.layers.RenderableLayer;
import gov.nasa.worldwind.render.GlobeAnnotation;
import gov.nasa.worldwind.render.Material;
import gov.nasa.worldwind.render.airspaces.CappedCylinder;

public class FlashyAnnotations extends ApplicationTemplate {
    @SuppressWarnings("unchecked")
    private static class AppFrame extends ApplicationTemplate.AppFrame {

        private AnnotationLayer layer;

        public AppFrame() {

            this.getWwd().getSceneController().setClutterFilter(new SimpleClutterFilter());

            CappedCylinder cappedCyl = new CappedCylinder(LatLon.fromDegrees(27, -100), 3000000);
            cappedCyl.getAttributes().setDrawInterior(true);
            cappedCyl.getAttributes().setInteriorMaterial(Material.GREEN);
            cappedCyl.getAttributes().setInteriorOpacity(.75f);
            cappedCyl.setAltitudes(10, 100000);
            RenderableLayer renderLayer = new RenderableLayer();

            renderLayer.addRenderable(cappedCyl);
            insertBeforeCompass(this.getWwd(), renderLayer);

            // Create example annotations
            this.setupAnnotations();

        }

        private void setupAnnotations() {

            // Create an AnnotationLayer with lots of annotations
            this.layer = new AnnotationLayer();

            GlobeAnnotation ga = new GlobeAnnotation("Annotation", Position.fromDegrees(20, -100.9, 1000));
            ga.getAttributes().setTextColor(Color.white);
            ga.getAttributes().setBackgroundColor(Color.BLACK);
            ga.getAttributes().setOpacity(.75f);
            ga.setAlwaysOnTop(true);
            layer.addAnnotation(ga);

            ga = new GlobeAnnotation("Annotation", Position.fromDegrees(25, -100.9, 1000));
            ga.getAttributes().setTextColor(Color.white);
            ga.getAttributes().setBackgroundColor(Color.BLACK);
            ga.getAttributes().setOpacity(.75f);
            ga.setAlwaysOnTop(true);
            layer.addAnnotation(ga);

            // Add layer to the layer list and update the layer panel
            insertBeforeCompass(this.getWwd(), layer);
        }

    }

    public static void main(String[] args) {
        ApplicationTemplate.start("WorldWind Annotations", AppFrame.class);
    }
}

Here is my (essentially no-op) Clutter Filter:

package gov.nasa.worldwindx.examples;

import java.util.List;

import gov.nasa.worldwind.render.Declutterable;
import gov.nasa.worldwind.render.DrawContext;
import gov.nasa.worldwind.util.ClutterFilter;

public class SimpleClutterFilter implements ClutterFilter{

    @Override
    public void apply(DrawContext dc, List<Declutterable> shapes) {
        for(Declutterable shape: shapes) {
            dc.addOrderedRenderable(shape);
        }

    }

}

And I also had to update the gov.nasa.worldwind.render.BasicAnnotationRenderer to have the OrderedAnnotations it creates implement Declutterable. (The only change to this inner class was adding isEnableDecluttering and getBounds):

public class OrderedAnnotation implements OrderedRenderable, Declutterable
{
protected Annotation annotation;


protected double eyeDistance;
protected Layer layer;

public OrderedAnnotation(Annotation annotation, double eyeDistance)
{
    this.annotation = annotation;
    this.eyeDistance = eyeDistance;
}

public OrderedAnnotation(Annotation annotation, Layer layer, double eyeDistance)
{
    this.annotation = annotation;
    this.eyeDistance = eyeDistance;
    this.layer = layer;
}

public double getDistanceFromEye()
{
    return this.eyeDistance;
}

public void render(DrawContext dc)
{
    OGLStackHandler stackHandler = new OGLStackHandler();
    BasicAnnotationRenderer.this.beginDrawAnnotations(dc, stackHandler);
    try
    {
        this.doRender(dc, this);
        // Draw as many as we can in a batch to save ogl state switching.
        while (dc.peekOrderedRenderables() instanceof OrderedAnnotation)
        {
            OrderedAnnotation oa = (OrderedAnnotation) dc.pollOrderedRenderables();
            this.doRender(dc, oa);
        }
    }
    catch (WWRuntimeException e)
    {
        Logging.logger().log(Level.SEVERE, "generic.ExceptionWhileRenderingAnnotation", e);
    }
    catch (Exception e)
    {
        Logging.logger().log(Level.SEVERE, "generic.ExceptionWhileRenderingAnnotation", e);
    }
    finally
    {
        BasicAnnotationRenderer.this.endDrawAnnotations(dc, stackHandler);
    }
}

public void pick(DrawContext dc, java.awt.Point pickPoint)
{
    OGLStackHandler stackHandler = new OGLStackHandler();
    BasicAnnotationRenderer.this.pickSupport.clearPickList();
    BasicAnnotationRenderer.this.beginDrawAnnotations(dc, stackHandler);
    try
    {
        this.annotation.setPickSupport(BasicAnnotationRenderer.this.pickSupport);
        this.doRender(dc, this);
        // Draw as many as we can in a batch to save ogl state switching.
        while (dc.peekOrderedRenderables() instanceof OrderedAnnotation)
        {
            OrderedAnnotation oa = (OrderedAnnotation) dc.pollOrderedRenderables();
            oa.annotation.setPickSupport(BasicAnnotationRenderer.this.pickSupport);
            this.doRender(dc, oa);
        }
    }
    catch (WWRuntimeException e)
    {
        Logging.logger().log(Level.SEVERE, "generic.ExceptionWhilePickingAnnotation", e);
    }
    catch (Exception e)
    {
        Logging.logger().log(Level.SEVERE, "generic.ExceptionWhilePickingAnnotation", e);
    }
    finally
    {
        BasicAnnotationRenderer.this.endDrawAnnotations(dc, stackHandler);
        BasicAnnotationRenderer.this.pickSupport.resolvePick(dc, pickPoint, this.layer);
        BasicAnnotationRenderer.this.pickSupport.clearPickList(); // to ensure entries can be garbage collected
    }
}

protected void doRender(DrawContext dc, OrderedAnnotation oa)
{
    // Swap the draw context's current layer with that of the ordered annotation
    Layer previousCurrentLayer = dc.getCurrentLayer();
    try
    {
        dc.setCurrentLayer(oa.layer);
        oa.annotation.renderNow(dc);
    }
    finally
    {
        dc.setCurrentLayer(previousCurrentLayer); // restore the original layer
    }
}

@Override
public boolean isEnableDecluttering() {
    return (annotation instanceof GlobeAnnotation);
}

@Override
public Rectangle2D getBounds(DrawContext dc) {
    if(annotation instanceof GlobeAnnotation) {
        return ((GlobeAnnotation) annotation).computeBounds(dc);
    }
    return null;
}

}

Upvotes: 1

Views: 570

Answers (1)

yılmaz
yılmaz

Reputation: 1826

First of all;

Draw order of PointPlacemarks

https://forum.worldwindcentral.com/forum/world-wind-java-forums/development-help/13263-layer-priority-order

In setupAnnotations method, you set alwaysOnTop as true for both GlobeAnnotation objects. This might be the reason.

private void setupAnnotations() {

            // Create an AnnotationLayer with lots of annotations
            this.layer = new AnnotationLayer();

            GlobeAnnotation ga = new GlobeAnnotation("Annotation", Position.fromDegrees(20, -100.9, 1000));
            ga.getAttributes().setTextColor(Color.white);
            ga.getAttributes().setBackgroundColor(Color.BLACK);
            ga.getAttributes().setOpacity(.75f);
            **ga.setAlwaysOnTop(true);**
            layer.addAnnotation(ga);

            ga = new GlobeAnnotation("Annotation", Position.fromDegrees(25, -100.9, 1000));
            ga.getAttributes().setTextColor(Color.white);
            ga.getAttributes().setBackgroundColor(Color.BLACK);
            ga.getAttributes().setOpacity(.75f);
            **ga.setAlwaysOnTop(true);**
            layer.addAnnotation(ga);

            // Add layer to the layer list and update the layer panel
            insertBeforeCompass(this.getWwd(), layer);
        }

Instead of that, putting annotations that you want to be always on top into separate layer and remaining ones into another layer might be solution by using the links above.

Upvotes: 2

Related Questions