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

com.metsci.glimpse.worldwind.tile.GlimpseReprojectingSurfaceTile Maven / Gradle / Ivy

There is a newer version: 3.2.0
Show newest version
/*
 * Copyright (c) 2016, Metron, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Metron, Inc. nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL METRON, INC. BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.metsci.glimpse.worldwind.tile;

import static com.metsci.glimpse.util.logging.LoggerUtils.logWarning;

import java.util.List;
import java.util.logging.Logger;

import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLContext;

import com.metsci.glimpse.axis.Axis2D;
import com.metsci.glimpse.canvas.FBOGlimpseCanvas;
import com.metsci.glimpse.layout.GlimpseAxisLayout2D;
import com.metsci.glimpse.layout.GlimpseLayout;
import com.metsci.glimpse.painter.decoration.BackgroundPainter;
import com.metsci.glimpse.painter.texture.ShadedTexturePainter;
import com.metsci.glimpse.support.projection.FlatProjection;
import com.metsci.glimpse.support.projection.GeoReprojection;
import com.metsci.glimpse.support.texture.ExternalTextureProjected2D;
import com.metsci.glimpse.support.texture.TextureProjected2D;
import com.metsci.glimpse.util.geo.projection.GeoProjection;

import gov.nasa.worldwind.geom.LatLon;
import gov.nasa.worldwind.util.OGLStackHandler;

public class GlimpseReprojectingSurfaceTile extends GlimpseResizingSurfaceTile
{
    private static final Logger logger = Logger.getLogger( GlimpseReprojectingSurfaceTile.class.getSimpleName( ) );

    private static double REPROJECT_DISCRETIZE_FRACTION = 0.01;

    protected FBOGlimpseCanvas reprojectCanvas;
    protected ShadedTexturePainter texturePainter;
    protected GlimpseAxisLayout2D reprojectLayout;

    protected TextureProjected2D texture;
    protected GeoReprojection reproject;

    protected GeoProjection projectionTo;

    protected double minX, maxX, minY, maxY;

    public GlimpseReprojectingSurfaceTile( GlimpseLayout layout, Axis2D axes, GeoProjection from, GeoProjection to, int preferredWidth, int preferredHeight, double minLat, double maxLat, double minLon, double maxLon )
    {
        super( layout, axes, from, 8192, 8192, preferredWidth, preferredHeight, minLat, maxLat, minLon, maxLon );

        this.projectionTo = to;
    }

    public GlimpseReprojectingSurfaceTile( GlimpseLayout layout, Axis2D axes, GeoProjection from, GeoProjection to, int preferredWidth, int preferredHeight, List corners )
    {
        super( layout, axes, from, 8192, 8192, preferredWidth, preferredHeight, corners );

        this.projectionTo = to;
    }

    public GlimpseReprojectingSurfaceTile( GlimpseLayout layout, Axis2D axes, GeoProjection from, GeoProjection to, int maxWidth, int maxHeight, int preferredWidth, int preferredHeight, double minLat, double maxLat, double minLon, double maxLon )
    {
        super( layout, axes, from, maxWidth, maxHeight, preferredWidth, preferredHeight, minLat, maxLat, minLon, maxLon );

        this.projectionTo = to;
    }

    public GlimpseReprojectingSurfaceTile( GlimpseLayout layout, Axis2D axes, GeoProjection from, GeoProjection to, int maxWidth, int maxHeight, int preferredWidth, int preferredHeight, List corners )
    {
        super( layout, axes, from, maxWidth, maxHeight, preferredWidth, preferredHeight, corners );

        this.projectionTo = to;
    }

    protected void init( GLContext context )
    {
        this.reprojectCanvas = new FBOGlimpseCanvas( context, width, height );
        this.texturePainter = new ShadedTexturePainter( );

        this.reprojectLayout = new GlimpseAxisLayout2D( new Axis2D( ) );
        this.reprojectLayout.addPainter( new BackgroundPainter( ).setColor( 0f, 0f, 0f, 0f ) );
        this.reprojectLayout.addPainter( this.texturePainter );

        this.reprojectCanvas.addLayout( this.reprojectLayout );

    }

    @Override
    protected int getTextureHandle( )
    {
        return reprojectCanvas.getTextureName( );
    }

    @Override
    protected void resizeCanvas( int width, int height )
    {
        super.resizeCanvas( width, height );
        reprojectCanvas.resize( width, height );
        updateProjection( width, height );
    }

    @Override
    protected void setTextureScale( TextureSurfaceTile tile, float scaleX, float scaleY )
    {
        // do nothing -- keep the TextureSurfaceTile scale at 1.0
        // (GlimpseReprojectingSurfaceTile fills the entire canvas
        //  when it reprojects the offscreen rendered texture)
    }

    protected void updateProjection( int width, int height )
    {
        minX = axes.getMinX( );
        maxX = axes.getMaxX( );
        minY = axes.getMinY( );
        maxY = axes.getMaxY( );

        // the scene was drawn onto the offscreenCanvas using the bounds specified by axes
        // create a projection which allows us to map to axis coordinates given
        // a 0.0 to 1.0 relative coordinate in the offscreenCanvas texture
        FlatProjection flat = new FlatProjection( axes, 0, scaleX, 0, scaleY );

        // build the reprojection (an instance of com.metsci.glimpse.support.projection.Projection)
        reproject = new GeoReprojection( flat, projection, projectionTo, REPROJECT_DISCRETIZE_FRACTION );

        // set the reprojection on the texture
        if ( texture != null )
        {
            texture.setProjection( reproject );
        }

        // set reprojectLayout axes to reflect the lat/lon bounds of the surface tile
        // in the "to" projection (for Worldwind, this projection is usually a
        // PlateCareeProjection)
        setAxes( reprojectLayout.getAxis( ), bounds, projectionTo );
    }

    @Override
    protected void drawOffscreen( GLContext glContext )
    {
        // draw the GlimpseLayout into the offscreenCanvas
        super.drawOffscreen( glContext );

        // get a handle to the texture offscreenCanvas drew into
        if ( texture == null )
        {
            init( glContext );

            int width = offscreenCanvas.getTargetBounds( ).getWidth( );
            int height = offscreenCanvas.getTargetBounds( ).getHeight( );
            int texHandle = offscreenCanvas.getTextureName( );

            texture = new ExternalTextureProjected2D( texHandle, width, height, false )
            {
                @Override
                protected void putVertexCoords( int texIndex, double texFracX, double texFracY, float[] temp )
                {
                    super.putVertexCoords( texIndex, ( float ) texFracX * scaleX, ( float ) texFracY * scaleY, temp );
                }

                @Override
                protected void putVertexTexCoords( int texIndex, double texFracX, double texFracY )
                {
                    super.putVertexTexCoords( texIndex, ( float ) texFracX * scaleX, ( float ) texFracY * scaleY );
                }

                @Override
                protected void prepare_glState( GL gl )
                {
                    gl.glEnable( GL2.GL_TEXTURE_2D );
                    gl.glDisable( GL2.GL_BLEND );
                }
            };

            texturePainter.removeAllDrawableTextures( );
            texturePainter.addDrawableTexture( texture );

            if ( reproject != null )
            {
                texture.setProjection( reproject );
            }
        }

        // rebuild the projection if the axes changed
        if ( didAxesChange( axes ) )
        {
            updateProjection( currentWidth, currentHeight );
        }

        OGLStackHandler stack = new OGLStackHandler( );
        GL2 gl = glContext.getGL( ).getGL2( );

        stack.pushAttrib( gl, GL2.GL_ALL_ATTRIB_BITS );
        stack.pushClientAttrib( gl, ( int ) GL2.GL_ALL_CLIENT_ATTRIB_BITS );
        stack.pushTexture( gl );
        gl.glLoadIdentity( );
        stack.pushModelview( gl );
        stack.pushProjection( gl );

        GLContext c = offscreenCanvas.getGLContext( );

        if ( c != null )
        {
            c.makeCurrent( );
            try
            {
                reprojectCanvas.paint( );
            }
            catch ( Exception e )
            {
                logWarning( logger, "Trouble drawing to offscreen buffer", e );
            }
            finally
            {
                glContext.makeCurrent( );
                stack.pop( gl );
            }
        }
    }

    protected boolean didAxesChange( Axis2D axis )
    {
        return ! ( axis.getMinX( ) == minX && axis.getMaxX( ) == maxX && axis.getMinY( ) == minY && axis.getMaxY( ) == maxY );
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy