protected void setDepthFunc(DrawContext dc, OrderedIcon uIcon, Vec4 screenPoint) { GL gl = dc.getGL(); if (uIcon.icon.isAlwaysOnTop()) { gl.glDepthFunc(GL.GL_ALWAYS); return; } Position eyePos = dc.getView().getEyePosition(); if (eyePos == null) { gl.glDepthFunc(GL.GL_ALWAYS); return; } double altitude = eyePos.getElevation(); if (altitude < (dc.getGlobe().getMaxElevation() * dc.getVerticalExaggeration())) { double depth = screenPoint.z - (8d * 0.00048875809d); depth = depth < 0d ? 0d : (depth > 1d ? 1d : depth); gl.glDepthFunc(GL.GL_LESS); gl.glDepthRange(depth, depth); } else if (uIcon.eyeDistance > uIcon.horizonDistance) { gl.glDepthFunc(GL.GL_EQUAL); gl.glDepthRange(1d, 1d); } else { gl.glDepthFunc(GL.GL_ALWAYS); } }
/** * Sets a specified texture's OpenGL <code>Texture</code> parameters. * * @param dc the current draw context. * @param texture the texture whose parameters to set. */ protected void setTextureParameters(DrawContext dc, Texture texture) { // Enable the appropriate mip-mapping texture filters if the caller has specified that // mip-mapping should be // enabled, and the texture itself supports mip-mapping. boolean useMipMapFilter = this.useMipMaps && (this.getTextureData().getMipmapData() != null || texture.isUsingAutoMipmapGeneration()); GL gl = dc.getGL(); gl.glTexParameteri( GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, useMipMapFilter ? GL.GL_LINEAR_MIPMAP_LINEAR : GL.GL_LINEAR); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE); if (this.isUseAnisotropy() && useMipMapFilter) { double maxAnisotropy = dc.getGLRuntimeCapabilities().getMaxTextureAnisotropy(); if (dc.getGLRuntimeCapabilities().isUseAnisotropicTextureFilter() && maxAnisotropy >= 2.0) { gl.glTexParameterf( GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAX_ANISOTROPY_EXT, (float) maxAnisotropy); } } }
protected void applyColor(DrawContext dc, java.awt.Color color, double opacity) { if (dc.isPickingMode()) return; double finalOpacity = opacity * (color.getAlpha() / 255.0); GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility. OGLUtil.applyColor(gl, color, finalOpacity, true); }
protected void drawIconsInBatch(DrawContext dc, OrderedIcon uIcon) { this.drawIcon(dc, uIcon); // Draw as many as we can in a batch to save ogl state switching. Object nextItem = dc.peekOrderedRenderables(); while (nextItem != null && nextItem instanceof OrderedIcon) { OrderedIcon oi = (OrderedIcon) nextItem; if (oi.getRenderer() != this) return; dc.pollOrderedRenderables(); // take it off the queue this.drawIcon(dc, oi); nextItem = dc.peekOrderedRenderables(); } }
protected void endDrawIcons(DrawContext dc) { if (dc.isPickingMode()) this.pickSupport.endPicking(dc); GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility. if (dc.isPickingMode()) { gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, OGLUtil.DEFAULT_TEX_ENV_MODE); gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_SRC0_RGB, OGLUtil.DEFAULT_SRC0_RGB); gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_COMBINE_RGB, OGLUtil.DEFAULT_COMBINE_RGB); } gl.glBindTexture(GL.GL_TEXTURE_2D, 0); this.oglStackHandler.pop(gl); }
protected void drawToolTip( DrawContext dc, java.awt.Rectangle viewport, String text, int x, int y, ToolTipAttributes attributes) { java.awt.geom.Rectangle2D textBounds = this.computeTextBounds(dc, text, attributes.getFont()); java.awt.geom.Rectangle2D bgBounds = this.computeBackgroundBounds( dc, textBounds.getWidth(), textBounds.getHeight(), attributes.getInsets()); java.awt.Point screenPoint = this.adjustDrawPointToViewport(x, y, bgBounds, viewport); java.awt.geom.Point2D textTranslation = this.computeTextTranslation(dc, textBounds, attributes.getInsets()); GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility. OGLStackHandler stackHandler = new OGLStackHandler(); stackHandler.pushModelview(gl); try { gl.glTranslated( screenPoint.getX() + bgBounds.getX(), screenPoint.getY() + bgBounds.getY(), 0); this.drawToolTipInterior(dc, bgBounds.getWidth(), bgBounds.getHeight(), attributes); this.drawToolTipOutline(dc, bgBounds.getWidth(), bgBounds.getHeight(), attributes); gl.glTranslated(textTranslation.getX(), textTranslation.getY(), 0); this.drawToolTipText(dc, text, 0, 0, attributes); } finally { stackHandler.pop(gl); } }
// X-PATCH Marjan // extracted skip conditions into an overrideable method protected boolean meetsRenderCriteria( DrawContext dc, WWIcon icon, Vec4 iconPoint, double eyeDistance) { if (this.isHorizonClippingEnabled() && eyeDistance > dc.getView().getHorizonDistance()) { return false; // don't render horizon-clipped icons } // If enabled, eliminate icons outside the view volume. Primarily used to control icon // visibility beyond // the view volume's far clipping plane. if (this.isViewClippingEnabled() && !dc.getView().getFrustumInModelCoordinates().contains(iconPoint)) { return false; // don't render frustum-clipped icons } return true; }
protected void addToolTip(DrawContext dc, WWIcon icon, Vec4 iconPoint) { if (icon.getToolTipFont() == null && icon.getToolTipText() == null) return; Vec4 screenPoint = dc.getView().project(iconPoint); if (screenPoint == null) return; if (icon.getToolTipOffset() != null) screenPoint = screenPoint.add3(icon.getToolTipOffset()); OrderedText tip = new OrderedText( icon.getToolTipText(), icon.getToolTipFont(), screenPoint, icon.getToolTipTextColor(), 0d); dc.addOrderedRenderable(tip); }
protected void beginDrawIcons(DrawContext dc) { GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility. this.oglStackHandler.clear(); int attributeMask = GL2.GL_DEPTH_BUFFER_BIT // for depth test, depth mask and depth func | GL2.GL_TRANSFORM_BIT // for modelview and perspective | GL2.GL_VIEWPORT_BIT // for depth range | GL2.GL_CURRENT_BIT // for current color | GL2.GL_COLOR_BUFFER_BIT // for alpha test func and ref, and blend | GL2.GL_DEPTH_BUFFER_BIT // for depth func | GL2.GL_ENABLE_BIT; // for enable/disable changes this.oglStackHandler.pushAttrib(gl, attributeMask); // Apply the depth buffer but don't change it. if ((!dc.isDeepPickingEnabled())) gl.glEnable(GL.GL_DEPTH_TEST); gl.glDepthMask(false); // Suppress any fully transparent image pixels gl.glEnable(GL2.GL_ALPHA_TEST); gl.glAlphaFunc(GL2.GL_GREATER, 0.001f); // Load a parallel projection with dimensions (viewportWidth, viewportHeight) this.oglStackHandler.pushProjectionIdentity(gl); gl.glOrtho( 0d, dc.getView().getViewport().width, 0d, dc.getView().getViewport().height, -1d, 1d); this.oglStackHandler.pushModelview(gl); this.oglStackHandler.pushTexture(gl); if (dc.isPickingMode()) { this.pickSupport.beginPicking(dc); // Set up to replace the non-transparent texture colors with the single pick color. gl.glEnable(GL.GL_TEXTURE_2D); gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_COMBINE); gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_SRC0_RGB, GL2.GL_PREVIOUS); gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_COMBINE_RGB, GL2.GL_REPLACE); } else { gl.glEnable(GL.GL_TEXTURE_2D); gl.glEnable(GL.GL_BLEND); gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE_MINUS_SRC_ALPHA); } }
protected void drawToolTipInterior( DrawContext dc, double width, double height, ToolTipAttributes attributes) { GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility. this.applyColor(dc, attributes.getInteriorColor(), attributes.getInteriorOpacity()); // Draw a filled rectangle with the background dimensions. gl.glRectd(0, 0, width, height); }
protected void doRender(DrawContext dc, String text, int x, int y) { OGLStackHandler stackHandler = new OGLStackHandler(); this.beginRendering(dc, stackHandler); try { this.draw(dc, dc.getView().getViewport(), text, x, y); } finally { this.endRendering(dc, stackHandler); } }
protected void endRendering(DrawContext dc, OGLStackHandler stackHandler) { if (dc == null) { String message = Logging.getMessage("nullValue.DrawContextIsNull"); Logging.logger().fine(message); throw new IllegalArgumentException(message); } GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility. stackHandler.pop(gl); }
/** * If this instance's image source is a <code>BufferedImage</code>, creates and returns the * texture, otherwise creates a task in a separate thread to retrieve it from its local or remote * location. * * @param dc the current draw context. * @return the new texture, or null if the texture is not yet available. */ protected Texture requestTexture(DrawContext dc) { if (this.isBufferedImageSource()) return this.makeBufferedImageTexture(dc); if (this.getTextureData() != null && this.getTexture(dc) == null) return this.makeTextureFromTextureData(dc); if (WorldWind.getTaskService().isFull()) return null; Runnable task = this.createRequestTask(); if (WorldWind.getTaskService().contains(task)) return null; // Use either the current layer or the layer list as the listener to notify when the request // completes. The // latter is used when the image source is requested during ordered rendering and the current // layer is null. this.listener = dc.getCurrentLayer() != null ? dc.getCurrentLayer() : dc.getLayers(); WorldWind.getTaskService().addTask(task); return null; }
protected void pickIconsInBatch(DrawContext dc, OrderedIcon uIcon) { this.drawIcon(dc, uIcon); // Draw as many as we can in a batch to save ogl state switching. // Note that there's a further qualification here than in render(): only items associated with // the // same layer can be batched because the pick resolution step at the end of batch rendering // associates the item's layer with the resolved picked object. Object nextItem = dc.peekOrderedRenderables(); while (nextItem != null && nextItem instanceof OrderedIcon && ((OrderedIcon) nextItem).layer == uIcon.layer) { OrderedIcon oi = (OrderedIcon) nextItem; if (oi.getRenderer() != this) return; dc.pollOrderedRenderables(); // take it off the queue this.drawIcon(dc, oi); nextItem = dc.peekOrderedRenderables(); } }
/** * Returns the {@link Texture} associated with this instance. * * @param dc the current draw context. * @return this instance's texture, or null if the texture does not currently exist. */ protected Texture getTexture(DrawContext dc) { if (this.getImageSource() == null) return null; Texture texture = dc.getTextureCache().getTexture(this.getImageSource()); if (this.width == null && texture != null) { this.width = texture.getWidth(); this.height = texture.getHeight(); this.texCoords = texture.getImageTexCoords(); } return texture; }
protected void beginRendering(DrawContext dc, OGLStackHandler stackHandler) { if (dc == null) { String message = Logging.getMessage("nullValue.DrawContextIsNull"); Logging.logger().fine(message); throw new IllegalArgumentException(message); } GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility. int attribMask = GL2.GL_COLOR_BUFFER_BIT // for alpha test func and ref, blend func | GL2.GL_CURRENT_BIT // for current color | GL2.GL_ENABLE_BIT // for enable/disable | GL2.GL_LINE_BIT // for line width | GL2.GL_TRANSFORM_BIT; // for matrix mode stackHandler.pushAttrib(gl, attribMask); stackHandler.pushTextureIdentity(gl); stackHandler.pushProjectionIdentity(gl); java.awt.Rectangle viewport = dc.getView().getViewport(); gl.glOrtho( viewport.x, viewport.x + viewport.width, viewport.y, viewport.y + viewport.height, -1, 1); stackHandler.pushModelviewIdentity(gl); // Enable the alpha test. gl.glEnable(GL2.GL_ALPHA_TEST); gl.glAlphaFunc(GL2.GL_GREATER, 0.0f); // Enable blending in premultiplied color mode. gl.glEnable(GL.GL_BLEND); OGLUtil.applyBlending(gl, true); gl.glDisable(GL.GL_CULL_FACE); gl.glDisable(GL.GL_DEPTH_TEST); gl.glDisable(GL2.GL_LIGHTING); gl.glDisable(GL.GL_TEXTURE_2D); }
protected void applyBackground( DrawContext dc, WWIcon icon, Vec4 screenPoint, double width, double height, double pedestalSpacing, double pedestalScale) { GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility. double backgroundScale; backgroundScale = icon.getBackgroundScale(); if (icon.getBackgroundTexture() != null) { if (icon.getBackgroundTexture().bind(dc)) { TextureCoords texCoords = icon.getBackgroundTexture().getTexCoords(); gl.glPushMatrix(); gl.glLoadIdentity(); double bgwidth = backgroundScale * width; double bgheight = backgroundScale * height; // Offset the background for the highlighted scale. // if (icon.isHighlighted()) // { // gl.glTranslated(0d, height * (icon.getHighlightScale() - 1) / 2, 0d); // } // Offset the background for the pedestal height. gl.glTranslated(0d, (pedestalScale * height) + pedestalSpacing, 0d); // Place the background centered behind the icon. gl.glTranslated(screenPoint.x - bgwidth / 2, screenPoint.y - (bgheight - height) / 2, 0d); // Scale to the background image dimension. gl.glScaled(bgwidth, bgheight, 1d); dc.drawUnitQuad(texCoords); gl.glPopMatrix(); } } }
protected void drawToolTipOutline( DrawContext dc, double width, double height, ToolTipAttributes attributes) { GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility. this.applyColor(dc, attributes.getOutlineColor(), attributes.getOutlineOpacity()); gl.glLineWidth((float) getOutlineWidth()); // Draw a line loop around the background rectangle. Inset the lines slightly to compensate for // OpenGL's line // rasterization algorithm. We want the line to straddle the rectangle pixels. double inset = 0.5; gl.glBegin(GL2.GL_LINE_LOOP); gl.glVertex2d(inset, inset); gl.glVertex2d(width - inset, inset); gl.glVertex2d(width - inset, height - inset); gl.glVertex2d(inset, height - inset); gl.glEnd(); }
/** * Creates a {@link Texture} from this instance's {@link TextureData} if the <code>TextureData * </code> exists. * * @param dc the current draw context. * @return the newly created texture, or null if this instance has no current <code>TextureData * </code> or if texture creation failed. */ protected Texture makeTextureFromTextureData(DrawContext dc) { if (dc == null) { String message = Logging.getMessage("nullValue.DrawContextIsNull"); Logging.logger().severe(message); throw new IllegalStateException(message); } if (this.getTextureData() == null) // texture not in cache yet texture data is null, can't initialize { String msg = Logging.getMessage("nullValue.TextureDataIsNull"); Logging.logger().severe(msg); throw new IllegalStateException(msg); } try { Texture texture = TextureIO.newTexture(this.getTextureData()); if (texture == null) { this.textureInitializationFailed = true; return null; } this.width = texture.getWidth(); this.height = texture.getHeight(); this.texCoords = texture.getImageTexCoords(); this.setTextureParameters(dc, texture); // Cache the texture and release the texture data. dc.getTextureCache().put(this.getImageSource(), texture); this.setTextureData(null); return texture; } catch (Exception e) { String name = this.isBufferedImageSource() ? "BufferedImage" : this.getImageSource().toString(); String msg = Logging.getMessage("generic.ExceptionAttemptingToCreateTexture", name); Logging.logger().log(java.util.logging.Level.SEVERE, msg, e); return null; } }
protected void drawMany(DrawContext dc, Iterable<? extends WWIcon> icons, Layer layer) { if (dc == null) { String msg = Logging.getMessage("nullValue.DrawContextIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } if (dc.getVisibleSector() == null) return; SectorGeometryList geos = dc.getSurfaceGeometry(); //noinspection RedundantIfStatement if (geos == null) return; if (icons == null) { String msg = Logging.getMessage("nullValue.IconIterator"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } Iterator<? extends WWIcon> iterator = icons.iterator(); if (!iterator.hasNext()) return; double horizon = dc.getView().getHorizonDistance(); while (iterator.hasNext()) { WWIcon icon = iterator.next(); if (!isIconValid(icon, true)) { // Record feedback data for this WWIcon if feedback is enabled. if (icon != null) this.recordFeedback(dc, icon, null, null); continue; } if (!icon.isVisible()) { // Record feedback data for this WWIcon if feedback is enabled. this.recordFeedback(dc, icon, null, null); continue; } // Determine Cartesian position from the surface geometry if the icon is near the surface, // otherwise draw it from the globe. Position pos = icon.getPosition(); Vec4 iconPoint = null; if (pos.getElevation() < dc.getGlobe().getMaxElevation() && !this.isAlwaysUseAbsoluteElevation()) { iconPoint = dc.getSurfaceGeometry().getSurfacePoint(icon.getPosition()); } if (iconPoint == null) { Angle lat = pos.getLatitude(); Angle lon = pos.getLongitude(); double elevation = pos.getElevation(); if (!this.isAlwaysUseAbsoluteElevation()) elevation += dc.getGlobe().getElevation(lat, lon); iconPoint = dc.getGlobe().computePointFromPosition(lat, lon, elevation); } double eyeDistance = icon.isAlwaysOnTop() ? 0 : dc.getView().getEyePoint().distanceTo3(iconPoint); // X-PATCH Marjan // extracted skip conditions into an overrideable method if (!meetsRenderCriteria(dc, icon, iconPoint, eyeDistance)) { this.recordFeedback(dc, icon, iconPoint, null); continue; } // X-END // The icons aren't drawn here, but added to the ordered queue to be drawn back-to-front. dc.addOrderedRenderable(new OrderedIcon(icon, iconPoint, layer, eyeDistance, horizon)); if (icon.isShowToolTip()) this.addToolTip(dc, icon, iconPoint); } }
protected TextRenderer getTextRenderer(DrawContext dc, java.awt.Font font) { return OGLTextRenderer.getOrCreateTextRenderer(dc.getTextRendererCache(), font); }
protected Vec4 drawIcon(DrawContext dc, OrderedIcon uIcon) { if (uIcon.point == null) { String msg = Logging.getMessage("nullValue.PointIsNull"); Logging.logger().severe(msg); // Record feedback data for this WWIcon if feedback is enabled. if (uIcon.icon != null) this.recordFeedback(dc, uIcon.icon, null, null); return null; } WWIcon icon = uIcon.icon; if (dc.getView().getFrustumInModelCoordinates().getNear().distanceTo(uIcon.point) < 0) { // Record feedback data for this WWIcon if feedback is enabled. this.recordFeedback(dc, icon, uIcon.point, null); return null; } final Vec4 screenPoint = dc.getView().project(uIcon.point); if (screenPoint == null) { // Record feedback data for this WWIcon if feedback is enabled. this.recordFeedback(dc, icon, uIcon.point, null); return null; } double pedestalScale; double pedestalSpacing; if (this.pedestal != null) { pedestalScale = this.pedestal.getScale(); pedestalSpacing = pedestal.getSpacingPixels(); } else { pedestalScale = 0d; pedestalSpacing = 0d; } GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility. this.setDepthFunc(dc, uIcon, screenPoint); gl.glMatrixMode(GL2.GL_MODELVIEW); gl.glLoadIdentity(); Dimension size = icon.getSize(); double width = size != null ? size.getWidth() : icon.getImageTexture().getWidth(dc); double height = size != null ? size.getHeight() : icon.getImageTexture().getHeight(dc); gl.glTranslated( screenPoint.x - width / 2, screenPoint.y + (pedestalScale * height) + pedestalSpacing, 0d); if (icon.isHighlighted()) { double heightDelta = this.pedestal != null ? 0 : height / 2; // expand only above the pedestal gl.glTranslated(width / 2, heightDelta, 0); gl.glScaled(icon.getHighlightScale(), icon.getHighlightScale(), icon.getHighlightScale()); gl.glTranslated(-width / 2, -heightDelta, 0); } Rectangle rect = new Rectangle( (int) (screenPoint.x - width / 2), (int) (screenPoint.y), (int) width, (int) (height + (pedestalScale * height) + pedestalSpacing)); if (dc.isPickingMode()) { // If in picking mode and pick clipping is enabled, check to see if the icon is within the // pick volume. if (this.isPickFrustumClippingEnabled() && !dc.getPickFrustums().intersectsAny(rect)) { // Record feedback data for this WWIcon if feedback is enabled. this.recordFeedback(dc, icon, uIcon.point, rect); return screenPoint; } else { java.awt.Color color = dc.getUniquePickColor(); int colorCode = color.getRGB(); this.pickSupport.addPickableObject(colorCode, icon, uIcon.getPosition(), false); gl.glColor3ub((byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue()); } } if (icon.getBackgroundTexture() != null) this.applyBackground(dc, icon, screenPoint, width, height, pedestalSpacing, pedestalScale); if (icon.getImageTexture().bind(dc)) { TextureCoords texCoords = icon.getImageTexture().getTexCoords(); gl.glScaled(width, height, 1d); dc.drawUnitQuad(texCoords); } if (this.pedestal != null && this.pedestal.getImageTexture() != null) { gl.glLoadIdentity(); gl.glTranslated(screenPoint.x - (pedestalScale * (width / 2)), screenPoint.y, 0d); gl.glScaled(width * pedestalScale, height * pedestalScale, 1d); if (this.pedestal.getImageTexture().bind(dc)) { TextureCoords texCoords = this.pedestal.getImageTexture().getTexCoords(); dc.drawUnitQuad(texCoords); } } // Record feedback data for this WWIcon if feedback is enabled. this.recordFeedback(dc, icon, uIcon.point, rect); return screenPoint; }
/** * Returns true if the IconRenderer should record feedback about how the specified WWIcon has been * processed. * * @param dc the current DrawContext. * @param icon the WWIcon to record feedback information for. * @return true to record feedback; false otherwise. */ protected boolean isFeedbackEnabled(DrawContext dc, WWIcon icon) { if (dc.isPickingMode()) return false; Boolean b = (Boolean) icon.getValue(AVKey.FEEDBACK_ENABLED); return (b != null && b); }