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

org.piccolo2d.util.PPaintContext Maven / Gradle / Ivy

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

import java.awt.AlphaComposite;
import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.font.FontRenderContext;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

import org.piccolo2d.PCamera;


/**
 * PPaintContext is used by piccolo nodes to paint themselves on the
 * screen. PPaintContext wraps a Graphics2D to implement painting.
 * 

* * @version 1.0 * @author Jesse Grosjean */ public class PPaintContext { /** Used for lowering quality of rendering when requested. */ public static final int LOW_QUALITY_RENDERING = 0; /** Used for improving quality of rendering when requested. */ public static final int HIGH_QUALITY_RENDERING = 1; /** Font context to use while in low quality rendering. */ public static final FontRenderContext RENDER_QUALITY_LOW_FRC = new FontRenderContext(null, false, true); /** Font context to use while in high quality rendering. */ public static final FontRenderContext RENDER_QUALITY_HIGH_FRC = new FontRenderContext(null, true, true); /** Used while calculating scale at which rendering is occurring. */ private static final double[] PTS = new double[4]; /** PaintContext is associated with this graphics context. */ private final Graphics2D graphics; /** Used while computing transparency. */ protected PStack compositeStack; /** Used to optimize clipping region. */ protected PStack clipStack; /** Tracks clipping region in local coordinate system. */ protected PStack localClipStack; /** Stack of cameras through which the node being painted is being viewed. */ protected PStack cameraStack; /** Stack of transforms being applied to the drawing context. */ protected PStack transformStack; /** The current render quality that all rendering should be done in. */ protected int renderQuality; /** * Creates a PPaintContext associated with the given graphics context. * * @param graphics graphics context to associate with this paint context */ public PPaintContext(final Graphics2D graphics) { this.graphics = graphics; compositeStack = new PStack(); clipStack = new PStack(); localClipStack = new PStack(); cameraStack = new PStack(); transformStack = new PStack(); renderQuality = HIGH_QUALITY_RENDERING; Shape clip = graphics.getClip(); if (clip == null) { clip = new PBounds(-Integer.MAX_VALUE / 2, -Integer.MAX_VALUE / 2, Integer.MAX_VALUE, Integer.MAX_VALUE); graphics.setClip(clip); } localClipStack.push(clip.getBounds2D()); } /** * Returns the graphics context associated with this paint context. * * @return graphics context associated with this paint context */ public Graphics2D getGraphics() { return graphics; } /** * Returns the clipping region in the local coordinate system applied by * graphics. * * @return clipping region in the local coordinate system applied by * graphics */ public Rectangle2D getLocalClip() { return (Rectangle2D) localClipStack.peek(); } /** * Returns scale of the current graphics context. By calculating how a unit * segment gets transformed after transforming it by the graphics context's * transform. * * @return scale of the current graphics context's transformation */ public double getScale() { // x1, y1, x2, y2 PTS[0] = 0; PTS[1] = 0; PTS[2] = 1; PTS[3] = 0; graphics.getTransform().transform(PTS, 0, PTS, 0, 2); return Point2D.distance(PTS[0], PTS[1], PTS[2], PTS[3]); } /** * Pushes the camera onto the camera stack. * * @param aCamera camera to push onto the stack */ public void pushCamera(final PCamera aCamera) { cameraStack.push(aCamera); } /** * Removes the camera at the top of the camera stack. * * @since 1.3 */ public void popCamera() { cameraStack.pop(); } /** * Returns the camera at the top of the camera stack, or null if stack is * empty. * * @return topmost camera on camera stack or null if stack is empty */ public PCamera getCamera() { return (PCamera) cameraStack.peek(); } /** * Pushes the given clip to the pain context. * * @param clip clip to be pushed */ public void pushClip(final Shape clip) { final Shape currentClip = graphics.getClip(); clipStack.push(currentClip); graphics.clip(clip); final Rectangle2D newLocalClip = clip.getBounds2D(); Rectangle2D.intersect(getLocalClip(), newLocalClip, newLocalClip); localClipStack.push(newLocalClip); } /** * Removes the topmost clipping region from the clipping stack. * * @param clip not used in this method */ public void popClip(final Shape clip) { final Shape newClip = (Shape) clipStack.pop(); graphics.setClip(newClip); localClipStack.pop(); } /** * Pushes the provided transparency onto the transparency stack if * necessary. If the transparency is fully opaque, then it does nothing. * * @param transparency transparency to be pushed onto the transparency stack */ public void pushTransparency(final float transparency) { if (transparency == 1.0f) { return; } final Composite current = graphics.getComposite(); float currentAlaph = 1.0f; compositeStack.push(current); if (current instanceof AlphaComposite) { currentAlaph = ((AlphaComposite) current).getAlpha(); } final AlphaComposite newComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, currentAlaph * transparency); graphics.setComposite(newComposite); } /** * Removes the topmost transparency if the given transparency is not opaque * (1f). * * @param transparency transparency to be popped */ public void popTransparency(final float transparency) { if (transparency == 1.0f) { return; } final Composite c = (Composite) compositeStack.pop(); graphics.setComposite(c); } /** * Pushed the provided transform onto the transform stack if it is not null. * * @param transform will be pushed onto the transform stack if not null */ public void pushTransform(final PAffineTransform transform) { if (transform != null) { final Rectangle2D newLocalClip = (Rectangle2D) getLocalClip().clone(); transform.inverseTransform(newLocalClip, newLocalClip); transformStack.push(graphics.getTransform()); localClipStack.push(newLocalClip); graphics.transform(transform); } } /** * Pops the topmost Transform from the top of the transform if the passed in * transform is not null. * * @param transform transform that should be at the top of the stack */ public void popTransform(final PAffineTransform transform) { if (transform != null) { graphics.setTransform((AffineTransform) transformStack.pop()); localClipStack.pop(); } } /** * Return the render quality used by this paint context. * * @return the current render quality */ public int getRenderQuality() { return renderQuality; } /** * Set the rendering hints for this paint context. The render quality is * most often set by the rendering PCanvas. Use PCanvas.setRenderQuality() * and PCanvas.setInteractingRenderQuality() to set these values. * * @param requestedQuality supports PPaintContext.HIGH_QUALITY_RENDERING or * PPaintContext.LOW_QUALITY_RENDERING */ public void setRenderQuality(final int requestedQuality) { renderQuality = requestedQuality; switch (renderQuality) { case HIGH_QUALITY_RENDERING: setRenderQualityToHigh(); break; case LOW_QUALITY_RENDERING: setRenderQualityToLow(); break; default: throw new RuntimeException("Quality must be either HIGH_QUALITY_RENDERING or LOW_QUALITY_RENDERING"); } } private void setRenderQualityToLow() { graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED); graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); } private void setRenderQualityToHigh() { graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy