diff --git a/gluegen-rt-natives-linux-amd64.jar b/gluegen-rt-natives-linux-amd64.jar index 826d6d6fa9..625b8479ed 100644 Binary files a/gluegen-rt-natives-linux-amd64.jar and b/gluegen-rt-natives-linux-amd64.jar differ diff --git a/gluegen-rt-natives-macosx-universal.jar b/gluegen-rt-natives-macosx-universal.jar index 79bd94ee67..0e791ff2ce 100644 Binary files a/gluegen-rt-natives-macosx-universal.jar and b/gluegen-rt-natives-macosx-universal.jar differ diff --git a/gluegen-rt-natives-windows-amd64.jar b/gluegen-rt-natives-windows-amd64.jar index 2d1fe14112..2ae552be1e 100644 Binary files a/gluegen-rt-natives-windows-amd64.jar and b/gluegen-rt-natives-windows-amd64.jar differ diff --git a/gluegen-rt.jar b/gluegen-rt.jar index aef08ef85c..51cd1a8826 100644 Binary files a/gluegen-rt.jar and b/gluegen-rt.jar differ diff --git a/gluegen.jar b/gluegen.jar new file mode 100644 index 0000000000..3c1d257c7e Binary files /dev/null and b/gluegen.jar differ diff --git a/jogl-all-natives-linux-amd64.jar b/jogl-all-natives-linux-amd64.jar index 55953e236b..fa74de8f96 100644 Binary files a/jogl-all-natives-linux-amd64.jar and b/jogl-all-natives-linux-amd64.jar differ diff --git a/jogl-all-natives-macosx-universal.jar b/jogl-all-natives-macosx-universal.jar index 124ef6d7e5..23d78f5370 100644 Binary files a/jogl-all-natives-macosx-universal.jar and b/jogl-all-natives-macosx-universal.jar differ diff --git a/jogl-all-natives-windows-amd64.jar b/jogl-all-natives-windows-amd64.jar index 4384250365..7b8dcff736 100644 Binary files a/jogl-all-natives-windows-amd64.jar and b/jogl-all-natives-windows-amd64.jar differ diff --git a/jogl-all.jar b/jogl-all.jar index dbbde557f5..ab93476acc 100644 Binary files a/jogl-all.jar and b/jogl-all.jar differ diff --git a/lib-external/jogl-gluegen/build-gluegen.sh b/lib-external/jogl-gluegen/build-gluegen.sh deleted file mode 100755 index a65db0ef30..0000000000 --- a/lib-external/jogl-gluegen/build-gluegen.sh +++ /dev/null @@ -1,6 +0,0 @@ -set -x - -cd gluegen/make -ant -Dtarget.sourcelevel=1.8 -Dtarget.targetlevel=1.8 -Dtarget.rt.jar=dummy.jar - - diff --git a/lib-external/jogl-gluegen/build-jogl.sh b/lib-external/jogl-gluegen/build-jogl.sh deleted file mode 100755 index 75dc73ee5e..0000000000 --- a/lib-external/jogl-gluegen/build-jogl.sh +++ /dev/null @@ -1,6 +0,0 @@ -set -x - -cd jogl/make -ant -Dtarget.sourcelevel=1.8 -Dtarget.targetlevel=1.8 -Dtarget.rt.jar=dummy.jar - - diff --git a/lib-external/jogl-gluegen/clean-gluegen.sh b/lib-external/jogl-gluegen/clean-gluegen.sh deleted file mode 100755 index d54a160109..0000000000 --- a/lib-external/jogl-gluegen/clean-gluegen.sh +++ /dev/null @@ -1,7 +0,0 @@ -set -x - -cd gluegen/make -ant clean -Dtarget.sourcelevel=1.8 -Dtarget.targetlevel=1.8 -Dtarget.rt.jar=dummy.jar - - - diff --git a/lib-external/jogl-gluegen/clean-jogl.sh b/lib-external/jogl-gluegen/clean-jogl.sh deleted file mode 100755 index fef80d1d48..0000000000 --- a/lib-external/jogl-gluegen/clean-jogl.sh +++ /dev/null @@ -1,7 +0,0 @@ -set -x - -cd jogl/make -ant clean -Dtarget.sourcelevel=1.8 -Dtarget.targetlevel=1.8 -Dtarget.rt.jar=dummy.jar - - - diff --git a/lib-external/jogl-gluegen/get-jogl.sh b/lib-external/jogl-gluegen/get-jogl.sh new file mode 100755 index 0000000000..ce4b7a6eb7 --- /dev/null +++ b/lib-external/jogl-gluegen/get-jogl.sh @@ -0,0 +1,13 @@ +set -x + +curl -O https://jogamp.org/deployment/v2.5.0-rc-20230523/jar/gluegen.jar +curl -O https://jogamp.org/deployment/v2.5.0-rc-20230523/jar/gluegen-rt.jar +curl -O https://jogamp.org/deployment/v2.5.0-rc-20230523/jar/gluegen-rt-natives-linux-amd64.jar +curl -O https://jogamp.org/deployment/v2.5.0-rc-20230523/jar/gluegen-rt-natives-macosx-universal.jar +curl -O https://jogamp.org/deployment/v2.5.0-rc-20230523/jar/gluegen-rt-natives-windows-amd64.jar +curl -O https://jogamp.org/deployment/v2.5.0-rc-20230523/jar/jogl-all.jar +curl -O https://jogamp.org/deployment/v2.5.0-rc-20230523/jar/jogl-all-natives-linux-amd64.jar +curl -O https://jogamp.org/deployment/v2.5.0-rc-20230523/jar/jogl-all-natives-macosx-universal.jar +curl -O https://jogamp.org/deployment/v2.5.0-rc-20230523/jar/jogl-all-natives-windows-amd64.jar + + diff --git a/lib-external/jogl-gluegen/get-source.sh b/lib-external/jogl-gluegen/get-source.sh deleted file mode 100755 index a4513d20ab..0000000000 --- a/lib-external/jogl-gluegen/get-source.sh +++ /dev/null @@ -1,12 +0,0 @@ -set -x - -git clone --recurse-submodules git://jogamp.org/srv/scm/gluegen.git gluegen -git clone --recurse-submodules git://jogamp.org/srv/scm/jogl.git jogl - -cd gluegen -git checkout java11 -cd ../jogl -git checkout java11 - - - diff --git a/lib-external/jogl-gluegen/linux-copy-jogl.sh b/lib-external/jogl-gluegen/linux-copy-jogl.sh deleted file mode 100755 index 0930845c10..0000000000 --- a/lib-external/jogl-gluegen/linux-copy-jogl.sh +++ /dev/null @@ -1,11 +0,0 @@ -set -x - -cp gluegen/build/gluegen-rt-natives-linux-amd64.jar ../.. -cp gluegen/build/gluegen-rt.jar ../.. -cp gluegen/LICENSE.txt ../../gluegen.LICENSE.txt - -cp jogl/build/jar/jogl-all.jar ../.. -cp jogl/build/jar/jogl-all-natives-linux-amd64.jar ../.. -cp jogl/LICENSE.txt ../../jogl.LICENSE.txt - - diff --git a/lib-external/jogl-gluegen/osx-copy-jogl.sh b/lib-external/jogl-gluegen/osx-copy-jogl.sh deleted file mode 100755 index 6c9461370b..0000000000 --- a/lib-external/jogl-gluegen/osx-copy-jogl.sh +++ /dev/null @@ -1,9 +0,0 @@ -set -x - -cp gluegen/build/gluegen-rt-natives-macosx-universal.jar ../.. -# The other artifacts are copied by the Linux build. -# cp gluegen/build/gluegen-rt.jar ../.. -# cp jogl/build/jar/jogl-all.jar ../.. -cp jogl/build/jar/jogl-all-natives-macosx-universal.jar ../.. - - diff --git a/lib-external/jogl-gluegen/win-build-gluegen.cmd b/lib-external/jogl-gluegen/win-build-gluegen.cmd deleted file mode 100644 index 9ad7c66323..0000000000 --- a/lib-external/jogl-gluegen/win-build-gluegen.cmd +++ /dev/null @@ -1,5 +0,0 @@ -REM Run in a MinGW-W64 Window - -cd gluegen/make -ant -Dtarget.sourcelevel=1.8 -Dtarget.targetlevel=1.8 -Dtarget.rt.jar=dummy.jar - diff --git a/lib-external/jogl-gluegen/win-build-jogl.cmd b/lib-external/jogl-gluegen/win-build-jogl.cmd deleted file mode 100644 index 4afddef19a..0000000000 --- a/lib-external/jogl-gluegen/win-build-jogl.cmd +++ /dev/null @@ -1,6 +0,0 @@ -REM Run in a MinGW-W64 Window - -cd jogl\make -ant -Dtarget.sourcelevel=1.8 -Dtarget.targetlevel=1.8 -Dtarget.rt.jar=dummy.jar - - diff --git a/lib-external/jogl-gluegen/win-clean-gluegen.cmd b/lib-external/jogl-gluegen/win-clean-gluegen.cmd deleted file mode 100644 index 2d877a560e..0000000000 --- a/lib-external/jogl-gluegen/win-clean-gluegen.cmd +++ /dev/null @@ -1,5 +0,0 @@ -REM Run in a MinGW-W64 Window - -cd gluegen/make -ant clean -Dtarget.sourcelevel=1.8 -Dtarget.targetlevel=1.8 -Dtarget.rt.jar=dummy.jar - diff --git a/lib-external/jogl-gluegen/win-clean-jogl.cmd b/lib-external/jogl-gluegen/win-clean-jogl.cmd deleted file mode 100644 index 42d53bfdba..0000000000 --- a/lib-external/jogl-gluegen/win-clean-jogl.cmd +++ /dev/null @@ -1,6 +0,0 @@ -REM Run in a MinGW-W64 Window - -cd jogl\make -ant clean -Dtarget.sourcelevel=1.8 -Dtarget.targetlevel=1.8 -Dtarget.rt.jar=dummy.jar -cd ..\.. - diff --git a/lib-external/jogl-gluegen/win-copy-jogl.cmd b/lib-external/jogl-gluegen/win-copy-jogl.cmd deleted file mode 100644 index 91a0bff02e..0000000000 --- a/lib-external/jogl-gluegen/win-copy-jogl.cmd +++ /dev/null @@ -1,11 +0,0 @@ -REM Run in a MinGW-W64 Window - -copy gluegen\build\gluegen-rt-natives-windows-amd64.jar ..\.. -REM Other artifacts are copied by the Linux build. -REM copy gluegen\build\gluegen-rt.jar ..\.. -REM copy jogl\build\jar\jogl-all.jar ..\.. -copy jogl\build\jar\jogl-all-natives-windows-amd64.jar ..\.. - - - - diff --git a/nbproject/build-impl.xml b/nbproject/build-impl.xml index 506f468c86..c02064ba01 100644 --- a/nbproject/build-impl.xml +++ b/nbproject/build-impl.xml @@ -119,43 +119,7 @@ is divided into following sections: - - - - - - - - - - - - - - - - - - - - - - - - - - Must set platform.home - Must set platform.bootcp - Must set platform.java - Must set platform.javac - - The J2SE Platform is not correctly set up. - Your active platform is: ${platform.active}, but the corresponding property "platforms.${platform.active}.home" is not found in the project's properties files. - Either open the project in the IDE and setup the Platform with the same name or add it manually. - For example like this: - ant -Duser.properties.file=<path_to_property_file> jar (where you put the property "platforms.${platform.active}.home" in a .properties file) - or ant -Dplatforms.${platform.active}.home=<path_to_JDK_home> jar (where no properties file is used) - + @@ -278,6 +242,20 @@ is divided into following sections: + + + + + + + + + + + + + + @@ -365,7 +343,7 @@ is divided into following sections: - + @@ -416,7 +394,7 @@ is divided into following sections: - + @@ -458,7 +436,7 @@ is divided into following sections: - + @@ -537,7 +515,7 @@ is divided into following sections: - + @@ -565,7 +543,7 @@ is divided into following sections: - + @@ -641,7 +619,7 @@ is divided into following sections: - + @@ -872,9 +850,6 @@ is divided into following sections: - - - @@ -924,7 +899,7 @@ is divided into following sections: - + @@ -958,7 +933,7 @@ is divided into following sections: - + @@ -990,7 +965,7 @@ is divided into following sections: - + @@ -1224,7 +1199,7 @@ is divided into following sections: To run this application from the command line without Ant, try: - ${platform.java} -jar "${dist.jar.resolved}" + java -jar "${dist.jar.resolved}" @@ -1326,8 +1301,8 @@ is divided into following sections: - - + + @@ -1520,19 +1495,16 @@ is divided into following sections: - - - - + - + - + diff --git a/nbproject/configs/AnnotationControls.properties b/nbproject/configs/AnnotationControls.properties new file mode 100644 index 0000000000..ef944d1651 --- /dev/null +++ b/nbproject/configs/AnnotationControls.properties @@ -0,0 +1 @@ +main.class=gov.nasa.worldwindx.examples.AnnotationControls diff --git a/nbproject/configs/Cones.properties b/nbproject/configs/Cones.properties new file mode 100644 index 0000000000..9832191404 --- /dev/null +++ b/nbproject/configs/Cones.properties @@ -0,0 +1 @@ +main.class=gov.nasa.worldwindx.examples.Cones diff --git a/nbproject/configs/EGM2008Offsets.properties b/nbproject/configs/EGM2008Offsets.properties new file mode 100644 index 0000000000..646d1236d5 --- /dev/null +++ b/nbproject/configs/EGM2008Offsets.properties @@ -0,0 +1 @@ +main.class=gov.nasa.worldwindx.examples.EGM2008Offsets diff --git a/nbproject/configs/EGM96Offsets.properties b/nbproject/configs/EGM96Offsets.properties new file mode 100644 index 0000000000..55026b5809 --- /dev/null +++ b/nbproject/configs/EGM96Offsets.properties @@ -0,0 +1 @@ +main.class=gov.nasa.worldwindx.examples.EGM96Offsets diff --git a/nbproject/configs/ExportImageOrElevations.properties b/nbproject/configs/ExportImageOrElevations.properties new file mode 100644 index 0000000000..301d17b18c --- /dev/null +++ b/nbproject/configs/ExportImageOrElevations.properties @@ -0,0 +1 @@ +main.class=gov.nasa.worldwindx.examples.ExportImageOrElevations diff --git a/nbproject/configs/Placemarks.properties b/nbproject/configs/Placemarks.properties new file mode 100644 index 0000000000..b2f33a4ace --- /dev/null +++ b/nbproject/configs/Placemarks.properties @@ -0,0 +1 @@ +main.class=gov.nasa.worldwindx.examples.Placemarks diff --git a/nbproject/configs/ScreenImageDragging.properties b/nbproject/configs/ScreenImageDragging.properties new file mode 100644 index 0000000000..a033a21e1d --- /dev/null +++ b/nbproject/configs/ScreenImageDragging.properties @@ -0,0 +1 @@ +main.class=gov.nasa.worldwindx.examples.ScreenImageDragging diff --git a/nbproject/genfiles.properties b/nbproject/genfiles.properties index 6a15e776fa..f7555ac948 100644 --- a/nbproject/genfiles.properties +++ b/nbproject/genfiles.properties @@ -1,8 +1,8 @@ -build.xml.data.CRC32=ed839dc9 +build.xml.data.CRC32=6106e3d1 build.xml.script.CRC32=b2ee8dee -build.xml.stylesheet.CRC32=f85dc8f2@1.102.0.48 +build.xml.stylesheet.CRC32=f85dc8f2@1.108.0.48 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. -nbproject/build-impl.xml.data.CRC32=ed839dc9 -nbproject/build-impl.xml.script.CRC32=2e7bce4f -nbproject/build-impl.xml.stylesheet.CRC32=12e0a6c2@1.102.0.48 +nbproject/build-impl.xml.data.CRC32=6106e3d1 +nbproject/build-impl.xml.script.CRC32=43da2f27 +nbproject/build-impl.xml.stylesheet.CRC32=12e0a6c2@1.108.0.48 diff --git a/nbproject/project.properties b/nbproject/project.properties index 1adab5d73f..fab181db51 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -104,7 +104,7 @@ manifest.custom.permissions= manifest.file=manifest.mf meta.inf.dir=${src.dir}/META-INF mkdist.disabled=false -platform.active=JDK_11 +platform.active=default_platform run.classpath=\ ${javac.classpath}:\ ${build.classes.dir} diff --git a/nbproject/project.xml b/nbproject/project.xml index cba6c32199..e27d90a9ba 100644 --- a/nbproject/project.xml +++ b/nbproject/project.xml @@ -4,7 +4,6 @@ WorldWindJava - diff --git a/src/gov/nasa/worldwind/AbstractSceneController.java b/src/gov/nasa/worldwind/AbstractSceneController.java index 0e2cd922c7..23e057b6a0 100644 --- a/src/gov/nasa/worldwind/AbstractSceneController.java +++ b/src/gov/nasa/worldwind/AbstractSceneController.java @@ -2,25 +2,25 @@ * Copyright 2006-2009, 2017, 2020 United States Government, as represented by the * Administrator of the National Aeronautics and Space Administration. * All rights reserved. - * + * * The NASA World Wind Java (WWJ) platform is licensed under the Apache License, * Version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. - * + * * NASA World Wind Java (WWJ) also contains the following 3rd party Open Source * software: - * + * * Jackson Parser – Licensed under Apache 2.0 * GDAL – Licensed under MIT * JOGL – Licensed under Berkeley Software Distribution (BSD) * Gluegen – Licensed under Berkeley Software Distribution (BSD) - * + * * A complete listing of 3rd Party software notices and licenses included in * NASA World Wind Java (WWJ) can be found in the WorldWindJava-v2.2 3rd-party * notices and licenses PDF found in code directory. @@ -75,15 +75,15 @@ public abstract class AbstractSceneController extends WWObjectImpl implements Sc protected double frameTime; protected double pickTime; /** - * The pick point in AWT screen coordinates, or null if the pick point is disabled. Initially + * The pick point in GL surface screen coordinates, or null if the pick point is disabled. Initially * null. */ - protected Point pickPoint = null; + private Point pickPoint = null; /** - * The pick rectangle in AWT screen coordinates, or null if the pick rectangle is disabled. Initially + * The pick rectangle in GL surface screen coordinates, or null if the pick rectangle is disabled. Initially * null. */ - protected Rectangle pickRect = null; + private Rectangle pickRect = null; protected boolean deepPick = false; protected GpuResourceCache gpuResourceCache; protected TextRendererCache textRendererCache = new TextRendererCache(); @@ -111,6 +111,7 @@ public AbstractSceneController() this.setVerticalExaggeration(Configuration.getDoubleValue(AVKey.VERTICAL_EXAGGERATION, 1d)); } + @Override public void reinitialize() { if (this.textRendererCache != null) @@ -119,6 +120,7 @@ public void reinitialize() } /** Releases resources associated with this scene controller. */ + @Override public void dispose() { if (this.lastPickedObjects != null) @@ -136,11 +138,13 @@ public void dispose() this.textRendererCache.dispose(); } + @Override public GpuResourceCache getGpuResourceCache() { return this.gpuResourceCache; } + @Override public void setGpuResourceCache(GpuResourceCache gpuResourceCache) { this.gpuResourceCache = gpuResourceCache; @@ -151,16 +155,19 @@ public TextRendererCache getTextRendererCache() return textRendererCache; } + @Override public Model getModel() { return this.model; } + @Override public View getView() { return this.view; } + @Override public void setModel(Model model) { if (this.model != null) @@ -173,6 +180,7 @@ public void setModel(Model model) this.firePropertyChange(AVKey.MODEL, oldModel, model); } + @Override public void setView(View view) { if (this.view != null) @@ -186,6 +194,7 @@ public void setView(View view) this.firePropertyChange(AVKey.VIEW, oldView, view); } + @Override public void setVerticalExaggeration(double verticalExaggeration) { Double oldVE = this.verticalExaggeration; @@ -193,36 +202,42 @@ public void setVerticalExaggeration(double verticalExaggeration) this.firePropertyChange(AVKey.VERTICAL_EXAGGERATION, oldVE, verticalExaggeration); } + @Override public double getVerticalExaggeration() { return this.verticalExaggeration; } /** {@inheritDoc} */ + @Override public void setPickPoint(Point pickPoint) { this.pickPoint = pickPoint; } /** {@inheritDoc} */ + @Override public Point getPickPoint() { return this.pickPoint; } /** {@inheritDoc} */ + @Override public void setPickRectangle(Rectangle pickRect) { this.pickRect = pickRect; } /** {@inheritDoc} */ + @Override public Rectangle getPickRectangle() { return this.pickRect; } /** {@inheritDoc} */ + @Override public PickedObjectList getPickedObjectList() { return this.lastPickedObjects; @@ -234,41 +249,49 @@ protected void setPickedObjectList(PickedObjectList pol) } /** {@inheritDoc} */ + @Override public PickedObjectList getObjectsInPickRectangle() { return this.lastObjectsInPickRect; } + @Override public void setDeepPickEnabled(boolean tf) { this.deepPick = tf; } + @Override public boolean isDeepPickEnabled() { return this.deepPick; } + @Override public SectorGeometryList getTerrain() { return this.dc.getSurfaceGeometry(); } + @Override public DrawContext getDrawContext() { return this.dc; } + @Override public double getFramesPerSecond() { return this.framesPerSecond; } + @Override public double getFrameTime() { return this.frameTime; } + @Override public void setPerFrameStatisticsKeys(Set keys) { this.perFrameStatisticsKeys.clear(); @@ -282,33 +305,39 @@ public void setPerFrameStatisticsKeys(Set keys) } } + @Override public Collection getPerFrameStatistics() { return perFrameStatistics; } + @Override public Collection getRenderingExceptions() { return this.renderingExceptions; } + @Override public ScreenCreditController getScreenCreditController() { return screenCreditController; } + @Override public void setScreenCreditController(ScreenCreditController screenCreditController) { this.screenCreditController = screenCreditController; } /** {@inheritDoc} */ + @Override public GLRuntimeCapabilities getGLRuntimeCapabilities() { return this.glRuntimeCaps; } /** {@inheritDoc} */ + @Override public void setGLRuntimeCapabilities(GLRuntimeCapabilities capabilities) { if (capabilities == null) @@ -411,6 +440,7 @@ public void setDeferOrderedRendering(boolean deferOrderedRendering) this.deferOrderedRendering = deferOrderedRendering; } + @Override public int repaint() { this.frameTime = System.currentTimeMillis(); @@ -635,8 +665,8 @@ protected void preRender(DrawContext dc) protected void pickTerrain(DrawContext dc) { - if (dc.isPickingMode() && dc.getVisibleSector() != null && dc.getSurfaceGeometry() != null && - dc.getSurfaceGeometry().size() > 0) + if (dc.isPickingMode() && dc.getVisibleSector() != null && dc.getSurfaceGeometry() != null + && dc.getSurfaceGeometry().size() > 0) { this.pickPoints.clear(); if (dc.getPickPoint() != null) @@ -757,7 +787,10 @@ else if (pol != null && pol.size() > 1) // used to cull the number of colors that the draw context must consider with identifying the unique // pick colors in the specified screen rectangle. if (minAndMaxColorCodes == null) - minAndMaxColorCodes = new int[] {colorCode, colorCode}; + minAndMaxColorCodes = new int[] + { + colorCode, colorCode + }; else { if (minAndMaxColorCodes[0] > colorCode) @@ -809,8 +842,8 @@ protected void pick(DrawContext dc) this.lastPickedObjects = new PickedObjectList(dc.getPickedObjects()); this.lastObjectsInPickRect = new PickedObjectList(dc.getObjectsInPickRectangle()); - if (this.isDeepPickEnabled() && - (this.lastPickedObjects.hasNonTerrainObjects() || this.lastObjectsInPickRect.hasNonTerrainObjects())) + if (this.isDeepPickEnabled() + && (this.lastPickedObjects.hasNonTerrainObjects() || this.lastObjectsInPickRect.hasNonTerrainObjects())) { this.doDeepPick(dc); } @@ -957,8 +990,8 @@ protected void draw(DrawContext dc) dc.setOrderedRenderingMode(false); // Draw the diagnostic displays. - if (dc.getSurfaceGeometry() != null && dc.getModel() != null && (dc.getModel().isShowWireframeExterior() || - dc.getModel().isShowWireframeInterior() || dc.getModel().isShowTessellationBoundingVolumes())) + if (dc.getSurfaceGeometry() != null && dc.getModel() != null && (dc.getModel().isShowWireframeExterior() + || dc.getModel().isShowWireframeInterior() || dc.getModel().isShowTessellationBoundingVolumes())) { Model model = dc.getModel(); @@ -994,7 +1027,6 @@ protected void draw(DrawContext dc) * * @param dc the relevant DrawContext */ - @SuppressWarnings({"UNUSED_SYMBOL", "UnusedDeclaration"}) protected void checkGLErrors(DrawContext dc) { GL gl = dc.getGL(); @@ -1010,7 +1042,6 @@ protected void checkGLErrors(DrawContext dc) //**************************************************************// //******************** Ordered Surface Renderable ************// //**************************************************************// - protected void preRenderOrderedSurfaceRenderables(DrawContext dc) { if (dc.getOrderedSurfaceRenderables().isEmpty()) @@ -1125,9 +1156,9 @@ protected void drawCompositeSurfaceObjects(DrawContext dc) if (tileCount == 0) return; - int attributeMask = - GL2.GL_COLOR_BUFFER_BIT // For alpha test enable, blend enable, alpha func, blend func, blend ref. - | GL2.GL_POLYGON_BIT; // For cull face enable, cull face, polygon mode. + int attributeMask + = GL2.GL_COLOR_BUFFER_BIT // For alpha test enable, blend enable, alpha func, blend func, blend ref. + | GL2.GL_POLYGON_BIT; // For cull face enable, cull face, polygon mode. GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility. OGLStackHandler ogsh = new OGLStackHandler(); diff --git a/src/gov/nasa/worldwind/SceneController.java b/src/gov/nasa/worldwind/SceneController.java index 2cbf20ee7b..7b93ad2664 100644 --- a/src/gov/nasa/worldwind/SceneController.java +++ b/src/gov/nasa/worldwind/SceneController.java @@ -128,7 +128,7 @@ public interface SceneController extends WWObject, Disposable double getFrameTime(); /** - * Specifies the current pick point in AWT screen coordinates, or null to indicate that there is no + * Specifies the current pick point in GL surface screen coordinates, or null to indicate that there is no * pick point. Each frame, this scene controller determines which objects are drawn at the pick point and places * them in a PickedObjectList. This list can be accessed by calling {@link #getPickedObjectList()}. *

@@ -140,7 +140,7 @@ public interface SceneController extends WWObject, Disposable void setPickPoint(Point pickPoint); /** - * Returns the current pick point in AWT screen coordinates. + * Returns the current pick point in GL surface coordinates. * * @return the current pick point, or null if no pick point is current. * @@ -149,7 +149,7 @@ public interface SceneController extends WWObject, Disposable Point getPickPoint(); /** - * Specifies the current pick rectangle in AWT screen coordinates, or null to indicate that there is no + * Specifies the current pick rectangle in GL surface coordinates, or null to indicate that there is no * pick rectangle. Each frame, this scene controller determines which objects intersect the pick rectangle and * places them in a PickedObjectList. This list can be accessed by calling {@link #getObjectsInPickRectangle()}. *

@@ -161,7 +161,7 @@ public interface SceneController extends WWObject, Disposable void setPickRectangle(Rectangle pickRect); /** - * Returns the current pick rectangle in AWT screen coordinates. + * Returns the current pick rectangle in GL surface coordinates. * * @return the current pick rectangle, or null if no pick rectangle is current. * diff --git a/src/gov/nasa/worldwind/WorldWindowImpl.java b/src/gov/nasa/worldwind/WorldWindowImpl.java index 51da668096..d375bcba25 100644 --- a/src/gov/nasa/worldwind/WorldWindowImpl.java +++ b/src/gov/nasa/worldwind/WorldWindowImpl.java @@ -2,25 +2,25 @@ * Copyright 2006-2009, 2017, 2020 United States Government, as represented by the * Administrator of the National Aeronautics and Space Administration. * All rights reserved. - * + * * The NASA World Wind Java (WWJ) platform is licensed under the Apache License, * Version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. - * + * * NASA World Wind Java (WWJ) also contains the following 3rd party Open Source * software: - * + * * Jackson Parser – Licensed under Apache 2.0 * GDAL – Licensed under MIT * JOGL – Licensed under Berkeley Software Distribution (BSD) * Gluegen – Licensed under Berkeley Software Distribution (BSD) - * + * * A complete listing of 3rd Party software notices and licenses included in * NASA World Wind Java (WWJ) can be found in the WorldWindJava-v2.2 3rd-party * notices and licenses PDF found in code directory. @@ -28,7 +28,6 @@ package gov.nasa.worldwind; -import com.jogamp.nativewindow.ScalableSurface; import gov.nasa.worldwind.avlist.AVKey; import gov.nasa.worldwind.cache.*; import gov.nasa.worldwind.event.*; @@ -68,6 +67,7 @@ public WorldWindowImpl() * Causes resources used by the WorldWindow to be freed. The WorldWindow cannot be used once this method is * called. An OpenGL context for the window must be current. */ + @Override public void shutdown() { WorldWind.getDataFileStore().removePropertyChangeListener(this); @@ -104,6 +104,7 @@ public void shutdown() sc.dispose(); } + @Override public GpuResourceCache getGpuResourceCache() { return this.gpuResourceCache; @@ -115,6 +116,7 @@ public void setGpuResourceCache(GpuResourceCache gpuResourceCache) this.sceneController.setGpuResourceCache(this.gpuResourceCache); } + @Override public void setModel(Model model) { // model can be null, that's ok - it indicates no model. @@ -122,11 +124,13 @@ public void setModel(Model model) this.sceneController.setModel(model); } + @Override public Model getModel() { return this.sceneController != null ? this.sceneController.getModel() : null; } + @Override public void setView(View view) { // view can be null, that's ok - it indicates no view. @@ -134,22 +138,26 @@ public void setView(View view) this.sceneController.setView(view); } + @Override public View getView() { return this.sceneController != null ? this.sceneController.getView() : null; } + @Override public void setModelAndView(Model model, View view) { this.setModel(model); this.setView(view); } + @Override public SceneController getSceneController() { return this.sceneController; } + @Override public void setSceneController(SceneController sc) { if (sc != null && this.getSceneController() != null) @@ -160,30 +168,36 @@ public void setSceneController(SceneController sc) this.sceneController = sc; } + @Override public InputHandler getInputHandler() { return this.inputHandler; } + @Override public void setInputHandler(InputHandler inputHandler) { this.inputHandler = inputHandler; } + @Override public void redraw() { } + @Override public void redrawNow() { } + @Override public void setPerFrameStatisticsKeys(Set keys) { if (this.sceneController != null) this.sceneController.setPerFrameStatisticsKeys(keys); } + @Override public Collection getPerFrameStatistics() { if (this.sceneController == null || this.sceneController.getPerFrameStatistics() == null) @@ -192,16 +206,19 @@ public Collection getPerFrameStatistics() return this.sceneController.getPerFrameStatistics(); } + @Override public PickedObjectList getObjectsAtCurrentPosition() { return null; } + @Override public PickedObjectList getObjectsInSelectionBox() { return null; } + @Override public Position getCurrentPosition() { if (this.sceneController == null) @@ -243,11 +260,13 @@ protected PickedObjectList getCurrentBoxSelection() return pol != null && pol.size() > 0 ? pol : null; } + @Override public void addRenderingListener(RenderingListener listener) { this.eventListeners.add(RenderingListener.class, listener); } + @Override public void removeRenderingListener(RenderingListener listener) { this.eventListeners.remove(RenderingListener.class, listener); @@ -261,11 +280,13 @@ protected void callRenderingListeners(RenderingEvent event) } } + @Override public void addPositionListener(PositionListener listener) { this.eventListeners.add(PositionListener.class, listener); } + @Override public void removePositionListener(PositionListener listener) { this.eventListeners.remove(PositionListener.class, listener); @@ -275,6 +296,7 @@ protected void callPositionListeners(final PositionEvent event) { EventQueue.invokeLater(new Runnable() { + @Override public void run() { for (PositionListener listener : eventListeners.getListeners(PositionListener.class)) @@ -285,11 +307,13 @@ public void run() }); } + @Override public void addSelectListener(SelectListener listener) { this.eventListeners.add(SelectListener.class, listener); } + @Override public void removeSelectListener(SelectListener listener) { this.eventListeners.remove(SelectListener.class, listener); @@ -299,6 +323,7 @@ protected void callSelectListeners(final SelectEvent event) { EventQueue.invokeLater(new Runnable() { + @Override public void run() { for (SelectListener listener : eventListeners.getListeners(SelectListener.class)) @@ -309,11 +334,13 @@ public void run() }); } + @Override public void addRenderingExceptionListener(RenderingExceptionListener listener) { this.eventListeners.add(RenderingExceptionListener.class, listener); } + @Override public void removeRenderingExceptionListener(RenderingExceptionListener listener) { this.eventListeners.remove(RenderingExceptionListener.class, listener); @@ -323,6 +350,7 @@ protected void callRenderingExceptionListeners(final Throwable exception) { EventQueue.invokeLater(new Runnable() { + @Override public void run() { for (RenderingExceptionListener listener : eventListeners.getListeners( @@ -341,32 +369,4 @@ public static GpuResourceCache createGpuResourceCache() long cacheSize = Configuration.getLongValue(AVKey.TEXTURE_CACHE_SIZE, FALLBACK_TEXTURE_CACHE_SIZE); return new BasicGpuResourceCache((long) (0.8 * cacheSize), cacheSize); } - - /** - * Configures JOGL's surface pixel scaling on the specified - * ScalableSurface to ensure backward compatibility with - * WorldWind applications developed prior to JOGL pixel scaling's - * introduction.This method is used by GLCanvas and - * GLJPanel to effectively disable JOGL's surface pixel scaling - * by requesting a 1:1 scale.

- * Since v2.2.0, JOGL defaults to using high-dpi pixel scales where - * possible. This causes WorldWind screen elements such as placemarks, the - * compass, the world map, the view controls, and the scale bar (plus many - * more) to appear smaller than they are intended to on screen. The high-dpi - * default also has the effect of degrading WorldWind rendering performance. - * - * @param surface The surface to configure. - */ - public static void configureIdentityPixelScale(ScalableSurface surface) - { - if (surface == null) - { - String message = Logging.getMessage("nullValue.SurfaceIsNull"); - Logging.logger().severe(message); - throw new IllegalArgumentException(message); - } - - float[] identityScale = new float[] {ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE}; - surface.setSurfaceScale(identityScale); - } } diff --git a/src/gov/nasa/worldwind/animation/MoveToDoubleAnimator.java b/src/gov/nasa/worldwind/animation/MoveToDoubleAnimator.java index 68305c6b3a..aa999bd25a 100644 --- a/src/gov/nasa/worldwind/animation/MoveToDoubleAnimator.java +++ b/src/gov/nasa/worldwind/animation/MoveToDoubleAnimator.java @@ -1,84 +1,86 @@ /* - * Copyright 2006-2009, 2017, 2020 United States Government, as represented by the - * Administrator of the National Aeronautics and Space Administration. + * Copyright 2006-2009, 2017, 2020 United States Government, + * as represented by the Administrator of the National Aeronautics and Space Administration. * All rights reserved. - * - * The NASA World Wind Java (WWJ) platform is licensed under the Apache License, - * Version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * The NASA World Wind Java (WWJ) platform is licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. - * - * NASA World Wind Java (WWJ) also contains the following 3rd party Open Source - * software: - * + * + * NASA World Wind Java (WWJ) also contains the following 3rd party Open Source software: + * * Jackson Parser – Licensed under Apache 2.0 * GDAL – Licensed under MIT - * JOGL – Licensed under Berkeley Software Distribution (BSD) + * JOGL – Licensed under Berkeley Software Distribution (BSD) * Gluegen – Licensed under Berkeley Software Distribution (BSD) - * + * * A complete listing of 3rd Party software notices and licenses included in - * NASA World Wind Java (WWJ) can be found in the WorldWindJava-v2.2 3rd-party - * notices and licenses PDF found in code directory. + * NASA World Wind Java (WWJ) can be found in the WorldWindJava-v2.2 3rd-party + * notices and licenses PDF found in the code directory. */ package gov.nasa.worldwind.animation; import gov.nasa.worldwind.util.PropertyAccessor; /** - * Animates the value to the specified end position, using the specified smoothing, until the value is within the - * specified minEpsilon of the end value. For each frame the animator interpolates between the current value and the - * target(end) value using (1.0-smoothing) as the interpolant, until the difference between the current - * value and the target(end) value is less than the minEpsilon value. + * Animates a double value toward a specified end position using a smoothing factor. + * The animation continues until the current value is within a defined {@code minEpsilon} + * distance of the end value. + *

+ * For each frame, the animator interpolates between the current value and the target value + * using {@code (1.0 - smoothing)} as the interpolation factor, until the absolute difference + * between the two is less than {@code minEpsilon}. + *

* * @author jym * @version $Id: MoveToDoubleAnimator.java 1171 2013-02-11 21:45:02Z dcollins $ */ -public class MoveToDoubleAnimator extends DoubleAnimator -{ +public class MoveToDoubleAnimator extends DoubleAnimator { + /** - * The amount of delta between the end value and the current value that is required to stop the animation. Defaults - * to .001. + * The minimum difference between the end value and the current value required + * to stop the animation. Defaults to {@code 0.001}. */ protected double minEpsilon = 1e-3; - /** The amount of smoothing. A number between 0 and 1. The higher the number the greater the smoothing. */ - protected double smoothing = .9; /** - * Construct a {@link MoveToDoubleAnimator} + * The smoothing factor, a number between 0 and 1. + * Higher values produce smoother, slower movement. + */ + protected double smoothing = 0.9; + + /** + * Constructs a {@link MoveToDoubleAnimator}. * - * @param end The target value, the value to animate to. - * @param smoothing The smoothing factor. A number between 0 and 1. The higher the number the greater the - * smoothing. - * @param propertyAccessor The accessor used to access the animated value. + * @param end The target value to animate toward. + * @param smoothing The smoothing factor (0–1). Higher means smoother/slower. + * @param propertyAccessor The accessor used to get and set the animated value. */ - public MoveToDoubleAnimator( - Double end, double smoothing, - PropertyAccessor.DoubleAccessor propertyAccessor) - { + public MoveToDoubleAnimator(Double end, double smoothing, + PropertyAccessor.DoubleAccessor propertyAccessor) { super(null, 0, end, propertyAccessor); this.interpolator = null; this.smoothing = smoothing; } /** - * Construct a {@link MoveToDoubleAnimator} + * Constructs a {@link MoveToDoubleAnimator}. * - * @param end The target value, the value to animate to. - * @param smoothing smoothing The smoothing factor. A number between 0 and 1. The higher the number the - * greater the smoothing. - * @param minEpsilon The minimum difference between the current value and the target value that triggers the - * end of the animation. Defaults to .001. - * @param propertyAccessor The double accessor used to access the animated value. + * @param end The target value to animate toward. + * @param smoothing The smoothing factor (0–1). Higher means smoother/slower. + * @param minEpsilon The minimum difference between the current value and target + * value that triggers the end of the animation. + * @param propertyAccessor The accessor used to get and set the animated value. */ - public MoveToDoubleAnimator( - Double end, double smoothing, double minEpsilon, - PropertyAccessor.DoubleAccessor propertyAccessor) - { + public MoveToDoubleAnimator(Double end, double smoothing, double minEpsilon, + PropertyAccessor.DoubleAccessor propertyAccessor) { super(null, 0, end, propertyAccessor); this.interpolator = null; this.smoothing = smoothing; @@ -86,31 +88,34 @@ public MoveToDoubleAnimator( } /** - * Set the value to the next value in the animation. This interpolates between the current value and the target - * value using 1.0-smoothing as the interpolant. + * Advances the animation to the next frame. + *

+ * Interpolates between the current value and the target value using + * {@code (1.0 - smoothing)} as the interpolation factor. + *

*/ - public void next() - { - if (hasNext()) + public void next() { + if (hasNext()) { set(1.0 - smoothing); + } } /** - * Get the next value using the given interpolantto perform a linear interplation. between the current value and the - * target(end) value. + * Computes the next interpolated double value based on the given interpolant. + * Performs linear interpolation between the current and target values. * - * @param interpolant The inerpolant to be used to perform the interpolation. A number between 0 and 1. - * - * @return the interpolated value. + * @param interpolant The interpolation factor (0–1). + * @return The interpolated value, or {@code null} if the animation has stopped. */ - public Double nextDouble(double interpolant) - { - double newValue = (1 - interpolant) * propertyAccessor.getDouble() + interpolant * this.end; - if (Math.abs(newValue - propertyAccessor.getDouble()) < minEpsilon) - { + public Double nextDouble(double interpolant) { + double currentValue = propertyAccessor.getDouble(); + double newValue = (1 - interpolant) * currentValue + interpolant * this.end; + + if (Math.abs(newValue - currentValue) < minEpsilon) { this.stop(); - return (null); + return null; } + return newValue; } } diff --git a/src/gov/nasa/worldwind/awt/AWTInputHandler.java b/src/gov/nasa/worldwind/awt/AWTInputHandler.java index 3697849cdc..4915cd6d77 100644 --- a/src/gov/nasa/worldwind/awt/AWTInputHandler.java +++ b/src/gov/nasa/worldwind/awt/AWTInputHandler.java @@ -2,25 +2,25 @@ * Copyright 2006-2009, 2017, 2020 United States Government, as represented by the * Administrator of the National Aeronautics and Space Administration. * All rights reserved. - * + * * The NASA World Wind Java (WWJ) platform is licensed under the Apache License, * Version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. - * + * * NASA World Wind Java (WWJ) also contains the following 3rd party Open Source * software: - * + * * Jackson Parser – Licensed under Apache 2.0 * GDAL – Licensed under MIT * JOGL – Licensed under Berkeley Software Distribution (BSD) * Gluegen – Licensed under Berkeley Software Distribution (BSD) - * + * * A complete listing of 3rd Party software notices and licenses included in * NASA World Wind Java (WWJ) can be found in the WorldWindJava-v2.2 3rd-party * notices and licenses PDF found in code directory. @@ -57,6 +57,7 @@ public class AWTInputHandler extends WWObjectImpl protected boolean forceRedrawOnMousePressed = Configuration.getBooleanValue(AVKey.REDRAW_ON_MOUSE_PRESSED, false); protected javax.swing.Timer hoverTimer = new javax.swing.Timer(600, new ActionListener() { + @Override public void actionPerformed(ActionEvent actionEvent) { if (AWTInputHandler.this.pickMatches(AWTInputHandler.this.hoverObjects)) @@ -75,6 +76,7 @@ public AWTInputHandler() { } + @Override public void dispose() { this.hoverTimer.stop(); @@ -91,6 +93,7 @@ public void dispose() this.objectsAtButtonPress = null; } + @Override public void setEventSource(WorldWindow newWorldWindow) { if (newWorldWindow != null && !(newWorldWindow instanceof Component)) @@ -139,6 +142,7 @@ public void setEventSource(WorldWindow newWorldWindow) this.selectListener = new SelectListener() { + @Override public void selected(SelectEvent event) { if (event.getEventAction().equals(SelectEvent.ROLLOVER)) @@ -160,16 +164,19 @@ public void removeHoverSelectListener() this.wwd.removeSelectListener(selectListener); } + @Override public WorldWindow getEventSource() { return this.wwd; } + @Override public void setHoverDelay(int delay) { this.hoverTimer.setDelay(delay); } + @Override public int getHoverDelay() { return this.hoverTimer.getDelay(); @@ -250,22 +257,25 @@ protected void setObjectsAtButtonPress(PickedObjectList objectsAtButtonPress) this.objectsAtButtonPress = objectsAtButtonPress; } + @Override public boolean isForceRedrawOnMousePressed() { return forceRedrawOnMousePressed; } + @Override public void setForceRedrawOnMousePressed(boolean forceRedrawOnMousePressed) { this.forceRedrawOnMousePressed = forceRedrawOnMousePressed; } -/* + + /* public ViewInputHandler getViewInputHandler() { return viewInputHandler; } - */ - + */ + @Override public void keyTyped(KeyEvent keyEvent) { if (this.wwd == null) @@ -286,6 +296,7 @@ public void keyTyped(KeyEvent keyEvent) } } + @Override public void keyPressed(KeyEvent keyEvent) { if (this.wwd == null) @@ -306,6 +317,7 @@ public void keyPressed(KeyEvent keyEvent) } } + @Override public void keyReleased(KeyEvent keyEvent) { if (this.wwd == null) @@ -326,7 +338,48 @@ public void keyReleased(KeyEvent keyEvent) } } - public void mouseClicked(final MouseEvent mouseEvent) + /** + * Construct a mouse event with GL surface screen coordinates + * @param e + * @return + */ + private MouseEvent glMouseEvent(MouseEvent awtMouseEvent) + { + int[] GLmousePt = wwd.getSceneController().getDrawContext().awtPointToGLpoint(awtMouseEvent.getPoint()); + MouseEvent e = new MouseEvent(awtMouseEvent.getComponent(), awtMouseEvent.getID(), + awtMouseEvent.getWhen(), awtMouseEvent.getModifiersEx(), + GLmousePt[0], GLmousePt[1], awtMouseEvent.getClickCount(), awtMouseEvent.isPopupTrigger(), + awtMouseEvent.getButton()); + + if (awtMouseEvent.isConsumed()) // needed in case this method is overridden by a subclass + e.consume(); + + return e; + } + + /** + * Construct a mouse wheel event with GL surface screen coordinates + * @param e + * @return + */ + private MouseWheelEvent glMouseWheelEvent(MouseWheelEvent awtEv) + { + int[] GLmousePt = wwd.getSceneController().getDrawContext().awtPointToGLpoint(awtEv.getPoint()); + MouseWheelEvent e = new MouseWheelEvent(awtEv.getComponent(), awtEv.getID(), + awtEv.getWhen(), awtEv.getModifiersEx(), + GLmousePt[0], GLmousePt[1], awtEv.getXOnScreen(), awtEv.getYOnScreen(), + awtEv.getClickCount(), awtEv.isPopupTrigger(), + awtEv.getScrollType(), awtEv.getScrollAmount(), + awtEv.getWheelRotation(), awtEv.getPreciseWheelRotation()); + + if (awtEv.isConsumed()) // needed in case this method is overridden by a subclass + e.consume(); + + return e; + } + + @Override + public void mouseClicked(final MouseEvent awtMouseEvent) { if (this.wwd == null) { @@ -338,10 +391,11 @@ public void mouseClicked(final MouseEvent mouseEvent) return; } - if (mouseEvent == null) + if (awtMouseEvent == null) { return; } + MouseEvent mouseEvent = glMouseEvent(awtMouseEvent); PickedObjectList pickedObjects = this.wwd.getObjectsAtCurrentPosition(); @@ -350,24 +404,26 @@ public void mouseClicked(final MouseEvent mouseEvent) if (pickedObjects != null && pickedObjects.getTopPickedObject() != null && !pickedObjects.getTopPickedObject().isTerrain()) { - // Something is under the cursor, so it's deemed "selected". + Point awtPt = awtMouseEvent.getPoint(); // AWT screen coordinates + + // Something is under the cursor, so it's deemed "selected". if (MouseEvent.BUTTON1 == mouseEvent.getButton()) { if (mouseEvent.getClickCount() <= 1) { this.callSelectListeners(new SelectEvent(this.wwd, SelectEvent.LEFT_CLICK, - mouseEvent, pickedObjects)); + awtPt, mouseEvent, pickedObjects)); } else { this.callSelectListeners(new SelectEvent(this.wwd, SelectEvent.LEFT_DOUBLE_CLICK, - mouseEvent, pickedObjects)); + awtPt, mouseEvent, pickedObjects)); } } else if (MouseEvent.BUTTON3 == mouseEvent.getButton()) { this.callSelectListeners(new SelectEvent(this.wwd, SelectEvent.RIGHT_CLICK, - mouseEvent, pickedObjects)); + awtPt, mouseEvent, pickedObjects)); } this.wwd.getView().firePropertyChange(AVKey.VIEW, null, this.wwd.getView()); @@ -381,20 +437,22 @@ else if (MouseEvent.BUTTON3 == mouseEvent.getButton()) } } - public void mousePressed(MouseEvent mouseEvent) + @Override + public void mousePressed(MouseEvent awtMouseEvent) { if (this.wwd == null) { return; } - if (mouseEvent == null) + if (awtMouseEvent == null) { return; } // Determine if the mouse point has changed since the last mouse move event. This can happen if user switches to // another window, moves the mouse, and then switches back to the WorldWind window. + MouseEvent mouseEvent = glMouseEvent(awtMouseEvent); boolean mousePointChanged = !mouseEvent.getPoint().equals(this.mousePoint); this.mousePoint = mouseEvent.getPoint(); @@ -416,16 +474,18 @@ public void mousePressed(MouseEvent mouseEvent) if (this.objectsAtButtonPress != null && objectsAtButtonPress.getTopPickedObject() != null && !this.objectsAtButtonPress.getTopPickedObject().isTerrain()) { + Point awtPt = awtMouseEvent.getPoint(); // AWT screen coordinates + // Something is under the cursor, so it's deemed "selected". if (MouseEvent.BUTTON1 == mouseEvent.getButton()) { this.callSelectListeners(new SelectEvent(this.wwd, SelectEvent.LEFT_PRESS, - mouseEvent, this.objectsAtButtonPress)); + awtPt, mouseEvent, this.objectsAtButtonPress)); } else if (MouseEvent.BUTTON3 == mouseEvent.getButton()) { this.callSelectListeners(new SelectEvent(this.wwd, SelectEvent.RIGHT_PRESS, - mouseEvent, this.objectsAtButtonPress)); + awtPt, mouseEvent, this.objectsAtButtonPress)); } // Initiate a repaint. @@ -448,18 +508,20 @@ else if (MouseEvent.BUTTON3 == mouseEvent.getButton()) } } - public void mouseReleased(MouseEvent mouseEvent) + @Override + public void mouseReleased(MouseEvent awtMouseEvent) { if (this.wwd == null) { return; } - if (mouseEvent == null) + if (awtMouseEvent == null) { return; } + MouseEvent mouseEvent = glMouseEvent(awtMouseEvent); this.mousePoint = mouseEvent.getPoint(); this.callMouseReleasedListeners(mouseEvent); if (!mouseEvent.isConsumed()) @@ -470,36 +532,40 @@ public void mouseReleased(MouseEvent mouseEvent) this.cancelDrag(); } - public void mouseEntered(MouseEvent mouseEvent) + @Override + public void mouseEntered(MouseEvent awtMouseEvent) { if (this.wwd == null) { return; } - if (mouseEvent == null) + if (awtMouseEvent == null) { return; } + MouseEvent mouseEvent = glMouseEvent(awtMouseEvent); this.callMouseEnteredListeners(mouseEvent); this.wwd.getView().getViewInputHandler().mouseEntered(mouseEvent); this.cancelHover(); this.cancelDrag(); } - public void mouseExited(MouseEvent mouseEvent) + @Override + public void mouseExited(MouseEvent awtMouseEvent) { if (this.wwd == null) { return; } - if (mouseEvent == null) + if (awtMouseEvent == null) { return; } + MouseEvent mouseEvent = glMouseEvent(awtMouseEvent); this.callMouseExitedListeners(mouseEvent); this.wwd.getView().getViewInputHandler().mouseExited(mouseEvent); @@ -514,16 +580,18 @@ public void mouseExited(MouseEvent mouseEvent) this.cancelDrag(); } - public void mouseDragged(MouseEvent mouseEvent) + @Override + public void mouseDragged(MouseEvent awtMouseEvent) { if (this.wwd == null) return; - if (mouseEvent == null) + if (awtMouseEvent == null) { return; } + MouseEvent mouseEvent = glMouseEvent(awtMouseEvent); Point prevMousePoint = this.mousePoint; this.mousePoint = mouseEvent.getPoint(); this.callMouseDraggedListeners(mouseEvent); @@ -536,8 +604,9 @@ public void mouseDragged(MouseEvent mouseEvent) && !pickedObjects.getTopPickedObject().isTerrain())) { this.isDragging = true; - DragSelectEvent selectEvent = new DragSelectEvent(this.wwd, SelectEvent.DRAG, mouseEvent, pickedObjects, - prevMousePoint); + DragSelectEvent selectEvent = new DragSelectEvent(this.wwd, SelectEvent.DRAG, + awtMouseEvent.getPoint(), mouseEvent, + pickedObjects, prevMousePoint); this.callSelectListeners(selectEvent); // If no listener consumed the event, then cancel the drag. @@ -562,18 +631,20 @@ public void mouseDragged(MouseEvent mouseEvent) } } - public void mouseMoved(MouseEvent mouseEvent) + @Override + public void mouseMoved(MouseEvent awtMouseEvent) { if (this.wwd == null) { return; } - if (mouseEvent == null) + if (awtMouseEvent == null) { return; } + MouseEvent mouseEvent = glMouseEvent(awtMouseEvent); this.mousePoint = mouseEvent.getPoint(); this.callMouseMovedListeners(mouseEvent); @@ -590,24 +661,27 @@ public void mouseMoved(MouseEvent mouseEvent) } } - public void mouseWheelMoved(MouseWheelEvent mouseWheelEvent) + @Override + public void mouseWheelMoved(MouseWheelEvent awtMouseWheelEvent) { if (this.wwd == null) { return; } - if (mouseWheelEvent == null) + if (awtMouseWheelEvent == null) { return; } + MouseWheelEvent mouseWheelEvent = glMouseWheelEvent(awtMouseWheelEvent); this.callMouseWheelMovedListeners(mouseWheelEvent); if (!mouseWheelEvent.isConsumed()) this.wwd.getView().getViewInputHandler().mouseWheelMoved(mouseWheelEvent); } + @Override public void focusGained(FocusEvent focusEvent) { if (this.wwd == null) @@ -623,6 +697,7 @@ public void focusGained(FocusEvent focusEvent) this.wwd.getView().getViewInputHandler().focusGained(focusEvent); } + @Override public void focusLost(FocusEvent focusEvent) { if (this.wwd == null) @@ -651,10 +726,10 @@ protected void doHover(boolean reset) PickedObject hover = this.hoverObjects.getTopPickedObject(); PickedObject last = pickedObjects.getTopPickedObject(); - Object oh = hover == null ? null : hover.getObject() != null ? hover.getObject() : - hover.getParentLayer() != null ? hover.getParentLayer() : null; - Object ol = last == null ? null : last.getObject() != null ? last.getObject() : - last.getParentLayer() != null ? last.getParentLayer() : null; + Object oh = hover == null ? null : hover.getObject() != null ? hover.getObject() + : hover.getParentLayer() != null ? hover.getParentLayer() : null; + Object ol = last == null ? null : last.getObject() != null ? last.getObject() + : last.getParentLayer() != null ? last.getParentLayer() : null; if (oh != null && ol != null && oh.equals(ol)) { return; // object picked is the hover object. don't do anything but wait for the timer to expire. @@ -720,17 +795,19 @@ protected void cancelDrag() if (this.isDragging) { this.callSelectListeners(new DragSelectEvent(this.wwd, SelectEvent.DRAG_END, null, - this.objectsAtButtonPress, this.mousePoint)); + null, this.objectsAtButtonPress, this.mousePoint)); } this.isDragging = false; } + @Override public void addSelectListener(SelectListener listener) { this.eventListeners.add(SelectListener.class, listener); } + @Override public void removeSelectListener(SelectListener listener) { this.eventListeners.remove(SelectListener.class, listener); @@ -744,41 +821,49 @@ protected void callSelectListeners(SelectEvent event) } } + @Override public void addKeyListener(KeyListener listener) { this.eventListeners.add(KeyListener.class, listener); } + @Override public void removeKeyListener(KeyListener listener) { this.eventListeners.remove(KeyListener.class, listener); } + @Override public void addMouseListener(MouseListener listener) { this.eventListeners.add(MouseListener.class, listener); } + @Override public void removeMouseListener(MouseListener listener) { this.eventListeners.remove(MouseListener.class, listener); } + @Override public void addMouseMotionListener(MouseMotionListener listener) { this.eventListeners.add(MouseMotionListener.class, listener); } + @Override public void removeMouseMotionListener(MouseMotionListener listener) { this.eventListeners.remove(MouseMotionListener.class, listener); } + @Override public void addMouseWheelListener(MouseWheelListener listener) { this.eventListeners.add(MouseWheelListener.class, listener); } + @Override public void removeMouseWheelListener(MouseWheelListener listener) { this.eventListeners.remove(MouseWheelListener.class, listener); @@ -872,6 +957,7 @@ protected void callMouseExitedListeners(MouseEvent event) } } + @Override public void propertyChange(PropertyChangeEvent event) { if (this.wwd == null) @@ -889,8 +975,8 @@ public void propertyChange(PropertyChangeEvent event) return; } - if (event.getPropertyName().equals(AVKey.VIEW) && - (event.getSource() == this.getWorldWindow().getSceneController())) + if (event.getPropertyName().equals(AVKey.VIEW) + && (event.getSource() == this.getWorldWindow().getSceneController())) { this.wwd.getView().getViewInputHandler().setWorldWindow(this.wwd); } diff --git a/src/gov/nasa/worldwind/awt/AbstractViewInputHandler.java b/src/gov/nasa/worldwind/awt/AbstractViewInputHandler.java index b0783cd1f4..012457796b 100644 --- a/src/gov/nasa/worldwind/awt/AbstractViewInputHandler.java +++ b/src/gov/nasa/worldwind/awt/AbstractViewInputHandler.java @@ -954,7 +954,7 @@ public double computeDragSlope(Point point1, Point point2, Vec4 vec1, Vec4 vec2) return slope - 1.0; } - protected static Point constrainToSourceBounds(Point point, Object source) + protected static Point constrainToSourceBounds(Point point, WorldWindow source) { if (point == null) return null; @@ -962,19 +962,24 @@ protected static Point constrainToSourceBounds(Point point, Object source) if (!(source instanceof Component)) return point; - Component c = (Component) source; + // source.getHeight(), source.getWidth() are AWT coords height, + // but the 'point' is MouseEvent GL surface coords. + // Clamp to GL viewport size. + int glWidth = source.getView().getViewport().width; + int glHeight = source.getView().getViewport().height; int x = (int) point.getX(); if (x < 0) x = 0; - if (x > c.getWidth()) - x = c.getWidth(); + if (x >= glWidth) + x = glWidth - 1; int y = (int) point.getY(); if (y < 0) y = 0; - if (y > c.getHeight()) - y = c.getHeight(); + + if (y >= glHeight) + y = glHeight - 1; return new Point(x, y); } diff --git a/src/gov/nasa/worldwind/awt/BasicViewInputHandler.java b/src/gov/nasa/worldwind/awt/BasicViewInputHandler.java index e7af6f0ca6..2008517ca6 100644 --- a/src/gov/nasa/worldwind/awt/BasicViewInputHandler.java +++ b/src/gov/nasa/worldwind/awt/BasicViewInputHandler.java @@ -219,10 +219,10 @@ public boolean inputActionPerformed(KeyEventState keys, String target, Point movement = ViewUtil.subtract(point, lastPoint); int headingInput = movement.x; - int pitchInput = movement.y; + int pitchInput = -movement.y; Point totalMovement = ViewUtil.subtract(point, mouseDownPoint); int totalHeadingInput = totalMovement.x; - int totalPitchInput = totalMovement.y; + int totalPitchInput = -totalMovement.y; ViewInputAttributes.DeviceAttributes deviceAttributes = getAttributes().getDeviceAttributes(ViewInputAttributes.DEVICE_MOUSE); @@ -258,16 +258,16 @@ public boolean inputActionPerformed(AbstractViewInputHandler inputHandler, return false; } + // 'mouseEvent' is in GL surface coords, (0,0) in lower left of canvas + // Make down mouse movement increase the pitch. Point movement = ViewUtil.subtract(point, lastPoint); int headingInput = movement.x; - int pitchInput = movement.y; + int pitchInput = -movement.y; if (mouseDownPoint == null) mouseDownPoint = lastPoint; Point totalMovement = ViewUtil.subtract(point, mouseDownPoint); int totalHeadingInput = totalMovement.x; - int totalPitchInput = totalMovement.y; - - + int totalPitchInput = -totalMovement.y; ViewInputAttributes.DeviceAttributes deviceAttributes = getAttributes().getDeviceAttributes(ViewInputAttributes.DEVICE_MOUSE); diff --git a/src/gov/nasa/worldwind/awt/WorldWindowGLCanvas.java b/src/gov/nasa/worldwind/awt/WorldWindowGLCanvas.java index 8a9942751b..3fb63c14ba 100644 --- a/src/gov/nasa/worldwind/awt/WorldWindowGLCanvas.java +++ b/src/gov/nasa/worldwind/awt/WorldWindowGLCanvas.java @@ -94,7 +94,6 @@ public WorldWindowGLCanvas() this.createView(); this.createDefaultInputHandler(); WorldWind.addPropertyChangeListener(WorldWind.SHUTDOWN_EVENT, this); - WorldWindowImpl.configureIdentityPixelScale(this); this.wwd.endInitialization(); } catch (Exception e) @@ -132,7 +131,6 @@ public WorldWindowGLCanvas(WorldWindow shareWith) this.createView(); this.createDefaultInputHandler(); WorldWind.addPropertyChangeListener(WorldWind.SHUTDOWN_EVENT, this); - WorldWindowImpl.configureIdentityPixelScale(this); this.wwd.endInitialization(); } catch (Exception e) @@ -172,7 +170,6 @@ public WorldWindowGLCanvas(WorldWindow shareWith, java.awt.GraphicsDevice device this.createView(); this.createDefaultInputHandler(); WorldWind.addPropertyChangeListener(WorldWind.SHUTDOWN_EVENT, this); - WorldWindowImpl.configureIdentityPixelScale(this); this.wwd.endInitialization(); } catch (Exception e) @@ -216,7 +213,6 @@ public WorldWindowGLCanvas(WorldWindow shareWith, java.awt.GraphicsDevice device this.createView(); this.createDefaultInputHandler(); WorldWind.addPropertyChangeListener(WorldWind.SHUTDOWN_EVENT, this); - WorldWindowImpl.configureIdentityPixelScale(this); this.wwd.endInitialization(); } catch (Exception e) @@ -227,7 +223,8 @@ public WorldWindowGLCanvas(WorldWindow shareWith, java.awt.GraphicsDevice device } } - public void propertyChange(PropertyChangeEvent evt) + @Override + public void propertyChange(PropertyChangeEvent evt) { if(this.wwd == evt.getSource()) this.firePropertyChange(evt); @@ -237,7 +234,8 @@ public void propertyChange(PropertyChangeEvent evt) this.shutdown(); } - public void shutdown() + @Override + public void shutdown() { WorldWind.removePropertyChangeListener(WorldWind.SHUTDOWN_EVENT, this); this.wwd.shutdown(); @@ -267,12 +265,14 @@ protected void createDefaultInputHandler() this.setInputHandler((InputHandler) WorldWind.createConfigurationComponent(AVKey.INPUT_HANDLER_CLASS_NAME)); } - public InputHandler getInputHandler() + @Override + public InputHandler getInputHandler() { return this.wwd.getInputHandler(); } - public void setInputHandler(InputHandler inputHandler) + @Override + public void setInputHandler(InputHandler inputHandler) { if (this.wwd.getInputHandler() != null) this.wwd.getInputHandler().setEventSource(null); // remove this window as a source of events @@ -282,153 +282,182 @@ public void setInputHandler(InputHandler inputHandler) inputHandler.setEventSource(this); } - public SceneController getSceneController() + @Override + public SceneController getSceneController() { return this.wwd.getSceneController(); } - public void setSceneController(SceneController sceneController) + @Override + public void setSceneController(SceneController sceneController) { this.wwd.setSceneController(sceneController); } - public GpuResourceCache getGpuResourceCache() + @Override + public GpuResourceCache getGpuResourceCache() { return this.wwd.getGpuResourceCache(); } - public void redraw() + @Override + public void redraw() { this.repaint(); } - public void redrawNow() + @Override + public void redrawNow() { this.wwd.redrawNow(); } - public void setModel(Model model) + @Override + public void setModel(Model model) { // null models are permissible this.wwd.setModel(model); } - public Model getModel() + @Override + public Model getModel() { return this.wwd.getModel(); } - public void setView(View view) + @Override + public void setView(View view) { // null views are permissible if (view != null) this.wwd.setView(view); } - public View getView() + @Override + public View getView() { return this.wwd.getView(); } - public void setModelAndView(Model model, View view) + @Override + public void setModelAndView(Model model, View view) { // null models/views are permissible this.setModel(model); this.setView(view); } - public void addRenderingListener(RenderingListener listener) + @Override + public void addRenderingListener(RenderingListener listener) { this.wwd.addRenderingListener(listener); } - public void removeRenderingListener(RenderingListener listener) + @Override + public void removeRenderingListener(RenderingListener listener) { this.wwd.removeRenderingListener(listener); } - public void addSelectListener(SelectListener listener) + @Override + public void addSelectListener(SelectListener listener) { this.wwd.getInputHandler().addSelectListener(listener); this.wwd.addSelectListener(listener); } - public void removeSelectListener(SelectListener listener) + @Override + public void removeSelectListener(SelectListener listener) { this.wwd.getInputHandler().removeSelectListener(listener); this.wwd.removeSelectListener(listener); } - public void addPositionListener(PositionListener listener) + @Override + public void addPositionListener(PositionListener listener) { this.wwd.addPositionListener(listener); } - public void removePositionListener(PositionListener listener) + @Override + public void removePositionListener(PositionListener listener) { this.wwd.removePositionListener(listener); } - public void addRenderingExceptionListener(RenderingExceptionListener listener) + @Override + public void addRenderingExceptionListener(RenderingExceptionListener listener) { this.wwd.addRenderingExceptionListener(listener); } - public void removeRenderingExceptionListener(RenderingExceptionListener listener) + @Override + public void removeRenderingExceptionListener(RenderingExceptionListener listener) { this.wwd.removeRenderingExceptionListener(listener); } - public Position getCurrentPosition() + @Override + public Position getCurrentPosition() { return this.wwd.getCurrentPosition(); } - public PickedObjectList getObjectsAtCurrentPosition() + @Override + public PickedObjectList getObjectsAtCurrentPosition() { return this.wwd.getSceneController() != null ? this.wwd.getSceneController().getPickedObjectList() : null; } - public PickedObjectList getObjectsInSelectionBox() + @Override + public PickedObjectList getObjectsInSelectionBox() { return this.wwd.getSceneController() != null ? this.wwd.getSceneController().getObjectsInPickRectangle() : null; } - public Object setValue(String key, Object value) + @Override + public Object setValue(String key, Object value) { return this.wwd.setValue(key, value); } - public AVList setValues(AVList avList) + @Override + public AVList setValues(AVList avList) { return this.wwd.setValues(avList); } - public Object getValue(String key) + @Override + public Object getValue(String key) { return this.wwd.getValue(key); } - public Collection getValues() + @Override + public Collection getValues() { return this.wwd.getValues(); } - public Set> getEntries() + @Override + public Set> getEntries() { return this.wwd.getEntries(); } - public String getStringValue(String key) + @Override + public String getStringValue(String key) { return this.wwd.getStringValue(key); } - public boolean hasKey(String key) + @Override + public boolean hasKey(String key) { return this.wwd.hasKey(key); } - public Object removeKey(String key) + @Override + public Object removeKey(String key) { return this.wwd.removeKey(key); } @@ -463,28 +492,53 @@ public void firePropertyChange(String propertyName, Object oldValue, Object newV super.firePropertyChange(propertyName, oldValue, newValue); } - public void firePropertyChange(PropertyChangeEvent propertyChangeEvent) + @Override + public void firePropertyChange(PropertyChangeEvent propertyChangeEvent) { this.wwd.firePropertyChange(propertyChangeEvent); } - public AVList copy() + @Override + public AVList copy() { return this.wwd.copy(); } - public AVList clearList() + @Override + public AVList clearList() { return this.wwd.clearList(); } - public void setPerFrameStatisticsKeys(Set keys) + @Override + public void setPerFrameStatisticsKeys(Set keys) { this.wwd.setPerFrameStatisticsKeys(keys); } - public Collection getPerFrameStatistics() + @Override + public Collection getPerFrameStatistics() { return this.wwd.getPerFrameStatistics(); } + + /** + * @return current mouse pointer position in GL surface screen coordinates. + */ + @Override + public Point getMousePosition() throws HeadlessException { + Point mpos = super.getMousePosition(); + int [] awtPt = { mpos.x, mpos.y }; + + if (wwd.getContext() == null) return mpos; + + GLDrawable drawable = wwd.getContext().getGLDrawable(); + if (drawable == null) return mpos; + + // Convert to GL surface coordinates + int [] glSurfacePt = drawable.getNativeSurface().convertToPixelUnits(awtPt); + int glSurfaceHeight = drawable.getSurfaceHeight(); + glSurfacePt[1] = glSurfaceHeight - glSurfacePt[1] - 1; + return new Point(glSurfacePt[0], glSurfacePt[1]); + } } diff --git a/src/gov/nasa/worldwind/awt/WorldWindowGLJPanel.java b/src/gov/nasa/worldwind/awt/WorldWindowGLJPanel.java index 5630b5b874..0b2a37322c 100644 --- a/src/gov/nasa/worldwind/awt/WorldWindowGLJPanel.java +++ b/src/gov/nasa/worldwind/awt/WorldWindowGLJPanel.java @@ -93,7 +93,6 @@ public WorldWindowGLJPanel() this.createView(); this.createDefaultInputHandler(); WorldWind.addPropertyChangeListener(WorldWind.SHUTDOWN_EVENT, this); - WorldWindowImpl.configureIdentityPixelScale(this); this.wwd.endInitialization(); } catch (Exception e) @@ -131,7 +130,6 @@ public WorldWindowGLJPanel(WorldWindow shareWith) this.createView(); this.createDefaultInputHandler(); WorldWind.addPropertyChangeListener(WorldWind.SHUTDOWN_EVENT, this); - WorldWindowImpl.configureIdentityPixelScale(this); this.wwd.endInitialization(); } catch (Exception e) @@ -175,7 +173,6 @@ public WorldWindowGLJPanel(WorldWindow shareWith, GLCapabilities capabilities, this.createView(); this.createDefaultInputHandler(); WorldWind.addPropertyChangeListener(WorldWind.SHUTDOWN_EVENT, this); - WorldWindowImpl.configureIdentityPixelScale(this); this.wwd.endInitialization(); } catch (Exception e) diff --git a/src/gov/nasa/worldwind/drag/DragContext.java b/src/gov/nasa/worldwind/drag/DragContext.java index 6623902e88..935f2c31b4 100644 --- a/src/gov/nasa/worldwind/drag/DragContext.java +++ b/src/gov/nasa/worldwind/drag/DragContext.java @@ -41,16 +41,16 @@ public class DragContext { /** - * In accordance with the AWT screen coordinates the top left point of the window is the origin. + * In accordance with the GL surface coordinates the top left point of the window is the origin. */ protected Point point; /** - * In accordance with the AWT screen coordinates the top left point of the window is the origin. This point is the + * In accordance with the GL surface coordinates the top left point of the window is the origin. This point is the * previous screen point. */ protected Point previousPoint; /** - * In accordance with the AWT screen coordinates the top left point of the window is the origin. This point refers + * In accordance with the GL surface coordinates the top left point of the window is the origin. This point refers * to the initial point of the drag event. */ protected Point initialPoint; @@ -81,9 +81,9 @@ public DragContext() } /** - * Returns the current screen point with the origin at the top left corner of the window. + * Returns the current GL surface point with the origin at the top left corner of the window. * - * @return the current screen point. + * @return the current GL surface point. */ public Point getPoint() { @@ -91,9 +91,9 @@ public Point getPoint() } /** - * Set the {@link DragContext} current screen point. + * Set the {@link DragContext} current GL surface point. * - * @param point the point to assign to the current screen point. + * @param point the point to assign to the current GL surface point. * * @throws IllegalArgumentException if the point is null. */ @@ -110,7 +110,7 @@ public void setPoint(Point point) } /** - * Returns the previous screen point with the origin at the top left corner of the window. + * Returns the previous GL surface point with the origin at the top left corner of the window. * * @return the previous point. */ @@ -120,9 +120,9 @@ public Point getPreviousPoint() } /** - * Set the {@link DragContext} previous screen point. + * Set the {@link DragContext} previous GL surface point. * - * @param previousPoint the screen point to assign to the previous screen point. + * @param previousPoint the GL surface point to assign to the previous screen point. * * @throws IllegalArgumentException if the previousPoint is null. */ @@ -139,10 +139,10 @@ public void setPreviousPoint(Point previousPoint) } /** - * Returns the initial screen point with the origin at the top left corner of the window. The initial point is the - * screen point at the initiation of the drag event. + * Returns the initial GL surface point with the origin at the top left corner of the window. The initial point is the + * GL surface point at the initiation of the drag event. * - * @return the initial screen point. + * @return the initial GL surface point. */ public Point getInitialPoint() { @@ -150,9 +150,9 @@ public Point getInitialPoint() } /** - * Set the {@link DragContext} initial screen point. + * Set the {@link DragContext} initial GL surface point. * - * @param initialPoint the screen point to assign to the initial screen point. + * @param initialPoint the GL surface point to assign to the initial screen point. * * @throws IllegalArgumentException if the initialPoint is null. */ diff --git a/src/gov/nasa/worldwind/drag/DraggableSupport.java b/src/gov/nasa/worldwind/drag/DraggableSupport.java index 3a5e7b52a5..7af85f8eb6 100644 --- a/src/gov/nasa/worldwind/drag/DraggableSupport.java +++ b/src/gov/nasa/worldwind/drag/DraggableSupport.java @@ -428,9 +428,7 @@ protected Vec4 computeScreenOffsetFromReferencePosition(Position dragObjectRefer Vec4 screenPointOffset = new Vec4( dragContext.getInitialPoint().getX() - dragObjectScreenPoint.getX(), - dragContext.getInitialPoint().getY() - ( - dragContext.getView().getViewport().getHeight() - - dragObjectScreenPoint.getY() - 1.0) + dragContext.getInitialPoint().getY() - dragObjectScreenPoint.getY() ); return screenPointOffset; diff --git a/src/gov/nasa/worldwind/event/DragSelectEvent.java b/src/gov/nasa/worldwind/event/DragSelectEvent.java index fcd36fe33a..c694b58f1b 100644 --- a/src/gov/nasa/worldwind/event/DragSelectEvent.java +++ b/src/gov/nasa/worldwind/event/DragSelectEvent.java @@ -42,10 +42,11 @@ public class DragSelectEvent extends SelectEvent { private final java.awt.Point previousPickPoint; - public DragSelectEvent(Object source, String eventAction, MouseEvent mouseEvent, PickedObjectList pickedObjects, - java.awt.Point previousPickPoint) + public DragSelectEvent(Object source, String eventAction, java.awt.Point awtPt, MouseEvent mouseEvent, + PickedObjectList pickedObjects, + java.awt.Point previousPickPoint) { - super(source, eventAction, mouseEvent, pickedObjects); + super(source, eventAction, awtPt, mouseEvent, pickedObjects); this.previousPickPoint = previousPickPoint; } diff --git a/src/gov/nasa/worldwind/event/SelectEvent.java b/src/gov/nasa/worldwind/event/SelectEvent.java index ac07024c64..1804356111 100644 --- a/src/gov/nasa/worldwind/event/SelectEvent.java +++ b/src/gov/nasa/worldwind/event/SelectEvent.java @@ -65,7 +65,6 @@ * @author tag * @version $Id: SelectEvent.java 1171 2013-02-11 21:45:02Z dcollins $ */ -@SuppressWarnings({"StringEquality"}) public class SelectEvent extends WWEvent { /** The user clicked the left mouse button while the cursor was over picked object. */ @@ -96,24 +95,26 @@ public class SelectEvent extends WWEvent * The user has selected one or more of objects using a selection box. A box rollover event is generated every frame * if one or more objects intersect the box, in which case the event's pickedObjects list contain the selected * objects. A box rollover event is generated once when the selection becomes empty, in which case the event's - * pickedObjects is null. In either case, the event's pickRect contains the selection box bounds in AWT - * screen coordinates. + * pickedObjects is null. In either case, the event's pickRect contains the + * selection box bounds in GL surface coordinates. */ public static final String BOX_ROLLOVER = "gov.nasa.worldwind.SelectEvent.BoxRollover"; private final String eventAction; - private final Point pickPoint; - private final Rectangle pickRect; - private final MouseEvent mouseEvent; + private final Point pickPoint; // GL surface coordinates + private final Rectangle pickRect; // GL surface coordinates + private final MouseEvent mouseEvent; // GL surface coordinates + private final Point awtMousePt; // AWT screen coordinates private final PickedObjectList pickedObjects; - public SelectEvent(Object source, String eventAction, MouseEvent mouseEvent, PickedObjectList pickedObjects) + public SelectEvent(Object source, String eventAction, Point awtPt, MouseEvent mouseEvent, PickedObjectList pickedObjects) { super(source); this.eventAction = eventAction; this.pickPoint = mouseEvent != null ? mouseEvent.getPoint() : null; this.pickRect = null; this.mouseEvent = mouseEvent; + this.awtMousePt = awtPt; this.pickedObjects = pickedObjects; } @@ -124,6 +125,7 @@ public SelectEvent(Object source, String eventAction, Point pickPoint, PickedObj this.pickPoint = pickPoint; this.pickRect = null; this.mouseEvent = null; + this.awtMousePt = null; this.pickedObjects = pickedObjects; } @@ -134,6 +136,7 @@ public SelectEvent(Object source, String eventAction, Rectangle pickRectangle, P this.pickPoint = null; this.pickRect = pickRectangle; this.mouseEvent = null; + this.awtMousePt = null; this.pickedObjects = pickedObjects; } @@ -151,6 +154,10 @@ public String getEventAction() return this.eventAction != null ? this.eventAction : "gov.nasa.worldwind.SelectEvent.UnknownEventAction"; } + public Point getAwtMousePt() { + return awtMousePt; + } + public Point getPickPoint() { return this.pickPoint; diff --git a/src/gov/nasa/worldwind/geom/LatLon.java b/src/gov/nasa/worldwind/geom/LatLon.java index acc1e29a7b..30e3385205 100644 --- a/src/gov/nasa/worldwind/geom/LatLon.java +++ b/src/gov/nasa/worldwind/geom/LatLon.java @@ -1272,6 +1272,7 @@ public static boolean locationsCrossDateLine(Iterable location LatLon pos = null; for (LatLon posNext : locations) { + if (posNext == null) break; if (pos != null) { // A segment cross the line if end pos have different longitude signs diff --git a/src/gov/nasa/worldwind/geom/Sector.java b/src/gov/nasa/worldwind/geom/Sector.java index 5b1e73092c..9a38490d96 100644 --- a/src/gov/nasa/worldwind/geom/Sector.java +++ b/src/gov/nasa/worldwind/geom/Sector.java @@ -284,6 +284,7 @@ public static Sector boundingSector(Iterable locations) { double maxLon = Angle.NEG180.getDegrees(); for (LatLon p : locations) { + if (p == null) break; double lat = p.getLatitude().getDegrees(); if (lat < minLat) { minLat = lat; diff --git a/src/gov/nasa/worldwind/globes/EllipsoidalGlobe.java b/src/gov/nasa/worldwind/globes/EllipsoidalGlobe.java index 479cf7fbe6..d5ccf17d09 100644 --- a/src/gov/nasa/worldwind/globes/EllipsoidalGlobe.java +++ b/src/gov/nasa/worldwind/globes/EllipsoidalGlobe.java @@ -2,25 +2,25 @@ * Copyright 2006-2009, 2017, 2020 United States Government, as represented by the * Administrator of the National Aeronautics and Space Administration. * All rights reserved. - * + * * The NASA World Wind Java (WWJ) platform is licensed under the Apache License, * Version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. - * + * * NASA World Wind Java (WWJ) also contains the following 3rd party Open Source * software: - * + * * Jackson Parser – Licensed under Apache 2.0 * GDAL – Licensed under MIT * JOGL – Licensed under Berkeley Software Distribution (BSD) * Gluegen – Licensed under Berkeley Software Distribution (BSD) - * + * * A complete listing of 3rd Party software notices and licenses included in * NASA World Wind Java (WWJ) can be found in the WorldWindJava-v2.2 3rd-party * notices and licenses PDF found in code directory. @@ -132,7 +132,10 @@ public Globe getGlobe() return this.globe; } - @SuppressWarnings({"RedundantIfStatement"}) + @SuppressWarnings( + { + "RedundantIfStatement" + }) @Override public boolean equals(Object o) { @@ -145,8 +148,8 @@ public boolean equals(Object o) if (Double.compare(stateKey.verticalExaggeration, verticalExaggeration) != 0) return false; - if (elevationModel != null ? !elevationModel.equals(stateKey.elevationModel) : - stateKey.elevationModel != null) + if (elevationModel != null ? !elevationModel.equals(stateKey.elevationModel) + : stateKey.elevationModel != null) return false; if (globe != null ? !globe.equals(stateKey.globe) : stateKey.globe != null) return false; @@ -238,7 +241,6 @@ public double getRadiusAt(Angle latitude, Angle longitude) // observing that the length of the ellipsoidal point at the specified latitude and longitude indicates the // radius at that location. The formula for the length of the ellipsoidal point was then converted into the // simplified form below. - double sinLat = Math.sin(latitude.radians); double rpm = this.equatorialRadius / Math.sqrt(1.0 - this.es * sinLat * sinLat); @@ -294,7 +296,10 @@ public double[] getMinAndMaxElevations(Angle latitude, Angle longitude) } return this.elevationModel != null ? this.elevationModel.getExtremeElevations(latitude, longitude) - : new double[] {0, 0}; + : new double[] + { + 0, 0 + }; } public double[] getMinAndMaxElevations(Sector sector) @@ -306,7 +311,10 @@ public double[] getMinAndMaxElevations(Sector sector) throw new IllegalArgumentException(message); } - return this.elevationModel != null ? this.elevationModel.getExtremeElevations(sector) : new double[] {0, 0}; + return this.elevationModel != null ? this.elevationModel.getExtremeElevations(sector) : new double[] + { + 0, 0 + }; } public Extent getExtent() @@ -347,7 +355,6 @@ protected Intersection[] intersect(Line line, double equRadius, double polRadius return null; // Taken from Lengyel, 2Ed., Section 5.2.3, page 148. - double m = equRadius / polRadius; // "ratio of the x semi-axis length to the y semi-axis length" double n = 1d; // "ratio of the x semi-axis length to the z semi-axis length" double m2 = m * m; @@ -373,16 +380,25 @@ protected Intersection[] intersect(Line line, double equRadius, double polRadius if (discriminant == 0) { Vec4 p = line.getPointAt((-b - discriminantRoot) / (2 * a)); - return new Intersection[] {new Intersection(p, true)}; + return new Intersection[] + { + new Intersection(p, true) + }; } else // (discriminant > 0) { Vec4 near = line.getPointAt((-b - discriminantRoot) / (2 * a)); Vec4 far = line.getPointAt((-b + discriminantRoot) / (2 * a)); if (c >= 0) // Line originates outside the Globe. - return new Intersection[] {new Intersection(near, false), new Intersection(far, false)}; + return new Intersection[] + { + new Intersection(near, false), new Intersection(far, false) + }; else // Line originates inside the Globe. - return new Intersection[] {new Intersection(far, false)}; + return new Intersection[] + { + new Intersection(far, false) + }; } } @@ -492,7 +508,10 @@ public double[] getElevations(Sector sector, List latLons, dou double[] elevations) { if (this.elevationModel == null) - return new double[] {0}; + return new double[] + { + 0 + }; double[] resolution = this.elevationModel.getElevations(sector, latLons, targetResolution, elevations); @@ -508,6 +527,16 @@ public double[] getElevations(Sector sector, List latLons, dou return resolution; } + /** + * Get the EGM96 offset class for this globe. + * + * @return The EGM96 offset class for this globe. + */ + public EGM96 getEGM96() + { + return this.egm96; + } + public double getElevation(Angle latitude, Angle longitude) { if (latitude == null || longitude == null) @@ -909,7 +938,8 @@ protected Vec4 geodeticToEllipsoidal(Angle latitude, Angle longitude, double met double cosLon = Math.cos(longitude.radians); double sinLon = Math.sin(longitude.radians); - double rpm = // getRadius (in meters) of vertical in prime meridian + double rpm + = // getRadius (in meters) of vertical in prime meridian this.equatorialRadius / Math.sqrt(1.0 - this.es * sinLat * sinLat); double x = (rpm + metersElevation) * cosLat * sinLon; @@ -1035,7 +1065,6 @@ protected void geodeticToCartesian(Sector sector, int numLat, int numLon, double // // return Position.fromRadians(lat, lon, elevation); // } - /** * Compute the geographic position to corresponds to a Cartesian point. * @@ -1059,7 +1088,10 @@ protected Position cartesianToGeodetic(Vec4 cart) * * @see #geodeticToEllipsoidal(gov.nasa.worldwind.geom.Angle, gov.nasa.worldwind.geom.Angle, double) */ - @SuppressWarnings({"SuspiciousNameCombination"}) + @SuppressWarnings( + { + "SuspiciousNameCombination" + }) protected Position ellipsoidalToGeodetic(Vec4 cart) { // Contributed by Nathan Kronenfeld. Integrated 1/24/2011. Brings this calculation in line with Vermeille's @@ -1370,4 +1402,4 @@ public static ElevationModel makeElevationModel(String key, String defaultValue) Object configSource = Configuration.getStringValue(key, defaultValue); return (ElevationModel) BasicFactory.create(AVKey.ELEVATION_MODEL_FACTORY, configSource); } -} \ No newline at end of file +} diff --git a/src/gov/nasa/worldwind/layers/CompassLayer.java b/src/gov/nasa/worldwind/layers/CompassLayer.java index 2c4bcb7cf8..0116a3fcf6 100644 --- a/src/gov/nasa/worldwind/layers/CompassLayer.java +++ b/src/gov/nasa/worldwind/layers/CompassLayer.java @@ -67,17 +67,20 @@ public class CompassLayer extends AbstractLayer protected class OrderedIcon implements OrderedRenderable { - public double getDistanceFromEye() + @Override + public double getDistanceFromEye() { return 0; } - public void pick(DrawContext dc, Point pickPoint) + @Override + public void pick(DrawContext dc, Point pickPoint) { CompassLayer.this.draw(dc); } - public void render(DrawContext dc) + @Override + public void render(DrawContext dc) { CompassLayer.this.draw(dc); } @@ -295,7 +298,8 @@ public void setLocationOffset(Vec4 locationOffset) this.locationOffset = locationOffset; } - protected void doRender(DrawContext dc) + @Override + protected void doRender(DrawContext dc) { if (dc.isContinuous2DGlobe() && this.frameStampForDrawing == dc.getFrameTimeStamp()) return; @@ -305,7 +309,8 @@ protected void doRender(DrawContext dc) this.frameStampForDrawing = dc.getFrameTimeStamp(); } - protected void doPick(DrawContext dc, Point pickPoint) + @Override + protected void doPick(DrawContext dc, Point pickPoint) { if (dc.isContinuous2DGlobe() && this.frameStampForPicking == dc.getFrameTimeStamp()) return; @@ -414,7 +419,7 @@ protected void draw(DrawContext dc) Vec4 center = new Vec4(locationSW.x + width * scale / 2, locationSW.y + height * scale / 2, 0); double px = dc.getPickPoint().x - center.x; - double py = viewport.getHeight() - dc.getPickPoint().y - center.y; + double py = dc.getPickPoint().y - center.y; Angle pickHeading = Angle.fromRadians(Math.atan2(px, py)); pickHeading = pickHeading.degrees >= 0 ? pickHeading : pickHeading.addDegrees(360); po.setValue("Heading", pickHeading); diff --git a/src/gov/nasa/worldwind/layers/ScalebarLayer.java b/src/gov/nasa/worldwind/layers/ScalebarLayer.java index 03f495b886..6cfd8af978 100644 --- a/src/gov/nasa/worldwind/layers/ScalebarLayer.java +++ b/src/gov/nasa/worldwind/layers/ScalebarLayer.java @@ -34,6 +34,8 @@ import gov.nasa.worldwind.util.*; import com.jogamp.opengl.*; +import com.jogamp.opengl.util.awt.TextRenderer; + import java.awt.*; import java.awt.geom.*; diff --git a/src/gov/nasa/worldwind/layers/TerrainProfileLayer.java b/src/gov/nasa/worldwind/layers/TerrainProfileLayer.java index d675ad6699..149ab8c2eb 100644 --- a/src/gov/nasa/worldwind/layers/TerrainProfileLayer.java +++ b/src/gov/nasa/worldwind/layers/TerrainProfileLayer.java @@ -37,6 +37,8 @@ import gov.nasa.worldwind.view.orbit.OrbitView; import com.jogamp.opengl.*; +import com.jogamp.opengl.util.awt.TextRenderer; + import java.awt.*; import java.awt.geom.*; import java.beans.PropertyChangeEvent; @@ -148,7 +150,6 @@ public TerrainProfileLayer() { * * @return true if the profile graph is minimized. */ - @SuppressWarnings({"UnusedDeclaration"}) public boolean getIsMinimized() { return this.isMinimized; } @@ -171,7 +172,6 @@ public void setIsMinimized(boolean state) { * * @return true if the profile graph is maximized. */ - @SuppressWarnings({"UnusedDeclaration"}) public boolean getIsMaximized() { return this.isMaximized; } @@ -262,7 +262,6 @@ public double getOpacity() { * * @return the graphic-to-viewport scale factor. */ - @SuppressWarnings({"UnusedDeclaration"}) public double getToViewportScale() { return toViewportScale; } @@ -275,7 +274,6 @@ public double getToViewportScale() { * * @param toViewportScale the graphic to viewport scale factor. */ - @SuppressWarnings({"UnusedDeclaration"}) public void setToViewportScale(double toViewportScale) { this.toViewportScale = toViewportScale; } @@ -305,7 +303,6 @@ public void setPosition(String position) { * * @return the screen location of the graph center if set (can be null). */ - @SuppressWarnings({"UnusedDeclaration"}) public Point getLocationCenter() { return this.locationCenter; } @@ -325,7 +322,6 @@ public void setLocationCenter(Point point) { * * @return the location offset. Will be null if no offset has been specified. */ - @SuppressWarnings({"UnusedDeclaration"}) public Vec4 getLocationOffset() { return locationOffset; } @@ -349,7 +345,6 @@ public void setLocationOffset(Vec4 locationOffset) { * * @return the layer's resize behavior. */ - @SuppressWarnings({"UnusedDeclaration"}) public String getResizeBehavior() { return resizeBehavior; } @@ -365,7 +360,6 @@ public String getResizeBehavior() { * * @param resizeBehavior the desired resize behavior */ - @SuppressWarnings({"UnusedDeclaration"}) public void setResizeBehavior(String resizeBehavior) { this.resizeBehavior = resizeBehavior; } @@ -384,7 +378,6 @@ public void setBorderWidth(int borderWidth) { this.borderWidth = borderWidth; } - @SuppressWarnings({"UnusedDeclaration"}) public String getUnit() { return this.unit; } @@ -503,7 +496,6 @@ public double getProfileLenghtFactor() { * * @return the profile start position lat/lon. */ - @SuppressWarnings({"UnusedDeclaration"}) public LatLon getStartLatLon() { return this.startLatLon; } @@ -527,7 +519,6 @@ public void setStartLatLon(LatLon latLon) { * * @return the profile end position lat/lon. */ - @SuppressWarnings({"UnusedDeclaration"}) public LatLon getEndLatLon() { return this.endLatLon; } @@ -551,7 +542,6 @@ public void setEndLatLon(LatLon latLon) { * * @return the number of elevation samples in the profile. */ - @SuppressWarnings({"UnusedDeclaration"}) public int getSamples() { return this.samples; } @@ -561,7 +551,6 @@ public int getSamples() { * * @param number the number of elevation samples in the profile. */ - @SuppressWarnings({"UnusedDeclaration"}) public void setSamples(int number) { this.samples = Math.abs(number); } @@ -589,7 +578,6 @@ public void setZeroBased(boolean state) { * * @return the object position the graph follows. */ - @SuppressWarnings({"UnusedDeclaration"}) public Position getObjectPosition() { return this.objectPosition; } @@ -609,7 +597,6 @@ public void setObjectPosition(Position pos) { * * @return the object heading the graph follows. */ - @SuppressWarnings({"UnusedDeclaration"}) public Angle getObjectHeading() { return this.objectHeading; } @@ -629,7 +616,6 @@ public void setObjectHeading(Angle heading) { * * @return the path positions that the profile follows. */ - @SuppressWarnings({"UnusedDeclaration"}) public List getPathPositions() { return this.pathPositions; } @@ -708,7 +694,6 @@ public void setPathType(String pathType) { * * @return the Path used to render the profile line on the ground. */ - @SuppressWarnings({"UnusedDeclaration"}) public Path getProfileLine() { return this.selectionShape; } @@ -718,7 +703,6 @@ public Path getProfileLine() { * * @return the Path used to render the picked position on the terrain. */ - @SuppressWarnings({"UnusedDeclaration"}) public Path getPickedLine() { return this.selectionShape; } @@ -728,7 +712,6 @@ public Path getPickedLine() { * * @return true is the profile line is displayed over the ground. */ - @SuppressWarnings({"UnusedDeclaration"}) public boolean isShowProfileLine() { return this.showProfileLine; } @@ -747,7 +730,6 @@ public void setShowProfileLine(boolean state) { * * @return true if the picked line is displayed over the ground. */ - @SuppressWarnings({"UnusedDeclaration"}) public boolean isShowPickedLine() { return this.showPickedLine; } @@ -757,7 +739,6 @@ public boolean isShowPickedLine() { * * @param state if the picked line should be displayed over the ground. */ - @SuppressWarnings({"UnusedDeclaration"}) public void setShowPickedLine(boolean state) { this.showPickedLine = state; } @@ -986,6 +967,7 @@ protected void drawGraph(DrawContext dc, Dimension dimension) { (byte) this.color.getBlue(), (byte) 100); gl.glBegin(GL2.GL_TRIANGLE_STRIP); for (i = 0; i < this.samples; i++) { + if (this.positions[i] == null) break; x = i * lengthStep * stepX; y = (this.positions[i].getElevation() - min) * stepY; gl.glVertex3d(x, 0, 0); @@ -997,6 +979,7 @@ protected void drawGraph(DrawContext dc, Dimension dimension) { gl.glColor4d(colorRGB[0], colorRGB[1], colorRGB[2], this.getOpacity()); gl.glBegin(GL2.GL_LINE_STRIP); for (i = 0; i < this.samples; i++) { + if (this.positions[i] == null) break; x = i * lengthStep * stepX; y = (this.positions[i].getElevation() - min) * stepY; gl.glVertex3d(x, y, 0); @@ -1274,12 +1257,11 @@ protected Position computePickPosition(DrawContext dc, Vec4 locationSW, Dimensio this.pickedSample = -1; Point pickPoint = dc.getPickPoint(); if (pickPoint != null && this.positions != null && !this.follow.equals(FOLLOW_CURSOR)) { - Rectangle viewport = dc.getView().getViewport(); // Check if pickpoint is inside the graph if (pickPoint.getX() >= locationSW.getX() && pickPoint.getX() < locationSW.getX() + mapSize.width - && viewport.height - pickPoint.getY() >= locationSW.getY() - && viewport.height - pickPoint.getY() < locationSW.getY() + mapSize.height) { + && pickPoint.getY() >= locationSW.getY() + && pickPoint.getY() < locationSW.getY() + mapSize.height) { // Find sample - Note: only works when graph expends over the full width int sample = (int) (((double) (pickPoint.getX() - locationSW.getX()) / mapSize.width) * this.samples); if (sample >= 0 && sample < this.samples) { diff --git a/src/gov/nasa/worldwind/layers/TiledImageLayer.java b/src/gov/nasa/worldwind/layers/TiledImageLayer.java index 67fba48604..1a19ce23e7 100644 --- a/src/gov/nasa/worldwind/layers/TiledImageLayer.java +++ b/src/gov/nasa/worldwind/layers/TiledImageLayer.java @@ -39,6 +39,8 @@ import javax.imageio.ImageIO; import com.jogamp.opengl.*; +import com.jogamp.opengl.util.awt.TextRenderer; + import javax.xml.xpath.XPath; import java.awt.image.*; import java.io.*; diff --git a/src/gov/nasa/worldwind/layers/ViewControlsSelectListener.java b/src/gov/nasa/worldwind/layers/ViewControlsSelectListener.java index 35b79f478e..5f1c3fb356 100644 --- a/src/gov/nasa/worldwind/layers/ViewControlsSelectListener.java +++ b/src/gov/nasa/worldwind/layers/ViewControlsSelectListener.java @@ -496,7 +496,7 @@ protected Angle computePanHeading(OrbitView view, ScreenAnnotation control) double size = control.getAttributes().getSize().width * control.getAttributes().getScale(); Vec4 center = new Vec4(control.getScreenPoint().x, control.getScreenPoint().y + size / 2, 0); double px = lastPickPoint.x - center.x; - double py = view.getViewport().getHeight() - lastPickPoint.y - center.y; + double py = lastPickPoint.y - center.y; Angle heading = view.getHeading().add(Angle.fromRadians(Math.atan2(px, py))); heading = heading.degrees >= 0 ? heading : heading.addDegrees(360); return heading; @@ -508,7 +508,7 @@ protected Angle computePanAmount(Globe globe, OrbitView view, ScreenAnnotation c double size = control.getAttributes().getSize().width * control.getAttributes().getScale(); Vec4 center = new Vec4(control.getScreenPoint().x, control.getScreenPoint().y + size / 2, 0); double px = lastPickPoint.x - center.x; - double py = view.getViewport().getHeight() - lastPickPoint.y - center.y; + double py = lastPickPoint.y - center.y; double pickDistance = Math.sqrt(px * px + py * py); double pickDistanceFactor = Math.min(pickDistance / 10, 5); @@ -547,7 +547,7 @@ protected Angle computeLookPitch(OrbitView view, ScreenAnnotation control, doubl // Compute last pick point 'pitch' relative to look control center on y double size = control.getAttributes().getSize().width * control.getAttributes().getScale(); Vec4 center = new Vec4(control.getScreenPoint().x, control.getScreenPoint().y + size / 2, 0); - double py = view.getViewport().getHeight() - lastPickPoint.y - center.y; + double py = lastPickPoint.y - center.y; double pickDistanceFactor = Math.min(Math.abs(py) / 3000, 5) * Math.signum(py); // New pitch Angle pitch = view.getPitch().add(Angle.fromRadians(pitchStep * pickDistanceFactor)); diff --git a/src/gov/nasa/worldwind/layers/WorldMapLayer.java b/src/gov/nasa/worldwind/layers/WorldMapLayer.java index 5d8c84f534..151d8b451b 100644 --- a/src/gov/nasa/worldwind/layers/WorldMapLayer.java +++ b/src/gov/nasa/worldwind/layers/WorldMapLayer.java @@ -700,11 +700,11 @@ protected Position computePickPosition(DrawContext dc, Vec4 locationSW, Dimensio // Check if pickpoint is inside the map if (pickPoint.getX() >= locationSW.getX() && pickPoint.getX() < locationSW.getX() + mapSize.width - && viewport.height - pickPoint.getY() >= locationSW.getY() - && viewport.height - pickPoint.getY() < locationSW.getY() + mapSize.height) + && pickPoint.getY() >= locationSW.getY() + && pickPoint.getY() < locationSW.getY() + mapSize.height) { double lon = (pickPoint.getX() - locationSW.getX()) / mapSize.width * 360 - 180; - double lat = (viewport.height - pickPoint.getY() - locationSW.getY()) / mapSize.height * 180 - 90; + double lat = (pickPoint.getY() - locationSW.getY()) / mapSize.height * 180 - 90; double pickAltitude = 1000e3; pickPosition = new Position(Angle.fromDegrees(lat), Angle.fromDegrees(lon), pickAltitude); } diff --git a/src/gov/nasa/worldwind/layers/mercator/MercatorTiledImageLayer.java b/src/gov/nasa/worldwind/layers/mercator/MercatorTiledImageLayer.java index 9ba7c0ff76..9d6f527329 100644 --- a/src/gov/nasa/worldwind/layers/mercator/MercatorTiledImageLayer.java +++ b/src/gov/nasa/worldwind/layers/mercator/MercatorTiledImageLayer.java @@ -38,6 +38,8 @@ import javax.imageio.ImageIO; import com.jogamp.opengl.*; +import com.jogamp.opengl.util.awt.TextRenderer; + import java.awt.*; import java.awt.geom.*; import java.awt.image.*; diff --git a/src/gov/nasa/worldwind/pick/PickSupport.java b/src/gov/nasa/worldwind/pick/PickSupport.java index de36c75420..002107ce1e 100644 --- a/src/gov/nasa/worldwind/pick/PickSupport.java +++ b/src/gov/nasa/worldwind/pick/PickSupport.java @@ -135,7 +135,7 @@ public PickedObject getTopObject(DrawContext dc, Point pickPoint) * objects are currently registered with this PickSupport. * * @param dc the draw context which receives the picked object. - * @param pickPoint the point in AWT screen coordinates. + * @param pickPoint the point in GL surface coordinates. * @param layer the layer associated with the picked object. * * @return the picked object added to the draw context, or null if no picked object is drawn at the @@ -166,11 +166,11 @@ public PickedObject resolvePick(DrawContext dc, Point pickPoint, Layer layer) } /** - * Adds a picked object registered with this PickSupport that is drawn at the specified point in AWT screen + * Adds a picked object registered with this PickSupport that is drawn at the specified point in GL surface * coordinates (if one exists) to the draw context's list of picked objects. * * @param dc the draw context which receives the picked object. - * @param pickPoint the point in AWT screen coordinates. + * @param pickPoint the point in GL surface coordinates. * @param layer the layer associated with the picked object. * * @return the picked object added to the draw context, or null if no picked object is drawn at the @@ -195,7 +195,7 @@ protected PickedObject doResolvePick(DrawContext dc, Point pickPoint, Layer laye * screen coordinates (if any) to the draw context's list of picked objects. * * @param dc the draw context which receives the picked objects. - * @param pickRect the rectangle in AWT screen coordinates. + * @param pickRect the rectangle in GL surface coordinates. * @param layer the layer associated with the picked objects. */ protected void doResolvePick(DrawContext dc, Rectangle pickRect, Layer layer) @@ -226,7 +226,7 @@ protected void doResolvePick(DrawContext dc, Rectangle pickRect, Layer layer) } /** - * Returns the framebuffer RGB color for a point in AWT screen coordinates, formatted as a pick color code. The red, + * Returns the framebuffer RGB color for a point in GL surface coordinates, formatted as a pick color code. The red, * green, and blue components are each stored as an 8-bit unsigned integer, and packed into bits 0-23 of the * returned integer as follows: bits 16-23 are red, bits 8-15 are green, and bits 0-7 are blue. This format is * consistent with the RGB integers used to create the pick colors. @@ -235,7 +235,7 @@ protected void doResolvePick(DrawContext dc, Rectangle pickRect, Layer layer) * outside the draw context's drawable area. * * @param dc the draw context to return a color for. - * @param pickPoint the point to return a color for, in AWT screen coordinates. + * @param pickPoint the point to return a color for, in GL surface coordinates. * * @return the RGB color corresponding to the specified point. */ diff --git a/src/gov/nasa/worldwind/render/AbstractAnnotation.java b/src/gov/nasa/worldwind/render/AbstractAnnotation.java index 25cb16b38f..72d1571bfc 100644 --- a/src/gov/nasa/worldwind/render/AbstractAnnotation.java +++ b/src/gov/nasa/worldwind/render/AbstractAnnotation.java @@ -34,6 +34,8 @@ import gov.nasa.worldwind.util.*; import com.jogamp.opengl.*; +import com.jogamp.opengl.util.awt.TextRenderer; + import java.awt.*; /** @@ -462,7 +464,6 @@ protected void drawTopLevelAnnotation(DrawContext dc, int x, int y, int width, i } } - @SuppressWarnings({"UnusedDeclaration"}) protected void applyScreenTransform(DrawContext dc, int x, int y, int width, int height, double scale) { double finalScale = scale * this.computeScale(dc); @@ -475,7 +476,6 @@ protected void applyScreenTransform(DrawContext dc, int x, int y, int width, int gl.glTranslated(-width / 2, 0, 0); } - @SuppressWarnings({"UnusedDeclaration"}) protected double computeScale(DrawContext dc) { double scale = this.attributes.getScale(); @@ -489,7 +489,6 @@ protected double computeScale(DrawContext dc) return scale; } - @SuppressWarnings({"UnusedDeclaration"}) protected double computeOpacity(DrawContext dc) { double opacity = this.attributes.getOpacity(); @@ -616,7 +615,6 @@ protected void drawBackgroundImage(DrawContext dc, int width, int height, double this.doDrawBackgroundTexture(dc, width, height, opacity, pickPosition, texture); } - @SuppressWarnings({"UnusedDeclaration"}) protected void doDrawBackgroundTexture(DrawContext dc, int width, int height, double opacity, Position pickPosition, WWTexture texture) { @@ -660,7 +658,6 @@ protected void doDrawBackgroundTexture(DrawContext dc, int width, int height, do } } - @SuppressWarnings({"UnusedDeclaration"}) protected void applyBackgroundTextureState(DrawContext dc, int width, int height, double opacity, WWTexture texture) { @@ -721,7 +718,6 @@ protected void transformImageCoordsToBackgroundImageCoords(DrawContext dc, WWTex * @param texture the texture to transform from Annotation background image coordinates to Annotation geometry * coordinates. */ - @SuppressWarnings({"UnusedDeclaration"}) protected void transformBackgroundImageCoordsToAnnotationCoords(DrawContext dc, int width, int height, WWTexture texture) { @@ -750,7 +746,6 @@ protected void transformBackgroundImageCoordsToAnnotationCoords(DrawContext dc, //******************** Border Rendering **********************// //**************************************************************// - @SuppressWarnings({"UnusedDeclaration"}) protected void drawBorder(DrawContext dc, int width, int height, double opacity, Position pickPosition) { if (this.getAttributes().getBorderWidth() <= 0) @@ -813,8 +808,7 @@ protected void drawText(DrawContext dc, int width, int height, double opacity, P return; java.awt.Rectangle screenInsetBounds = this.transformByModelview(dc, insetBounds); - java.awt.Point glPickPoint = this.glPointFromAWTPoint(dc, dc.getPickPoint()); - if (!screenInsetBounds.contains(glPickPoint)) + if (!screenInsetBounds.contains(dc.getPickPoint())) return; } @@ -897,7 +891,6 @@ protected void drawPlainText(DrawContext dc, int x, int y, int lineHeight, doubl } } - @SuppressWarnings({"UnusedDeclaration"}) protected void drawHTML(DrawContext dc, int x, int y, int lineHeight, double opacity, Object pickObject, Position pickPosition, String text) { @@ -941,14 +934,12 @@ protected void drawChildren(DrawContext dc, int width, int height, double opacit } } - @SuppressWarnings({"UnusedDeclaration"}) protected void doDrawChildren(DrawContext dc, java.awt.Rectangle bounds, double opacity, Position pickPosition) { this.layoutManager.setPickSupport(this.pickSupport); this.layoutManager.drawAnnotations(dc, bounds, this.childList, opacity, pickPosition); } - @SuppressWarnings({"UnusedDeclaration"}) protected void beginDrawChildren(DrawContext dc, java.awt.Rectangle bounds) { this.layoutManager.beginDrawAnnotations(dc, bounds); @@ -1051,15 +1042,6 @@ protected java.awt.Rectangle transformByModelview(DrawContext dc, java.awt.Recta return new java.awt.Rectangle((int) origin.x, (int) origin.y, (int) size.x, (int) size.y); } - protected java.awt.Point glPointFromAWTPoint(DrawContext dc, java.awt.Point awtPoint) - { - if (dc.getView() == null || dc.getView().getViewport() == null) - return null; - - java.awt.Rectangle viewport = dc.getView().getViewport(); - return new java.awt.Point(awtPoint.x, viewport.height - awtPoint.y - 1); - } - //**************************************************************// //******************** Text Utilities ************************// //**************************************************************// diff --git a/src/gov/nasa/worldwind/render/AbstractBrowserBalloon.java b/src/gov/nasa/worldwind/render/AbstractBrowserBalloon.java index 9c77cd54fc..a4d6b2bd29 100644 --- a/src/gov/nasa/worldwind/render/AbstractBrowserBalloon.java +++ b/src/gov/nasa/worldwind/render/AbstractBrowserBalloon.java @@ -1731,7 +1731,7 @@ protected void drawResizeControl(DrawContext dc, OrderedBrowserBalloon obb) // Compute the screen rectangle in AWT coordinates (origin top left). Rectangle awtScreenRect = new Rectangle(obb.screenRect.x, - dc.getView().getViewport().height - obb.screenRect.y - obb.screenRect.height, + obb.screenRect.y - obb.screenRect.height, obb.screenRect.width, obb.screenRect.height); Color color = dc.getUniquePickColor(); diff --git a/src/gov/nasa/worldwind/render/DeclutteringTextRenderer.java b/src/gov/nasa/worldwind/render/DeclutteringTextRenderer.java index 81faf5ce86..394e81e879 100644 --- a/src/gov/nasa/worldwind/render/DeclutteringTextRenderer.java +++ b/src/gov/nasa/worldwind/render/DeclutteringTextRenderer.java @@ -36,6 +36,8 @@ import com.jogamp.opengl.*; import com.jogamp.opengl.glu.GLU; import com.jogamp.opengl.glu.gl2.GLUgl2; +import com.jogamp.opengl.util.awt.TextRenderer; + import java.awt.*; import java.awt.geom.*; import java.io.IOException; diff --git a/src/gov/nasa/worldwind/render/DrawContext.java b/src/gov/nasa/worldwind/render/DrawContext.java index 750955b933..c6e8567a5e 100644 --- a/src/gov/nasa/worldwind/render/DrawContext.java +++ b/src/gov/nasa/worldwind/render/DrawContext.java @@ -345,14 +345,14 @@ public interface DrawContext extends WWObject, Disposable Color getClearColor(); /** - * Returns the framebuffer RGB color for a point in AWT screen coordinates, formatted as a pick color code. The red, + * Returns the framebuffer RGB color for a point in GL surface coordinates, formatted as a pick color code. The red, * green, and blue components are each stored as an 8-bit unsigned integer, and packed into bits 0-23 of the * returned integer as follows: bits 16-23 are red, bits 8-15 are green, and bits 0-7 are blue. This format is * consistent with the RGB integers used to create the pick colors in getUniquePickColor. *

* This returns 0 if the point contains the clear color, or is outside this draw context's drawable area. * - * @param point the point to return a color for, in AWT screen coordinates. + * @param point the point to return a color for, in GL surface coordinates. * * @return the RGB color corresponding to the specified point. * @@ -361,7 +361,7 @@ public interface DrawContext extends WWObject, Disposable int getPickColorAtPoint(Point point); /** - * Returns an array of the unique framebuffer RGB colors within a rectangle in AWT screen coordinates, formatted as + * Returns an array of the unique framebuffer RGB colors within a rectangle in GL surface coordinates, formatted as * pick color codes. The red, green, and blue components are each stored as an 8-bit unsigned integer, and packed * into bits 0-23 of the returned integers as follows: bits 16-23 are red, bits 8-15 are green, and bits 0-7 are * blue. This format is consistent with the RGB integers used to create the pick colors in getUniquePickColor. @@ -376,7 +376,7 @@ public interface DrawContext extends WWObject, Disposable * the colors that must be considered by this method and the caller. When specified, these integers must be * formatted exactly as the integers this method returns. * - * @param rectangle the rectangle to return unique colors for, in AWT screen coordinates. + * @param rectangle the rectangle to return unique colors for, in GL surface coordinates. * @param minAndMaxColorCodes an two element array representing the minimum and maximum RGB colors to return. May be * null to specify that all color codes must be returned. * @@ -502,7 +502,7 @@ public interface DrawContext extends WWObject, Disposable SurfaceTileRenderer getGeographicSurfaceTileRenderer(); /** - * Returns the current pick point in AWT screen coordinates. + * Returns the current pick point in GL surface coordinates. * * @return the current pick point, or null if no pick point is available. * @@ -511,7 +511,7 @@ public interface DrawContext extends WWObject, Disposable Point getPickPoint(); /** - * Specifies the current pick point in AWT screen coordinates, or null to indicate that there is no + * Specifies the current pick point in GL surface coordinates, or null to indicate that there is no * pick point. During each pick traversal, layers determine if their contents are drawn at the pick point. If so, * layers add each unique picked object to a PickedObjectList on this draw context by calling {@link * #addPickedObject(gov.nasa.worldwind.pick.PickedObject)}. This list can be accessed by calling {@link @@ -525,7 +525,7 @@ public interface DrawContext extends WWObject, Disposable void setPickPoint(Point pickPoint); /** - * Returns the current pick rectangle in AWT screen coordinates. + * Returns the current pick rectangle in GL surface coordinates. * * @return the current pick rectangle, or null if no pick rectangle is current. * @@ -534,7 +534,7 @@ public interface DrawContext extends WWObject, Disposable Rectangle getPickRectangle(); /** - * Specifies the current pick rectangle in AWT screen coordinates, or null to indicate that there is no + * Specifies the current pick rectangle in GL surface coordinates, or null to indicate that there is no * pick rectangle. During each pick traversal, layers determine if their contents intersect the pick rectangle. If * so, layers add each unique picked object to a PickedObjectList on this draw context by calling {@link * #addObjectInPickRectangle(gov.nasa.worldwind.pick.PickedObject)}. This is list can be accessed by calling {@link @@ -1046,4 +1046,16 @@ public interface DrawContext extends WWObject, Disposable boolean is2DGlobe(); boolean isContinuous2DGlobe(); + + /** + * Convert AWT effective screen location to GL surface location using DPI scaling. + */ + int [] awtPointToGLpoint(Point pt); + + /** + * Convert GL surface coordinate point to AWT device point using DPI scaling. + * @param glPoint + * @return + */ + public Point glPointToAwtPoint(Point glPoint); } diff --git a/src/gov/nasa/worldwind/render/DrawContextImpl.java b/src/gov/nasa/worldwind/render/DrawContextImpl.java index 4c3cf88c92..c24100b162 100644 --- a/src/gov/nasa/worldwind/render/DrawContextImpl.java +++ b/src/gov/nasa/worldwind/render/DrawContextImpl.java @@ -87,15 +87,15 @@ public class DrawContextImpl extends WWObjectImpl implements DrawContext protected boolean pickingMode = false; protected boolean deepPickingMode = false; /** - * Indicates the current pick point in AWT screen coordinates, or null to indicate that there is no + * Indicates the current pick point in GL screen coordinates, or null to indicate that there is no * pick point. Initially null. */ - protected Point pickPoint = null; + private Point pickPoint = null; /** - * Indicates the current pick rectangle in AWT screen coordinates, or null to indicate that there is no + * Indicates the current pick rectangle in GL screen coordinates, or null to indicate that there is no * pick rectangle. Initially null. */ - protected Rectangle pickRect = null; + private Rectangle pickRect = null; protected boolean isOrderedRenderingMode = false; protected boolean preRenderMode = false; protected Point viewportCenterScreenPoint = null; @@ -154,7 +154,8 @@ public OrderedRenderableEntry(OrderedRenderable orderedRenderable, double distan protected PriorityQueue orderedRenderables = new PriorityQueue(100, new Comparator() { - public int compare(OrderedRenderableEntry orA, OrderedRenderableEntry orB) + @Override + public int compare(OrderedRenderableEntry orA, OrderedRenderableEntry orB) { double eA = orA.distanceFromEye; double eB = orB.distanceFromEye; @@ -171,47 +172,56 @@ public int compare(OrderedRenderableEntry orA, OrderedRenderableEntry orB) * * @throws com.jogamp.opengl.GLException - If an OpenGL context is not current when this method is called. */ - public void dispose() + @Override + public void dispose() { this.geographicSurfaceTileRenderer.dispose(); } - public final GL getGL() + @Override + public final GL getGL() { return this.getGLContext().getGL(); } - public final GLU getGLU() + @Override + public final GLU getGLU() { return this.glu; } - public final GLContext getGLContext() + @Override + public final GLContext getGLContext() { return this.glContext; } - public final int getDrawableHeight() + @Override + public final int getDrawableHeight() { return this.getGLDrawable().getSurfaceHeight(); } - public final int getDrawableWidth() + @Override + public final int getDrawableWidth() { return this.getGLDrawable().getSurfaceWidth(); } - public final GLDrawable getGLDrawable() + @Override + public final GLDrawable getGLDrawable() { return this.getGLContext().getGLDrawable(); } - public GLRuntimeCapabilities getGLRuntimeCapabilities() + @Override + public GLRuntimeCapabilities getGLRuntimeCapabilities() { return this.glRuntimeCaps; } - public void setGLRuntimeCapabilities(GLRuntimeCapabilities capabilities) + @Override + public void setGLRuntimeCapabilities(GLRuntimeCapabilities capabilities) { if (capabilities == null) { @@ -223,7 +233,8 @@ public void setGLRuntimeCapabilities(GLRuntimeCapabilities capabilities) this.glRuntimeCaps = capabilities; } - public final void initialize(GLContext glContext) + @Override + public final void initialize(GLContext glContext) { if (glContext == null) { @@ -252,7 +263,8 @@ public final void initialize(GLContext glContext) this.currentLayer = null; } - public final void setModel(Model model) + @Override + public final void setModel(Model model) { this.model = model; if (this.model == null) @@ -263,53 +275,63 @@ public final void setModel(Model model) this.globe = g; } - public final Model getModel() + @Override + public final Model getModel() { return this.model; } - public final LayerList getLayers() + @Override + public final LayerList getLayers() { return this.model.getLayers(); } - public final Sector getVisibleSector() + @Override + public final Sector getVisibleSector() { return this.visibleSector; } - public final void setVisibleSector(Sector s) + @Override + public final void setVisibleSector(Sector s) { // don't check for null - it is possible that no globe is active, no view is active, no sectors visible, etc. this.visibleSector = s; } - public void setSurfaceGeometry(SectorGeometryList surfaceGeometry) + @Override + public void setSurfaceGeometry(SectorGeometryList surfaceGeometry) { this.surfaceGeometry = surfaceGeometry; } - public SectorGeometryList getSurfaceGeometry() + @Override + public SectorGeometryList getSurfaceGeometry() { return surfaceGeometry; } - public final Globe getGlobe() + @Override + public final Globe getGlobe() { return this.globe != null ? this.globe : this.model.getGlobe(); } - public final void setView(View view) + @Override + public final void setView(View view) { this.view = view; } - public final View getView() + @Override + public final View getView() { return this.view; } - public final void setGLContext(GLContext glContext) + @Override + public final void setGLContext(GLContext glContext) { if (glContext == null) { @@ -321,27 +343,32 @@ public final void setGLContext(GLContext glContext) this.glContext = glContext; } - public final double getVerticalExaggeration() + @Override + public final double getVerticalExaggeration() { return verticalExaggeration; } - public final void setVerticalExaggeration(double verticalExaggeration) + @Override + public final void setVerticalExaggeration(double verticalExaggeration) { this.verticalExaggeration = verticalExaggeration; } - public GpuResourceCache getTextureCache() + @Override + public GpuResourceCache getTextureCache() { return this.gpuResourceCache; } - public GpuResourceCache getGpuResourceCache() + @Override + public GpuResourceCache getGpuResourceCache() { return this.gpuResourceCache; } - public void setGpuResourceCache(GpuResourceCache gpuResourceCache) + @Override + public void setGpuResourceCache(GpuResourceCache gpuResourceCache) { if (gpuResourceCache == null) { @@ -353,12 +380,14 @@ public void setGpuResourceCache(GpuResourceCache gpuResourceCache) this.gpuResourceCache = gpuResourceCache; } - public TextRendererCache getTextRendererCache() + @Override + public TextRendererCache getTextRendererCache() { return textRendererCache; } - public void setTextRendererCache(TextRendererCache textRendererCache) + @Override + public void setTextRendererCache(TextRendererCache textRendererCache) { if (textRendererCache == null) { @@ -370,12 +399,14 @@ public void setTextRendererCache(TextRendererCache textRendererCache) this.textRendererCache = textRendererCache; } - public AnnotationRenderer getAnnotationRenderer() + @Override + public AnnotationRenderer getAnnotationRenderer() { return annotationRenderer; } - public void setAnnotationRenderer(AnnotationRenderer ar) + @Override + public void setAnnotationRenderer(AnnotationRenderer ar) { if (ar == null) { @@ -386,57 +417,68 @@ public void setAnnotationRenderer(AnnotationRenderer ar) annotationRenderer = ar; } - public LightingModel getStandardLightingModel() + @Override + public LightingModel getStandardLightingModel() { return standardLighting; } - public void setStandardLightingModel(LightingModel standardLighting) + @Override + public void setStandardLightingModel(LightingModel standardLighting) { this.standardLighting = standardLighting; } - public Point getPickPoint() + @Override + public Point getPickPoint() { return this.pickPoint; } - public void setPickPoint(Point pickPoint) + @Override + public void setPickPoint(Point pickPoint) { - this.pickPoint = pickPoint; + this.pickPoint = pickPoint; } - public Rectangle getPickRectangle() + @Override + public Rectangle getPickRectangle() { return this.pickRect; } - public void setPickRectangle(Rectangle pickRect) + @Override + public void setPickRectangle(Rectangle pickRect) { this.pickRect = pickRect; } - public Point getViewportCenterScreenPoint() + @Override + public Point getViewportCenterScreenPoint() { return viewportCenterScreenPoint; } - public void setViewportCenterScreenPoint(Point viewportCenterScreenPoint) + @Override + public void setViewportCenterScreenPoint(Point viewportCenterScreenPoint) { this.viewportCenterScreenPoint = viewportCenterScreenPoint; } - public Position getViewportCenterPosition() + @Override + public Position getViewportCenterPosition() { return viewportCenterPosition; } - public void setViewportCenterPosition(Position viewportCenterPosition) + @Override + public void setViewportCenterPosition(Position viewportCenterPosition) { this.viewportCenterPosition = viewportCenterPosition; } - public void addPickedObjects(PickedObjectList pickedObjects) + @Override + public void addPickedObjects(PickedObjectList pickedObjects) { if (pickedObjects == null) { @@ -457,7 +499,8 @@ public void addPickedObjects(PickedObjectList pickedObjects) } } - public void addPickedObject(PickedObject pickedObject) + @Override + public void addPickedObject(PickedObject pickedObject) { if (null == pickedObject) { @@ -472,17 +515,20 @@ public void addPickedObject(PickedObject pickedObject) this.pickedObjects.add(pickedObject); } - public PickedObjectList getPickedObjects() + @Override + public PickedObjectList getPickedObjects() { return this.pickedObjects; } - public PickedObjectList getObjectsInPickRectangle() + @Override + public PickedObjectList getObjectsInPickRectangle() { return this.objectsInPickRect; } - public void addObjectInPickRectangle(PickedObject pickedObject) + @Override + public void addObjectInPickRectangle(PickedObject pickedObject) { if (pickedObject == null) { @@ -494,7 +540,8 @@ public void addObjectInPickRectangle(PickedObject pickedObject) this.objectsInPickRect.add(pickedObject); } - public Color getUniquePickColor() + @Override + public Color getUniquePickColor() { this.uniquePickNumber++; @@ -512,7 +559,8 @@ public Color getUniquePickColor() return new Color(this.uniquePickNumber, true); // has alpha } - public Color getUniquePickColorRange(int count) + @Override + public Color getUniquePickColorRange(int count) { if (count < 1) return null; @@ -532,13 +580,15 @@ public Color getUniquePickColorRange(int count) return new Color(range.location, true); // return a pointer to the beginning of the requested range } - public Color getClearColor() + @Override + public Color getClearColor() { return this.clearColor; } /** {@inheritDoc} */ - public int getPickColorAtPoint(Point point) + @Override + public int getPickColorAtPoint(Point point) { if (point == null) { @@ -547,10 +597,8 @@ public int getPickColorAtPoint(Point point) throw new IllegalArgumentException(msg); } - // Translate the point from AWT screen coordinates to OpenGL screen coordinates. - Rectangle viewport = this.getView().getViewport(); int x = point.x; - int y = viewport.height - point.y - 1; + int y = point.y; // Read the framebuffer color at the specified point in OpenGL screen coordinates as a 24-bit RGB value. if (this.pixelColors == null || this.pixelColors.capacity() < 3) @@ -566,7 +614,8 @@ public int getPickColorAtPoint(Point point) } /** {@inheritDoc} */ - public int[] getPickColorsInRectangle(Rectangle rectangle, int[] minAndMaxColorCodes) + @Override + public int[] getPickColorsInRectangle(Rectangle rectangle, int[] minAndMaxColorCodes) { if (rectangle == null) { @@ -577,10 +626,7 @@ public int[] getPickColorsInRectangle(Rectangle rectangle, int[] minAndMaxColorC Rectangle viewport = this.getView().getViewport(); - // Transform the rectangle from AWT screen coordinates to OpenGL screen coordinates and compute its intersection - // with the viewport. Transformation to GL coordinates must be done prior to computing the intersection, because - // the viewport is in GL coordinates. The resultant rectangle represents the area that's valid to read from GL. - Rectangle r = new Rectangle(rectangle.x, viewport.height - rectangle.y - 1, rectangle.width, rectangle.height); + Rectangle r = new Rectangle(rectangle.x, rectangle.y, rectangle.width, rectangle.height); r = r.intersection(viewport); if (r.isEmpty()) // Return null if the rectangle is empty. @@ -641,52 +687,62 @@ public int[] getPickColorsInRectangle(Rectangle rectangle, int[] minAndMaxColorC return array; } - public boolean isPickingMode() + @Override + public boolean isPickingMode() { return this.pickingMode; } - public void enablePickingMode() + @Override + public void enablePickingMode() { this.pickingMode = true; } - public void disablePickingMode() + @Override + public void disablePickingMode() { this.pickingMode = false; } - public boolean isDeepPickingEnabled() + @Override + public boolean isDeepPickingEnabled() { return this.deepPickingMode; } - public void setDeepPickingEnabled(boolean tf) + @Override + public void setDeepPickingEnabled(boolean tf) { this.deepPickingMode = tf; } - public boolean isPreRenderMode() + @Override + public boolean isPreRenderMode() { return preRenderMode; } - public void setPreRenderMode(boolean preRenderMode) + @Override + public void setPreRenderMode(boolean preRenderMode) { this.preRenderMode = preRenderMode; } - public boolean isOrderedRenderingMode() + @Override + public boolean isOrderedRenderingMode() { return this.isOrderedRenderingMode; } - public void setOrderedRenderingMode(boolean tf) + @Override + public void setOrderedRenderingMode(boolean tf) { this.isOrderedRenderingMode = tf; } - public DeclutteringTextRenderer getDeclutteringTextRenderer() + @Override + public DeclutteringTextRenderer getDeclutteringTextRenderer() { return declutteringTextRenderer; } @@ -703,7 +759,8 @@ public boolean isContinuous2DGlobe() return this.globe instanceof Globe2D && ((Globe2D) this.getGlobe()).isContinuous(); } - public void addOrderedRenderable(OrderedRenderable orderedRenderable) + @Override + public void addOrderedRenderable(OrderedRenderable orderedRenderable) { if (null == orderedRenderable) { @@ -716,7 +773,8 @@ public void addOrderedRenderable(OrderedRenderable orderedRenderable) } /** {@inheritDoc} */ - public void addOrderedRenderable(OrderedRenderable orderedRenderable, boolean isBehind) + @Override + public void addOrderedRenderable(OrderedRenderable orderedRenderable, boolean isBehind) { if (null == orderedRenderable) { @@ -734,14 +792,16 @@ public void addOrderedRenderable(OrderedRenderable orderedRenderable, boolean is new OrderedRenderableEntry(orderedRenderable, eyeDistance, System.nanoTime(), this)); } - public OrderedRenderable peekOrderedRenderables() + @Override + public OrderedRenderable peekOrderedRenderables() { OrderedRenderableEntry ore = this.orderedRenderables.peek(); return ore != null ? ore.or : null; } - public OrderedRenderable pollOrderedRenderables() + @Override + public OrderedRenderable pollOrderedRenderables() { OrderedRenderableEntry ore = this.orderedRenderables.poll(); @@ -810,7 +870,8 @@ public ClutterFilter getClutterFilter() return this.clutterFilter; } - public void applyClutterFilter() + @Override + public void applyClutterFilter() { if (this.getClutterFilter() == null) return; @@ -826,7 +887,8 @@ public void applyClutterFilter() // Sort the declutterables front-to-back. Collections.sort(declutterableArray, new Comparator() { - public int compare(OrderedRenderableEntry orA, OrderedRenderableEntry orB) + @Override + public int compare(OrderedRenderableEntry orA, OrderedRenderableEntry orB) { double eA = orA.distanceFromEye; double eB = orB.distanceFromEye; @@ -854,7 +916,8 @@ public int compare(OrderedRenderableEntry orA, OrderedRenderableEntry orB) } /** {@inheritDoc} */ - public void addOrderedSurfaceRenderable(OrderedRenderable orderedRenderable) + @Override + public void addOrderedSurfaceRenderable(OrderedRenderable orderedRenderable) { if (orderedRenderable == null) { @@ -867,7 +930,8 @@ public void addOrderedSurfaceRenderable(OrderedRenderable orderedRenderable) } /** {@inheritDoc} */ - public Queue getOrderedSurfaceRenderables() + @Override + public Queue getOrderedSurfaceRenderables() { return this.orderedSurfaceRenderables; } @@ -903,7 +967,8 @@ public Queue getOrderedSurfaceRenderables() // } // } - public void drawUnitQuad() + @Override + public void drawUnitQuad() { GL2 gl = this.getGL().getGL2(); // GL initialization checks for GL2 compatibility. @@ -915,7 +980,8 @@ public void drawUnitQuad() gl.glEnd(); } - public void drawUnitQuad(TextureCoords texCoords) + @Override + public void drawUnitQuad(TextureCoords texCoords) { GL2 gl = this.getGL().getGL2(); // GL initialization checks for GL2 compatibility. @@ -931,7 +997,8 @@ public void drawUnitQuad(TextureCoords texCoords) gl.glEnd(); } - public void drawUnitQuadOutline() + @Override + public void drawUnitQuadOutline() { GL2 gl = this.getGL().getGL2(); // GL initialization checks for GL2 compatibility. @@ -943,7 +1010,8 @@ public void drawUnitQuadOutline() gl.glEnd(); } - public void drawNormals(float length, FloatBuffer vBuf, FloatBuffer nBuf) + @Override + public void drawNormals(float length, FloatBuffer vBuf, FloatBuffer nBuf) { if (vBuf == null || nBuf == null) return; @@ -971,7 +1039,8 @@ public void drawNormals(float length, FloatBuffer vBuf, FloatBuffer nBuf) gl.glEnd(); } - public Vec4 getPointOnTerrain(Angle latitude, Angle longitude) + @Override + public Vec4 getPointOnTerrain(Angle latitude, Angle longitude) { if (latitude == null || longitude == null) { @@ -997,28 +1066,33 @@ public Vec4 getPointOnTerrain(Angle latitude, Angle longitude) return null; } - public SurfaceTileRenderer getGeographicSurfaceTileRenderer() + @Override + public SurfaceTileRenderer getGeographicSurfaceTileRenderer() { return this.geographicSurfaceTileRenderer; } - public Collection getPerFrameStatistics() + @Override + public Collection getPerFrameStatistics() { return this.perFrameStatistics; } - public void setPerFrameStatisticsKeys(Set statKeys, Collection stats) + @Override + public void setPerFrameStatisticsKeys(Set statKeys, Collection stats) { this.perFrameStatisticsKeys = statKeys; this.perFrameStatistics = stats; } - public Set getPerFrameStatisticsKeys() + @Override + public Set getPerFrameStatisticsKeys() { return perFrameStatisticsKeys; } - public void setPerFrameStatistic(String key, String displayName, Object value) + @Override + public void setPerFrameStatistic(String key, String displayName, Object value) { if (this.perFrameStatistics == null || this.perFrameStatisticsKeys == null) return; @@ -1041,7 +1115,8 @@ public void setPerFrameStatistic(String key, String displayName, Object value) this.perFrameStatistics.add(new PerformanceStatistic(key, displayName, value)); } - public void setPerFrameStatistics(Collection stats) + @Override + public void setPerFrameStatistics(Collection stats) { if (stats == null) { @@ -1059,17 +1134,20 @@ public void setPerFrameStatistics(Collection stats) } } - public long getFrameTimeStamp() + @Override + public long getFrameTimeStamp() { return this.frameTimestamp; } - public void setFrameTimeStamp(long frameTimeStamp) + @Override + public void setFrameTimeStamp(long frameTimeStamp) { this.frameTimestamp = frameTimeStamp; } - public List getVisibleSectors(double[] resolutions, long timeLimit, Sector sector) + @Override + public List getVisibleSectors(double[] resolutions, long timeLimit, Sector sector) { if (resolutions == null) { @@ -1106,19 +1184,22 @@ else if (this.visibleSectors.getSectorSize() == resolutions[resolutions.length - return this.visibleSectors.getSectors(); } - public void setCurrentLayer(Layer layer) + @Override + public void setCurrentLayer(Layer layer) { this.currentLayer = layer; } - public Layer getCurrentLayer() + @Override + public Layer getCurrentLayer() { return this.currentLayer; } protected LinkedHashMap credits = new LinkedHashMap(); - public void addScreenCredit(ScreenCredit credit) + @Override + public void addScreenCredit(ScreenCredit credit) { if (credit == null) { @@ -1130,27 +1211,32 @@ public void addScreenCredit(ScreenCredit credit) this.credits.put(credit, this.frameTimestamp); } - public Map getScreenCredits() + @Override + public Map getScreenCredits() { return this.credits; } - public int getRedrawRequested() + @Override + public int getRedrawRequested() { return redrawRequested; } - public void setRedrawRequested(int redrawRequested) + @Override + public void setRedrawRequested(int redrawRequested) { this.redrawRequested = redrawRequested; } - public PickPointFrustumList getPickFrustums() + @Override + public PickPointFrustumList getPickFrustums() { return this.pickFrustumList; } - public void setPickPointFrustumDimension(Dimension dim) + @Override + public void setPickPointFrustumDimension(Dimension dim) { if (dim == null) { @@ -1169,25 +1255,20 @@ public void setPickPointFrustumDimension(Dimension dim) this.pickPointFrustumDimension = new Dimension(dim); } - public Dimension getPickPointFrustumDimension() + @Override + public Dimension getPickPointFrustumDimension() { return this.pickPointFrustumDimension; } - public void addPickPointFrustum() + @Override + public void addPickPointFrustum() { //Compute the current picking frustum if (getPickPoint() != null) { - Rectangle viewport = getView().getViewport(); - - double viewportWidth = viewport.getWidth() <= 0.0 ? 1.0 : viewport.getWidth(); - double viewportHeight = viewport.getHeight() <= 0.0 ? 1.0 : viewport.getHeight(); - - //Get the pick point and translate screen center to zero Point ptCenter = new Point(getPickPoint()); - ptCenter.y = (int) viewportHeight - ptCenter.y; - ptCenter.translate((int) (-viewportWidth / 2), (int) (-viewportHeight / 2)); + ptCenter.translate(-viewportCenterScreenPoint.x, -viewportCenterScreenPoint.y); //Number of pixels around pick point to include in frustum int offsetX = pickPointFrustumDimension.width / 2; @@ -1199,7 +1280,9 @@ public void addPickPointFrustum() //Compute the distance to the near plane in screen coordinates double width = getView().getFieldOfView().tanHalfAngle() * getView().getNearClipDistance(); - double x = width / (viewportWidth / 2.0); + double viewportWidth = getView().getViewport().getWidth(); + if (viewportWidth <= 0.0) viewportWidth = 1.0; + double x = width / (viewportWidth/2); double screenDist = getView().getNearClipDistance() / x; //Create the four vectors that define the top-left, top-right, bottom-left, and bottom-right vectors @@ -1213,10 +1296,10 @@ public void addPickPointFrustum() getView().getNearClipDistance(), getView().getFarClipDistance()); //Create the screen rectangle associated with this frustum - Rectangle rectScreen = new Rectangle(getPickPoint().x - offsetX, - (int) viewportHeight - getPickPoint().y - offsetY, - pickPointFrustumDimension.width, - pickPointFrustumDimension.height); + Rectangle rectScreen = new Rectangle(getPickPoint().x - offsetX + 1, + getPickPoint().y - offsetY - 1, + pickPointFrustumDimension.width, + pickPointFrustumDimension.height); //Transform the frustum to Model Coordinates Matrix modelviewTranspose = getView().getModelviewMatrix().getTranspose(); @@ -1227,24 +1310,21 @@ public void addPickPointFrustum() } } - public void addPickRectangleFrustum() + @Override + public void addPickRectangleFrustum() { // Do nothing if the pick rectangle is either null or has zero dimension. if (this.getPickRectangle() == null || this.getPickRectangle().isEmpty()) return; - View view = this.getView(); - - Rectangle viewport = view.getViewport(); - double viewportWidth = viewport.getWidth() <= 0.0 ? 1.0 : viewport.getWidth(); - double viewportHeight = viewport.getHeight() <= 0.0 ? 1.0 : viewport.getHeight(); - - // Get the pick rectangle, transform it from AWT screen coordinates to OpenGL screen coordinates, then translate + // Get the pick rectangle, transform it from GL surface coordinates to OpenGL screen coordinates, then translate // it such that the screen's center is at the origin. Rectangle pr = new Rectangle(this.getPickRectangle()); - pr.y = (int) viewportHeight - pr.y; - pr.translate((int) (-viewportWidth / 2), (int) (-viewportHeight / 2)); + pr.translate(-viewportCenterScreenPoint.x, -viewportCenterScreenPoint.y); + double viewportWidth = view.getViewport().getWidth(); + if (viewportWidth <= 0.0) viewportWidth = 1.0; + // Create the four vectors that define the top-left, top-right, bottom-left, and bottom-right corners of the // pick rectangle in screen coordinates. double screenDist = viewportWidth / (2 * view.getFieldOfView().tanHalfAngle()); @@ -1265,22 +1345,24 @@ public void addPickRectangleFrustum() // Create the screen rectangle in OpenGL screen coordinates associated with this frustum. We translate the // specified pick rectangle from AWT coordinates to GL coordinates by inverting the y axis. Rectangle screenRect = new Rectangle(this.getPickRectangle()); - screenRect.y = (int) viewportHeight - screenRect.y; this.pickFrustumList.add(new PickPointFrustum(frustum, screenRect)); } - public Collection getRenderingExceptions() + @Override + public Collection getRenderingExceptions() { return this.renderingExceptions; } - public void setRenderingExceptions(Collection exceptions) + @Override + public void setRenderingExceptions(Collection exceptions) { this.renderingExceptions = exceptions; } - public void addRenderingException(Throwable t) + @Override + public void addRenderingException(Throwable t) { // If the renderingExceptions Collection is non-null, it's used as the data structure that accumulates rendering // exceptions. Otherwise this DrawContext ignores all rendering exceptions passed to this method. @@ -1297,7 +1379,8 @@ public void addRenderingException(Throwable t) this.renderingExceptions.add(t); } - public void pushProjectionOffest(Double offset) + @Override + public void pushProjectionOffest(Double offset) { // Modify the projection transform to shift the depth values slightly toward the camera in order to // ensure the lines are selected during depth buffering. @@ -1313,7 +1396,8 @@ public void pushProjectionOffest(Double offset) gl.glLoadMatrixf(pm, 0); } - public void popProjectionOffest() + @Override + public void popProjectionOffest() { GL2 gl = this.getGL().getGL2(); // GL initialization checks for GL2 compatibility. @@ -1325,7 +1409,8 @@ public void popProjectionOffest() public static final float DEFAULT_DEPTH_OFFSET_FACTOR = 1f; public static final float DEFAULT_DEPTH_OFFSET_UNITS = 1f; - public void drawOutlinedShape(OutlinedShape renderer, Object shape) + @Override + public void drawOutlinedShape(OutlinedShape renderer, Object shape) { // Draw the outlined shape using a multiple pass algorithm. The motivation for this algorithm is twofold: // @@ -1433,7 +1518,8 @@ public void drawOutlinedShape(OutlinedShape renderer, Object shape) } } - public void beginStandardLighting() + @Override + public void beginStandardLighting() { if (this.standardLighting != null) { @@ -1442,7 +1528,8 @@ public void beginStandardLighting() } } - public void endStandardLighting() + @Override + public void endStandardLighting() { if (this.standardLighting != null) { @@ -1450,7 +1537,8 @@ public void endStandardLighting() } } - public boolean isSmall(Extent extent, int numPixels) + @Override + public boolean isSmall(Extent extent, int numPixels) { return extent != null && extent.getDiameter() <= numPixels * this.getView().computePixelSizeAtDistance( // burkey couldnt we make this minimum dimension @@ -1458,29 +1546,34 @@ public boolean isSmall(Extent extent, int numPixels) extent.getCenter())); // -- so box could return small when one dim is narrow? } // i see really skinny telephone poles that dont need to be rendered at distance but are tall - public Terrain getTerrain() + @Override + public Terrain getTerrain() { return this.terrain; } - public Vec4 computeTerrainPoint(Angle lat, Angle lon, double offset) + @Override + public Vec4 computeTerrainPoint(Angle lat, Angle lon, double offset) { return this.getTerrain().getSurfacePoint(lat, lon, offset); } protected Terrain terrain = new Terrain() { - public Globe getGlobe() + @Override + public Globe getGlobe() { return DrawContextImpl.this.getGlobe(); } - public double getVerticalExaggeration() + @Override + public double getVerticalExaggeration() { return DrawContextImpl.this.getVerticalExaggeration(); } - public Vec4 getSurfacePoint(Position position) + @Override + public Vec4 getSurfacePoint(Position position) { if (position == null) { @@ -1504,7 +1597,8 @@ public Vec4 getSurfacePoint(Position position) return pt; } - public Vec4 getSurfacePoint(Angle latitude, Angle longitude, double metersOffset) + @Override + public Vec4 getSurfacePoint(Angle latitude, Angle longitude, double metersOffset) { if (latitude == null || longitude == null) { @@ -1529,7 +1623,8 @@ public Vec4 getSurfacePoint(Angle latitude, Angle longitude, double metersOffset return pt; } - public Intersection[] intersect(Position pA, Position pB) + @Override + public Intersection[] intersect(Position pA, Position pB) { SectorGeometryList sectorGeometry = DrawContextImpl.this.getSurfaceGeometry(); if (sectorGeometry == null) @@ -1544,7 +1639,8 @@ public Intersection[] intersect(Position pA, Position pB) return sectorGeometry.intersect(new Line(ptA, ptB.subtract3(ptA))); } - public Intersection[] intersect(Position pA, Position pB, int altitudeMode) + @Override + public Intersection[] intersect(Position pA, Position pB, int altitudeMode) { if (pA == null || pB == null) { @@ -1570,7 +1666,8 @@ else if (altitudeMode == WorldWind.CLAMP_TO_GROUND) return this.intersect(new Position(pA, altitudeA), new Position(pB, altitudeB)); } - public Double getElevation(LatLon location) + @Override + public Double getElevation(LatLon location) { if (location == null) { @@ -1589,25 +1686,29 @@ public Double getElevation(LatLon location) } }; - public void restoreDefaultBlending() + @Override + public void restoreDefaultBlending() { this.getGL().glBlendFunc(GL.GL_ONE, GL.GL_ZERO); this.getGL().glDisable(GL.GL_BLEND); } - public void restoreDefaultCurrentColor() + @Override + public void restoreDefaultCurrentColor() { GL2 gl = this.getGL().getGL2(); // GL initialization checks for GL2 compatibility. gl.glColor4f(1, 1, 1, 1); } - public void restoreDefaultDepthTesting() + @Override + public void restoreDefaultDepthTesting() { this.getGL().glEnable(GL.GL_DEPTH_TEST); this.getGL().glDepthMask(true); } - public Vec4 computePointFromPosition(Position position, int altitudeMode) + @Override + public Vec4 computePointFromPosition(Position position, int altitudeMode) { if (position == null) { @@ -1636,4 +1737,32 @@ else if (altitudeMode == WorldWind.RELATIVE_TO_GROUND) return point; } + + /** {@inheritDoc} */ + @Override + public int [] awtPointToGLpoint(Point pt) { + if (pt == null) return null; + + int [] awtPt = { pt.x, pt.y }; + if (glContext == null) return awtPt; + + GLDrawable drawable = glContext.getGLDrawable(); + if (drawable == null) return awtPt; + + // Convert to GL surface coordinates + int [] glSurfacePt = drawable.getNativeSurface().convertToPixelUnits(awtPt); + int glSurfaceHeight = drawable.getSurfaceHeight(); + glSurfacePt[1] = glSurfaceHeight-1 - glSurfacePt[1]; + return glSurfacePt; + } + + public Point glPointToAwtPoint(Point glPoint) { + GLDrawable drawable = glContext.getGLDrawable(); + if (drawable == null) return glPoint; + + final int viewportHeight = getView().getViewport().height; + int [] glPt = { glPoint.x, viewportHeight-1 - glPoint.y }; + getGLDrawable().getNativeSurface().convertToWindowUnits(glPt); + return new Point(glPt[0], glPt[1]); + } } diff --git a/src/gov/nasa/worldwind/render/GeographicTextRenderer.java b/src/gov/nasa/worldwind/render/GeographicTextRenderer.java index a362b387dc..d3aa21fa5d 100644 --- a/src/gov/nasa/worldwind/render/GeographicTextRenderer.java +++ b/src/gov/nasa/worldwind/render/GeographicTextRenderer.java @@ -38,6 +38,8 @@ import com.jogamp.opengl.*; import com.jogamp.opengl.glu.GLU; import com.jogamp.opengl.glu.gl2.GLUgl2; +import com.jogamp.opengl.util.awt.TextRenderer; + import java.awt.*; import java.awt.geom.*; import java.io.IOException; diff --git a/src/gov/nasa/worldwind/render/MultiLineTextRenderer.java b/src/gov/nasa/worldwind/render/MultiLineTextRenderer.java index d8677398b8..201b35eb64 100644 --- a/src/gov/nasa/worldwind/render/MultiLineTextRenderer.java +++ b/src/gov/nasa/worldwind/render/MultiLineTextRenderer.java @@ -33,6 +33,8 @@ import gov.nasa.worldwind.util.*; import com.jogamp.opengl.*; +import com.jogamp.opengl.util.awt.TextRenderer; + import java.awt.*; import java.awt.geom.*; import java.util.*; diff --git a/src/gov/nasa/worldwind/render/Path.java b/src/gov/nasa/worldwind/render/Path.java index dbb8d5fef5..a72fa785a4 100644 --- a/src/gov/nasa/worldwind/render/Path.java +++ b/src/gov/nasa/worldwind/render/Path.java @@ -569,7 +569,7 @@ public PickedObject getTopObject(DrawContext dc, Point pickPoint) { * AVKey.ORDINAL_LIST. * * @param dc the draw context which receives the picked objects. - * @param pickRect the rectangle in AWT screen coordinates. + * @param pickRect the rectangle in GL surface coordinates. * @param layer the layer associated with the picked objects. */ @SuppressWarnings({"unchecked"}) diff --git a/src/gov/nasa/worldwind/render/PointPlacemark.java b/src/gov/nasa/worldwind/render/PointPlacemark.java index 93c6e2d5c8..9ac04e0b57 100644 --- a/src/gov/nasa/worldwind/render/PointPlacemark.java +++ b/src/gov/nasa/worldwind/render/PointPlacemark.java @@ -40,6 +40,8 @@ import gov.nasa.worldwind.util.*; import com.jogamp.opengl.*; +import com.jogamp.opengl.util.awt.TextRenderer; + import javax.xml.stream.*; import java.awt.*; import java.awt.geom.*; diff --git a/src/gov/nasa/worldwind/render/ScreenAnnotationBalloon.java b/src/gov/nasa/worldwind/render/ScreenAnnotationBalloon.java index 82dbae6710..863a50d62c 100644 --- a/src/gov/nasa/worldwind/render/ScreenAnnotationBalloon.java +++ b/src/gov/nasa/worldwind/render/ScreenAnnotationBalloon.java @@ -68,7 +68,8 @@ public ScreenAnnotationBalloon(String text, Point point) } /** {@inheritDoc} */ - protected ScreenAnnotation createAnnotation() + @Override + protected ScreenAnnotation createAnnotation() { ScreenAnnotation annotation = new ScreenAnnotation(this.getDecodedText(), this.screenPoint); @@ -79,22 +80,22 @@ protected ScreenAnnotation createAnnotation() } /** {@inheritDoc} */ - protected ScreenAnnotation getAnnotation() + @Override + protected ScreenAnnotation getAnnotation() { return this.annotation; } /** {@inheritDoc} */ - protected void computePosition(DrawContext dc) + @Override + protected void computePosition(DrawContext dc) { - Rectangle viewport = dc.getView().getViewport(); - - int y = (int) viewport.getHeight() - this.screenPoint.y - 1; - this.getAnnotation().setScreenPoint(new Point(this.screenPoint.x, y)); + this.getAnnotation().setScreenPoint(new Point(this.screenPoint)); } /** {@inheritDoc} */ - public void setScreenLocation(Point point) + @Override + public void setScreenLocation(Point point) { if (point == null) { @@ -107,7 +108,8 @@ public void setScreenLocation(Point point) } /** {@inheritDoc} */ - public Point getScreenLocation() + @Override + public Point getScreenLocation() { return this.screenPoint; } diff --git a/src/gov/nasa/worldwind/render/ScreenBrowserBalloon.java b/src/gov/nasa/worldwind/render/ScreenBrowserBalloon.java index f90914b995..65d1660ca4 100644 --- a/src/gov/nasa/worldwind/render/ScreenBrowserBalloon.java +++ b/src/gov/nasa/worldwind/render/ScreenBrowserBalloon.java @@ -82,13 +82,15 @@ protected OrderedBrowserBalloon createOrderedRenderable() } /** {@inheritDoc} */ - public Point getScreenLocation() + @Override + public Point getScreenLocation() { return this.screenLocation; } /** {@inheritDoc} */ - public void setScreenLocation(Point point) + @Override + public void setScreenLocation(Point point) { if (point == null) { @@ -111,7 +113,8 @@ public void setScreenLocation(Point point) * * @param dc the current draw context. */ - protected void computeBalloonPoints(DrawContext dc, OrderedBrowserBalloon obb) + @Override + protected void computeBalloonPoints(DrawContext dc, OrderedBrowserBalloon obb) { this.screenOffset = null; obb.screenRect = null; @@ -130,12 +133,11 @@ protected void computeBalloonPoints(DrawContext dc, OrderedBrowserBalloon obb) // bottom left). Note: The screen offset denotes how to place the screen reference point relative to the frame. // For example, an offset of (-10, -10) in pixels places the reference point below and to the left of the frame. // Since the screen reference point is fixed, the frame appears to move relative to the reference point. - int y = dc.getView().getViewport().height - this.screenLocation.y; - obb.screenRect = new Rectangle(this.screenLocation.x - this.screenOffset.x, y - this.screenOffset.y, + obb.screenRect = new Rectangle(this.screenLocation.x - this.screenOffset.x, this.screenLocation.y - this.screenOffset.y, size.width, size.height); // Compute the screen extent as the rectangle containing the balloon's screen rectangle and its screen point. obb.screenExtent = new Rectangle(obb.screenRect); - obb.screenExtent.add(this.screenLocation.x, y); + obb.screenExtent.add(this.screenLocation.x, this.screenLocation.y); // Compute the pickable screen extent as the screen extent, plus the width of the balloon's pickable outline. // This extent is used during picking to ensure that the balloon's outline is pickable when it exceeds the // balloon's screen extent. @@ -147,7 +149,8 @@ protected void computeBalloonPoints(DrawContext dc, OrderedBrowserBalloon obb) } /** {@inheritDoc} */ - protected void setupDepthTest(DrawContext dc, OrderedBrowserBalloon obb) + @Override + protected void setupDepthTest(DrawContext dc, OrderedBrowserBalloon obb) { dc.getGL().glDisable(GL.GL_DEPTH_TEST); } diff --git a/src/gov/nasa/worldwind/render/ScreenCredit.java b/src/gov/nasa/worldwind/render/ScreenCredit.java index e4a38a4d03..3e4c0533e6 100644 --- a/src/gov/nasa/worldwind/render/ScreenCredit.java +++ b/src/gov/nasa/worldwind/render/ScreenCredit.java @@ -47,6 +47,4 @@ public interface ScreenCredit extends Renderable void setLink(String link); String getLink(); - - public void pick(DrawContext dc, java.awt.Point pickPoint); } diff --git a/src/gov/nasa/worldwind/render/ScreenCreditController.java b/src/gov/nasa/worldwind/render/ScreenCreditController.java index aa2ae11949..d060ecc0e4 100644 --- a/src/gov/nasa/worldwind/render/ScreenCreditController.java +++ b/src/gov/nasa/worldwind/render/ScreenCreditController.java @@ -70,7 +70,8 @@ public ScreenCreditController(WorldWindow wwd) wwd.addSelectListener(this); } - public void dispose() + @Override + public void dispose() { wwd.removeSelectListener(this); if (wwd.getSceneController() == this) @@ -87,7 +88,7 @@ public void setEnabled(boolean enabled) this.enabled = enabled; } - public void pick(DrawContext dc, Point pickPoint) + public void pick(DrawContext dc, @SuppressWarnings("unused") Point pickPoint) { if (dc == null) { @@ -113,13 +114,13 @@ public void pick(DrawContext dc, Point pickPoint) Rectangle viewport = new Rectangle(x, y, creditWidth, creditHeight); credit.setViewport(viewport); - credit.pick(dc, pickPoint); x += (separation + creditWidth); } } - public void render(DrawContext dc) + @Override + public void render(DrawContext dc) { if (dc == null) { @@ -136,7 +137,7 @@ public void render(DrawContext dc) Set> credits = dc.getScreenCredits().entrySet(); - int y = dc.getView().getViewport().height - (bottomMargin + creditHeight / 2); + int y = bottomMargin + creditHeight / 2; int x = leftMargin + creditWidth / 2; for (Map.Entry entry : credits) @@ -156,7 +157,8 @@ public void render(DrawContext dc) } } - public void selected(SelectEvent event) + @Override + public void selected(SelectEvent event) { if (event.getMouseEvent() != null && event.getMouseEvent().isConsumed()) return; diff --git a/src/gov/nasa/worldwind/render/ScreenImage.java b/src/gov/nasa/worldwind/render/ScreenImage.java index 69c33b5cb7..488d283002 100644 --- a/src/gov/nasa/worldwind/render/ScreenImage.java +++ b/src/gov/nasa/worldwind/render/ScreenImage.java @@ -78,13 +78,6 @@ public class ScreenImage extends WWObjectImpl implements Renderable, Exportable * is computed in computeOffsets and used in draw Initially null. */ protected Point screenLocation; - /** - * Indicates the location of this screen image in the viewport (on the screen) in AWT coordinates. This property is - * assigned in setScreenLocation and computeOffsets. In computeOffsets, this - * is computed by converting the screenLocation from OpenGL coordinates to AWT coordinates. Initially - * null. - */ - protected Point awtScreenLocation; protected double dx; protected double dy; protected Layer pickLayer; @@ -122,7 +115,7 @@ public void render(DrawContext dc) */ public Point getScreenLocation() { - return this.awtScreenLocation; + return this.screenLocation; } /** @@ -136,7 +129,7 @@ public Point getScreenLocation() public Point getScreenLocation(DrawContext dc) { this.computeOffsets(dc); - return this.awtScreenLocation; + return this.screenLocation; } /** @@ -151,17 +144,16 @@ public Point getScreenLocation(DrawContext dc) */ public void setScreenLocation(Point screenLocation) { - // Use units PIXELS for the X screen offset, and and INSET_PIXELS for the Y screen offset. The Offset is in - // OpenGL coordinates with the origin in the lower-left corner, but the Point is in AWT coordinates with the - // origin in the upper-left corner. This offset translates the origin from the lower-left to the upper-left - // corner. - this.screenOffset = new Offset(screenLocation.getX(), screenLocation.getY(), AVKey.PIXELS, AVKey.INSET_PIXELS); + // Use units PIXELS for the X screen offset, and and PIXELS for the Y screen offset. The Offset is in + // OpenGL coordinates with the origin in the lower-left corner, as is the Point. This offset + // translates the origin from the lower-left to the upper-left corner. + this.screenOffset = new Offset(screenLocation.getX(), screenLocation.getY(), AVKey.PIXELS, AVKey.PIXELS); this.imageOffset = new Offset(0.5, 0.5, AVKey.FRACTION, AVKey.FRACTION); // Set cached screen location to the initial screen location so that it can be retrieved if getScreenLocation() // is called before the image is rendered. This maintains backward compatibility with the previous behavior of // ScreenImage. - this.awtScreenLocation = new Point(screenLocation); + this.screenLocation = new Point(screenLocation); } /** @@ -544,12 +536,7 @@ else if (this.getImageSource() == null) // If no image source is set, draw a rec { this.screenLocation = new Point(viewportWidth / 2, viewportHeight / 2); } - - // Convert the screen location from OpenGL to AWT coordinates and store the result in awtScreenLocation. The - // awtScreenLocation property is used in getScreenLocation to indicate the screen location in AWT - // coordinates. - this.awtScreenLocation = new Point(this.screenLocation.x, viewportHeight - this.screenLocation.y); - + Point.Double overlayPoint; if (this.imageOffset != null) overlayPoint = this.imageOffset.computeOffset(this.width, this.height, null, null); diff --git a/src/gov/nasa/worldwind/render/SurfaceText.java b/src/gov/nasa/worldwind/render/SurfaceText.java index bdb5490b3a..74386e9aae 100644 --- a/src/gov/nasa/worldwind/render/SurfaceText.java +++ b/src/gov/nasa/worldwind/render/SurfaceText.java @@ -36,6 +36,8 @@ import gov.nasa.worldwind.util.*; import com.jogamp.opengl.GL2; +import com.jogamp.opengl.util.awt.TextRenderer; + import java.awt.*; import java.awt.geom.*; import java.util.Arrays; diff --git a/src/gov/nasa/worldwind/render/TextRenderer.java b/src/gov/nasa/worldwind/render/TextRenderer.java deleted file mode 100644 index 7ed52bbb85..0000000000 --- a/src/gov/nasa/worldwind/render/TextRenderer.java +++ /dev/null @@ -1,2095 +0,0 @@ -/* - * Copyright 2006-2009, 2017, 2020 United States Government, as represented by the - * Administrator of the National Aeronautics and Space Administration. - * All rights reserved. - * - * The NASA World Wind Java (WWJ) platform is licensed under the Apache License, - * Version 2.0 (the "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * NASA World Wind Java (WWJ) also contains the following 3rd party Open Source - * software: - * - * Jackson Parser – Licensed under Apache 2.0 - * GDAL – Licensed under MIT - * JOGL – Licensed under Berkeley Software Distribution (BSD) - * Gluegen – Licensed under Berkeley Software Distribution (BSD) - * - * A complete listing of 3rd Party software notices and licenses included in - * NASA World Wind Java (WWJ) can be found in the WorldWindJava-v2.2 3rd-party - * notices and licenses PDF found in code directory. - */ -/* - * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. - * Copyright (c) 2010 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution 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 Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed or intended for use - * in the design, construction, operation or maintenance of any nuclear - * facility. - * - * Sun gratefully acknowledges that this software was originally authored - * and developed by Kenneth Bradley Russell and Christopher John Kline. - */ -/** - * @version $Id: TextRenderer.java 2387 2014-10-15 20:25:02Z tgaskins $ - */ - -package gov.nasa.worldwind.render; - -import com.jogamp.common.nio.Buffers; -import com.jogamp.opengl.GLExtensions; -import com.jogamp.opengl.util.FPSAnimator; -import com.jogamp.opengl.util.awt.TextureRenderer; -import com.jogamp.opengl.util.packrect.*; -import com.jogamp.opengl.util.texture.TextureCoords; -import jogamp.opengl.Debug; - -import com.jogamp.opengl.*; -import com.jogamp.opengl.awt.GLCanvas; -import com.jogamp.opengl.glu.GLU; -import java.awt.*; -import java.awt.event.*; -import java.awt.font.*; -import java.awt.geom.*; -import java.nio.*; -import java.text.CharacterIterator; -import java.util.*; -import java.util.List; - -// For debugging purposes - - -/** Renders bitmapped Java 2D text into an OpenGL window with high - performance, full Unicode support, and a simple API. Performs - appropriate caching of text rendering results in an OpenGL texture - internally to avoid repeated font rasterization. The caching is - completely automatic, does not require any user intervention, and - has no visible controls in the public API.

- - Using the {@link TextRenderer TextRenderer} is simple. Add a - "TextRenderer renderer;" field to your {@link - com.jogamp.opengl.GLEventListener GLEventListener}. In your {@link - com.jogamp.opengl.GLEventListener#init init} method, add: - -

-    renderer = new TextRenderer(new Font("SansSerif", Font.BOLD, 36));
-    
- -

In the {@link com.jogamp.opengl.GLEventListener#display display} method of your - {@link com.jogamp.opengl.GLEventListener GLEventListener}, add: -

-    renderer.beginRendering(drawable.getWidth(), drawable.getHeight());
-    // optionally set the color
-    renderer.setColor(1.0f, 0.2f, 0.2f, 0.8f);
-    renderer.draw("Text to draw", xPosition, yPosition);
-    // ... more draw commands, color changes, etc.
-    renderer.endRendering();
-    
- - Unless you are sharing textures and display lists between OpenGL - contexts, you do not need to call the {@link #dispose dispose} - method of the TextRenderer; the OpenGL resources it uses - internally will be cleaned up automatically when the OpenGL - context is destroyed.

- - Note that the TextRenderer may cause the vertex and texture - coordinate array buffer bindings to change, or to be unbound. This - is important to note if you are using Vertex Buffer Objects (VBOs) - in your application.

- - Internally, the renderer uses a rectangle packing algorithm to - pack both glyphs and full Strings' rendering results (which are - variable size) onto a larger OpenGL texture. The internal backing - store is maintained using a {@link - com.jogamp.opengl.util.awt.TextureRenderer TextureRenderer}. A least - recently used (LRU) algorithm is used to discard previously - rendered strings; the specific algorithm is undefined, but is - currently implemented by flushing unused Strings' rendering - results every few hundred rendering cycles, where a rendering - cycle is defined as a pair of calls to {@link #beginRendering - beginRendering} / {@link #endRendering endRendering}. - - @author John Burkey - @author Kenneth Russell -*/ -public class TextRenderer { - private static final boolean DEBUG; - - static { - Debug.initSingleton(); - DEBUG = Debug.isPropertyDefined("jogl.debug.TextRenderer", true); - } - - // These are occasionally useful for more in-depth debugging - private static boolean DISABLE_GLYPH_CACHE = false; - private static final boolean DRAW_BBOXES = false; - static - { - String arg = System.getProperty("gov.nasa.worldwind.textrender.useglyphcache"); - if (arg != null && arg.toLowerCase().startsWith("f")) - DISABLE_GLYPH_CACHE = true; - } - - static final int kSize = 256; - - // Every certain number of render cycles, flush the strings which - // haven't been used recently - private static final int CYCLES_PER_FLUSH = 100; - - // The amount of vertical dead space on the backing store before we - // force a compaction - private static final float MAX_VERTICAL_FRAGMENTATION = 0.7f; - static final int kQuadsPerBuffer = 100; - static final int kCoordsPerVertVerts = 3; - static final int kCoordsPerVertTex = 2; - static final int kVertsPerQuad = 4; - static final int kTotalBufferSizeVerts = kQuadsPerBuffer * kVertsPerQuad; - static final int kTotalBufferSizeCoordsVerts = kQuadsPerBuffer * kVertsPerQuad * kCoordsPerVertVerts; - static final int kTotalBufferSizeCoordsTex = kQuadsPerBuffer * kVertsPerQuad * kCoordsPerVertTex; - static final int kTotalBufferSizeBytesVerts = kTotalBufferSizeCoordsVerts * 4; - static final int kTotalBufferSizeBytesTex = kTotalBufferSizeCoordsTex * 4; - static final int kSizeInBytes_OneVertices_VertexData = kCoordsPerVertVerts * 4; - static final int kSizeInBytes_OneVertices_TexData = kCoordsPerVertTex * 4; - private final Font font; - private final boolean antialiased; - private final boolean useFractionalMetrics; - - // Whether we're attempting to use automatic mipmap generation support - private boolean mipmap; - private RectanglePacker packer; - private boolean haveMaxSize; - private final RenderDelegate renderDelegate; - private TextureRenderer cachedBackingStore; - private Graphics2D cachedGraphics; - private FontRenderContext cachedFontRenderContext; - private final Map stringLocations = new HashMap(); - private final GlyphProducer mGlyphProducer; - - private int numRenderCycles; - - // Need to keep track of whether we're in a beginRendering() / - // endRendering() cycle so we can re-enter the exact same state if - // we have to reallocate the backing store - private boolean inBeginEndPair; - private boolean isOrthoMode; - private int beginRenderingWidth; - private int beginRenderingHeight; - private boolean beginRenderingDepthTestDisabled; - - // For resetting the color after disposal of the old backing store - private boolean haveCachedColor; - private float cachedR; - private float cachedG; - private float cachedB; - private float cachedA; - private Color cachedColor; - private boolean needToResetColor; - - // For debugging only - private Frame dbgFrame; - - // Debugging purposes only - private boolean debugged; - Pipelined_QuadRenderer mPipelinedQuadRenderer; - - //emzic: added boolean flag - private boolean useVertexArrays = true; - - //emzic: added boolean flag - private boolean isExtensionAvailable_GL_VERSION_1_5; - private boolean checkFor_isExtensionAvailable_GL_VERSION_1_5; - - // Whether GL_LINEAR filtering is enabled for the backing store - private boolean smoothing = true; - - /** Creates a new TextRenderer with the given font, using no - antialiasing or fractional metrics, and the default - RenderDelegate. Equivalent to TextRenderer(font, false, - false). - - @param font the font to render with - */ - public TextRenderer(Font font) { - this(font, false, false, null, false); - } - - /** Creates a new TextRenderer with the given font, using no - antialiasing or fractional metrics, and the default - RenderDelegate. If mipmap is true, attempts to use - OpenGL's automatic mipmap generation for better smoothing when - rendering the TextureRenderer's contents at a distance. - Equivalent to TextRenderer(font, false, false). - - @param font the font to render with - @param mipmap whether to attempt use of automatic mipmap generation - */ - public TextRenderer(Font font, boolean mipmap) { - this(font, false, false, null, mipmap); - } - - /** Creates a new TextRenderer with the given Font, specified font - properties, and default RenderDelegate. The - antialiased and useFractionalMetrics - flags provide control over the same properties at the Java 2D - level. No mipmap support is requested. Equivalent to - TextRenderer(font, antialiased, useFractionalMetrics, - null). - - @param font the font to render with - @param antialiased whether to use antialiased fonts - @param useFractionalMetrics whether to use fractional font - metrics at the Java 2D level - */ - public TextRenderer(Font font, boolean antialiased, - boolean useFractionalMetrics) { - this(font, antialiased, useFractionalMetrics, null, false); - } - - /** Creates a new TextRenderer with the given Font, specified font - properties, and given RenderDelegate. The - antialiased and useFractionalMetrics - flags provide control over the same properties at the Java 2D - level. The renderDelegate provides more control - over the text rendered. No mipmap support is requested. - - @param font the font to render with - @param antialiased whether to use antialiased fonts - @param useFractionalMetrics whether to use fractional font - metrics at the Java 2D level - @param renderDelegate the render delegate to use to draw the - text's bitmap, or null to use the default one - */ - public TextRenderer(Font font, boolean antialiased, - boolean useFractionalMetrics, RenderDelegate renderDelegate) { - this(font, antialiased, useFractionalMetrics, renderDelegate, false); - } - - /** Creates a new TextRenderer with the given Font, specified font - properties, and given RenderDelegate. The - antialiased and useFractionalMetrics - flags provide control over the same properties at the Java 2D - level. The renderDelegate provides more control - over the text rendered. If mipmap is true, attempts - to use OpenGL's automatic mipmap generation for better smoothing - when rendering the TextureRenderer's contents at a distance. - - @param font the font to render with - @param antialiased whether to use antialiased fonts - @param useFractionalMetrics whether to use fractional font - metrics at the Java 2D level - @param renderDelegate the render delegate to use to draw the - text's bitmap, or null to use the default one - @param mipmap whether to attempt use of automatic mipmap generation - */ - public TextRenderer(Font font, boolean antialiased, - boolean useFractionalMetrics, RenderDelegate renderDelegate, - boolean mipmap) { - this.font = font; - this.antialiased = antialiased; - this.useFractionalMetrics = useFractionalMetrics; - this.mipmap = mipmap; - - // FIXME: consider adjusting the size based on font size - // (it will already automatically resize if necessary) - packer = new RectanglePacker(new Manager(), kSize, kSize); - - if (renderDelegate == null) { - renderDelegate = new DefaultRenderDelegate(); - } - - this.renderDelegate = renderDelegate; - - mGlyphProducer = new GlyphProducer(font.getNumGlyphs()); - } - - /** - * Returns the bounding rectangle of the given String, assuming it was rendered at the origin.See - * {@link #getBounds(CharSequence) getBounds(CharSequence)}. - * - * @param str The string. - * @return The bounding rectangle for str. - */ - public Rectangle2D getBounds(String str) { - return getBounds((CharSequence) str); - } - - /** - * Returns the bounding rectangle of the given CharSequence, assuming it was rendered at the origin.The coordinate - * system of the returned rectangle is Java 2D's, with increasing Y coordinates in the downward direction.The - * relative coordinate (0, 0) in the returned rectangle corresponds to the baseline of the leftmost character of the - * rendered string, in similar fashion to the results returned by, for example, - * {@link java.awt.font.GlyphVector#getVisualBounds}. Most applications will use only the width and height of the - * returned Rectangle for the purposes of centering or justifying the String. It is not specified which Java 2D - * bounds ({@link - * java.awt.font.GlyphVector#getVisualBounds getVisualBounds}, - * {@link java.awt.font.GlyphVector#getPixelBounds getPixelBounds}, etc.) the returned bounds correspond to, - * although every effort is made to ensure an accurate bound. - * - * @param str The string. - * @return The bounds of the string. - */ - public Rectangle2D getBounds(CharSequence str) { - // FIXME: this should be more optimized and use the glyph cache - Rect r = stringLocations.get(str); - - if (r != null) { - TextData data = (TextData) r.getUserData(); - - // Reconstitute the Java 2D results based on the cached values - return new Rectangle2D.Double(-data.origin().x, -data.origin().y, - r.w(), r.h()); - } - - // Must return a Rectangle compatible with the layout algorithm -- - // must be idempotent - return normalize(renderDelegate.getBounds(str, font, - getFontRenderContext())); - } - - /** - * Returns the Font this renderer is using. - * - * @return The Font. - */ - public Font getFont() { - return font; - } - - /** - * * Returns a FontRenderContext which can be used for external text-related size computations.This object should be - * considered transient and may become invalidated between - * {@link #beginRendering beginRendering} / {@link #endRendering endRendering} pairs. - * - * @return A FontRenderContext. - */ - public FontRenderContext getFontRenderContext() { - if (cachedFontRenderContext == null) { - cachedFontRenderContext = getGraphics2D().getFontRenderContext(); - } - - return cachedFontRenderContext; - } - - /** Begins rendering with this {@link TextRenderer TextRenderer} - into the current OpenGL drawable, pushing the projection and - modelview matrices and some state bits and setting up a - two-dimensional orthographic projection with (0, 0) as the - lower-left coordinate and (width, height) as the upper-right - coordinate. Binds and enables the internal OpenGL texture - object, sets the texture environment mode to GL_MODULATE, and - changes the current color to the last color set with this - TextRenderer via {@link #setColor setColor}. This method - disables the depth test and is equivalent to - beginRendering(width, height, true). - - @param width the width of the current on-screen OpenGL drawable - @param height the height of the current on-screen OpenGL drawable - @throws com.jogamp.opengl.GLException If an OpenGL context is not current when this method is called - */ - public void beginRendering(int width, int height) throws GLException { - beginRendering(width, height, true); - } - - /** Begins rendering with this {@link TextRenderer TextRenderer} - into the current OpenGL drawable, pushing the projection and - modelview matrices and some state bits and setting up a - two-dimensional orthographic projection with (0, 0) as the - lower-left coordinate and (width, height) as the upper-right - coordinate. Binds and enables the internal OpenGL texture - object, sets the texture environment mode to GL_MODULATE, and - changes the current color to the last color set with this - TextRenderer via {@link #setColor setColor}. Disables the depth - test if the disableDepthTest argument is true. - - @param width the width of the current on-screen OpenGL drawable - @param height the height of the current on-screen OpenGL drawable - @param disableDepthTest whether to disable the depth test - @throws GLException If an OpenGL context is not current when this method is called - */ - public void beginRendering(int width, int height, boolean disableDepthTest) - throws GLException { - beginRendering(true, width, height, disableDepthTest); - } - - /** Begins rendering of 2D text in 3D with this {@link TextRenderer - TextRenderer} into the current OpenGL drawable. Assumes the end - user is responsible for setting up the modelview and projection - matrices, and will render text using the {@link #draw3D draw3D} - method. This method pushes some OpenGL state bits, binds and - enables the internal OpenGL texture object, sets the texture - environment mode to GL_MODULATE, and changes the current color - to the last color set with this TextRenderer via {@link - #setColor setColor}. - - @throws GLException If an OpenGL context is not current when this method is called - */ - public void begin3DRendering() throws GLException { - beginRendering(false, 0, 0, false); - } - - /** Changes the current color of this TextRenderer to the supplied - one. The default color is opaque white. - - @param color the new color to use for rendering text - @throws GLException If an OpenGL context is not current when this method is called - */ - public void setColor(Color color) throws GLException { - boolean noNeedForFlush = (haveCachedColor && (cachedColor != null) && - color.equals(cachedColor)); - - if (!noNeedForFlush) { - flushGlyphPipeline(); - } - - getBackingStore().setColor(color); - haveCachedColor = true; - cachedColor = color; - } - - /** Changes the current color of this TextRenderer to the supplied - one, where each component ranges from 0.0f - 1.0f. The alpha - component, if used, does not need to be premultiplied into the - color channels as described in the documentation for {@link - com.jogamp.opengl.util.texture.Texture Texture}, although - premultiplied colors are used internally. The default color is - opaque white. - - @param r the red component of the new color - @param g the green component of the new color - @param b the blue component of the new color - @param a the alpha component of the new color, 0.0f = completely - transparent, 1.0f = completely opaque - @throws GLException If an OpenGL context is not current when this method is called - */ - public void setColor(float r, float g, float b, float a) - throws GLException { - boolean noNeedForFlush = (haveCachedColor && (cachedColor == null) && - (r == cachedR) && (g == cachedG) && (b == cachedB) && - (a == cachedA)); - - if (!noNeedForFlush) { - flushGlyphPipeline(); - } - - getBackingStore().setColor(r, g, b, a); - haveCachedColor = true; - cachedR = r; - cachedG = g; - cachedB = b; - cachedA = a; - cachedColor = null; - } - - /** Draws the supplied CharSequence at the desired location using - the renderer's current color. The baseline of the leftmost - character is at position (x, y) specified in OpenGL coordinates, - where the origin is at the lower-left of the drawable and the Y - coordinate increases in the upward direction. - - @param str the string to draw - @param x the x coordinate at which to draw - @param y the y coordinate at which to draw - @throws GLException If an OpenGL context is not current when this method is called - */ - public void draw(CharSequence str, int x, int y) throws GLException { - draw3D(str, x, y, 0, 1); - } - - /** - * * Draws the supplied String at the desired location using the renderer's current color.See - * {@link #draw(CharSequence, int, int) draw(CharSequence, int, int)}. - * - * @param str The string to draw. - * @param x The desired x location. - * @param y The desired y location. - */ - public void draw(String str, int x, int y) throws GLException { - draw3D(str, x, y, 0, 1); - } - - /** Draws the supplied CharSequence at the desired 3D location using - the renderer's current color. The baseline of the leftmost - character is placed at position (x, y, z) in the current - coordinate system. - - @param str the string to draw - @param x the x coordinate at which to draw - @param y the y coordinate at which to draw - @param z the z coordinate at which to draw - @param scaleFactor a uniform scale factor applied to the width and height of the drawn rectangle - @throws GLException If an OpenGL context is not current when this method is called - */ - public void draw3D(CharSequence str, float x, float y, float z, - float scaleFactor) { - internal_draw3D(str, x, y, z, scaleFactor); - } - - /** - * * Draws the supplied String at the desired 3D location using the renderer's current color.See {@link #draw3D(CharSequence, float, float, float, float) draw3D(CharSequence, float, float, - * float, float)}. - * - * @param str The string to draw. - * @param x The x location. - * @param y The y location. - * @param z The z location. - * @param scaleFactor The scale factor. - */ - public void draw3D(String str, float x, float y, float z, float scaleFactor) { - internal_draw3D(str, x, y, z, scaleFactor); - } - - /** - * Returns the pixel width of the given character. - * - * @param inChar The character to measure. - * @return The pixel width. - */ - public float getCharWidth(char inChar) { - return mGlyphProducer.getGlyphPixelWidth(inChar); - } - - /** Causes the TextRenderer to flush any internal caches it may be - maintaining and draw its rendering results to the screen. This - should be called after each call to draw() if you are setting - OpenGL state such as the modelview matrix between calls to - draw(). */ - public void flush() { - flushGlyphPipeline(); - } - - /** Ends a render cycle with this {@link TextRenderer TextRenderer}. - Restores the projection and modelview matrices as well as - several OpenGL state bits. Should be paired with {@link - #beginRendering beginRendering}. - - @throws GLException If an OpenGL context is not current when this method is called - */ - public void endRendering() throws GLException { - endRendering(true); - } - - /** Ends a 3D render cycle with this {@link TextRenderer TextRenderer}. - Restores several OpenGL state bits. Should be paired with {@link - #begin3DRendering begin3DRendering}. - - @throws GLException If an OpenGL context is not current when this method is called - */ - public void end3DRendering() throws GLException { - endRendering(false); - } - - /** Disposes of all resources this TextRenderer is using. It is not - valid to use the TextRenderer after this method is called. - - @throws GLException If an OpenGL context is not current when this method is called - */ - public void dispose() throws GLException { - packer.dispose(); - packer = null; - cachedBackingStore = null; - cachedGraphics = null; - cachedFontRenderContext = null; - - if (dbgFrame != null) { - dbgFrame.dispose(); - } - } - - //---------------------------------------------------------------------- - // Internals only below this point - // - - private static Rectangle2D preNormalize(Rectangle2D src) { - // Need to round to integer coordinates - // Also give ourselves a little slop around the reported - // bounds of glyphs because it looks like neither the visual - // nor the pixel bounds works perfectly well - int minX = (int) Math.floor(src.getMinX()) - 1; - int minY = (int) Math.floor(src.getMinY()) - 1; - int maxX = (int) Math.ceil(src.getMaxX()) + 1; - int maxY = (int) Math.ceil(src.getMaxY()) + 1; - return new Rectangle2D.Double(minX, minY, maxX - minX, maxY - minY); - } - - - private Rectangle2D normalize(Rectangle2D src) { - // Give ourselves a boundary around each entity on the backing - // store in order to prevent bleeding of nearby Strings due to - // the fact that we use linear filtering - - // NOTE that this boundary is quite heuristic and is related - // to how far away in 3D we may view the text -- - // heuristically, 1.5% of the font's height - int boundary = (int) Math.max(1, 0.015 * font.getSize()); - - return new Rectangle2D.Double((int) Math.floor(src.getMinX() - boundary), - (int) Math.floor(src.getMinY() - boundary), - (int) Math.ceil(src.getWidth() + 2 * boundary), - (int) Math.ceil(src.getHeight()) + 2 * boundary); - } - - private TextureRenderer getBackingStore() { - TextureRenderer renderer = (TextureRenderer) packer.getBackingStore(); - - if (renderer != cachedBackingStore) { - // Backing store changed since last time; discard any cached Graphics2D - if (cachedGraphics != null) { - cachedGraphics.dispose(); - cachedGraphics = null; - cachedFontRenderContext = null; - } - - cachedBackingStore = renderer; - } - - return cachedBackingStore; - } - - private Graphics2D getGraphics2D() { - TextureRenderer renderer = getBackingStore(); - - if (cachedGraphics == null) { - cachedGraphics = renderer.createGraphics(); - - // Set up composite, font and rendering hints - cachedGraphics.setComposite(AlphaComposite.Src); - cachedGraphics.setColor(Color.WHITE); - cachedGraphics.setFont(font); - cachedGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, - (antialiased ? RenderingHints.VALUE_TEXT_ANTIALIAS_ON - : RenderingHints.VALUE_TEXT_ANTIALIAS_OFF)); - cachedGraphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, - (useFractionalMetrics - ? RenderingHints.VALUE_FRACTIONALMETRICS_ON - : RenderingHints.VALUE_FRACTIONALMETRICS_OFF)); - } - - return cachedGraphics; - } - - private void beginRendering(boolean ortho, int width, int height, - boolean disableDepthTestForOrtho) { - GL2 gl = GLContext.getCurrentGL().getGL2(); - - if (DEBUG && !debugged) { - debug(gl); - } - - inBeginEndPair = true; - isOrthoMode = ortho; - beginRenderingWidth = width; - beginRenderingHeight = height; - beginRenderingDepthTestDisabled = disableDepthTestForOrtho; - - if (ortho) { - getBackingStore().beginOrthoRendering(width, height, - disableDepthTestForOrtho); - } else { - getBackingStore().begin3DRendering(); - } - - // Push client attrib bits used by the pipelined quad renderer - gl.glPushClientAttrib((int) GL2.GL_ALL_CLIENT_ATTRIB_BITS); - - if (!haveMaxSize) { - // Query OpenGL for the maximum texture size and set it in the - // RectanglePacker to keep it from expanding too large - int[] sz = new int[1]; - gl.glGetIntegerv(GL2.GL_MAX_TEXTURE_SIZE, sz, 0); - packer.setMaxSize(sz[0], sz[0]); - haveMaxSize = true; - } - - if (needToResetColor && haveCachedColor) { - if (cachedColor == null) { - getBackingStore().setColor(cachedR, cachedG, cachedB, cachedA); - } else { - getBackingStore().setColor(cachedColor); - } - - needToResetColor = false; - } - - // Disable future attempts to use mipmapping if TextureRenderer - // doesn't support it - if (mipmap && !getBackingStore().isUsingAutoMipmapGeneration()) { - if (DEBUG) { - System.err.println("Disabled mipmapping in TextRenderer"); - } - - mipmap = false; - } - } - - /** - * emzic: here the call to glBindBuffer crashes on certain graphicscard/driver combinations - * this is why the ugly try-catch block has been added, which falls back to the old textrenderer - * - * @param ortho - * @throws GLException - */ - private void endRendering(boolean ortho) throws GLException { - flushGlyphPipeline(); - - inBeginEndPair = false; - - GL2 gl = GLContext.getCurrentGL().getGL2(); - - // Pop client attrib bits used by the pipelined quad renderer - gl.glPopClientAttrib(); - - // The OpenGL spec is unclear about whether this changes the - // buffer bindings, so preemptively zero out the GL_ARRAY_BUFFER - // binding - if (getUseVertexArrays() && is15Available(gl)) { - try { - gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0); - } catch (Exception e) { - isExtensionAvailable_GL_VERSION_1_5 = false; - } - } - - if (ortho) { - getBackingStore().endOrthoRendering(); - } else { - getBackingStore().end3DRendering(); - } - - if (++numRenderCycles >= CYCLES_PER_FLUSH) { - numRenderCycles = 0; - - if (DEBUG) { - System.err.println("Clearing unused entries in endRendering()"); - } - - clearUnusedEntries(); - } - } - - private void clearUnusedEntries() { - final java.util.List deadRects = new ArrayList(); - - // Iterate through the contents of the backing store, removing - // text strings that haven't been used recently - packer.visit(new RectVisitor() { - @Override - public void visit(Rect rect) { - TextData data = (TextData) rect.getUserData(); - - if (data.used()) { - data.clearUsed(); - } else { - deadRects.add(rect); - } - } - }); - - for (Rect r : deadRects) { - packer.remove(r); - stringLocations.remove(((TextData) r.getUserData()).string()); - - int unicodeToClearFromCache = ((TextData) r.getUserData()).unicodeID; - - if (unicodeToClearFromCache > 0) { - mGlyphProducer.clearCacheEntry(unicodeToClearFromCache); - } - - // if (DEBUG) { - // Graphics2D g = getGraphics2D(); - // g.setComposite(AlphaComposite.Clear); - // g.fillRect(r.x(), r.y(), r.w(), r.h()); - // g.setComposite(AlphaComposite.Src); - // } - } - - // If we removed dead rectangles this cycle, try to do a compaction - float frag = packer.verticalFragmentationRatio(); - - if (!deadRects.isEmpty() && (frag > MAX_VERTICAL_FRAGMENTATION)) { - if (DEBUG) { - System.err.println( - "Compacting TextRenderer backing store due to vertical fragmentation " + - frag); - } - - packer.compact(); - } - - if (DEBUG) { - getBackingStore().markDirty(0, 0, getBackingStore().getWidth(), - getBackingStore().getHeight()); - } - } - - private void internal_draw3D(CharSequence str, float x, float y, float z, - float scaleFactor) { - for (Glyph glyph : mGlyphProducer.getGlyphs(str)) { - float advance = glyph.draw3D(x, y, z, scaleFactor); - x += advance * scaleFactor; - } - } - - private void flushGlyphPipeline() { - if (mPipelinedQuadRenderer != null) { - mPipelinedQuadRenderer.draw(); - } - } - - private void draw3D_ROBUST(CharSequence str, float x, float y, float z, - float scaleFactor) { - String curStr; - if (str instanceof String) { - curStr = (String) str; - } else { - curStr = str.toString(); - } - - // Look up the string on the backing store - Rect rect = stringLocations.get(curStr); - - if (rect == null) { - // Rasterize this string and place it on the backing store - Graphics2D g = getGraphics2D(); - Rectangle2D origBBox = preNormalize(renderDelegate.getBounds(curStr, font, getFontRenderContext())); - Rectangle2D bbox = normalize(origBBox); - Point origin = new Point((int) -bbox.getMinX(), - (int) -bbox.getMinY()); - rect = new Rect(0, 0, (int) bbox.getWidth(), - (int) bbox.getHeight(), - new TextData(curStr, origin, origBBox, -1)); - - packer.add(rect); - stringLocations.put(curStr, rect); - - // Re-fetch the Graphics2D in case the addition of the rectangle - // caused the old backing store to be thrown away - g = getGraphics2D(); - - // OK, should now have an (x, y) for this rectangle; rasterize - // the String - int strx = rect.x() + origin.x; - int stry = rect.y() + origin.y; - - // Clear out the area we're going to draw into - g.setComposite(AlphaComposite.Clear); - g.fillRect(rect.x(), rect.y(), rect.w(), rect.h()); - g.setComposite(AlphaComposite.Src); - - // Draw the string - renderDelegate.draw(g, curStr, strx, stry); - - if (DRAW_BBOXES) { - TextData data = (TextData) rect.getUserData(); - // Draw a bounding box on the backing store - g.drawRect(strx - data.origOriginX(), - stry - data.origOriginY(), - (int) data.origRect().getWidth(), - (int) data.origRect().getHeight()); - g.drawRect(strx - data.origin().x, - stry - data.origin().y, - rect.w(), - rect.h()); - } - - // Mark this region of the TextureRenderer as dirty - getBackingStore().markDirty(rect.x(), rect.y(), rect.w(), - rect.h()); - } - - // OK, now draw the portion of the backing store to the screen - TextureRenderer renderer = getBackingStore(); - - // NOTE that the rectangles managed by the packer have their - // origin at the upper-left but the TextureRenderer's origin is - // at its lower left!!! - TextData data = (TextData) rect.getUserData(); - data.markUsed(); - - Rectangle2D origRect = data.origRect(); - - // Align the leftmost point of the baseline to the (x, y, z) coordinate requested - renderer.draw3DRect(x - (scaleFactor * data.origOriginX()), - y - (scaleFactor * ((float) origRect.getHeight() - data.origOriginY())), z, - rect.x() + (data.origin().x - data.origOriginX()), - renderer.getHeight() - rect.y() - (int) origRect.getHeight() - - (data.origin().y - data.origOriginY()), - (int) origRect.getWidth(), (int) origRect.getHeight(), scaleFactor); - } - - //---------------------------------------------------------------------- - // Debugging functionality - // - private void debug(GL gl) { - dbgFrame = new Frame("TextRenderer Debug Output"); - - GLCanvas dbgCanvas = new GLCanvas(new GLCapabilities(gl.getGLProfile())); - dbgCanvas.setSharedContext(GLContext.getCurrent()); - dbgCanvas.addGLEventListener(new DebugListener(gl, dbgFrame)); - dbgFrame.add(dbgCanvas); - - final FPSAnimator anim = new FPSAnimator(dbgCanvas, 10); - dbgFrame.addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent e) { - // Run this on another thread than the AWT event queue to - // make sure the call to Animator.stop() completes before - // exiting - new Thread(new Runnable() { - @Override - public void run() { - anim.stop(); - } - }).start(); - } - }); - dbgFrame.setSize(kSize, kSize); - dbgFrame.setVisible(true); - anim.start(); - debugged = true; - } - - /** Class supporting more full control over the process of rendering - the bitmapped text. Allows customization of whether the backing - store text bitmap is full-color or intensity only, the size of - each individual rendered text rectangle, and the contents of - each individual rendered text string. The default implementation - of this interface uses an intensity-only texture, a - closely-cropped rectangle around the text, and renders text - using the color white, which is modulated by the set color - during the rendering process. */ - public static interface RenderDelegate { - /** - * Indicates whether the backing store of this TextRenderer should be intensity-only (the default) or - * full-color. - * - * @return whether or not intensity only is on. - */ - public boolean intensityOnly(); - - /** - * Computes the bounds of the given String relative to the origin. - * - * @param str The string to process. - * @param font The font to use. - * @param frc The render context to use. - * @return The bounds given the parameters. - */ - public Rectangle2D getBounds(String str, Font font, - FontRenderContext frc); - - /** - * Computes the bounds of the given character sequence relative to the origin. - * - * @param str The string to process. - * @param font The font to use. - * @param frc The render context to use. - * @return The bounds given the parameters. - */ - public Rectangle2D getBounds(CharSequence str, Font font, - FontRenderContext frc); - - /** - * Computes the bounds of the given GlyphVector, already assumed to have been created for a particular Font, - * relative to the origin. - * - * @param gv The string to process. - * @param frc The render context to use. - * @return The bounds given the parameters. - */ - public Rectangle2D getBounds(GlyphVector gv, FontRenderContext frc); - - /** - * * Render the passed character sequence at the designated location using the supplied Graphics2D instance.The - * surrounding region will already have been cleared to the RGB color (0, 0, 0) with zero alpha.The initial - * drawing context of the passed Graphics2D will be set to use AlphaComposite.Src, the color white, the Font - * specified in the TextRenderer's constructor, and the rendering hints specified in the TextRenderer - * constructor.Changes made by the end user may be visible in successive calls to this method, but are not - * guaranteed to be preserved.Implementors of this method should reset the Graphics2D's state to that desired - * each time this method is called, in particular those states which are not the defaults. - * - * @param graphics The canvas to draw on. - * @param str The string to draw. - * @param x The x location. - * @param y The y location. - */ - public void draw(Graphics2D graphics, String str, int x, int y); - - /** - * * Render the passed GlyphVector at the designated location using the supplied Graphics2D instance.The - * surrounding region will already have been cleared to the RGB color (0, 0, 0) with zero alpha.The initial - * drawing context of the passed Graphics2D will be set to use AlphaComposite.Src, the color white, the Font - * specified in the TextRenderer's constructor, and the rendering hints specified in the TextRenderer - * constructor.Changes made by the end user may be visible in successive calls to this method, but are not - * guaranteed to be preserved.Implementors of this method should reset the Graphics2D's state to that desired - * each time this method is called, in particular those states which are not the defaults. - * - * @param graphics The canvas to draw on. - * @param str The string to draw. - * @param x The x location. - * @param y The y location. - */ - public void drawGlyphVector(Graphics2D graphics, GlyphVector str, - int x, int y); - } - - private static class CharSequenceIterator implements CharacterIterator { - CharSequence mSequence; - int mLength; - int mCurrentIndex; - - CharSequenceIterator() { - } - - CharSequenceIterator(CharSequence sequence) { - initFromCharSequence(sequence); - } - - public void initFromCharSequence(CharSequence sequence) { - mSequence = sequence; - mLength = mSequence.length(); - mCurrentIndex = 0; - } - - @Override - public char last() { - mCurrentIndex = Math.max(0, mLength - 1); - - return current(); - } - - @Override - public char current() { - if ((mLength == 0) || (mCurrentIndex >= mLength)) { - return CharacterIterator.DONE; - } - - return mSequence.charAt(mCurrentIndex); - } - - @Override - public char next() { - mCurrentIndex++; - - return current(); - } - - @Override - public char previous() { - mCurrentIndex = Math.max(mCurrentIndex - 1, 0); - - return current(); - } - - @Override - public char setIndex(int position) { - mCurrentIndex = position; - - return current(); - } - - @Override - public int getBeginIndex() { - return 0; - } - - @Override - public int getEndIndex() { - return mLength; - } - - @Override - public int getIndex() { - return mCurrentIndex; - } - - @Override - public Object clone() { - CharSequenceIterator iter = new CharSequenceIterator(mSequence); - iter.mCurrentIndex = mCurrentIndex; - - return iter; - } - - @Override - public char first() { - if (mLength == 0) { - return CharacterIterator.DONE; - } - - mCurrentIndex = 0; - - return current(); - } - } - - // Data associated with each rectangle of text - static class TextData { - // Back-pointer to String this TextData describes, if it - // represents a String rather than a single glyph - private final String str; - - // If this TextData represents a single glyph, this is its - // unicode ID - int unicodeID; - - // The following must be defined and used VERY precisely. This is - // the offset from the upper-left corner of this rectangle (Java - // 2D coordinate system) at which the string must be rasterized in - // order to fit within the rectangle -- the leftmost point of the - // baseline. - private final Point origin; - - // This represents the pre-normalized rectangle, which fits - // within the rectangle on the backing store. We keep a - // one-pixel border around entries on the backing store to - // prevent bleeding of adjacent letters when using GL_LINEAR - // filtering for rendering. The origin of this rectangle is - // equivalent to the origin above. - private final Rectangle2D origRect; - - private boolean used; // Whether this text was used recently - - TextData(String str, Point origin, Rectangle2D origRect, int unicodeID) { - this.str = str; - this.origin = origin; - this.origRect = origRect; - this.unicodeID = unicodeID; - } - - String string() { - return str; - } - - Point origin() { - return origin; - } - - // The following three methods are used to locate the glyph - // within the expanded rectangle coming from normalize() - int origOriginX() { - return (int) -origRect.getMinX(); - } - - int origOriginY() { - return (int) -origRect.getMinY(); - } - - Rectangle2D origRect() { - return origRect; - } - - boolean used() { - return used; - } - - void markUsed() { - used = true; - } - - void clearUsed() { - used = false; - } - } - - class Manager implements BackingStoreManager { - private Graphics2D g; - - @Override - public Object allocateBackingStore(int w, int h) { - // FIXME: should consider checking Font's attributes to see - // whether we're likely to need to support a full RGBA backing - // store (i.e., non-default Paint, foreground color, etc.), but - // for now, let's just be more efficient - TextureRenderer renderer; - - if (renderDelegate.intensityOnly()) { - renderer = TextureRenderer.createAlphaOnlyRenderer(w, h, mipmap); - } else { - renderer = new TextureRenderer(w, h, true, mipmap); - } - renderer.setSmoothing(smoothing); - - if (DEBUG) { - System.err.println(" TextRenderer allocating backing store " + - w + " x " + h); - } - - return renderer; - } - - @Override - public void deleteBackingStore(Object backingStore) { - ((TextureRenderer) backingStore).dispose(); - } - - @Override - public boolean preExpand(Rect cause, int attemptNumber) { - // Only try this one time; clear out potentially obsolete entries - // NOTE: this heuristic and the fact that it clears the used bit - // of all entries seems to cause cycling of entries in some - // situations, where the backing store becomes small compared to - // the amount of text on the screen (see the TextFlow demo) and - // the entries continually cycle in and out of the backing - // store, decreasing performance. If we added a little age - // information to the entries, and only cleared out entries - // above a certain age, this behavior would be eliminated. - // However, it seems the system usually stabilizes itself, so - // for now we'll just keep things simple. Note that if we don't - // clear the used bit here, the backing store tends to increase - // very quickly to its maximum size, at least with the TextFlow - // demo when the text is being continually re-laid out. - if (attemptNumber == 0) { - if (DEBUG) { - System.err.println( - "Clearing unused entries in preExpand(): attempt number " + - attemptNumber); - } - - if (inBeginEndPair) { - // Draw any outstanding glyphs - flush(); - } - - clearUnusedEntries(); - - return true; - } - - return false; - } - - @Override - public boolean additionFailed(Rect cause, int attemptNumber) { - // Heavy hammer -- might consider doing something different - packer.clear(); - stringLocations.clear(); - mGlyphProducer.clearAllCacheEntries(); - - if (DEBUG) { - System.err.println( - " *** Cleared all text because addition failed ***"); - } - - if (attemptNumber == 0) { - return true; - } - - return false; - } - - @Override - public boolean canCompact() { - return true; - } - - @Override - public void beginMovement(Object oldBackingStore, Object newBackingStore) { - // Exit the begin / end pair if necessary - if (inBeginEndPair) { - // Draw any outstanding glyphs - flush(); - - GL2 gl = GLContext.getCurrentGL().getGL2(); - - // Pop client attrib bits used by the pipelined quad renderer - gl.glPopClientAttrib(); - - // The OpenGL spec is unclear about whether this changes the - // buffer bindings, so preemptively zero out the GL_ARRAY_BUFFER - // binding - if (getUseVertexArrays() && is15Available(gl)) { - try { - gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0); - } catch (Exception e) { - isExtensionAvailable_GL_VERSION_1_5 = false; - } - } - - if (isOrthoMode) { - ((TextureRenderer) oldBackingStore).endOrthoRendering(); - } else { - ((TextureRenderer) oldBackingStore).end3DRendering(); - } - } - - TextureRenderer newRenderer = (TextureRenderer) newBackingStore; - g = newRenderer.createGraphics(); - } - - @Override - public void move(Object oldBackingStore, Rect oldLocation, - Object newBackingStore, Rect newLocation) { - TextureRenderer oldRenderer = (TextureRenderer) oldBackingStore; - TextureRenderer newRenderer = (TextureRenderer) newBackingStore; - - if (oldRenderer == newRenderer) { - // Movement on the same backing store -- easy case - g.copyArea(oldLocation.x(), oldLocation.y(), oldLocation.w(), - oldLocation.h(), newLocation.x() - oldLocation.x(), - newLocation.y() - oldLocation.y()); - } else { - // Need to draw from the old renderer's image into the new one - Image img = oldRenderer.getImage(); - g.drawImage(img, newLocation.x(), newLocation.y(), - newLocation.x() + newLocation.w(), - newLocation.y() + newLocation.h(), oldLocation.x(), - oldLocation.y(), oldLocation.x() + oldLocation.w(), - oldLocation.y() + oldLocation.h(), null); - } - } - - @Override - public void endMovement(Object oldBackingStore, Object newBackingStore) { - g.dispose(); - - // Sync the whole surface - TextureRenderer newRenderer = (TextureRenderer) newBackingStore; - newRenderer.markDirty(0, 0, newRenderer.getWidth(), - newRenderer.getHeight()); - - // Re-enter the begin / end pair if necessary - if (inBeginEndPair) { - if (isOrthoMode) { - ((TextureRenderer) newBackingStore).beginOrthoRendering(beginRenderingWidth, - beginRenderingHeight, beginRenderingDepthTestDisabled); - } else { - ((TextureRenderer) newBackingStore).begin3DRendering(); - } - - // Push client attrib bits used by the pipelined quad renderer - GL2 gl = GLContext.getCurrentGL().getGL2(); - gl.glPushClientAttrib((int) GL2.GL_ALL_CLIENT_ATTRIB_BITS); - - if (haveCachedColor) { - if (cachedColor == null) { - ((TextureRenderer) newBackingStore).setColor(cachedR, - cachedG, cachedB, cachedA); - } else { - ((TextureRenderer) newBackingStore).setColor(cachedColor); - } - } - } else { - needToResetColor = true; - } - } - } - - public static class DefaultRenderDelegate implements RenderDelegate { - @Override - public boolean intensityOnly() { - return true; - } - - @Override - public Rectangle2D getBounds(CharSequence str, Font font, - FontRenderContext frc) { - return getBounds(font.createGlyphVector(frc, - new CharSequenceIterator(str)), - frc); - } - - @Override - public Rectangle2D getBounds(String str, Font font, - FontRenderContext frc) { - return getBounds(font.createGlyphVector(frc, str), frc); - } - - @Override - public Rectangle2D getBounds(GlyphVector gv, FontRenderContext frc) { - return gv.getVisualBounds(); - } - - @Override - public void drawGlyphVector(Graphics2D graphics, GlyphVector str, - int x, int y) { - graphics.drawGlyphVector(str, x, y); - } - - @Override - public void draw(Graphics2D graphics, String str, int x, int y) { - graphics.drawString(str, x, y); - } - } - - //---------------------------------------------------------------------- - // Glyph-by-glyph rendering support - // - - // A temporary to prevent excessive garbage creation - private final char[] singleUnicode = new char[1]; - - /** A Glyph represents either a single unicode glyph or a - substring of characters to be drawn. The reason for the dual - behavior is so that we can take in a sequence of unicode - characters and partition them into runs of individual glyphs, - but if we encounter complex text and/or unicode sequences we - don't understand, we can render them using the - string-by-string method.

- - Glyphs need to be able to re-upload themselves to the backing - store on demand as we go along in the render sequence. - */ - - class Glyph { - // If this Glyph represents an individual unicode glyph, this - // is its unicode ID. If it represents a String, this is -1. - private int unicodeID; - // If the above field isn't -1, then these fields are used. - // The glyph code in the font - private int glyphCode; - // The GlyphProducer which created us - private GlyphProducer producer; - // The advance of this glyph - private float advance; - // The GlyphVector for this single character; this is passed - // in during construction but cleared during the upload - // process - private GlyphVector singleUnicodeGlyphVector; - // The rectangle of this glyph on the backing store, or null - // if it has been cleared due to space pressure - private Rect glyphRectForTextureMapping; - // If this Glyph represents a String, this is the sequence of - // characters - private String str; - // Whether we need a valid advance when rendering this string - // (i.e., whether it has other single glyphs coming after it) - private boolean needAdvance; - - // Creates a Glyph representing an individual Unicode character - public Glyph(int unicodeID, - int glyphCode, - float advance, - GlyphVector singleUnicodeGlyphVector, - GlyphProducer producer) { - this.unicodeID = unicodeID; - this.glyphCode = glyphCode; - this.advance = advance; - this.singleUnicodeGlyphVector = singleUnicodeGlyphVector; - this.producer = producer; - } - - // Creates a Glyph representing a sequence of characters, with - // an indication of whether additional single glyphs are being - // rendered after it - public Glyph(String str, boolean needAdvance) { - this.str = str; - this.needAdvance = needAdvance; - } - - /** Returns this glyph's unicode ID */ - public int getUnicodeID() { - return unicodeID; - } - - /** Returns this glyph's (font-specific) glyph code */ - public int getGlyphCode() { - return glyphCode; - } - - /** Returns the advance for this glyph */ - public float getAdvance() { - return advance; - } - - /** Draws this glyph and returns the (x) advance for this glyph */ - public float draw3D(float inX, float inY, float z, float scaleFactor) { - if (str != null) { - draw3D_ROBUST(str, inX, inY, z, scaleFactor); - if (!needAdvance) { - return 0; - } - // Compute and return the advance for this string - GlyphVector gv = font.createGlyphVector(getFontRenderContext(), str); - float totalAdvance = 0; - for (int i = 0; i < gv.getNumGlyphs(); i++) { - totalAdvance += gv.getGlyphMetrics(i).getAdvance(); - } - return totalAdvance; - } - - // This is the code path taken for individual glyphs - if (glyphRectForTextureMapping == null) { - upload(); - } - - try { - if (mPipelinedQuadRenderer == null) { - mPipelinedQuadRenderer = new Pipelined_QuadRenderer(); - } - - TextureRenderer renderer = getBackingStore(); - // Handles case where NPOT texture is used for backing store - TextureCoords wholeImageTexCoords = renderer.getTexture().getImageTexCoords(); - float xScale = wholeImageTexCoords.right(); - float yScale = wholeImageTexCoords.bottom(); - - Rect rect = glyphRectForTextureMapping; - TextData data = (TextData) rect.getUserData(); - data.markUsed(); - - Rectangle2D origRect = data.origRect(); - - float x = inX - (scaleFactor * data.origOriginX()); - float y = inY - (scaleFactor * ((float) origRect.getHeight() - data.origOriginY())); - - int texturex = rect.x() + (data.origin().x - data.origOriginX()); - int texturey = renderer.getHeight() - rect.y() - (int) origRect.getHeight() - - (data.origin().y - data.origOriginY()); - int width = (int) origRect.getWidth(); - int height = (int) origRect.getHeight(); - - float tx1 = xScale * texturex / renderer.getWidth(); - float ty1 = yScale * (1.0f - - ((float) texturey / (float) renderer.getHeight())); - float tx2 = xScale * (texturex + width) / renderer.getWidth(); - float ty2 = yScale * (1.0f - - ((float) (texturey + height) / (float) renderer.getHeight())); - - mPipelinedQuadRenderer.glTexCoord2f(tx1, ty1); - mPipelinedQuadRenderer.glVertex3f(x, y, z); - mPipelinedQuadRenderer.glTexCoord2f(tx2, ty1); - mPipelinedQuadRenderer.glVertex3f(x + (width * scaleFactor), y, - z); - mPipelinedQuadRenderer.glTexCoord2f(tx2, ty2); - mPipelinedQuadRenderer.glVertex3f(x + (width * scaleFactor), - y + (height * scaleFactor), z); - mPipelinedQuadRenderer.glTexCoord2f(tx1, ty2); - mPipelinedQuadRenderer.glVertex3f(x, - y + (height * scaleFactor), z); - } catch (Exception e) { - e.printStackTrace(); - } - return advance; - } - - /** Notifies this glyph that it's been cleared out of the cache */ - public void clear() { - glyphRectForTextureMapping = null; - } - - private void upload() { - GlyphVector gv = getGlyphVector(); - Rectangle2D origBBox = preNormalize(renderDelegate.getBounds(gv, getFontRenderContext())); - Rectangle2D bbox = normalize(origBBox); - Point origin = new Point((int) -bbox.getMinX(), - (int) -bbox.getMinY()); - Rect rect = new Rect(0, 0, (int) bbox.getWidth(), - (int) bbox.getHeight(), - new TextData(null, origin, origBBox, unicodeID)); - packer.add(rect); - glyphRectForTextureMapping = rect; - Graphics2D g = getGraphics2D(); - // OK, should now have an (x, y) for this rectangle; rasterize - // the glyph - int strx = rect.x() + origin.x; - int stry = rect.y() + origin.y; - - // Clear out the area we're going to draw into - g.setComposite(AlphaComposite.Clear); - g.fillRect(rect.x(), rect.y(), rect.w(), rect.h()); - g.setComposite(AlphaComposite.Src); - - // Draw the string - renderDelegate.drawGlyphVector(g, gv, strx, stry); - - if (DRAW_BBOXES) { - TextData data = (TextData) rect.getUserData(); - // Draw a bounding box on the backing store - g.drawRect(strx - data.origOriginX(), - stry - data.origOriginY(), - (int) data.origRect().getWidth(), - (int) data.origRect().getHeight()); - g.drawRect(strx - data.origin().x, - stry - data.origin().y, - rect.w(), - rect.h()); - } - - // Mark this region of the TextureRenderer as dirty - getBackingStore().markDirty(rect.x(), rect.y(), rect.w(), - rect.h()); - // Re-register ourselves with our producer - producer.register(this); - } - - private GlyphVector getGlyphVector() { - GlyphVector gv = singleUnicodeGlyphVector; - if (gv != null) { - singleUnicodeGlyphVector = null; // Don't need this anymore - return gv; - } - singleUnicode[0] = (char) unicodeID; - return font.createGlyphVector(getFontRenderContext(), singleUnicode); - } - } - - class GlyphProducer { - final int undefined = -2; - FontRenderContext fontRenderContext; - List glyphsOutput = new ArrayList(); - HashMap fullGlyphVectorCache = new HashMap(); - HashMap glyphMetricsCache = new HashMap(); - // The mapping from unicode character to font-specific glyph ID - int[] unicodes2Glyphs; - // The mapping from glyph ID to Glyph - Glyph[] glyphCache; - // We re-use this for each incoming string - CharSequenceIterator iter = new CharSequenceIterator(); - - GlyphProducer(int fontLengthInGlyphs) { - unicodes2Glyphs = new int[512]; - glyphCache = new Glyph[fontLengthInGlyphs]; - clearAllCacheEntries(); - } - - public List getGlyphs(CharSequence inString) { - glyphsOutput.clear(); - GlyphVector fullRunGlyphVector; - fullRunGlyphVector = fullGlyphVectorCache.get(inString.toString()); - if (fullRunGlyphVector == null) { - iter.initFromCharSequence(inString); - fullRunGlyphVector = font.createGlyphVector(getFontRenderContext(), iter); - fullGlyphVectorCache.put(inString.toString(), fullRunGlyphVector); - } - boolean complex = (fullRunGlyphVector.getLayoutFlags() != 0); - if (complex || DISABLE_GLYPH_CACHE) { - // Punt to the robust version of the renderer - glyphsOutput.add(new Glyph(inString.toString(), false)); - return glyphsOutput; - } - - int lengthInGlyphs = fullRunGlyphVector.getNumGlyphs(); - int i = 0; - while (i < lengthInGlyphs) { - Character letter = CharacterCache.valueOf(inString.charAt(i)); - GlyphMetrics metrics = glyphMetricsCache.get(letter); - if (metrics == null) { - metrics = fullRunGlyphVector.getGlyphMetrics(i); - glyphMetricsCache.put(letter, metrics); - } - Glyph glyph = getGlyph(inString, metrics, i); - if (glyph != null) { - glyphsOutput.add(glyph); - i++; - } else { - // Assemble a run of characters that don't fit in - // the cache - StringBuilder buf = new StringBuilder(); - while (i < lengthInGlyphs && - getGlyph(inString, fullRunGlyphVector.getGlyphMetrics(i), i) == null) { - buf.append(inString.charAt(i++)); - } - glyphsOutput.add(new Glyph(buf.toString(), - // Any more glyphs after this run? - i < lengthInGlyphs)); - } - } - return glyphsOutput; - } - - public void clearCacheEntry(int unicodeID) { - int glyphID = unicodes2Glyphs[unicodeID]; - if (glyphID != undefined) { - Glyph glyph = glyphCache[glyphID]; - if (glyph != null) { - glyph.clear(); - } - glyphCache[glyphID] = null; - } - unicodes2Glyphs[unicodeID] = undefined; - } - - public void clearAllCacheEntries() { - for (int i = 0; i < unicodes2Glyphs.length; i++) { - clearCacheEntry(i); - } - } - - public void register(Glyph glyph) { - unicodes2Glyphs[glyph.getUnicodeID()] = glyph.getGlyphCode(); - glyphCache[glyph.getGlyphCode()] = glyph; - } - - public float getGlyphPixelWidth(char unicodeID) { - Glyph glyph = getGlyph(unicodeID); - if (glyph != null) { - return glyph.getAdvance(); - } - - // Have to do this the hard / uncached way - singleUnicode[0] = unicodeID; - GlyphVector gv = font.createGlyphVector(fontRenderContext, - singleUnicode); - return gv.getGlyphMetrics(0).getAdvance(); - } - - // Returns a glyph object for this single glyph. Returns null - // if the unicode or glyph ID would be out of bounds of the - // glyph cache. - private Glyph getGlyph(CharSequence inString, - GlyphMetrics glyphMetrics, - int index) { - char unicodeID = inString.charAt(index); - - if (unicodeID >= unicodes2Glyphs.length) { - return null; - } - - int glyphID = unicodes2Glyphs[unicodeID]; - if (glyphID != undefined) { - return glyphCache[glyphID]; - } - - // Must fabricate the glyph - singleUnicode[0] = unicodeID; - GlyphVector gv = font.createGlyphVector(getFontRenderContext(), singleUnicode); - return getGlyph(unicodeID, gv, glyphMetrics); - } - - // It's unclear whether this variant might produce less - // optimal results than if we can see the entire GlyphVector - // for the incoming string - private Glyph getGlyph(int unicodeID) { - if (unicodeID >= unicodes2Glyphs.length) { - return null; - } - - int glyphID = unicodes2Glyphs[unicodeID]; - if (glyphID != undefined) { - return glyphCache[glyphID]; - } - singleUnicode[0] = (char) unicodeID; - GlyphVector gv = font.createGlyphVector(getFontRenderContext(), singleUnicode); - return getGlyph(unicodeID, gv, gv.getGlyphMetrics(0)); - } - - private Glyph getGlyph(int unicodeID, - GlyphVector singleUnicodeGlyphVector, - GlyphMetrics metrics) { - int glyphCode = singleUnicodeGlyphVector.getGlyphCode(0); - // Have seen huge glyph codes (65536) coming out of some fonts in some Unicode situations - if (glyphCode >= glyphCache.length) { - return null; - } - Glyph glyph = new Glyph(unicodeID, - glyphCode, - metrics.getAdvance(), - singleUnicodeGlyphVector, - this); - register(glyph); - return glyph; - } - } - - private static class CharacterCache { - private CharacterCache() { - } - - static final Character CACHE[] = new Character[127 + 1]; - - static { - for (int i = 0; i < CACHE.length; i++) { - CACHE[i] = (char) i; - } - } - - public static Character valueOf(char c) { - if (c <= 127) { // must cache - return CharacterCache.CACHE[c]; - } - return c; - } - } - - class Pipelined_QuadRenderer { - int mOutstandingGlyphsVerticesPipeline = 0; - FloatBuffer mTexCoords; - FloatBuffer mVertCoords; - boolean usingVBOs; - int mVBO_For_ResuableTileVertices; - int mVBO_For_ResuableTileTexCoords; - - Pipelined_QuadRenderer() { - GL2 gl = GLContext.getCurrentGL().getGL2(); - mVertCoords = Buffers.newDirectFloatBuffer(kTotalBufferSizeCoordsVerts); - mTexCoords = Buffers.newDirectFloatBuffer(kTotalBufferSizeCoordsTex); - - usingVBOs = getUseVertexArrays() && is15Available(gl); - - if (usingVBOs) { - try { - int[] vbos = new int[2]; - gl.glGenBuffers(2, IntBuffer.wrap(vbos)); - - mVBO_For_ResuableTileVertices = vbos[0]; - mVBO_For_ResuableTileTexCoords = vbos[1]; - - gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, - mVBO_For_ResuableTileVertices); - gl.glBufferData(GL2.GL_ARRAY_BUFFER, kTotalBufferSizeBytesVerts, - null, GL2.GL_STREAM_DRAW); // stream draw because this is a single quad use pipeline - - gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, - mVBO_For_ResuableTileTexCoords); - gl.glBufferData(GL2.GL_ARRAY_BUFFER, kTotalBufferSizeBytesTex, - null, GL2.GL_STREAM_DRAW); // stream draw because this is a single quad use pipeline - } catch (Exception e) { - isExtensionAvailable_GL_VERSION_1_5 = false; - usingVBOs = false; - } - } - } - - public void glTexCoord2f(float v, float v1) { - mTexCoords.put(v); - mTexCoords.put(v1); - } - - public void glVertex3f(float inX, float inY, float inZ) { - mVertCoords.put(inX); - mVertCoords.put(inY); - mVertCoords.put(inZ); - - mOutstandingGlyphsVerticesPipeline++; - - if (mOutstandingGlyphsVerticesPipeline >= kTotalBufferSizeVerts) { - this.draw(); - } - } - - private void draw() { - if (useVertexArrays) { - drawVertexArrays(); - } else { - drawIMMEDIATE(); - } - } - - private void drawVertexArrays() { - if (mOutstandingGlyphsVerticesPipeline > 0) { - GL2 gl = GLContext.getCurrentGL().getGL2(); - - TextureRenderer renderer = getBackingStore(); - renderer.getTexture(); // triggers texture uploads. Maybe this should be more obvious? - - mVertCoords.rewind(); - mTexCoords.rewind(); - - gl.glEnableClientState(GL2.GL_VERTEX_ARRAY); - - if (usingVBOs) { - gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, - mVBO_For_ResuableTileVertices); - gl.glBufferSubData(GL2.GL_ARRAY_BUFFER, 0, - mOutstandingGlyphsVerticesPipeline * kSizeInBytes_OneVertices_VertexData, - mVertCoords); // upload only the new stuff - gl.glVertexPointer(3, GL2.GL_FLOAT, 0, 0); - } else { - gl.glVertexPointer(3, GL2.GL_FLOAT, 0, mVertCoords); - } - - gl.glEnableClientState(GL2.GL_TEXTURE_COORD_ARRAY); - - if (usingVBOs) { - gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, - mVBO_For_ResuableTileTexCoords); - gl.glBufferSubData(GL2.GL_ARRAY_BUFFER, 0, - mOutstandingGlyphsVerticesPipeline * kSizeInBytes_OneVertices_TexData, - mTexCoords); // upload only the new stuff - gl.glTexCoordPointer(2, GL2.GL_FLOAT, 0, 0); - } else { - gl.glTexCoordPointer(2, GL2.GL_FLOAT, 0, mTexCoords); - } - - gl.glDrawArrays(GL2.GL_QUADS, 0, - mOutstandingGlyphsVerticesPipeline); - - mVertCoords.rewind(); - mTexCoords.rewind(); - mOutstandingGlyphsVerticesPipeline = 0; - } - } - - private void drawIMMEDIATE() { - if (mOutstandingGlyphsVerticesPipeline > 0) { - TextureRenderer renderer = getBackingStore(); - renderer.getTexture(); // triggers texture uploads. Maybe this should be more obvious? - - GL2 gl = GLContext.getCurrentGL().getGL2(); - gl.glBegin(GL2.GL_QUADS); - - try { - int numberOfQuads = mOutstandingGlyphsVerticesPipeline / 4; - mVertCoords.rewind(); - mTexCoords.rewind(); - - for (int i = 0; i < numberOfQuads; i++) { - gl.glTexCoord2f(mTexCoords.get(), mTexCoords.get()); - gl.glVertex3f(mVertCoords.get(), mVertCoords.get(), - mVertCoords.get()); - - gl.glTexCoord2f(mTexCoords.get(), mTexCoords.get()); - gl.glVertex3f(mVertCoords.get(), mVertCoords.get(), - mVertCoords.get()); - - gl.glTexCoord2f(mTexCoords.get(), mTexCoords.get()); - gl.glVertex3f(mVertCoords.get(), mVertCoords.get(), - mVertCoords.get()); - - gl.glTexCoord2f(mTexCoords.get(), mTexCoords.get()); - gl.glVertex3f(mVertCoords.get(), mVertCoords.get(), - mVertCoords.get()); - } - } catch (Exception e) { - e.printStackTrace(); - } finally { - gl.glEnd(); - mVertCoords.rewind(); - mTexCoords.rewind(); - mOutstandingGlyphsVerticesPipeline = 0; - } - } - } - } - - class DebugListener implements GLEventListener { - private GLU glu; - private Frame frame; - - DebugListener(GL gl, Frame frame) { - this.glu = GLU.createGLU(gl); - this.frame = frame; - } - - @Override - public void display(GLAutoDrawable drawable) { - GL2 gl = GLContext.getCurrentGL().getGL2(); - gl.glClear(GL2.GL_DEPTH_BUFFER_BIT | GL2.GL_COLOR_BUFFER_BIT); - - if (packer == null) { - return; - } - - TextureRenderer rend = getBackingStore(); - final int w = rend.getWidth(); - final int h = rend.getHeight(); - rend.beginOrthoRendering(w, h); - rend.drawOrthoRect(0, 0); - rend.endOrthoRendering(); - - if ((frame.getWidth() != w) || (frame.getHeight() != h)) { - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - frame.setSize(w, h); - } - }); - } - } - - @Override - public void dispose(GLAutoDrawable drawable) { - glu=null; - frame=null; - } - - // Unused methods - @Override - public void init(GLAutoDrawable drawable) { - } - - @Override - public void reshape(GLAutoDrawable drawable, int x, int y, int width, - int height) { - } - - public void displayChanged(GLAutoDrawable drawable, - boolean modeChanged, boolean deviceChanged) { - } - } - - /** - * Sets whether vertex arrays are being used internally for rendering, or whether text is rendered using the OpenGL - * immediate mode commands.This is provided as a concession for certain graphics cards which have poor vertex array - * performance. Defaults to true. - * - * @param useVertexArrays The desired value. - */ - public void setUseVertexArrays(boolean useVertexArrays) { - this.useVertexArrays = useVertexArrays; - } - - /** - * Indicates whether vertex arrays are being used internally for - * rendering, or whether text is rendered using the OpenGL - * immediate mode commands.Defaults to true. - * @return whether userVertexArrays is on or off. - */ - public final boolean getUseVertexArrays() { - return useVertexArrays; - } - - /** - * Sets whether smoothing (i.e., GL_LINEAR filtering) is enabled in the backing TextureRenderer of this - * TextRenderer.A few graphics cards do not behave well when this is enabled, resulting in fuzzy text. Defaults to - * true. - * - * @param smoothing The new smoothing setting. - */ - public void setSmoothing(boolean smoothing) { - this.smoothing = smoothing; - getBackingStore().setSmoothing(smoothing); - } - - /** - * Indicates whether smoothing is enabled in the backing TextureRenderer of this TextRenderer.A few graphics cards - * do not behave well when this is enabled, resulting in fuzzy text. Defaults to true. - * - * @return The current smoothing setting. - */ - public boolean getSmoothing() { - return smoothing; - } - - private boolean is15Available(GL gl) { - if (!checkFor_isExtensionAvailable_GL_VERSION_1_5) { - isExtensionAvailable_GL_VERSION_1_5 = gl.isExtensionAvailable(GLExtensions.VERSION_1_5); - checkFor_isExtensionAvailable_GL_VERSION_1_5 = true; - } - return isExtensionAvailable_GL_VERSION_1_5; - } -} diff --git a/src/gov/nasa/worldwind/render/TextRendererCache.java b/src/gov/nasa/worldwind/render/TextRendererCache.java index 5f670f784e..82a710bbe6 100644 --- a/src/gov/nasa/worldwind/render/TextRendererCache.java +++ b/src/gov/nasa/worldwind/render/TextRendererCache.java @@ -27,6 +27,8 @@ */ package gov.nasa.worldwind.render; +import com.jogamp.opengl.util.awt.TextRenderer; + import gov.nasa.worldwind.Disposable; import gov.nasa.worldwind.util.Logging; diff --git a/src/gov/nasa/worldwind/render/ToolTipRenderer.java b/src/gov/nasa/worldwind/render/ToolTipRenderer.java index b9e4b7af0f..13fb44fb69 100644 --- a/src/gov/nasa/worldwind/render/ToolTipRenderer.java +++ b/src/gov/nasa/worldwind/render/ToolTipRenderer.java @@ -30,6 +30,8 @@ import gov.nasa.worldwind.util.*; import com.jogamp.opengl.*; +import com.jogamp.opengl.util.awt.TextRenderer; + import javax.swing.*; import javax.swing.border.*; import java.awt.*; diff --git a/src/gov/nasa/worldwind/symbology/AbstractTacticalSymbol.java b/src/gov/nasa/worldwind/symbology/AbstractTacticalSymbol.java index af167bd955..7c410ec413 100644 --- a/src/gov/nasa/worldwind/symbology/AbstractTacticalSymbol.java +++ b/src/gov/nasa/worldwind/symbology/AbstractTacticalSymbol.java @@ -28,6 +28,7 @@ package gov.nasa.worldwind.symbology; +import com.jogamp.opengl.util.awt.TextRenderer; import com.jogamp.opengl.util.texture.*; import com.jogamp.opengl.util.texture.awt.AWTTextureIO; import gov.nasa.worldwind.*; diff --git a/src/gov/nasa/worldwind/symbology/TacticalGraphicLabel.java b/src/gov/nasa/worldwind/symbology/TacticalGraphicLabel.java index d24b0dcfb9..0837534eaa 100644 --- a/src/gov/nasa/worldwind/symbology/TacticalGraphicLabel.java +++ b/src/gov/nasa/worldwind/symbology/TacticalGraphicLabel.java @@ -37,6 +37,8 @@ import gov.nasa.worldwind.util.*; import com.jogamp.opengl.*; +import com.jogamp.opengl.util.awt.TextRenderer; + import java.awt.*; import java.awt.geom.*; diff --git a/src/gov/nasa/worldwind/terrain/RectangularTessellator.java b/src/gov/nasa/worldwind/terrain/RectangularTessellator.java index 869e99424a..07ea6ba500 100644 --- a/src/gov/nasa/worldwind/terrain/RectangularTessellator.java +++ b/src/gov/nasa/worldwind/terrain/RectangularTessellator.java @@ -39,6 +39,8 @@ import gov.nasa.worldwind.util.*; import com.jogamp.opengl.*; +import com.jogamp.opengl.util.awt.TextRenderer; + import java.awt.*; import java.nio.*; import java.util.*; diff --git a/src/gov/nasa/worldwind/util/EGM2008.java b/src/gov/nasa/worldwind/util/EGM2008.java new file mode 100644 index 0000000000..f8e64d9900 --- /dev/null +++ b/src/gov/nasa/worldwind/util/EGM2008.java @@ -0,0 +1,255 @@ +/* + * Copyright 2006-2009, 2017, 2020 United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The NASA World Wind Java (WWJ) platform is licensed under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * NASA World Wind Java (WWJ) also contains the following 3rd party Open Source + * software: + * + * Jackson Parser – Licensed under Apache 2.0 + * GDAL – Licensed under MIT + * JOGL – Licensed under Berkeley Software Distribution (BSD) + * Gluegen – Licensed under Berkeley Software Distribution (BSD) + * + * A complete listing of 3rd Party software notices and licenses included in + * NASA World Wind Java (WWJ) can be found in the WorldWindJava-v2.2 3rd-party + * notices and licenses PDF found in code directory. + */ + +package gov.nasa.worldwind.util; + +import gov.nasa.worldwind.cache.BasicMemoryCache; +import gov.nasa.worldwind.geom.Angle; +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.net.URL; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; + +public class EGM2008 +{ + public static final int N_ROW_MARKERS = 2; // The beginning and end of each row of latitude data is a flag of some sort + public static final int N_LONGITUDE_COLS = 8640 + N_ROW_MARKERS; // Number of float32s in a row of data in the data file. + public static final int N_LATITUDE_ROWS = 4321; // Number of rows. + public static final double GRID_RESOLUTION = 2.5d / 60d; // 2.5 minute grid + public static final double CELL_AREA = GRID_RESOLUTION * GRID_RESOLUTION; + protected static final long CACHE_SIZE = EGM2008.N_LONGITUDE_COLS * 4 * 45 * 15; // Cache 15 degrees worth of offsets. + public static final int N_LAT_ROW_BYTES = N_LONGITUDE_COLS * 4; // Offsets are float32 + + protected String offsetsFilePath; + protected BufferWrapper deltas; + protected final BasicMemoryCache offsetCache; + + protected class GridCell + { + public double x1; + public double y1; + public double x2; + public double y2; + + public GridCell(double x1, double y1) + { + this.x1 = x1; + this.y1 = y1; + this.x2 = x1 + EGM2008.GRID_RESOLUTION; + this.y2 = y1 + EGM2008.GRID_RESOLUTION; + } + + public GridCell() + { + this(0, 0); + } + + public GridCell intersect(GridCell that) + { + GridCell intersection = new GridCell(); + intersection.x1 = Math.max(this.x1, that.x1); + intersection.x2 = Math.min(this.x2, that.x2); + intersection.y1 = Math.max(this.y1, that.y1); + intersection.y2 = Math.min(this.y2, that.y2); + return intersection; + } + + @Override + public String toString() + { + return String.format("%5.2f,%5.2f,%5.2f,%5.2f", x1, y1, x2, y2); + } + + public double area() + { + return (this.x2 - this.x1) * (this.y2 - this.y1); + } + } + + /** + * Allows the retrieval of geoid offsets from the EGM2008 2.5 Minute Interpolation Grid sourced from the + * National Geospatial-Intelligence Agency Office of Geomatics (https://earth-info.nga.mil/). + * + * The EGM2008 data path. This data file is not included in the SDK due to its size. The data may be downloaded here: + * https://builds.worldwind.arc.nasa.gov/artifactory/EGM2008-Data/egm2008_25.dat + * + * @param offsetsFilePath a path pointing to a file with the geoid offsets. + */ + public EGM2008(String offsetsFilePath) + { + if (offsetsFilePath == null) + { + String msg = Logging.getMessage("nullValue.PathIsNull"); + Logging.logger().severe(msg); + throw new IllegalArgumentException(msg); + } + File test = new File(offsetsFilePath); + if (test.exists()) + { + this.offsetsFilePath = offsetsFilePath; + } + else + { + Class c = EGM2008.class; + URL url = c.getResource("/" + offsetsFilePath); + if (url != null) + { + test = WWIO.getFileForLocalAddress(url); + this.offsetsFilePath = test.getAbsolutePath(); + } + else + { + this.offsetsFilePath = null; + } + } + this.offsetCache = new BasicMemoryCache((EGM2008.CACHE_SIZE * 8) / 10, EGM2008.CACHE_SIZE); + this.offsetCache.setName(EGM2008.class.getName()); + } + + public float getOffset(Angle lat, Angle lon) throws IOException + { + return this.getOffset((float) lat.degrees, (float) lon.degrees); + } + + public int getLatRow(double lat) + { + // Compute the row in the data file corresponding to a given latitude. + // Latitude row zero in the data corresponds to 90 degrees latitude (north pole) and increases southward + // Longitude column zero in the data corresponds to 0 degrees of longitude and increases eastward + float lat180 = 90f - (float) lat; + return (int) Math.floor(lat180 / EGM2008.GRID_RESOLUTION); + } + + public int getLonCol(double lon) + { + // Compute the column in the data file corresponding to a given latitude and longitude. + // Latitude row zero in the data corresponds to 90 degrees latitude (north pole) and increases southward + // Longitude column zero in the data corresponds to 0 degrees of longitude and increases eastward + float lon360 = (float) lon; + if (lon < 0) + { + lon360 = lon360 + 360; + } + return (int) Math.floor(lon360 / EGM2008.GRID_RESOLUTION); + } + + public float[][] getLatRows(int latRow) throws IOException + { + int[] interpRowIndices = + { + latRow, latRow + 1 + }; + float[][] latDataArray = new float[2][]; + boolean retrievalRequired = false; + for (int i = 0; i < interpRowIndices.length; i++) + { + if (interpRowIndices[i] < EGM2008.N_LATITUDE_ROWS) + { + float[] latData = (float[]) this.offsetCache.getObject(interpRowIndices[i]); + latDataArray[i] = latData; + if (latData == null) + { + retrievalRequired = true; + } + } + } + if (retrievalRequired) + { + try (RandomAccessFile offsetFile = new RandomAccessFile(this.offsetsFilePath, "r")) + { + for (int i = 0; i < interpRowIndices.length; i++) + { + if (interpRowIndices[i] < EGM2008.N_LATITUDE_ROWS && latDataArray[i] == null) + { + offsetFile.seek(interpRowIndices[i] * EGM2008.N_LAT_ROW_BYTES); + byte[] latByteData = new byte[EGM2008.N_LAT_ROW_BYTES]; + offsetFile.read(latByteData); + ByteBuffer latByteBuffer = ByteBuffer.wrap(latByteData).order(ByteOrder.LITTLE_ENDIAN); + FloatBuffer latFloatBuffer = latByteBuffer.asFloatBuffer(); + float[] latData = new float[EGM2008.N_LONGITUDE_COLS]; + latFloatBuffer.get(latData); + this.offsetCache.add(interpRowIndices[i], latData, EGM2008.N_LAT_ROW_BYTES); + latDataArray[i] = latData; + } + } + } + } + return latDataArray; + } + + public float getOffset(double lat, double lon) throws IOException + { + if (this.offsetsFilePath == null) + { + return 0f; + } + int latRow = this.getLatRow(lat); + int lonCol = this.getLonCol(lon); + + float[][] latDataArray = getLatRows(latRow); + + float baseOffset = latDataArray[0][lonCol + EGM2008.N_ROW_MARKERS / 2]; + if (latDataArray[1] == null) + { + return baseOffset; + } + + // Interpolate with surrounding offset cells + float lat180 = 90f - (float) lat; + float lon360 = (float) lon; + if (lon < 0) + { + lon360 = lon360 + 360; + } + GridCell offsetCell = new GridCell(lon360, lat180); + double baseLat = ((double) latRow) * EGM2008.GRID_RESOLUTION; + double baseLon = ((double) lonCol) * EGM2008.GRID_RESOLUTION; + float interpOffset = 0; + for (int x = 0; x < 2; x++) + { + double cellLon = baseLon + ((double) x) * EGM2008.GRID_RESOLUTION; + for (int y = 0; y < 2; y++) + { + float cellOffset = latDataArray[y][lonCol + EGM2008.N_ROW_MARKERS / 2 + x]; + double cellLat = baseLat + ((double) y) * EGM2008.GRID_RESOLUTION; + GridCell interpCell = new GridCell(cellLon, cellLat); + GridCell intersection = offsetCell.intersect(interpCell); + interpOffset += cellOffset * (intersection.area() / EGM2008.CELL_AREA); + } + } + return interpOffset; + } + + public boolean isEGMDataAvailable() + { + return this.offsetsFilePath != null; + } +} diff --git a/src/gov/nasa/worldwind/util/OGLTextRenderer.java b/src/gov/nasa/worldwind/util/OGLTextRenderer.java index 271568cc94..a5b77a291d 100644 --- a/src/gov/nasa/worldwind/util/OGLTextRenderer.java +++ b/src/gov/nasa/worldwind/util/OGLTextRenderer.java @@ -27,6 +27,8 @@ */ package gov.nasa.worldwind.util; +import com.jogamp.opengl.util.awt.TextRenderer; + import gov.nasa.worldwind.render.*; /** diff --git a/src/gov/nasa/worldwind/util/PlacemarkClutterFilter.java b/src/gov/nasa/worldwind/util/PlacemarkClutterFilter.java index e41b6a8100..0d785e5e3f 100644 --- a/src/gov/nasa/worldwind/util/PlacemarkClutterFilter.java +++ b/src/gov/nasa/worldwind/util/PlacemarkClutterFilter.java @@ -34,6 +34,8 @@ import gov.nasa.worldwind.render.*; import com.jogamp.opengl.*; +import com.jogamp.opengl.util.awt.TextRenderer; + import java.awt.*; import java.awt.geom.*; import java.util.*; diff --git a/src/gov/nasa/worldwind/util/layertree/LayerTree.java b/src/gov/nasa/worldwind/util/layertree/LayerTree.java index 0b4ee0937a..ca504bb616 100644 --- a/src/gov/nasa/worldwind/util/layertree/LayerTree.java +++ b/src/gov/nasa/worldwind/util/layertree/LayerTree.java @@ -27,6 +27,8 @@ */ package gov.nasa.worldwind.util.layertree; +import java.awt.Point; + import gov.nasa.worldwind.avlist.AVKey; import gov.nasa.worldwind.render.Offset; import gov.nasa.worldwind.util.Logging; @@ -87,11 +89,11 @@ public LayerTree(LayerTreeModel model) * Creates a new LayerTree with an empty LayerTreeModel and the specified screen * location. * - * @param offset the screen location of the tree's upper left corner, relative to the screen's upper left corner. + * @param offset the screen location of the tree's lower left corner, relative to the screen's lower left corner. * * @throws IllegalArgumentException if offset is null. */ - public LayerTree(Offset offset) + public LayerTree(Point offset) { if (offset == null) { @@ -107,12 +109,12 @@ public LayerTree(Offset offset) * Creates a new LayerTree with the specified model and the specified screen location. * * @param model the tree model to use. - * @param offset the screen location of the tree's upper left corner, relative to the screen's upper left corner. + * @param offset the screen location of the tree's lower left corner, relative to the screen's lower left corner. (GL surface pixels) * * @throws IllegalArgumentException if model is null, or if offset is * null. */ - public LayerTree(LayerTreeModel model, Offset offset) + public LayerTree(LayerTreeModel model, Point offset) { if (model == null) { @@ -139,7 +141,7 @@ public LayerTree(LayerTreeModel model, Offset offset) * @param model this tree's model to use, or null to create a new LayerTreeModel. * @param offset the screen location of this tree's upper left corner, or null to use the default. */ - protected void initialize(LayerTreeModel model, Offset offset) + protected void initialize(LayerTreeModel model, Point offset) { if (model == null) model = this.createTreeModel(); @@ -167,10 +169,10 @@ protected LayerTreeModel createTreeModel() * * @return new TreeLayout. */ - protected TreeLayout createTreeLayout(Offset offset) + protected TreeLayout createTreeLayout(Point offset) { if (offset == null) - offset = DEFAULT_OFFSET; + offset = new Point(DEFAULT_OFFSET.getX().intValue(), DEFAULT_OFFSET.getY().intValue()); BasicTreeLayout layout = new BasicTreeLayout(this, offset); layout.getFrame().setFrameTitle(DEFAULT_FRAME_TITLE); @@ -196,7 +198,8 @@ protected TreeLayout createTreeLayout(Offset offset) } /** {@inheritDoc} */ - public LayerTreeModel getModel() + @Override + public LayerTreeModel getModel() { return (LayerTreeModel) super.getModel(); } diff --git a/src/gov/nasa/worldwind/util/tree/BasicTreeLayout.java b/src/gov/nasa/worldwind/util/tree/BasicTreeLayout.java index 8bb6c85172..d9325e46f8 100644 --- a/src/gov/nasa/worldwind/util/tree/BasicTreeLayout.java +++ b/src/gov/nasa/worldwind/util/tree/BasicTreeLayout.java @@ -28,6 +28,7 @@ package gov.nasa.worldwind.util.tree; +import com.jogamp.opengl.util.awt.TextRenderer; import com.jogamp.opengl.util.texture.TextureCoords; import gov.nasa.worldwind.WWObjectImpl; import gov.nasa.worldwind.avlist.AVKey; @@ -160,7 +161,7 @@ public BasicTreeLayout(Tree tree) */ public BasicTreeLayout(Tree tree, int x, int y) { - this(tree, new Offset((double) x, (double) y, AVKey.PIXELS, AVKey.INSET_PIXELS)); + this(tree, new Point(x, y)); } /** @@ -170,7 +171,7 @@ public BasicTreeLayout(Tree tree, int x, int y) * @param screenLocation The location of the upper left corner of the tree frame. The offset is interpreted relative * to the lower left corner of the screen. */ - public BasicTreeLayout(Tree tree, Offset screenLocation) + public BasicTreeLayout(Tree tree, Point screenLocation) { this.tree = tree; this.frame = this.createFrame(); @@ -186,7 +187,8 @@ public BasicTreeLayout(Tree tree, Offset screenLocation) // events between TreeLayout and Tree. this.tree.addPropertyChangeListener(new PropertyChangeListener() { - public void propertyChange(PropertyChangeEvent propertyChangeEvent) + @Override + public void propertyChange(PropertyChangeEvent propertyChangeEvent) { // Ignore events originated by this TreeLayout, and repaint events. There is no need to recompute the // tree layout just because a repaint was triggered. @@ -341,7 +343,8 @@ public void setDrawNodeStateSymbol(boolean drawNodeStateSymbol) } /** {@inheritDoc} */ - public long getUpdateTime() + @Override + public long getUpdateTime() { return this.updateTime; } @@ -364,7 +367,8 @@ protected ScrollFrame createFrame() * * @return Size of the rendered tree. */ - public Dimension getSize(DrawContext dc, Dimension frameSize) + @Override + public Dimension getSize(DrawContext dc, Dimension frameSize) { this.updateAttributes(dc); @@ -472,7 +476,8 @@ protected boolean mustDisplayNode(TreeNode node, int level) } /** {@inheritDoc} */ - public void preRender(DrawContext dc) + @Override + public void preRender(DrawContext dc) { // Adjust scroll position if an application has requested that the layout scroll to make a node visible. this.scrollToNode(dc); @@ -481,7 +486,8 @@ public void preRender(DrawContext dc) } /** {@inheritDoc} */ - public void render(DrawContext dc) + @Override + public void render(DrawContext dc) { this.frame.render(dc); } @@ -514,7 +520,8 @@ protected synchronized void scrollToNode(DrawContext dc) } /** {@inheritDoc} */ - public void renderScrollable(DrawContext dc, Point location, Dimension frameSize, Rectangle clipBounds) + @Override + public void renderScrollable(DrawContext dc, Point location, Dimension frameSize, Rectangle clipBounds) { TreeModel model = this.tree.getModel(); TreeNode root = model.getRoot(); @@ -1321,7 +1328,8 @@ protected Rectangle findNodeBounds(TreeNode needle, TreeNode haystack, DrawConte } /** {@inheritDoc} */ - public synchronized void makeVisible(TreePath path) + @Override + public synchronized void makeVisible(TreePath path) { TreeNode node = this.tree.getNode(path); if (node == null) @@ -1345,7 +1353,7 @@ public synchronized void makeVisible(TreePath path) * * @return Screen location, measured in pixels from the upper left corner of the screen. */ - public Offset getScreenLocation() + public Point getScreenLocation() { return this.frame.getScreenLocation(); } @@ -1356,19 +1364,21 @@ public Offset getScreenLocation() * * @param screenLocation New screen location. */ - public void setScreenLocation(Offset screenLocation) + public void setScreenLocation(Point screenLocation) { frame.setScreenLocation(screenLocation); } /** {@inheritDoc} */ - public TreeAttributes getAttributes() + @Override + public TreeAttributes getAttributes() { return this.normalAttributes; } /** {@inheritDoc} */ - public void setAttributes(TreeAttributes attributes) + @Override + public void setAttributes(TreeAttributes attributes) { if (attributes == null) { @@ -1464,7 +1474,8 @@ public boolean isHighlighted() * * @param highlighted True if the tree should be highlighted. */ - public void setHighlighted(boolean highlighted) + @Override + public void setHighlighted(boolean highlighted) { this.highlighted = highlighted; } diff --git a/src/gov/nasa/worldwind/util/tree/DragControl.java b/src/gov/nasa/worldwind/util/tree/DragControl.java index ac0b8e0e28..8f6edace36 100644 --- a/src/gov/nasa/worldwind/util/tree/DragControl.java +++ b/src/gov/nasa/worldwind/util/tree/DragControl.java @@ -101,7 +101,7 @@ else if (event.isDragEnd()) /** * Called when a drag begins. This implementation saves the first drag point to {@link #dragRefPoint}. * - * @param point Point at which dragging started. + * @param point Point at which dragging started (GL surface pixels) */ protected void beginDrag(Point point) { @@ -111,7 +111,7 @@ protected void beginDrag(Point point) /** * Called for each point within a drag action. * - * @param point Current drag point. + * @param point Current drag point. (GL surface pixels) */ protected abstract void drag(Point point); diff --git a/src/gov/nasa/worldwind/util/tree/FrameResizeControl.java b/src/gov/nasa/worldwind/util/tree/FrameResizeControl.java index 69f3f26776..fcfb13b54d 100644 --- a/src/gov/nasa/worldwind/util/tree/FrameResizeControl.java +++ b/src/gov/nasa/worldwind/util/tree/FrameResizeControl.java @@ -28,13 +28,11 @@ package gov.nasa.worldwind.util.tree; -import gov.nasa.worldwind.avlist.AVKey; import gov.nasa.worldwind.render.*; import gov.nasa.worldwind.util.AbstractResizeHotSpot; import java.awt.*; import java.awt.event.*; -import java.awt.geom.*; /** * A screen control for resizing a frame. This class handles the resize input events, but does does not actually draw @@ -89,15 +87,15 @@ protected void setSize(Dimension newSize) @Override protected Point getScreenPoint() { - Point2D point2D = this.frame.getScreenPoint(); - return new Point((int)point2D.getX(), (int)point2D.getY()); + Point point = this.frame.getScreenLocation(); + return new Point(point); } /** {@inheritDoc} */ @Override protected void setScreenPoint(Point newPoint) { - this.frame.setScreenLocation(new Offset(newPoint.getX(), newPoint.getY(), AVKey.PIXELS, AVKey.INSET_PIXELS)); + this.frame.setScreenLocation(newPoint); } /** {@inheritDoc} */ @@ -113,7 +111,8 @@ protected Dimension getMinimumSize() * * @param event The event to handle. */ - public void mouseWheelMoved(MouseWheelEvent event) + @Override + public void mouseWheelMoved(MouseWheelEvent event) { if (event == null || event.isConsumed()) return; diff --git a/src/gov/nasa/worldwind/util/tree/ScrollBar.java b/src/gov/nasa/worldwind/util/tree/ScrollBar.java index 431a8084a5..a973053661 100644 --- a/src/gov/nasa/worldwind/util/tree/ScrollBar.java +++ b/src/gov/nasa/worldwind/util/tree/ScrollBar.java @@ -683,7 +683,8 @@ public boolean isAutoScrolling() * * @param dc the DrawContext to be used */ - public void render(DrawContext dc) + @Override + public void render(DrawContext dc) { if (dc.getFrameTimeStamp() != this.frameNumber) { @@ -1110,7 +1111,9 @@ protected void beginDrag(Point point) this.dragRefValue = this.scrollBar.getValue(); } - protected void drag(Point point) + /** {@inheritDoc} */ + @Override + protected void drag(Point point) { int delta; int adjustment; @@ -1118,7 +1121,10 @@ protected void drag(Point point) if (AVKey.VERTICAL.equals(scrollBar.getOrientation())) { - delta = point.y - this.dragRefPoint.y; + // scroll bar zero position is at the top in GL surface coordinates. + // 'point' will be in GL surface coordinates, so moving the mouse + // towards the bottom of the screen yields a smaller y value. + delta = this.dragRefPoint.y - point.y; screenDimension = this.scrollBar.scrollBounds.height - this.scrollBar.getMinScrollKnobSize(); } else diff --git a/src/gov/nasa/worldwind/util/tree/ScrollFrame.java b/src/gov/nasa/worldwind/util/tree/ScrollFrame.java index ebb1d63c6e..057fd378fa 100644 --- a/src/gov/nasa/worldwind/util/tree/ScrollFrame.java +++ b/src/gov/nasa/worldwind/util/tree/ScrollFrame.java @@ -28,6 +28,7 @@ package gov.nasa.worldwind.util.tree; +import com.jogamp.opengl.util.awt.TextRenderer; import com.jogamp.opengl.util.texture.*; import gov.nasa.worldwind.*; import gov.nasa.worldwind.avlist.AVKey; @@ -98,7 +99,7 @@ public class ScrollFrame extends DragControl implements PreRenderable, Renderabl protected Scrollable contents; /** Indicates the location of the upper left corner of the frame. */ - protected Offset screenLocation; + protected Point screenLocation; /** Indicates whether or not to draw a title bar in the frame. Default is true. */ protected boolean drawTitleBar = true; @@ -209,11 +210,6 @@ public class ScrollFrame extends DragControl implements PreRenderable, Renderabl protected long frameNumber = -1; /** Indicates that the frame must be regenerated because the size or attributes have changed. */ protected boolean mustRecomputeFrameGeometry = true; - /** - * Indicates the location of the upper left corner of the frame, in AWT coordinates (origin at the upper left corner - * of the screen. - */ - protected Point2D awtScreenPoint; /** Bounds of the full frame. */ protected Rectangle frameBounds; /** Bounds of the frame inside the frame border. */ @@ -262,7 +258,7 @@ public ScrollFrame() */ public ScrollFrame(int x, int y) { - this(new Offset((double) x, (double) y, AVKey.PIXELS, AVKey.INSET_PIXELS)); + this(new Point(x, y)); } /** @@ -270,7 +266,7 @@ public ScrollFrame(int x, int y) * * @param screenLocation initial location of the upper left corner of the frame. */ - public ScrollFrame(Offset screenLocation) + public ScrollFrame(Point screenLocation) { super(null); this.setScreenLocation(screenLocation); @@ -628,43 +624,32 @@ public Rectangle getBounds(DrawContext dc) { this.updateBounds(dc); - return new Rectangle((int) this.awtScreenPoint.getX(), (int) this.awtScreenPoint.getY(), this.frameSize.width, + return new Rectangle(screenLocation.x, screenLocation.y, this.frameSize.width, this.frameSize.height); } /** - * Get the location of the upper left corner of the tree, measured in screen coordinates with the origin at the - * upper left corner of the screen. + * Get the location of the lower left corner of the tree, measured in screen + * coordinates with the origin at the lower left corner of the screen. * - * @return Screen location, measured in pixels from the upper left corner of the screen. + * @return Screen location, measured in GL surface pixels from the lower left corner of the screen. */ - public Offset getScreenLocation() + public Point getScreenLocation() { return this.screenLocation; } /** - * Set the location of the upper left corner of the tree, measured in screen coordinates with the origin at the - * upper left corner of the screen. + * Set the location of the lower left corner of the tree, measured in GL surface coordinates + * with the origin at the lower left corner of the screen. * * @param screenLocation New screen location. */ - public void setScreenLocation(Offset screenLocation) + public void setScreenLocation(Point screenLocation) { this.screenLocation = screenLocation; } - /** - * Get the location of the upper left corner of the frame, measured from the upper left corner of the screen. - * - * @return The location of the upper left corner of the frame. This method will return null until the has been - * rendered. - */ - protected Point2D getScreenPoint() - { - return this.awtScreenPoint; - } - /** * Indicates the frame attributes used to draw the frame when it is not highlighted. * @@ -1043,9 +1028,10 @@ protected int computeTileTextureDimension(Dimension frameSize, Dimension content } /** {@inheritDoc} */ - public void preRender(DrawContext dc) + @Override + public void preRender(DrawContext dc) { - Offset screenLocation = this.getScreenLocation(); + Point screenLocation = this.getScreenLocation(); if (screenLocation == null) return; @@ -1057,8 +1043,7 @@ public void preRender(DrawContext dc) Point pickPoint = dc.getPickPoint(); if (pickPoint != null) { - int glY = dc.getView().getViewport().height - pickPoint.y; - this.setHighlighted(this.pickBounds.contains(new Point(pickPoint.x, glY))); + this.setHighlighted(this.pickBounds.contains(pickPoint)); } this.determineActiveAttributes(); @@ -1078,9 +1063,10 @@ public void preRender(DrawContext dc) } /** {@inheritDoc} */ - public void render(DrawContext dc) + @Override + public void render(DrawContext dc) { - Offset screenLocation = this.getScreenLocation(); + Point screenLocation = this.getScreenLocation(); if (screenLocation == null || this.frameBounds == null) return; @@ -1244,26 +1230,23 @@ public void updateBounds(DrawContext dc) if (!this.frameSize.equals(previousFrameSize)) this.mustRecomputeFrameGeometry = true; - // Compute point in OpenGL coordinates - Point2D upperLeft = this.screenLocation.computeOffset(viewport.width, viewport.height, 1.0, 1.0); - - this.awtScreenPoint = new Point((int) upperLeft.getX(), (int) (viewport.height - upperLeft.getY())); + // Set frame bounds + this.frameBounds = new Rectangle(screenLocation.x, screenLocation.y, + this.frameSize.width, this.frameSize.height); - this.frameBounds = new Rectangle((int) upperLeft.getX(), (int) upperLeft.getY() - this.frameSize.height, - this.frameSize.width, this.frameSize.height); - - // Compute the pickable screen extent as the frame extent, plus the width of the frame's pickable outline. - // This extent is used during picking to ensure that the frame's outline is pickable when it exceeds the - // frame's screen extent. + // Compute the pickable screen extent in GL surface coordinates as the frame extent, + // plus the width of the frame's pickable outline. + // This extent is used during picking to ensure that the frame's outline is pickable + // when it exceeds the frame's screen extent. this.pickBounds = new Rectangle( this.frameBounds.x - this.borderPickWidth / 2, this.frameBounds.y - this.borderPickWidth / 2, this.frameBounds.width + this.borderPickWidth, this.frameBounds.height + this.borderPickWidth); - this.innerBounds = new Rectangle((int) upperLeft.getX() + this.frameBorder, - (int) upperLeft.getY() - frameSize.height + this.frameBorder, frameSize.width - this.frameBorder * 2, - frameSize.height - this.frameBorder * 2); + this.innerBounds = new Rectangle(frameBounds.x + this.frameBorder, + frameBounds.y + this.frameBorder, frameSize.width - this.frameBorder * 2, + frameSize.height - this.frameBorder * 2); // If the content size has yet not been computed, compute it now. if (contentSize == null) @@ -2269,18 +2252,17 @@ protected void beginDrag(Point point) { if (this.isEnableMove()) { - Point2D location = this.awtScreenPoint; - this.dragRefPoint = new Point((int) location.getX() - point.x, (int) location.getY() - point.y); + this.dragRefPoint = new Point( screenLocation.x - point.x, screenLocation.y - point.y); } } - public void drag(Point point) + @Override + public void drag(Point point) { if (this.isEnableMove()) { - double x = point.x + this.dragRefPoint.x; - double y = point.y + this.dragRefPoint.y; - this.setScreenLocation(new Offset(x, y, AVKey.PIXELS, AVKey.INSET_PIXELS)); + Point pt = new Point(point.x + this.dragRefPoint.x, point.y + this.dragRefPoint.y); + this.setScreenLocation(pt); } } @@ -2293,8 +2275,8 @@ public void selected(SelectEvent event) super.selected(event); // Minimize the frame if the title bar was double clicked. - Rectangle titleBarBounds = new Rectangle((int) this.awtScreenPoint.getX() + this.frameBorder, - (int) this.awtScreenPoint.getY() + this.frameBorder * 2, this.innerBounds.width, this.titleBarHeight); + Rectangle titleBarBounds = new Rectangle(this.screenLocation.x + this.frameBorder, + this.screenLocation.y + this.frameBorder * 2, this.innerBounds.width, this.titleBarHeight); if (event.isLeftDoubleClick()) { @@ -2475,7 +2457,8 @@ class TextureTile implements Comparable * @return -1 if this tile was accessed less recently than that tile, 0 if the access times are the same, or 1 * if this tile was accessed more recently. */ - public int compareTo(TextureTile that) + @Override + public int compareTo(TextureTile that) { if (that == null) { diff --git a/src/gov/nasa/worldwind/view/BasicView.java b/src/gov/nasa/worldwind/view/BasicView.java index 2857760067..22809dbe66 100644 --- a/src/gov/nasa/worldwind/view/BasicView.java +++ b/src/gov/nasa/worldwind/view/BasicView.java @@ -591,7 +591,7 @@ public void goTo(Position position, double distance) public Line computeRayFromScreenPoint(double x, double y) { return ViewUtil.computeRayFromScreenPoint(this, x, y, - this.modelview, this.projection, this.viewport); + this.modelview, this.projection); } public Position computePositionFromScreenPoint(double x, double y) diff --git a/src/gov/nasa/worldwind/view/ViewUtil.java b/src/gov/nasa/worldwind/view/ViewUtil.java index e2dbd2d988..dbd8d97c68 100644 --- a/src/gov/nasa/worldwind/view/ViewUtil.java +++ b/src/gov/nasa/worldwind/view/ViewUtil.java @@ -536,7 +536,7 @@ public static Angle normalizedRoll(Angle unnormalizedRoll) } public static Line computeRayFromScreenPoint(View view, double x, double y, - Matrix modelview, Matrix projection, java.awt.Rectangle viewport) + Matrix modelview, Matrix projection) { if (modelview == null || projection == null) { @@ -544,12 +544,6 @@ public static Line computeRayFromScreenPoint(View view, double x, double y, Logging.logger().severe(message); throw new IllegalArgumentException(message); } - if (viewport == null) - { - String message = Logging.getMessage("nullValue.RectangleIsNull"); - Logging.logger().severe(message); - throw new IllegalArgumentException(message); - } // Compute a ray originating from the view, and passing through the screen point (x, y). // @@ -566,9 +560,8 @@ public static Line computeRayFromScreenPoint(View view, double x, double y, if (eye == null) return null; - double yInGLCoords = viewport.height - y - 1; - Vec4 a = view.unProject(new Vec4(x, yInGLCoords, 0, 0)); - Vec4 b = view.unProject(new Vec4(x, yInGLCoords, 1, 0)); + Vec4 a = view.unProject(new Vec4(x, y, 0, 0)); + Vec4 b = view.unProject(new Vec4(x, y, 1, 0)); if (a == null || b == null) return null; diff --git a/src/gov/nasa/worldwind/view/orbit/OrbitViewInputHandler.java b/src/gov/nasa/worldwind/view/orbit/OrbitViewInputHandler.java index f429cc0b49..3d622eda72 100644 --- a/src/gov/nasa/worldwind/view/orbit/OrbitViewInputHandler.java +++ b/src/gov/nasa/worldwind/view/orbit/OrbitViewInputHandler.java @@ -159,7 +159,6 @@ protected void onMoveTo(Position focalPosition, ViewInputAttributes.DeviceAttrib } } - @SuppressWarnings("UnusedParameters") protected void onMoveTo2D(Position focalPosition, ViewInputAttributes.DeviceAttributes deviceAttributes, ViewInputAttributes.ActionAttributes actionAttribs) { @@ -314,7 +313,6 @@ protected void onHorizontalTranslateRel(Angle forwardChange, Angle sideChange, } } - @SuppressWarnings("UnusedParameters") protected void onHorizontalTranslate2D(double forwardInput, double sideInput, double totalForwardInput, double totalSideInput, ViewInputAttributes.DeviceAttributes deviceAttributes, @@ -335,9 +333,9 @@ protected void onHorizontalTranslate2D(double forwardInput, double sideInput, Point p1 = constrainToSourceBounds(this.getMouseDownPoint(), this.getWorldWindow()); Point p2 = constrainToSourceBounds(this.getMousePoint(), this.getWorldWindow()); Line ray1 = ViewUtil.computeRayFromScreenPoint(orbitView, p1.x, p1.y, this.mouseDownModelview, - this.mouseDownProjection, this.mouseDownViewport); + this.mouseDownProjection); Line ray2 = ViewUtil.computeRayFromScreenPoint(orbitView, p2.x, p2.y, this.mouseDownModelview, - this.mouseDownProjection, this.mouseDownViewport); + this.mouseDownProjection); // Compute a model coordinate plane passing through the position under the cursor when the mouse button was // pressed. Fall back to a plane normal to the globe if the cursor was off the globe. @@ -400,7 +398,6 @@ protected void onResetHeading(ViewInputAttributes.ActionAttributes actionAttribs * * @param actionAttribs input that caused the change. */ - @SuppressWarnings("UnusedParameters") protected void onResetRoll(ViewInputAttributes.ActionAttributes actionAttribs) { View view = this.getView(); diff --git a/src/gov/nasa/worldwindx/applications/antenna/AntennaAxes.java b/src/gov/nasa/worldwindx/applications/antenna/AntennaAxes.java index de6ad819d8..23dc2412e0 100644 --- a/src/gov/nasa/worldwindx/applications/antenna/AntennaAxes.java +++ b/src/gov/nasa/worldwindx/applications/antenna/AntennaAxes.java @@ -37,6 +37,8 @@ import gov.nasa.worldwind.util.*; import com.jogamp.opengl.*; +import com.jogamp.opengl.util.awt.TextRenderer; + import javax.xml.stream.*; import java.awt.*; import java.io.IOException; diff --git a/src/gov/nasa/worldwindx/applications/sar/render/TrackSegmentInfo.java b/src/gov/nasa/worldwindx/applications/sar/render/TrackSegmentInfo.java index 5455ebed9f..3503bd4c49 100644 --- a/src/gov/nasa/worldwindx/applications/sar/render/TrackSegmentInfo.java +++ b/src/gov/nasa/worldwindx/applications/sar/render/TrackSegmentInfo.java @@ -34,6 +34,8 @@ import gov.nasa.worldwindx.applications.sar.*; import com.jogamp.opengl.*; +import com.jogamp.opengl.util.awt.TextRenderer; + import java.awt.*; /** diff --git a/src/gov/nasa/worldwindx/applications/sar/segmentplane/SegmentPlaneRenderer.java b/src/gov/nasa/worldwindx/applications/sar/segmentplane/SegmentPlaneRenderer.java index 9444f7228d..b99607e25a 100644 --- a/src/gov/nasa/worldwindx/applications/sar/segmentplane/SegmentPlaneRenderer.java +++ b/src/gov/nasa/worldwindx/applications/sar/segmentplane/SegmentPlaneRenderer.java @@ -40,6 +40,8 @@ import gov.nasa.worldwind.util.*; import com.jogamp.opengl.*; +import com.jogamp.opengl.util.awt.TextRenderer; + import java.awt.*; import java.nio.*; import java.util.*; diff --git a/src/gov/nasa/worldwindx/applications/worldwindow/core/ToolTipAnnotation.java b/src/gov/nasa/worldwindx/applications/worldwindow/core/ToolTipAnnotation.java index 53e831a7c2..c8bf39e19a 100644 --- a/src/gov/nasa/worldwindx/applications/worldwindow/core/ToolTipAnnotation.java +++ b/src/gov/nasa/worldwindx/applications/worldwindow/core/ToolTipAnnotation.java @@ -98,7 +98,7 @@ protected void doRenderNow(DrawContext dc) protected Point adjustDrawPointToViewport(Point point, Rectangle bounds, Rectangle viewport) { int x = point.x; - int y = (int) viewport.getHeight() - point.y - 1; + int y = point.y; if (x + this.getOffsetX() + bounds.getWidth() > viewport.getWidth()) x = (int) (viewport.getWidth() - bounds.getWidth()) - 1 - this.getOffsetX(); diff --git a/src/gov/nasa/worldwindx/examples/Annotations.java b/src/gov/nasa/worldwindx/examples/Annotations.java index cd0e8972dc..866ba403c6 100644 --- a/src/gov/nasa/worldwindx/examples/Annotations.java +++ b/src/gov/nasa/worldwindx/examples/Annotations.java @@ -38,6 +38,8 @@ import gov.nasa.worldwindx.examples.util.PowerOfTwoPaddedImage; import com.jogamp.opengl.*; +import com.jogamp.opengl.util.awt.TextRenderer; + import javax.swing.*; import javax.swing.Box; import javax.swing.border.*; diff --git a/src/gov/nasa/worldwindx/examples/ContextMenusOnShapes.java b/src/gov/nasa/worldwindx/examples/ContextMenusOnShapes.java index c432b47db4..9ace62fed7 100644 --- a/src/gov/nasa/worldwindx/examples/ContextMenusOnShapes.java +++ b/src/gov/nasa/worldwindx/examples/ContextMenusOnShapes.java @@ -72,7 +72,6 @@ public void selected(SelectEvent event) { } } - @SuppressWarnings({"UnusedDeclaration"}) protected void highlight(SelectEvent event, Object o) { if (this.lastPickedPlacemark == o) { return; // same thing selected @@ -110,7 +109,7 @@ protected void showContextMenu(SelectEvent event) { } ContextMenu menu = new ContextMenu((Component) event.getSource(), menuInfo); - menu.show(event.getMouseEvent()); + menu.show(event.getAwtMousePt()); } } } @@ -145,7 +144,7 @@ protected void makeMenuItems() { } } - public void show(final MouseEvent event) { + public void show(final Point screenPt) { JPopupMenu popup = new JPopupMenu(); popup.add(this.menuTitleItem); @@ -156,7 +155,7 @@ public void show(final MouseEvent event) { popup.add(subMenu); } - popup.show(sourceComponent, event.getX(), event.getY()); + popup.show(sourceComponent, (int)screenPt.getX(), (int)screenPt.getY()); } } diff --git a/src/gov/nasa/worldwindx/examples/EGM2008Offsets.java b/src/gov/nasa/worldwindx/examples/EGM2008Offsets.java new file mode 100644 index 0000000000..f2b403ca0d --- /dev/null +++ b/src/gov/nasa/worldwindx/examples/EGM2008Offsets.java @@ -0,0 +1,237 @@ +/* + * Copyright 2006-2009, 2017, 2020 United States Government, as represented by the + * Administrator of the National Aeronautics and Space Administration. + * All rights reserved. + * + * The NASA World Wind Java (WWJ) platform is licensed under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * NASA World Wind Java (WWJ) also contains the following 3rd party Open Source + * software: + * + * Jackson Parser – Licensed under Apache 2.0 + * GDAL – Licensed under MIT + * JOGL – Licensed under Berkeley Software Distribution (BSD) + * Gluegen – Licensed under Berkeley Software Distribution (BSD) + * + * A complete listing of 3rd Party software notices and licenses included in + * NASA World Wind Java (WWJ) can be found in the WorldWindJava-v2.2 3rd-party + * notices and licenses PDF found in code directory. + */ +package gov.nasa.worldwindx.examples; + +import gov.nasa.worldwind.Model; +import gov.nasa.worldwind.avlist.AVKey; +import gov.nasa.worldwind.geom.LatLon; +import gov.nasa.worldwind.geom.Position; +import gov.nasa.worldwind.geom.Sector; +import gov.nasa.worldwind.globes.Earth; +import gov.nasa.worldwind.globes.Globe; +import gov.nasa.worldwind.layers.RenderableLayer; +import gov.nasa.worldwind.render.PointPlacemark; +import gov.nasa.worldwind.util.EGM2008; +import java.awt.Dimension; + +import java.io.IOException; +import java.util.ArrayList; +import javax.swing.SwingUtilities; + +/** + * Shows how to apply EGM2008 offsets to Earth elevations. + * + * This EGM2008 data file is not included in the SDK due to its size. The data may be downloaded here: + * https://builds.worldwind.arc.nasa.gov/artifactory/EGM2008-Data/egm2008_25.dat + * + * This example looks for the EGM2008 data in the WorldWind src/config folder by default. + */ +public class EGM2008Offsets extends ApplicationTemplate +{ + public static class AppFrame extends ApplicationTemplate.AppFrame + { + /** + * Attempt to retrieve the best elevations for a specified list of locations. The elevations returned are the best currently + * available for the data set and the area bounding the locations. Since the necessary elevation data might not + * be in memory at the time of the call, this method iterates until the necessary elevation data is in memory + * and can be used to determine the locations elevations. + * + * @param locations a list of locations to determine elevations for + */ + public void loadBestElevations(ArrayList locations) + { + Globe globe = this.getWwd().getModel().getGlobe(); + ArrayList sectors = new ArrayList<>(); + ArrayList> locationsList = new ArrayList<>(); + double delta = 0.0001; + for (LatLon ll : locations) + { + double lat = ll.latitude.degrees; + double lon = ll.longitude.degrees; + sectors.add(Sector.fromDegrees(lat, lat + delta, lon, lon + delta)); + ArrayList sectorLocations = new ArrayList<>(); + sectorLocations.add(ll); + sectorLocations.add(LatLon.fromDegrees(lat + delta, lon + delta)); + locationsList.add(sectorLocations); + } + + double[] targetResolutions = new double[sectors.size()]; + double[] actualResolutions = new double[sectors.size()]; + for (int i = 0, len = sectors.size(); i < len; i++) + { + targetResolutions[i] = globe.getElevationModel().getBestResolution(sectors.get(i)); + } + boolean resolutionsAchieved = false; + double[] elevations = new double[2]; + while (!resolutionsAchieved) + { + for (int i = 0, len = sectors.size(); i < len; i++) + { + actualResolutions[i] = globe.getElevations(sectors.get(i), locationsList.get(i), targetResolutions[i], elevations); + } + + resolutionsAchieved = true; + for (int i = 0, len = actualResolutions.length; i < len && resolutionsAchieved; i++) + { + resolutionsAchieved = actualResolutions[i] <= targetResolutions[i]; + } + if (!resolutionsAchieved) + { + try + { + Thread.sleep(200); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + } + } + } + + public AppFrame() + { + Model m = this.wwjPanel.getWwd().getModel(); + Earth earth = (Earth) m.getGlobe(); + final RenderableLayer layer = new RenderableLayer(); + double[] locations = new double[] + { + 37.0, -119.0, + 36.0, -117.016667, + 89.0, 0.0, + -80.0, 0.0, + -90.0, 0.0 + }; + EGM2008 egm2008Offsets = new EGM2008("config/egm2008_25.dat"); + boolean egmAvailable = egm2008Offsets.isEGMDataAvailable(); + if (!egmAvailable) + { + System.out.println("*** EGM 2008 data not available."); + } + + // Run the elevation query in a separate thread to avoid locking up the user interface + Thread t = new Thread(() -> + { + ArrayList elevLocations = new ArrayList<>(); + for (int i = 0; i < locations.length; i += 2) + { + elevLocations.add(LatLon.fromDegrees(locations[i], locations[i + 1])); + } + + loadBestElevations(elevLocations); + + try + { + for (int i = 0; i < locations.length; i += 2) + { + Position pos = Position.fromDegrees(locations[i], locations[i + 1], 0); + PointPlacemark placemark = new PointPlacemark(pos); + String label = String.format("lat: %7.4f, lon: %7.4f", locations[i], locations[i + 1]); + float egmOffset = egm2008Offsets.getOffset(pos.latitude, pos.longitude); + double elevation = earth.getElevation(pos.latitude, pos.longitude); + if (egmAvailable) + { + placemark.setValue(AVKey.DISPLAY_NAME, String.format("EGM2008 Offset: %7.4f\nEllipsoid elevation:%7.4f\nEGM2008 Adjusted elevation: %7.4f", + egmOffset, elevation, elevation - egmOffset)); + } + else + { + placemark.setValue(AVKey.DISPLAY_NAME, String.format("EGM2008 Offset: N/A\nEllipsoid elevation:%7.4f\nEGM2008 Adjusted elevation: N/A", + elevation)); + } + placemark.setLabelText(label); + layer.addRenderable(placemark); + } + } + catch (IOException iex) + { + iex.printStackTrace(); + } + + SwingUtilities.invokeLater(() -> + { + System.out.println("Elevations retrieved"); + getWwd().redraw(); + }); + }); + t.start(); + + try + { + // Test offsets for some coordinates + float lat = 47; + float lon = -94; + System.out.println(lat + "," + lon + "," + egm2008Offsets.getOffset(lat, lon)); + + lat = 37; + lon = -119; + System.out.println(lat + "," + lon + "," + egm2008Offsets.getOffset(lat, lon)); + + // Try previous coordinates to verify caching + lat = 47; + lon = -94; + System.out.println(lat + "," + lon + "," + egm2008Offsets.getOffset(lat, lon)); + + lat = 37; + lon = -119; + System.out.println(lat + "," + lon + "," + egm2008Offsets.getOffset(lat, lon)); + + lat = 47.02f; + lon = -94.02f; + System.out.println(lat + "," + lon + "," + egm2008Offsets.getOffset(lat, lon)); + + float gridResolution = (float) EGM2008.GRID_RESOLUTION; + lat = 47 + gridResolution; + lon = -94 - gridResolution; + System.out.println(lat + "," + lon + "," + egm2008Offsets.getOffset(lat, lon)); + + lat = 36.0f; + lon = -117.0f; + System.out.println(lat + "," + lon + "," + egm2008Offsets.getOffset(lat, lon)); + + lat = 36.0f; + lon = -117.041666666667f; + System.out.println(lat + "," + lon + "," + egm2008Offsets.getOffset(lat, lon)); + + System.out.println(); + } + catch (IOException iex) + { + iex.printStackTrace(); + } + + this.wwjPanel.toolTipController.setAnnotationSize(new Dimension(500, 0)); + insertBeforeCompass(getWwd(), layer); + } + } + + public static void main(String[] args) + { + ApplicationTemplate.start("WorldWind EGM2008 Offsets", AppFrame.class); + } +} diff --git a/src/gov/nasa/worldwindx/examples/EGM96Offsets.java b/src/gov/nasa/worldwindx/examples/EGM96Offsets.java index a64d11b1bc..39b7adf6b0 100644 --- a/src/gov/nasa/worldwindx/examples/EGM96Offsets.java +++ b/src/gov/nasa/worldwindx/examples/EGM96Offsets.java @@ -2,39 +2,50 @@ * Copyright 2006-2009, 2017, 2020 United States Government, as represented by the * Administrator of the National Aeronautics and Space Administration. * All rights reserved. - * + * * The NASA World Wind Java (WWJ) platform is licensed under the Apache License, * Version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. - * + * * NASA World Wind Java (WWJ) also contains the following 3rd party Open Source * software: - * + * * Jackson Parser – Licensed under Apache 2.0 * GDAL – Licensed under MIT * JOGL – Licensed under Berkeley Software Distribution (BSD) * Gluegen – Licensed under Berkeley Software Distribution (BSD) - * + * * A complete listing of 3rd Party software notices and licenses included in * NASA World Wind Java (WWJ) can be found in the WorldWindJava-v2.2 3rd-party * notices and licenses PDF found in code directory. */ - package gov.nasa.worldwindx.examples; import gov.nasa.worldwind.Model; +import gov.nasa.worldwind.avlist.AVKey; +import gov.nasa.worldwind.geom.LatLon; +import gov.nasa.worldwind.geom.Position; +import gov.nasa.worldwind.geom.Sector; import gov.nasa.worldwind.globes.Earth; +import gov.nasa.worldwind.globes.Globe; +import gov.nasa.worldwind.layers.RenderableLayer; +import gov.nasa.worldwind.render.PointPlacemark; +import gov.nasa.worldwind.util.EGM96; +import java.awt.Dimension; import java.io.IOException; +import java.util.ArrayList; +import javax.swing.SwingUtilities; /** * Shows how to apply EGM96 offsets to the Earth. + * * @author tag * @version $Id: EGM96Offsets.java 1501 2013-07-11 15:59:11Z tgaskins $ */ @@ -42,17 +53,118 @@ public class EGM96Offsets extends ApplicationTemplate { public static class AppFrame extends ApplicationTemplate.AppFrame { + /** + * Attempt to retrieve the best elevations for a specified list of locations. The elevations returned are the best currently + * available for the data set and the area bounding the locations. Since the necessary elevation data might not + * be in memory at the time of the call, this method iterates until the necessary elevation data is in memory + * and can be used to determine the locations elevations. + * + * @param locations a list of locations to determine elevations for + */ + public void loadBestElevations(ArrayList locations) + { + Globe globe = this.getWwd().getModel().getGlobe(); + ArrayList sectors = new ArrayList<>(); + ArrayList> locationsList = new ArrayList<>(); + double delta = 0.0001; + for (LatLon ll : locations) + { + double lat = ll.latitude.degrees; + double lon = ll.longitude.degrees; + sectors.add(Sector.fromDegrees(lat, lat + delta, lon, lon + delta)); + ArrayList sectorLocations = new ArrayList<>(); + sectorLocations.add(ll); + sectorLocations.add(LatLon.fromDegrees(lat + delta, lon + delta)); + locationsList.add(sectorLocations); + } + + double[] targetResolutions = new double[sectors.size()]; + double[] actualResolutions = new double[sectors.size()]; + for (int i = 0, len = sectors.size(); i < len; i++) + { + targetResolutions[i] = globe.getElevationModel().getBestResolution(sectors.get(i)); + } + boolean resolutionsAchieved = false; + double[] elevations = new double[2]; + while (!resolutionsAchieved) + { + for (int i = 0, len = sectors.size(); i < len; i++) + { + actualResolutions[i] = globe.getElevations(sectors.get(i), locationsList.get(i), targetResolutions[i], elevations); + } + + resolutionsAchieved = true; + for (int i = 0, len = actualResolutions.length; i < len && resolutionsAchieved; i++) + { + resolutionsAchieved = actualResolutions[i] <= targetResolutions[i]; + } + if (!resolutionsAchieved) + { + try + { + Thread.sleep(200); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + } + } + } + public AppFrame() { Model m = this.wwjPanel.getWwd().getModel(); + Earth earth = (Earth) m.getGlobe(); try { - ((Earth) m.getGlobe()).applyEGMA96Offsets("config/EGM96.dat"); + earth.applyEGMA96Offsets("config/EGM96.dat"); } catch (IOException e) { e.printStackTrace(); } + final RenderableLayer layer = new RenderableLayer(); + double[] locations = new double[] + { + 37.0, -119.0, + 36.0, -117.016667, + 89.0, 0.0, + -80.0, 0.0, + -90.0, 0.0 + }; + Thread t = new Thread(() -> + { + ArrayList elevLocations = new ArrayList<>(); + for (int i = 0; i < locations.length; i += 2) + { + elevLocations.add(LatLon.fromDegrees(locations[i], locations[i + 1])); + } + + loadBestElevations(elevLocations); + + EGM96 egm96Offsets = earth.getEGM96(); + for (int i = 0; i < locations.length; i += 2) + { + Position pos = Position.fromDegrees(locations[i], locations[i + 1], 0); + PointPlacemark placemark = new PointPlacemark(pos); + String label = String.format("lat: %7.4f, lon: %7.4f", locations[i], locations[i + 1]); + placemark.setValue(AVKey.DISPLAY_NAME, String.format("EGM96 Offset: %7.4f\nEGM96 Adjusted elevation: %7.4f", + egm96Offsets.getOffset(pos.latitude, pos.longitude), + earth.getElevation(pos.latitude, pos.longitude))); + placemark.setLabelText(label); + layer.addRenderable(placemark); + } + SwingUtilities.invokeLater(() -> + { + System.out.println("Elevations retrieved"); + getWwd().redraw(); + }); + }); + t.start(); + + this.wwjPanel.toolTipController.setAnnotationSize(new Dimension(500, 0)); + insertBeforeCompass(getWwd(), layer); } } diff --git a/src/gov/nasa/worldwindx/examples/analytics/AnalyticSurfaceLegend.java b/src/gov/nasa/worldwindx/examples/analytics/AnalyticSurfaceLegend.java index 85d358249b..69b42dfc81 100644 --- a/src/gov/nasa/worldwindx/examples/analytics/AnalyticSurfaceLegend.java +++ b/src/gov/nasa/worldwindx/examples/analytics/AnalyticSurfaceLegend.java @@ -37,6 +37,8 @@ import java.text.Format; import java.util.ArrayList; +import com.jogamp.opengl.util.awt.TextRenderer; + /** * @author dcollins * @version $Id: AnalyticSurfaceLegend.java 2053 2014-06-10 20:16:57Z tgaskins $ @@ -158,7 +160,8 @@ public int getHeight(DrawContext dc) return this.screenImage.getImageHeight(dc); } - public void render(DrawContext dc) + @Override + public void render(DrawContext dc) { if (dc == null) { @@ -225,27 +228,32 @@ public static AnalyticSurfaceLegend.LabelAttributes createLegendLabelAttributes( { return new AnalyticSurfaceLegend.LabelAttributes() { - public double getValue() + @Override + public double getValue() { return value; } - public String getText() + @Override + public String getText() { return text; } - public Font getFont() + @Override + public Font getFont() { return font; } - public Color getColor() + @Override + public Color getColor() { return color; } - public Point2D getOffset() + @Override + public Point2D getOffset() { return new Point2D.Double(xOffset, yOffset); } @@ -320,18 +328,16 @@ protected void drawLabel(DrawContext dc, LabelAttributes attr, double x, double tr.beginRendering(viewport.width, viewport.height); try { - double yInGLCoords = viewport.height - y - 1; - // Draw the text outline, in a contrasting color. tr.setColor(WWUtil.computeContrastingColor(color)); - tr.draw(text, (int) x - 1, (int) yInGLCoords - 1); - tr.draw(text, (int) x + 1, (int) yInGLCoords - 1); - tr.draw(text, (int) x + 1, (int) yInGLCoords + 1); - tr.draw(text, (int) x - 1, (int) yInGLCoords + 1); + tr.draw(text, (int) x - 1, (int) y - 1); + tr.draw(text, (int) x + 1, (int) y - 1); + tr.draw(text, (int) x + 1, (int) y + 1); + tr.draw(text, (int) x - 1, (int) y + 1); // Draw the text over its outline, in the specified color. tr.setColor(color); - tr.draw(text, (int) x, (int) yInGLCoords); + tr.draw(text, (int) x, (int) y); } finally { @@ -411,7 +417,8 @@ public LabelRenderable(AnalyticSurfaceLegend legend, LabelAttributes attr, doubl this.orderedLabel = new OrderedLabel(legend, attr, x, y, halign, valign); } - public void render(DrawContext dc) + @Override + public void render(DrawContext dc) { dc.addOrderedRenderable(this.orderedLabel); } @@ -437,17 +444,20 @@ public OrderedLabel(AnalyticSurfaceLegend legend, LabelAttributes attr, double x this.valign = valign; } - public double getDistanceFromEye() + @Override + public double getDistanceFromEye() { return 0; } - public void render(DrawContext dc) + @Override + public void render(DrawContext dc) { this.legend.drawLabel(dc, this.attr, this.x, this.y, this.halign, this.valign); } - public void pick(DrawContext dc, Point pickPoint) + @Override + public void pick(DrawContext dc, Point pickPoint) { // Intentionally left blank. } diff --git a/src/gov/nasa/worldwindx/examples/kml/KMLViewer.java b/src/gov/nasa/worldwindx/examples/kml/KMLViewer.java index 12b60e1fa9..759426f6f4 100644 --- a/src/gov/nasa/worldwindx/examples/kml/KMLViewer.java +++ b/src/gov/nasa/worldwindx/examples/kml/KMLViewer.java @@ -37,7 +37,6 @@ import gov.nasa.worldwind.layers.RenderableLayer; import gov.nasa.worldwind.ogc.kml.*; import gov.nasa.worldwind.ogc.kml.impl.KMLController; -import gov.nasa.worldwind.render.Offset; import gov.nasa.worldwind.util.*; import javax.swing.*; @@ -76,7 +75,7 @@ public AppFrame() // Add the on-screen layer tree, refreshing model with the WorldWindow's current layer list. We // intentionally refresh the tree's model before adding the layer that contains the tree itself. This // prevents the tree's layer from being displayed in the tree itself. - this.layerTree = new LayerTree(new Offset(20d, 160d, AVKey.PIXELS, AVKey.INSET_PIXELS)); + this.layerTree = new LayerTree(new Point(20, 160)); this.layerTree.getModel().refresh(this.getWwd().getModel().getLayers()); // Set up a layer to display the on-screen layer tree in the WorldWindow. This layer is not displayed in @@ -119,7 +118,8 @@ protected void addDocumentLayer(KMLRoot document) // Set up to receive SSLHandshakeExceptions that occur during resource retrieval. WorldWind.getRetrievalService().setSSLExceptionListener(new RetrievalService.SSLExceptionListener() { - public void onException(Throwable e, String path) + @Override + public void onException(Throwable e, String path) { System.out.println(path); System.out.println(e); @@ -164,14 +164,16 @@ protected void addKMLLayer(KMLRoot kmlRoot) // we ensure that the network link tree view appearance is consistent with the KML specification. layerNode.addPropertyChangeListener(AVKey.RETRIEVAL_STATE_SUCCESSFUL, new PropertyChangeListener() { - public void propertyChange(final PropertyChangeEvent event) + @Override + public void propertyChange(final PropertyChangeEvent event) { if (event.getSource() instanceof KMLNetworkLinkTreeNode) { // Manipulate the tree on the EDT. SwingUtilities.invokeLater(new Runnable() { - public void run() + @Override + public void run() { ((KMLNetworkLinkTreeNode) event.getSource()).expandOpenContainers(layerTree); getWwd().redraw(); @@ -213,7 +215,8 @@ public WorkerThread(Object kmlSource, AppFrame appFrame) * If loading the KML source fails, this prints the exception and its stack trace to the standard error stream, * but otherwise does nothing. */ - public void run() + @Override + public void run() { try { @@ -226,7 +229,8 @@ public void run() final KMLRoot finalKMLRoot = kmlRoot; SwingUtilities.invokeLater(new Runnable() { - public void run() + @Override + public void run() { appFrame.addKMLLayer(finalKMLRoot); } @@ -287,7 +291,8 @@ protected static void makeMenu(final AppFrame appFrame) JMenuItem openFileMenuItem = new JMenuItem(new AbstractAction("Open File...") { - public void actionPerformed(ActionEvent actionEvent) + @Override + public void actionPerformed(ActionEvent actionEvent) { try { @@ -311,7 +316,8 @@ public void actionPerformed(ActionEvent actionEvent) JMenuItem openURLMenuItem = new JMenuItem(new AbstractAction("Open URL...") { - public void actionPerformed(ActionEvent actionEvent) + @Override + public void actionPerformed(ActionEvent actionEvent) { try { @@ -334,6 +340,7 @@ public void actionPerformed(ActionEvent actionEvent) public static void main(String[] args) { //noinspection UnusedDeclaration - final AppFrame af = (AppFrame) start("WorldWind KML Viewer", AppFrame.class); + @SuppressWarnings("unused") + final AppFrame af = (AppFrame) start("WorldWind KML Viewer", AppFrame.class); } } diff --git a/src/gov/nasa/worldwindx/examples/util/BalloonController.java b/src/gov/nasa/worldwindx/examples/util/BalloonController.java index f1708c1e95..ccd2c2abd9 100644 --- a/src/gov/nasa/worldwindx/examples/util/BalloonController.java +++ b/src/gov/nasa/worldwindx/examples/util/BalloonController.java @@ -163,6 +163,19 @@ public void setBalloonOffset(int balloonOffset) //*********************** Event handling *****************************// //********************************************************************// + /** + * Construct a mouse event with GL surface screen coordinates + * @param e + * @return + */ + private MouseEvent glMouseEvent(MouseEvent awtMouseEvent) { + int[] GLmousePt = wwd.getSceneController().getDrawContext().awtPointToGLpoint(awtMouseEvent.getPoint()); + MouseEvent e = new MouseEvent(awtMouseEvent.getComponent(), awtMouseEvent.getID(), + awtMouseEvent.getWhen(), awtMouseEvent.getModifiersEx(), + awtMouseEvent.getClickCount(), GLmousePt[0], GLmousePt[1], awtMouseEvent.isPopupTrigger(), + awtMouseEvent.getButton()); + return e; + } /** * Handle a mouse click. If the top picked object has a balloon attached to it the balloon will be made visible. A * balloon may be attached to a KML feature, or to any picked object though {@link AVKey#BALLOON}. @@ -170,11 +183,13 @@ public void setBalloonOffset(int balloonOffset) * @param e Mouse event */ @Override - public void mouseClicked(MouseEvent e) + public void mouseClicked(MouseEvent awtEv) { - if (e == null || e.isConsumed()) + if (awtEv == null || awtEv.isConsumed()) return; + MouseEvent e = glMouseEvent(awtEv); + // Implementation note: handle the balloon with a mouse listener instead of a select listener so that the balloon // can be turned off if the user clicks on the terrain. try @@ -219,6 +234,9 @@ public void mouseClicked(MouseEvent e) // Wrap the handler in a try/catch to keep exceptions from bubbling up Logging.logger().warning(ex.getMessage() != null ? ex.getMessage() : ex.toString()); } + + if (e.isConsumed()) + awtEv.consume(); } @Override @@ -248,7 +266,8 @@ else if (this.resizeController != null && !this.resizeController.isResizing()) } } - @SuppressWarnings("deprecation") + @Override + @SuppressWarnings("deprecation") public void selected(SelectEvent event) { if (event == null || event.isConsumed() @@ -984,8 +1003,7 @@ protected void showBalloon(Balloon balloon, Position position) Vec4 screenVec4 = this.wwd.getView().project( this.wwd.getModel().getGlobe().computePointFromPosition(position)); - Point screenPoint = new Point((int) screenVec4.x, - (int) (this.wwd.getView().getViewport().height - screenVec4.y)); + Point screenPoint = new Point((int) screenVec4.x, (int) screenVec4.y); // If the balloon is attached to the screen rather than the globe, move it to the // current point. Otherwise move it to the position under the current point. @@ -1327,8 +1345,7 @@ protected Point getBalloonPointForScreenOverlay(KMLScreenOverlay overlay) Rectangle viewport = this.wwd.getView().getViewport(); Point2D point2D = offset.computeOffset(viewport.width, viewport.height, 1d, 1d); - int y = (int) point2D.getY(); - return new Point((int) point2D.getX(), viewport.height - y); + return new Point((int) point2D.getX(), (int) point2D.getY()); } /** @@ -1504,7 +1521,8 @@ public DocumentRetrievalTask(String url, KMLRoot context, String featureRef, lon * gov.nasa.worldwind.ogc.kml.KMLRoot, String)}. If an exception occurs, or the timeout is exceeded, schedule a * callback on the EDT to {@link BalloonController#onDocumentFailed(String, Exception)} */ - public void run() + @Override + public void run() { KMLRoot root = null; @@ -1544,7 +1562,8 @@ else if (docSource != null) final KMLRoot pinnedRoot = root; // Final ref that can be accessed by anonymous class SwingUtilities.invokeLater(new Runnable() { - public void run() + @Override + public void run() { BalloonController.this.onDocumentLoaded(docUrl, pinnedRoot, featureRef); } @@ -1558,7 +1577,8 @@ public void run() // Schedule a callback on the EDT to report the error to the BalloonController SwingUtilities.invokeLater(new Runnable() { - public void run() + @Override + public void run() { BalloonController.this.onDocumentFailed(docUrl, e); } diff --git a/src/gov/nasa/worldwindx/examples/util/LayerManagerLayer.java b/src/gov/nasa/worldwindx/examples/util/LayerManagerLayer.java index 57dd7465f2..24a72f8714 100644 --- a/src/gov/nasa/worldwindx/examples/util/LayerManagerLayer.java +++ b/src/gov/nasa/worldwindx/examples/util/LayerManagerLayer.java @@ -644,7 +644,7 @@ protected void drag(SelectEvent event) Point cursorOffset = new Point(event.getMouseEvent().getPoint().x - this.dragRefCursorPoint.x, event.getMouseEvent().getPoint().y - this.dragRefCursorPoint.y); Point targetPoint = new Point(this.dragRefPoint.x + cursorOffset.x, - this.dragRefPoint.y - cursorOffset.y); + this.dragRefPoint.y + cursorOffset.y); this.moveTo(targetPoint); event.consume(); } diff --git a/src/gov/nasa/worldwindx/examples/util/ScreenSelector.java b/src/gov/nasa/worldwindx/examples/util/ScreenSelector.java index ec266fd0b8..b6a42bdbbd 100644 --- a/src/gov/nasa/worldwindx/examples/util/ScreenSelector.java +++ b/src/gov/nasa/worldwindx/examples/util/ScreenSelector.java @@ -163,8 +163,8 @@ public void endSelection(Point point) maxX = this.startPoint.x; } - // Compute the selection's extremes along the y axis. The selection is defined in AWT screen coordinates, so - // the origin is in the upper left corner and the y axis points down. + // Compute the selection's extremes along the y axis. The selection is defined in GL surface coordinates, so + // the origin is in the lower left corner and the y axis points up. double minY, maxY; if (this.startPoint.y < this.endPoint.y) { @@ -185,7 +185,7 @@ public void endSelection(Point point) if (minY == maxY && minX < maxX) minY = maxY - 1; - this.rect.setRect(minX, maxY, maxX - minX, maxY - minY); + this.rect.setRect(minX, minY, maxX - minX, maxY - minY); } public void clearSelection() @@ -215,17 +215,20 @@ public void setBorderColor(Color color) this.borderColor = color; } - public double getDistanceFromEye() + @Override + public double getDistanceFromEye() { return 0; // Screen rectangle is drawn on top of other ordered renderables, except other screen objects. } - public void pick(DrawContext dc, Point pickPoint) + @Override + public void pick(DrawContext dc, Point pickPoint) { // Intentionally left blank. SelectionRectangle is not pickable. } - public void render(DrawContext dc) + @Override + public void render(DrawContext dc) { if (dc == null) { @@ -270,7 +273,7 @@ protected void drawOrderedRenderable(DrawContext dc) gl.glOrtho(0, viewport.getWidth(), 0, viewport.getHeight(), -1, 1); // l, r, b, t, n, f this.BEogsh.pushModelviewIdentity(gl); gl.glTranslated(0.5, 0.5, 0.0); - gl.glTranslated(selection.getX(), viewport.getHeight() - selection.getY(), 0); + gl.glTranslated(selection.getX(), selection.getY(), 0); gl.glScaled(selection.getWidth() - 1, selection.getHeight() - 1, 1); // Disable the depth test and enable blending so this screen rectangle appears on top of the existing @@ -460,12 +463,14 @@ protected void sendMessage(Message message) } } - public void mouseClicked(MouseEvent mouseEvent) + @Override + public void mouseClicked(MouseEvent mouseEvent) { // Intentionally left blank. ScreenSelector does not respond to mouse clicked events. } - public void mousePressed(MouseEvent mouseEvent) + @Override + public void mousePressed(MouseEvent mouseEvent) { if (mouseEvent == null) // Ignore null events. return; @@ -478,7 +483,8 @@ public void mousePressed(MouseEvent mouseEvent) mouseEvent.consume(); // Consume the mouse event to prevent the view from responding to it. } - public void mouseReleased(MouseEvent mouseEvent) + @Override + public void mouseReleased(MouseEvent mouseEvent) { if (mouseEvent == null) // Ignore null events. return; @@ -491,17 +497,20 @@ public void mouseReleased(MouseEvent mouseEvent) mouseEvent.consume(); // Consume the mouse event to prevent the view from responding to it. } - public void mouseEntered(MouseEvent mouseEvent) + @Override + public void mouseEntered(MouseEvent mouseEvent) { // Intentionally left blank. ScreenSelector does not respond to mouse entered events. } - public void mouseExited(MouseEvent mouseEvent) + @Override + public void mouseExited(MouseEvent mouseEvent) { // Intentionally left blank. ScreenSelector does not respond to mouse exited events. } - public void mouseDragged(MouseEvent mouseEvent) + @Override + public void mouseDragged(MouseEvent mouseEvent) { if (mouseEvent == null) // Ignore null events. return; @@ -513,7 +522,8 @@ public void mouseDragged(MouseEvent mouseEvent) mouseEvent.consume(); // Consume the mouse event to prevent the view from responding to it. } - public void mouseMoved(MouseEvent mouseEvent) + @Override + public void mouseMoved(MouseEvent mouseEvent) { // Intentionally left blank. ScreenSelector does not respond to mouse moved events. } @@ -530,8 +540,7 @@ protected void selectionStarted(MouseEvent mouseEvent) this.sendMessage(new Message(SELECTION_STARTED, this)); } - @SuppressWarnings({"UnusedParameters"}) - protected void selectionEnded(MouseEvent mouseEvent) + protected void selectionEnded(@SuppressWarnings("unused") MouseEvent mouseEvent) { this.selectionRect.clearSelection(); this.getWwd().getSceneController().setPickRectangle(null); @@ -577,19 +586,20 @@ protected Point limitPointToWorldWindow(Point point) int x = point.x; if (x < viewport.x) x = viewport.x; - if (x > viewport.x + viewport.width) - x = viewport.x + viewport.width; + if (x >= viewport.x + viewport.width) + x = viewport.x + viewport.width - 1; int y = point.y; if (y < viewport.y) y = viewport.y; - if (y > viewport.y + viewport.height) - y = viewport.y + viewport.height; + if (y >= viewport.y + viewport.height) + y = viewport.y + viewport.height - 1; return new Point(x, y); } - public void selected(SelectEvent event) + @Override + public void selected(SelectEvent event) { try { diff --git a/src/gov/nasa/worldwindx/examples/util/StatusLayer.java b/src/gov/nasa/worldwindx/examples/util/StatusLayer.java index 9544a97cee..76f9d4c6e5 100644 --- a/src/gov/nasa/worldwindx/examples/util/StatusLayer.java +++ b/src/gov/nasa/worldwindx/examples/util/StatusLayer.java @@ -27,6 +27,7 @@ */ package gov.nasa.worldwindx.examples.util; +import com.jogamp.opengl.util.awt.TextRenderer; import com.jogamp.opengl.util.texture.*; import gov.nasa.worldwind.*; import gov.nasa.worldwind.event.*; diff --git a/src/gov/nasa/worldwindx/examples/util/ToolTipAnnotation.java b/src/gov/nasa/worldwindx/examples/util/ToolTipAnnotation.java index 5113946db4..ab47aad371 100644 --- a/src/gov/nasa/worldwindx/examples/util/ToolTipAnnotation.java +++ b/src/gov/nasa/worldwindx/examples/util/ToolTipAnnotation.java @@ -116,7 +116,7 @@ protected void doRenderNow(DrawContext dc) protected Point adjustDrawPointToViewport(Point point, Rectangle bounds, Rectangle viewport) { int x = point.x; - int y = (int) viewport.getHeight() - point.y - 1; + int y = point.y; if (x + this.getOffsetX() + bounds.getWidth() > viewport.getWidth()) x = (int) (viewport.getWidth() - bounds.getWidth()) - 1 - this.getOffsetX(); diff --git a/src/gov/nasa/worldwindx/examples/util/ToolTipController.java b/src/gov/nasa/worldwindx/examples/util/ToolTipController.java index 0cadd531d9..05e58a7e63 100644 --- a/src/gov/nasa/worldwindx/examples/util/ToolTipController.java +++ b/src/gov/nasa/worldwindx/examples/util/ToolTipController.java @@ -2,25 +2,25 @@ * Copyright 2006-2009, 2017, 2020 United States Government, as represented by the * Administrator of the National Aeronautics and Space Administration. * All rights reserved. - * + * * The NASA World Wind Java (WWJ) platform is licensed under the Apache License, * Version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. - * + * * NASA World Wind Java (WWJ) also contains the following 3rd party Open Source * software: - * + * * Jackson Parser – Licensed under Apache 2.0 * GDAL – Licensed under MIT * JOGL – Licensed under Berkeley Software Distribution (BSD) * Gluegen – Licensed under Berkeley Software Distribution (BSD) - * + * * A complete listing of 3rd Party software notices and licenses included in * NASA World Wind Java (WWJ) can be found in the WorldWindJava-v2.2 3rd-party * notices and licenses PDF found in code directory. @@ -34,6 +34,7 @@ import gov.nasa.worldwindx.examples.ApplicationTemplate; import gov.nasa.worldwind.layers.*; import gov.nasa.worldwind.util.*; +import java.awt.Dimension; /** * Controls display of tool tips on picked objects. Any shape implementing {@link AVList} can participate. Shapes @@ -52,6 +53,7 @@ public class ToolTipController implements SelectListener, Disposable protected Object lastHoverObject; protected AnnotationLayer layer; protected ToolTipAnnotation annotation; + protected Dimension annotationSize = null; /** * Create a controller for a specified {@link WorldWindow} that displays tool tips on hover and/or rollover. @@ -84,6 +86,16 @@ public ToolTipController(WorldWindow wwd) this.wwd.addSelectListener(this); } + public Dimension getAnnotationSize() + { + return this.annotationSize; + } + + public void setAnnotationSize(Dimension value) + { + this.annotationSize = value; + } + public void dispose() { this.wwd.removeSelectListener(this); @@ -91,14 +103,14 @@ public void dispose() protected String getHoverText(SelectEvent event) { - return event.getTopObject() != null && event.getTopObject() instanceof AVList ? - ((AVList) event.getTopObject()).getStringValue(this.hoverKey) : null; + return event.getTopObject() != null && event.getTopObject() instanceof AVList + ? ((AVList) event.getTopObject()).getStringValue(this.hoverKey) : null; } protected String getRolloverText(SelectEvent event) { - return event.getTopObject() != null && event.getTopObject() instanceof AVList ? - ((AVList) event.getTopObject()).getStringValue(this.rolloverKey) : null; + return event.getTopObject() != null && event.getTopObject() instanceof AVList + ? ((AVList) event.getTopObject()).getStringValue(this.rolloverKey) : null; } public void selected(SelectEvent event) @@ -167,6 +179,7 @@ protected void showToolTip(SelectEvent event, String text) else { annotation = new ToolTipAnnotation(text); + annotation.getAttributes().setSize(this.annotationSize); } if (layer == null)