|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* This file is part of libbluray
|
|
Packit |
5e46da |
* Copyright (C) 2012-2014 libbluray
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
* This library is free software; you can redistribute it and/or
|
|
Packit |
5e46da |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
5e46da |
* License as published by the Free Software Foundation; either
|
|
Packit |
5e46da |
* version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
* This library is distributed in the hope that it will be useful,
|
|
Packit |
5e46da |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
5e46da |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
5e46da |
* Lesser General Public License for more details.
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
5e46da |
* License along with this library. If not, see
|
|
Packit |
5e46da |
* <http://www.gnu.org/licenses/>.
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
package java.awt;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
import java.lang.reflect.Field;
|
|
Packit |
5e46da |
import java.text.AttributedCharacterIterator;
|
|
Packit |
5e46da |
import java.util.ArrayList;
|
|
Packit |
5e46da |
import java.util.Arrays;
|
|
Packit |
5e46da |
import java.util.Collections;
|
|
Packit |
5e46da |
import java.util.HashSet;
|
|
Packit |
5e46da |
import java.awt.image.AreaAveragingScaleFilter;
|
|
Packit |
5e46da |
import java.awt.image.BufferedImage;
|
|
Packit |
5e46da |
import java.awt.image.ImageConsumer;
|
|
Packit |
5e46da |
import java.awt.image.ImageObserver;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
import org.dvb.ui.DVBBufferedImage;
|
|
Packit |
5e46da |
import org.dvb.ui.DVBAlphaComposite;
|
|
Packit |
5e46da |
import org.dvb.ui.DVBGraphics;
|
|
Packit |
5e46da |
import org.dvb.ui.UnsupportedDrawingOperationException;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
import sun.awt.ConstrainableGraphics;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
import org.videolan.GUIManager;
|
|
Packit |
5e46da |
import org.videolan.Logger;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
abstract class BDGraphicsBase extends DVBGraphics implements ConstrainableGraphics {
|
|
Packit |
5e46da |
private static final Color DEFAULT_COLOR = Color.BLACK;
|
|
Packit |
5e46da |
private static final Font DEFAULT_FONT = new Font("Dialog", Font.PLAIN, 12);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
private int width;
|
|
Packit |
5e46da |
private int height;
|
|
Packit |
5e46da |
private int[] backBuffer;
|
|
Packit |
5e46da |
private Area dirty;
|
|
Packit |
5e46da |
private GraphicsConfiguration gc;
|
|
Packit |
5e46da |
private Color foreground;
|
|
Packit |
5e46da |
protected Color background;
|
|
Packit |
5e46da |
private Font font;
|
|
Packit |
5e46da |
private BDFontMetrics fontMetrics;
|
|
Packit |
5e46da |
private AlphaComposite composite;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/** The current xor color. If null then we are in paint mode. */
|
|
Packit |
5e46da |
private Color xorColor;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/** Translated X, Y offset from native offset. */
|
|
Packit |
5e46da |
private int originX;
|
|
Packit |
5e46da |
private int originY;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/** The actual clip rectangle that is intersection of user clip and constrained rectangle. */
|
|
Packit |
5e46da |
private Rectangle actualClip;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/** The current user clip rectangle or null if no clip has been set. This is stored in the
|
|
Packit |
5e46da |
native coordinate system and not the (possibly) translated Java coordinate system. */
|
|
Packit |
5e46da |
private Rectangle clip = null;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/** The rectangle this graphics object has been constrained too. This is stored in the
|
|
Packit |
5e46da |
native coordinate system and not the (possibly) translated Java coordinate system.
|
|
Packit |
5e46da |
If it is null then this graphics has not been constrained. The constrained rectangle
|
|
Packit |
5e46da |
is another layer of clipping independant of the user clip. */
|
|
Packit |
5e46da |
private Rectangle constrainedRect = null;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BDGraphicsBase(BDGraphicsBase g) {
|
|
Packit |
5e46da |
backBuffer = g.backBuffer;
|
|
Packit |
5e46da |
dirty = g.dirty;
|
|
Packit |
5e46da |
width = g.width;
|
|
Packit |
5e46da |
height = g.height;
|
|
Packit |
5e46da |
gc = g.gc;
|
|
Packit |
5e46da |
foreground = g.foreground;
|
|
Packit |
5e46da |
background = g.background;
|
|
Packit |
5e46da |
composite = g.composite;
|
|
Packit |
5e46da |
font = g.font;
|
|
Packit |
5e46da |
fontMetrics = g.fontMetrics;
|
|
Packit |
5e46da |
originX = g.originX;
|
|
Packit |
5e46da |
originY = g.originY;
|
|
Packit |
5e46da |
if (g.clip != null) {
|
|
Packit |
5e46da |
clip = new Rectangle(g.clip);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
setupClip();
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BDGraphicsBase(BDRootWindow window) {
|
|
Packit |
5e46da |
width = window.getWidth();
|
|
Packit |
5e46da |
height = window.getHeight();
|
|
Packit |
5e46da |
backBuffer = window.getBdBackBuffer();
|
|
Packit |
5e46da |
dirty = window.getDirtyArea();
|
|
Packit |
5e46da |
gc = window.getGraphicsConfiguration();
|
|
Packit |
5e46da |
foreground = window.getForeground();
|
|
Packit |
5e46da |
background = window.getBackground();
|
|
Packit |
5e46da |
font = window.getFont();
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
postInit();
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BDGraphicsBase(BDImage image) {
|
|
Packit |
5e46da |
width = image.getWidth();
|
|
Packit |
5e46da |
height = image.getHeight();
|
|
Packit |
5e46da |
backBuffer = image.getBdBackBuffer();
|
|
Packit |
5e46da |
dirty = image.getDirtyArea();
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
gc = image.getGraphicsConfiguration();
|
|
Packit |
5e46da |
Component component = image.getComponent();
|
|
Packit |
5e46da |
if (component != null) {
|
|
Packit |
5e46da |
foreground = component.getForeground();
|
|
Packit |
5e46da |
background = component.getBackground();
|
|
Packit |
5e46da |
font = component.getFont();
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (background == null)
|
|
Packit |
5e46da |
background = new Color(0, 0, 0, 0);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
postInit();
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
private void postInit() {
|
|
Packit |
5e46da |
if (foreground == null)
|
|
Packit |
5e46da |
foreground = DEFAULT_COLOR;
|
|
Packit |
5e46da |
if (background == null)
|
|
Packit |
5e46da |
background = DEFAULT_COLOR;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* if font is not set, use AWT default font from BDJO */
|
|
Packit |
5e46da |
if (font == null) {
|
|
Packit |
5e46da |
font = GUIManager.getInstance().getDefaultFont();
|
|
Packit |
5e46da |
if (font == null) {
|
|
Packit |
5e46da |
font = DEFAULT_FONT;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
fontMetrics = null;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
composite = AlphaComposite.SrcOver;
|
|
Packit |
5e46da |
setupClip();
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
public Graphics create() {
|
|
Packit |
5e46da |
return new BDGraphics((BDGraphics)this);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* DVBGraphics methods
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
public int[] getAvailableCompositeRules()
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
int[] rules = { DVBAlphaComposite.CLEAR, DVBAlphaComposite.SRC,
|
|
Packit |
5e46da |
DVBAlphaComposite.SRC_OVER, DVBAlphaComposite.DST_OVER,
|
|
Packit |
5e46da |
DVBAlphaComposite.SRC_IN, DVBAlphaComposite.DST_IN,
|
|
Packit |
5e46da |
DVBAlphaComposite.SRC_OUT, DVBAlphaComposite.DST_OUT };
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
int[] rules = {
|
|
Packit |
5e46da |
DVBAlphaComposite.CLEAR,
|
|
Packit |
5e46da |
DVBAlphaComposite.SRC,
|
|
Packit |
5e46da |
DVBAlphaComposite.SRC_OVER };
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return rules;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
public DVBAlphaComposite getDVBComposite()
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
Composite comp = getComposite();
|
|
Packit |
5e46da |
if (!(comp instanceof AlphaComposite))
|
|
Packit |
5e46da |
return null;
|
|
Packit |
5e46da |
return DVBAlphaComposite.getInstance(
|
|
Packit |
5e46da |
((AlphaComposite)comp).getRule(),
|
|
Packit |
5e46da |
((AlphaComposite)comp).getAlpha());
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
public void setDVBComposite(DVBAlphaComposite comp)
|
|
Packit |
5e46da |
throws UnsupportedDrawingOperationException
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if ((comp.getRule() < DVBAlphaComposite.CLEAR) ||
|
|
Packit |
5e46da |
(comp.getRule() > DVBAlphaComposite.SRC_OVER)) {
|
|
Packit |
5e46da |
logger.error("setDVBComposite() FAILED: unsupported rule " + comp.getRule());
|
|
Packit |
5e46da |
throw new UnsupportedDrawingOperationException("Unsupported composition rule: " + comp.getRule());
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
setComposite(AlphaComposite.getInstance(comp.getRule(), comp.getAlpha()));
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
public void translate(int x, int y) {
|
|
Packit |
5e46da |
originX += x;
|
|
Packit |
5e46da |
originY += y;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
public void setFont(Font font) {
|
|
Packit |
5e46da |
if (font != null && !font.equals(this.font)) {
|
|
Packit |
5e46da |
this.font = font;
|
|
Packit |
5e46da |
fontMetrics = null;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
public Font getFont() {
|
|
Packit |
5e46da |
if (font == null)
|
|
Packit |
5e46da |
return DEFAULT_FONT;
|
|
Packit |
5e46da |
return font;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
public FontMetrics getFontMetrics() {
|
|
Packit |
5e46da |
if (font != null && fontMetrics == null) {
|
|
Packit |
5e46da |
fontMetrics = BDFontMetrics.getFontMetrics(font);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (fontMetrics == null) {
|
|
Packit |
5e46da |
logger.error("getFontMetrics() failed");
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
return fontMetrics;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
public FontMetrics getFontMetrics(Font font) {
|
|
Packit |
5e46da |
if (font != null) {
|
|
Packit |
5e46da |
return BDFontMetrics.getFontMetrics(font);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
logger.error("getFontMetrics(null) from " + Logger.dumpStack());
|
|
Packit |
5e46da |
return null;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
public void setColor(Color c) {
|
|
Packit |
5e46da |
if ((c != null) && (c != foreground))
|
|
Packit |
5e46da |
foreground = c;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
public Color getColor() {
|
|
Packit |
5e46da |
return foreground;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
public Composite getComposite() {
|
|
Packit |
5e46da |
return composite;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
public GraphicsConfiguration getDeviceConfiguration() {
|
|
Packit |
5e46da |
if (gc == null)
|
|
Packit |
5e46da |
logger.error("getDeviceConfiguration() failed");
|
|
Packit |
5e46da |
return gc;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
public void setComposite(Composite comp) {
|
|
Packit |
5e46da |
if ((comp != null) && (comp != composite)) {
|
|
Packit |
5e46da |
if (!(comp instanceof AlphaComposite)) {
|
|
Packit |
5e46da |
logger.error("Composite is not AlphaComposite");
|
|
Packit |
5e46da |
throw new IllegalArgumentException("Only AlphaComposite is supported");
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
composite = (AlphaComposite) comp;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
public void setPaintMode() {
|
|
Packit |
5e46da |
xorColor = null;
|
|
Packit |
5e46da |
composite = AlphaComposite.SrcOver;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
public void setXORMode(Color color) {
|
|
Packit |
5e46da |
xorColor = color;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/** Gets the current clipping area. */
|
|
Packit |
5e46da |
public Rectangle getClipBounds() {
|
|
Packit |
5e46da |
if (clip != null)
|
|
Packit |
5e46da |
return new Rectangle (clip.x - originX, clip.y - originY, clip.width, clip.height);
|
|
Packit |
5e46da |
return null;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
public void constrain(int x, int y, int w, int h) {
|
|
Packit |
5e46da |
Rectangle rect;
|
|
Packit |
5e46da |
if (constrainedRect != null)
|
|
Packit |
5e46da |
rect = constrainedRect;
|
|
Packit |
5e46da |
else
|
|
Packit |
5e46da |
rect = new Rectangle(0, 0, width, height);
|
|
Packit |
5e46da |
constrainedRect = rect.intersection(new Rectangle(rect.x + x, rect.y + y, w, h));
|
|
Packit |
5e46da |
originX = constrainedRect.x;
|
|
Packit |
5e46da |
originY = constrainedRect.y;
|
|
Packit |
5e46da |
setupClip();
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/** Returns a Shape object representing the clip. */
|
|
Packit |
5e46da |
public Shape getClip() {
|
|
Packit |
5e46da |
return getClipBounds();
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/** Crops the clipping rectangle. */
|
|
Packit |
5e46da |
public void clipRect(int x, int y, int w, int h) {
|
|
Packit |
5e46da |
Rectangle rect = new Rectangle(x + originX, y + originY, w, h);
|
|
Packit |
5e46da |
if (clip != null)
|
|
Packit |
5e46da |
clip = clip.intersection(rect);
|
|
Packit |
5e46da |
else
|
|
Packit |
5e46da |
clip = rect;
|
|
Packit |
5e46da |
setupClip();
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/** Sets the clipping rectangle. */
|
|
Packit |
5e46da |
public void setClip(int x, int y, int w, int h) {
|
|
Packit |
5e46da |
clip = new Rectangle (x + originX, y + originY, w, h);
|
|
Packit |
5e46da |
setupClip();
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/** Sets the clip to a Shape (only Rectangle allowed). */
|
|
Packit |
5e46da |
public void setClip(Shape clip) {
|
|
Packit |
5e46da |
if (clip == null) {
|
|
Packit |
5e46da |
this.clip = null;
|
|
Packit |
5e46da |
setupClip();
|
|
Packit |
5e46da |
} else if (clip instanceof Rectangle) {
|
|
Packit |
5e46da |
Rectangle rect = (Rectangle) clip;
|
|
Packit |
5e46da |
setClip(rect.x, rect.y, rect.width, rect.height);
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
logger.error("Shape is not Rectangle: " + clip.getClass().getName());
|
|
Packit |
5e46da |
throw new IllegalArgumentException("setClip(Shape) only supports Rectangle objects");
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
private void setupClip() {
|
|
Packit |
5e46da |
Rectangle rect;
|
|
Packit |
5e46da |
if (constrainedRect != null)
|
|
Packit |
5e46da |
rect = constrainedRect;
|
|
Packit |
5e46da |
else
|
|
Packit |
5e46da |
rect = new Rectangle(0, 0, width, height);
|
|
Packit |
5e46da |
if (clip != null)
|
|
Packit |
5e46da |
actualClip = clip.intersection(rect);
|
|
Packit |
5e46da |
else
|
|
Packit |
5e46da |
actualClip = rect;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
private int alphaBlend(int dest, int src) {
|
|
Packit |
5e46da |
int As = src >>> 24;
|
|
Packit |
5e46da |
if (As == 0)
|
|
Packit |
5e46da |
return dest;
|
|
Packit |
5e46da |
if (As == 255)
|
|
Packit |
5e46da |
return src;
|
|
Packit |
5e46da |
int Ad = (dest >>> 24);
|
|
Packit |
5e46da |
if (Ad == 0)
|
|
Packit |
5e46da |
return src;
|
|
Packit |
5e46da |
int R, G, B;
|
|
Packit |
5e46da |
R = ((src >>> 16) & 255) * As * 255;
|
|
Packit |
5e46da |
G = ((src >>> 8) & 255) * As * 255;
|
|
Packit |
5e46da |
B = (src & 255) * As * 255;
|
|
Packit |
5e46da |
Ad = Ad * (255 - As);
|
|
Packit |
5e46da |
As = As * 255 + Ad;
|
|
Packit |
5e46da |
R = (R + ((dest >>> 16) & 255) * Ad) / As;
|
|
Packit |
5e46da |
G = (G + ((dest >>> 8) & 255) * Ad) / As;
|
|
Packit |
5e46da |
B = (B + (dest & 255) * Ad) / As;
|
|
Packit |
5e46da |
R = Math.min(255, R);
|
|
Packit |
5e46da |
G = Math.min(255, G);
|
|
Packit |
5e46da |
B = Math.min(255, B);
|
|
Packit |
5e46da |
Ad = As / 255;
|
|
Packit |
5e46da |
Ad = Math.min(255, Ad);
|
|
Packit |
5e46da |
return (Ad << 24) | (R << 16) | (G << 8) | B;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
private int applyComposite(int rgb) {
|
|
Packit |
5e46da |
return ((int)((rgb >>> 24) * composite.getAlpha()) << 24) | (rgb & 0x00FFFFFF);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
private void drawSpanN(int x, int y, int length, int rgb) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
Rectangle rect = new Rectangle(x, y, length, 1);
|
|
Packit |
5e46da |
rect = actualClip.intersection(rect);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (rect.width <= 0 || rect.height <= 0 || rect.x < 0 || rect.y < 0 || backBuffer == null) {
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
x = rect.x;
|
|
Packit |
5e46da |
length = rect.width;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (xorColor != null) {
|
|
Packit |
5e46da |
for (int i = 0; i < length; i++) {
|
|
Packit |
5e46da |
backBuffer[y * width + x + i] ^= xorColor.getRGB() ^ rgb;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
dirty.add(rect);
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
switch (composite.getRule()) {
|
|
Packit |
5e46da |
case AlphaComposite.CLEAR:
|
|
Packit |
5e46da |
for (int i = 0; i < length; i++) {
|
|
Packit |
5e46da |
backBuffer[y * width + x + i] = 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
case AlphaComposite.SRC:
|
|
Packit |
5e46da |
rgb = applyComposite(rgb);
|
|
Packit |
5e46da |
for (int i = 0; i < length; i++) {
|
|
Packit |
5e46da |
backBuffer[y * width + x + i] = rgb;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
case AlphaComposite.SRC_OVER:
|
|
Packit |
5e46da |
rgb = applyComposite(rgb);
|
|
Packit |
5e46da |
for (int i = 0; i < length; i++) {
|
|
Packit |
5e46da |
backBuffer[y * width + x + i] = alphaBlend(backBuffer[y * width + x + i], rgb);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
dirty.add(rect);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
private void drawSpanN(int x, int y, int length, int src[], int srcOffset, boolean flipX) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* avoid overreading source */
|
|
Packit |
5e46da |
if (srcOffset + length > src.length) {
|
|
Packit |
5e46da |
length -= srcOffset + length - src.length;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
/* avoid underreading source */
|
|
Packit |
5e46da |
if (srcOffset < 0) {
|
|
Packit |
5e46da |
length += srcOffset;
|
|
Packit |
5e46da |
x -= srcOffset;
|
|
Packit |
5e46da |
srcOffset = 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (length <= 0) {
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
Rectangle rect = new Rectangle(x, y, length, 1);
|
|
Packit |
5e46da |
rect = actualClip.intersection(rect);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (rect.width <= 0 || rect.height <= 0 || rect.x < 0 || rect.y < 0 || backBuffer == null) {
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
int dstOffset;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
srcOffset += rect.x - x;
|
|
Packit |
5e46da |
x = rect.x;
|
|
Packit |
5e46da |
length = rect.width;
|
|
Packit |
5e46da |
dstOffset = y * width + x;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (xorColor != null) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (flipX) {
|
|
Packit |
5e46da |
for (int i = 0; i < length; i++) {
|
|
Packit |
5e46da |
backBuffer[dstOffset + length -1 - i] ^= xorColor.getRGB() ^ src[srcOffset + i];
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
for (int i = 0; i < length; i++) {
|
|
Packit |
5e46da |
backBuffer[dstOffset + i] ^= xorColor.getRGB() ^ src[srcOffset + i];
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
dirty.add(rect);
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
switch (composite.getRule()) {
|
|
Packit |
5e46da |
case AlphaComposite.CLEAR:
|
|
Packit |
5e46da |
for (int i = 0; i < length; i++) {
|
|
Packit |
5e46da |
backBuffer[dstOffset + i] = 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
case AlphaComposite.SRC:
|
|
Packit |
5e46da |
if (flipX) {
|
|
Packit |
5e46da |
for (int i = 0; i < length; i++) {
|
|
Packit |
5e46da |
backBuffer[dstOffset + length -1 - i] = applyComposite(src[srcOffset + i]);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
for (int i = 0; i < length; i++) {
|
|
Packit |
5e46da |
backBuffer[dstOffset + i] = applyComposite(src[srcOffset + i]);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
case AlphaComposite.SRC_OVER:
|
|
Packit |
5e46da |
if (flipX) {
|
|
Packit |
5e46da |
for (int i = 0; i < length; i++) {
|
|
Packit |
5e46da |
backBuffer[dstOffset + length -1 - i] = alphaBlend(backBuffer[dstOffset + length -1 - i], applyComposite(src[srcOffset + i]));
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
for (int i = 0; i < length; i++) {
|
|
Packit |
5e46da |
backBuffer[dstOffset + i] = alphaBlend(backBuffer[dstOffset + i], applyComposite(src[srcOffset + i]));
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
dirty.add(rect);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
private void drawSpan(int x, int y, int length, int rgb) {
|
|
Packit |
5e46da |
x += originX;
|
|
Packit |
5e46da |
y += originY;
|
|
Packit |
5e46da |
drawSpanN(x, y, length, rgb);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
private void drawSpan(int x, int y, int length, int src[], int srcOffset, boolean flipX) {
|
|
Packit |
5e46da |
x += originX;
|
|
Packit |
5e46da |
y += originY;
|
|
Packit |
5e46da |
drawSpanN(x, y, length, src, srcOffset, flipX);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
private void drawPointN(int x, int y, int rgb) {
|
|
Packit |
5e46da |
drawSpanN(x, y, 1, rgb);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
private void drawGlyph(int[] rgbArray, int x0, int y0, int w, int h) {
|
|
Packit |
5e46da |
for (int y = 0; y < h; y++)
|
|
Packit |
5e46da |
for (int x = 0; x < w; x++)
|
|
Packit |
5e46da |
drawPoint(x + x0, y + y0, rgbArray[y * w + x]);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
private void drawPoint(int x, int y, int rgb) {
|
|
Packit |
5e46da |
x += originX;
|
|
Packit |
5e46da |
y += originY;
|
|
Packit |
5e46da |
if (actualClip.contains(x, y))
|
|
Packit |
5e46da |
drawPointN(x, y, rgb);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
public void clearRect(int x, int y, int w, int h) {
|
|
Packit |
5e46da |
x += originX;
|
|
Packit |
5e46da |
y += originY;
|
|
Packit |
5e46da |
Rectangle rect = new Rectangle(x, y, w, h);
|
|
Packit |
5e46da |
rect = actualClip.intersection(rect);
|
|
Packit |
5e46da |
if (rect.isEmpty() || backBuffer == null) {
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
x = rect.x;
|
|
Packit |
5e46da |
y = rect.y;
|
|
Packit |
5e46da |
w = rect.width;
|
|
Packit |
5e46da |
h = rect.height;
|
|
Packit |
5e46da |
int rgb = background.getRGB();
|
|
Packit |
5e46da |
for (int i = 0; i < h; i++)
|
|
Packit |
5e46da |
Arrays.fill(backBuffer, (y + i) * width + x, (y + i) * width + x + w, rgb);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
dirty.add(rect);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
public void fillRect(int x, int y, int w, int h) {
|
|
Packit |
5e46da |
x += originX;
|
|
Packit |
5e46da |
y += originY;
|
|
Packit |
5e46da |
Rectangle rect = new Rectangle(x, y, w, h);
|
|
Packit |
5e46da |
rect = actualClip.intersection(rect);
|
|
Packit |
5e46da |
x = rect.x;
|
|
Packit |
5e46da |
y = rect.y;
|
|
Packit |
5e46da |
w = rect.width;
|
|
Packit |
5e46da |
h = rect.height;
|
|
Packit |
5e46da |
int rgb = foreground.getRGB();
|
|
Packit |
5e46da |
for (int Y = y; Y < (y + h); Y++)
|
|
Packit |
5e46da |
drawSpanN(x, Y, w, rgb);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
public void drawRect(int x, int y, int w, int h) {
|
|
Packit |
5e46da |
x += originX;
|
|
Packit |
5e46da |
y += originY;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
drawLineN(x, y, x + w, y);
|
|
Packit |
5e46da |
drawLineN(x, y + h, x + w, y + h);
|
|
Packit |
5e46da |
drawLineN(x, y, x, y + h);
|
|
Packit |
5e46da |
drawLineN(x + w, y, x + w, y + h);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
private void drawLineN(int x1, int y1, int x2, int y2) {
|
|
Packit |
5e46da |
int rgb = foreground.getRGB();
|
|
Packit |
5e46da |
int dy = y2 - y1;
|
|
Packit |
5e46da |
int dx = x2 - x1;
|
|
Packit |
5e46da |
int stepx, stepy;
|
|
Packit |
5e46da |
int fraction;
|
|
Packit |
5e46da |
if (dy < 0) {
|
|
Packit |
5e46da |
dy = -dy;
|
|
Packit |
5e46da |
stepy = -1;
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
stepy = 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (dx < 0) {
|
|
Packit |
5e46da |
dx = -dx;
|
|
Packit |
5e46da |
stepx = -1;
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
stepx = 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
dy <<= 1;
|
|
Packit |
5e46da |
dx <<= 1;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
drawPointN(x1, y1, rgb);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (dx > dy) {
|
|
Packit |
5e46da |
fraction = dy - (dx >> 1);
|
|
Packit |
5e46da |
while (x1 != x2) {
|
|
Packit |
5e46da |
if (fraction >= 0) {
|
|
Packit |
5e46da |
y1 += stepy;
|
|
Packit |
5e46da |
fraction -= dx;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
x1 += stepx;
|
|
Packit |
5e46da |
fraction += dy;
|
|
Packit |
5e46da |
drawPointN(x1, y1, rgb);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
fraction = dx - (dy >> 1);
|
|
Packit |
5e46da |
while (y1 != y2) {
|
|
Packit |
5e46da |
if (fraction >= 0) {
|
|
Packit |
5e46da |
x1 += stepx;
|
|
Packit |
5e46da |
fraction -= dy;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
y1 += stepy;
|
|
Packit |
5e46da |
fraction += dx;
|
|
Packit |
5e46da |
drawPointN(x1, y1, rgb);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
public void drawLine(int x1, int y1, int x2, int y2) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
x1 += originX;
|
|
Packit |
5e46da |
y1 += originY;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
x2 += originX;
|
|
Packit |
5e46da |
y2 += originY;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
drawLineN(x1, y1, x2, y2);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/**
|
|
Packit |
5e46da |
* Copies an area of the canvas that this graphics context paints to.
|
|
Packit |
5e46da |
* @param X the x-coordinate of the source.
|
|
Packit |
5e46da |
* @param Y the y-coordinate of the source.
|
|
Packit |
5e46da |
* @param W the width.
|
|
Packit |
5e46da |
* @param H the height.
|
|
Packit |
5e46da |
* @param dx the horizontal distance to copy the pixels.
|
|
Packit |
5e46da |
* @param dy the vertical distance to copy the pixels.
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
public void copyArea(int x, int y, int w, int h, int dx, int dy) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
x += originX;
|
|
Packit |
5e46da |
y += originY;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
Rectangle rect = new Rectangle(x, y, w, h);
|
|
Packit |
5e46da |
rect = actualClip.intersection(rect);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (rect.width <= 0 || rect.height <= 0 || backBuffer == null) {
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
x = rect.x;
|
|
Packit |
5e46da |
y = rect.y;
|
|
Packit |
5e46da |
w = rect.width;
|
|
Packit |
5e46da |
h = rect.height;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
int subImage[] = new int[w * h];
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// copy back buffer
|
|
Packit |
5e46da |
for (int i = 0; i < h; i++) {
|
|
Packit |
5e46da |
System.arraycopy(backBuffer, ((y + i) * width) + x, subImage, w * i, w);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// draw sub image
|
|
Packit |
5e46da |
for (int i = 0; i < h; i++) {
|
|
Packit |
5e46da |
drawSpanN(x + dx, y + i + dy, w, subImage, w * i, false);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/** Draws lines defined by an array of x points and y points */
|
|
Packit |
5e46da |
public void drawPolyline(int xPoints[], int yPoints[], int nPoints) {
|
|
Packit |
5e46da |
if (nPoints == 1) {
|
|
Packit |
5e46da |
drawPoint(xPoints[0], yPoints[0], foreground.getRGB());
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
for (int i = 0; i < (nPoints - 1); i++)
|
|
Packit |
5e46da |
drawLine(xPoints[i], xPoints[i], xPoints[i + 1], xPoints[i + 1]);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/** Draws a polygon defined by an array of x points and y points */
|
|
Packit |
5e46da |
public void drawPolygon(int xPoints[], int yPoints[], int nPoints) {
|
|
Packit |
5e46da |
if (nPoints == 1) {
|
|
Packit |
5e46da |
drawPoint(xPoints[0], yPoints[0], foreground.getRGB());
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
for (int i = 0; i < (nPoints - 1); i++)
|
|
Packit |
5e46da |
drawLine(xPoints[i], xPoints[i], xPoints[i + 1], xPoints[i + 1]);
|
|
Packit |
5e46da |
if (nPoints > 2)
|
|
Packit |
5e46da |
drawLine(xPoints[0], xPoints[0], xPoints[nPoints - 1], xPoints[nPoints - 1]);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/** Fills a polygon with the current fill mask */
|
|
Packit |
5e46da |
public void fillPolygon(int xPoints[], int yPoints[], int nPoints) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
int minY = Integer.MAX_VALUE;
|
|
Packit |
5e46da |
int maxY = Integer.MIN_VALUE;
|
|
Packit |
5e46da |
int colour = foreground.getRGB();
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (nPoints < 3) {
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (int i = 0; i < nPoints; i++) {
|
|
Packit |
5e46da |
if (yPoints[i] > maxY) {
|
|
Packit |
5e46da |
maxY = yPoints[i];
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (yPoints[i] < minY) {
|
|
Packit |
5e46da |
minY = yPoints[i];
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// check the last point to see if its the same as the first
|
|
Packit |
5e46da |
if (xPoints[0] == xPoints[nPoints - 1] && yPoints[0] == yPoints[nPoints - 1]) {
|
|
Packit |
5e46da |
nPoints--;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
PolyEdge[] polyEdges = new PolyEdge[nPoints];
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (int i = 0; i < nPoints - 1; i++) {
|
|
Packit |
5e46da |
polyEdges[i] = new PolyEdge(xPoints[i], yPoints[i], xPoints[i + 1], yPoints[i + 1]);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// add the last one
|
|
Packit |
5e46da |
polyEdges[nPoints - 1] = new PolyEdge(xPoints[nPoints - 1], yPoints[nPoints - 1], xPoints[0], yPoints[0]);
|
|
Packit |
5e46da |
ArrayList xList = new ArrayList();
|
|
Packit |
5e46da |
for (int i = minY; i <= maxY; i++) {
|
|
Packit |
5e46da |
for (int j = 0; j < nPoints; j++) {
|
|
Packit |
5e46da |
if (polyEdges[j].intersects(i)) {
|
|
Packit |
5e46da |
int x = polyEdges[j].intersectionX(i);
|
|
Packit |
5e46da |
xList.add(new Integer(x));
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// probably a better way of doing this (removing duplicates);
|
|
Packit |
5e46da |
HashSet hs = new HashSet();
|
|
Packit |
5e46da |
hs.addAll(xList);
|
|
Packit |
5e46da |
xList.clear();
|
|
Packit |
5e46da |
xList.addAll(hs);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (xList.size() % 2 > 0) {
|
|
Packit |
5e46da |
xList.clear();
|
|
Packit |
5e46da |
continue; // this should be impossible unless the poly is open somewhere
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
Collections.sort(xList);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (int j = 0; j < xList.size(); j +=2 ) {
|
|
Packit |
5e46da |
int x1 = ((Integer)xList.get(j)).intValue();
|
|
Packit |
5e46da |
int x2 = ((Integer)xList.get(j + 1)).intValue();
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
drawSpan(x1, i, x2 - x1, colour);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
xList.clear();
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/** Draws an oval to fit in the given rectangle */
|
|
Packit |
5e46da |
public void drawOval(int x, int y, int w, int h) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
int startX;
|
|
Packit |
5e46da |
int endX;
|
|
Packit |
5e46da |
int offset;
|
|
Packit |
5e46da |
int[] xList;
|
|
Packit |
5e46da |
int[] yList;
|
|
Packit |
5e46da |
int numPoints;
|
|
Packit |
5e46da |
int count;
|
|
Packit |
5e46da |
float as;
|
|
Packit |
5e46da |
float bs;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (w <= 0 || h <=0 ) {
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
count = 0;
|
|
Packit |
5e46da |
numPoints = ((h/2) + (h/2) + 1) * 2;
|
|
Packit |
5e46da |
numPoints += 1; // to close
|
|
Packit |
5e46da |
xList = new int[numPoints];
|
|
Packit |
5e46da |
yList = new int[numPoints];
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
as = (w/2.0f) * (w/2.0f);
|
|
Packit |
5e46da |
bs = (h/2.0f) * (h/2.0f);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (int i = -h/2; i <= h/2; i++) {
|
|
Packit |
5e46da |
offset = (int) Math.sqrt( (1.0 - ((i*i)/bs)) * as );
|
|
Packit |
5e46da |
startX = x - offset + w/2;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
xList[count] = startX;
|
|
Packit |
5e46da |
yList[count] = y + i + h/2;
|
|
Packit |
5e46da |
count++;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (int i = h/2; i >= -h/2; i--) {
|
|
Packit |
5e46da |
offset = (int) Math.sqrt( (1.0 - ((i*i)/bs)) * as );
|
|
Packit |
5e46da |
endX = x + offset + w/2;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
xList[count] = endX;
|
|
Packit |
5e46da |
yList[count] = y + i + h/2;
|
|
Packit |
5e46da |
count++;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
xList[count] = xList[0]; // close the loop
|
|
Packit |
5e46da |
yList[count] = yList[0]; // close the loop
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
drawPolyline(xList, yList, numPoints);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/** Fills an oval to fit in the given rectangle */
|
|
Packit |
5e46da |
public void fillOval(int x, int y, int w, int h) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
int startX;
|
|
Packit |
5e46da |
int endX;
|
|
Packit |
5e46da |
int offset;
|
|
Packit |
5e46da |
int colour;
|
|
Packit |
5e46da |
float as;
|
|
Packit |
5e46da |
float bs;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (w <= 0 || h <= 0) {
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
as = (w/2.0f) * (w/2.0f);
|
|
Packit |
5e46da |
bs = (h/2.0f) * (h/2.0f);
|
|
Packit |
5e46da |
colour = foreground.getRGB();
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for(int i=-h/2; i<=h/2; i++) {
|
|
Packit |
5e46da |
offset = (int) Math.sqrt( (1.0 - ((i*i)/bs)) * as );
|
|
Packit |
5e46da |
startX = x - offset + w/2;
|
|
Packit |
5e46da |
endX = x + offset + w/2;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
drawSpan(startX, y + i + h/2, endX - startX + 1, colour);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
private int getAngle(int centreX, int centreY, int pointX, int pointY) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
float vStartX;
|
|
Packit |
5e46da |
float vStartY;
|
|
Packit |
5e46da |
float vEndX;
|
|
Packit |
5e46da |
float vEndY;
|
|
Packit |
5e46da |
float length;
|
|
Packit |
5e46da |
double angle;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
vStartX = 1; // vector pointing right (this is where angle starts for arcs)
|
|
Packit |
5e46da |
vStartY = 0;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
vEndX = pointX - centreX;
|
|
Packit |
5e46da |
vEndY = pointY - centreY;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
length = (float) Math.sqrt(vEndX*vEndX + vEndY*vEndY);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
vEndX /= length;
|
|
Packit |
5e46da |
vEndY /= length;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
angle = Math.acos(vStartX*vEndX + vStartY*vEndY);
|
|
Packit |
5e46da |
angle = angle * 180.0 / Math.PI;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (vEndY > 0) {
|
|
Packit |
5e46da |
angle = 360 - angle;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return (int)(angle + 0.5);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
private void drawArcI(boolean fill, int x, int y, int width, int height, int startAngle, int arcAngle) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
int endAngle;
|
|
Packit |
5e46da |
int startX;
|
|
Packit |
5e46da |
int endX;
|
|
Packit |
5e46da |
int offset;
|
|
Packit |
5e46da |
int[] xList;
|
|
Packit |
5e46da |
int[] yList;
|
|
Packit |
5e46da |
int count;
|
|
Packit |
5e46da |
int numPoints;
|
|
Packit |
5e46da |
int tempX;
|
|
Packit |
5e46da |
int tempY;
|
|
Packit |
5e46da |
int angle;
|
|
Packit |
5e46da |
int widthDiv2;
|
|
Packit |
5e46da |
int heightDiv2;
|
|
Packit |
5e46da |
float as;
|
|
Packit |
5e46da |
float bs;
|
|
Packit |
5e46da |
boolean addedZero;
|
|
Packit |
5e46da |
boolean circle;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// sanity checks
|
|
Packit |
5e46da |
if (width <= 0 || height <= 0 || arcAngle == 0) {
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// init variables
|
|
Packit |
5e46da |
count = 0;
|
|
Packit |
5e46da |
addedZero = false;
|
|
Packit |
5e46da |
circle = false;
|
|
Packit |
5e46da |
widthDiv2 = (int)(width/2.0f + 0.5f);
|
|
Packit |
5e46da |
heightDiv2 = (int)(height/2.0f + 0.5f);
|
|
Packit |
5e46da |
numPoints = ((height + 1/2) + (height + 1/2) + 1) * 2 + 1;
|
|
Packit |
5e46da |
xList = new int[numPoints];
|
|
Packit |
5e46da |
yList = new int[numPoints];
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
as = (width/2.0f) * (width/2.0f);
|
|
Packit |
5e46da |
bs = (height/2.0f) * (height/2.0f);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// check if we actually want to draw a circle
|
|
Packit |
5e46da |
if (Math.abs(arcAngle) >= 360) {
|
|
Packit |
5e46da |
circle = true;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (startAngle < 0) {
|
|
Packit |
5e46da |
startAngle %= 360;
|
|
Packit |
5e46da |
startAngle = Math.abs(startAngle);
|
|
Packit |
5e46da |
startAngle = 360 - startAngle;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (arcAngle < 0) {
|
|
Packit |
5e46da |
int temp;
|
|
Packit |
5e46da |
temp = startAngle;
|
|
Packit |
5e46da |
endAngle = startAngle;
|
|
Packit |
5e46da |
startAngle = 360 + arcAngle + temp;
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
endAngle = startAngle + arcAngle;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
startAngle %= 360;
|
|
Packit |
5e46da |
endAngle %= 360;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (int i = heightDiv2; i >= -heightDiv2; i--) {
|
|
Packit |
5e46da |
boolean hit = false;
|
|
Packit |
5e46da |
int offsetAngle;
|
|
Packit |
5e46da |
int startXAngle;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
offset = (int) Math.sqrt( (1.0 - i*i/bs) * as );
|
|
Packit |
5e46da |
startX = x + offset + widthDiv2;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
offsetAngle = (int) Math.sqrt( (1.0 - i*i/bs) * bs ); // we calculate these as if it were a circle
|
|
Packit |
5e46da |
startXAngle = x + offsetAngle + height/2;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
tempX = startX;
|
|
Packit |
5e46da |
tempY = y + i + height/2;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
angle = getAngle(x + height/2, y + height/2, startXAngle, tempY);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (startAngle < endAngle) {
|
|
Packit |
5e46da |
if (angle < endAngle && angle >= startAngle) {
|
|
Packit |
5e46da |
xList[count] = tempX;
|
|
Packit |
5e46da |
yList[count] = tempY;
|
|
Packit |
5e46da |
count++;
|
|
Packit |
5e46da |
hit = true;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
if (!(angle > endAngle && angle < startAngle)) {
|
|
Packit |
5e46da |
xList[count] = tempX;
|
|
Packit |
5e46da |
yList[count] = tempY;
|
|
Packit |
5e46da |
count++;
|
|
Packit |
5e46da |
hit = true;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!hit && !addedZero && !circle && fill) {
|
|
Packit |
5e46da |
xList[count] = x + width/2;
|
|
Packit |
5e46da |
yList[count] = y + height/2;
|
|
Packit |
5e46da |
count++;
|
|
Packit |
5e46da |
addedZero = true;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!hit && !fill && !circle && count > 1) {
|
|
Packit |
5e46da |
drawPolyline(xList, yList, count);
|
|
Packit |
5e46da |
count = 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (int i = -heightDiv2; i <= heightDiv2; i++) {
|
|
Packit |
5e46da |
boolean hit = false;
|
|
Packit |
5e46da |
int offsetAngle;
|
|
Packit |
5e46da |
int endXAngle;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
offset = (int) Math.sqrt( (1.0 - i*i/bs) * as );
|
|
Packit |
5e46da |
endX = x - offset + width/2;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
offsetAngle = (int) Math.sqrt( (1.0 - i*i/bs) * bs ); // we calculate these as if it were a circle
|
|
Packit |
5e46da |
endXAngle = x - offsetAngle + height/2;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
tempX = endX;
|
|
Packit |
5e46da |
tempY = y + i + height/2;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
angle = getAngle(x + height/2, y + height/2, endXAngle, tempY);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (startAngle < endAngle) {
|
|
Packit |
5e46da |
if (angle <= endAngle && angle >= startAngle) {
|
|
Packit |
5e46da |
xList[count] = tempX;
|
|
Packit |
5e46da |
yList[count] = tempY;
|
|
Packit |
5e46da |
count++;
|
|
Packit |
5e46da |
hit = true;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
if (!(angle > endAngle && angle < startAngle)) {
|
|
Packit |
5e46da |
xList[count] = tempX;
|
|
Packit |
5e46da |
yList[count] = tempY;
|
|
Packit |
5e46da |
count++;
|
|
Packit |
5e46da |
hit = true;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!hit && !addedZero && !circle && fill) {
|
|
Packit |
5e46da |
xList[count] = x + width/2;
|
|
Packit |
5e46da |
yList[count] = y + height/2;
|
|
Packit |
5e46da |
count++;
|
|
Packit |
5e46da |
addedZero = true;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!hit && !fill && !circle && count > 1) {
|
|
Packit |
5e46da |
drawPolyline(xList, yList, count);
|
|
Packit |
5e46da |
count = 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (fill) {
|
|
Packit |
5e46da |
fillPolygon(xList, yList, count);
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
if (circle) {
|
|
Packit |
5e46da |
drawPolygon(xList, yList, count); // we need to connect start to end in the case of 360
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
drawPolyline(xList, yList, count); // shape must be open so no connection
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/**
|
|
Packit |
5e46da |
* Draws an arc bounded by the given rectangle from startAngle to
|
|
Packit |
5e46da |
* endAngle. 0 degrees is a vertical line straight up from the
|
|
Packit |
5e46da |
* center of the rectangle. Positive start angle indicate clockwise
|
|
Packit |
5e46da |
* rotations, negative angle are counter-clockwise.
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
public void drawArc(int x, int y, int w, int h, int startAngle, int endAngle) {
|
|
Packit |
5e46da |
drawArcI(false, x, y, w, h, startAngle, endAngle);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/** fills an arc. arguments are the same as drawArc. */
|
|
Packit |
5e46da |
public void fillArc(int x, int y, int w, int h, int startAngle, int endAngle) {
|
|
Packit |
5e46da |
drawArcI(true, x, y, w, h, startAngle, endAngle);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/** Draws a rounded rectangle. */
|
|
Packit |
5e46da |
public void drawRoundRect(int x, int y, int w, int h, int arcWidth, int arcHeight) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
int[] xList;
|
|
Packit |
5e46da |
int[] yList;
|
|
Packit |
5e46da |
int numPoints;
|
|
Packit |
5e46da |
int count;
|
|
Packit |
5e46da |
int startX;
|
|
Packit |
5e46da |
int endX;
|
|
Packit |
5e46da |
int offset;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (w <= 0 || h <= 0) {
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (arcWidth == 0 || arcHeight == 0) {
|
|
Packit |
5e46da |
drawRect(x, y, w, h);
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (arcWidth < 0) { // matches behaviour of normal java version
|
|
Packit |
5e46da |
arcWidth *= -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (arcHeight < 0) {
|
|
Packit |
5e46da |
arcHeight *= -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
count = 0;
|
|
Packit |
5e46da |
numPoints = ((arcHeight/2) + 1) * 2;
|
|
Packit |
5e46da |
numPoints += ((arcHeight/2) + 1) * 2;
|
|
Packit |
5e46da |
numPoints += 1; // last point to close the loop
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
xList = new int[numPoints];
|
|
Packit |
5e46da |
yList = new int[numPoints];
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
float as = (arcWidth/2.0f) * (arcWidth/2.0f);
|
|
Packit |
5e46da |
float bs = (arcHeight/2.0f) * (arcHeight/2.0f);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// draw top curved half of box
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (int i = 0; -arcHeight/2 <= i; i--) {
|
|
Packit |
5e46da |
offset = (int) Math.sqrt( (1.0 - ((i*i)/bs)) * as );
|
|
Packit |
5e46da |
startX = x - offset + arcWidth/2;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
xList[count] = startX;
|
|
Packit |
5e46da |
yList[count] = y+i+(arcHeight/2);
|
|
Packit |
5e46da |
count++;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (int i = -arcHeight / 2; i <= 0; i++) {
|
|
Packit |
5e46da |
offset = (int) Math.sqrt( (1.0 - ((i*i)/bs)) * as );
|
|
Packit |
5e46da |
endX = x + offset + (w-arcWidth) + arcWidth/2;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
xList[count] = endX;
|
|
Packit |
5e46da |
yList[count] = y + i + (arcHeight/2);
|
|
Packit |
5e46da |
count++;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// draw bottom box
|
|
Packit |
5e46da |
for (int i = 0; i <= arcHeight / 2; i++) {
|
|
Packit |
5e46da |
offset = (int) Math.sqrt( (1.0 - ((i*i)/bs)) * as );
|
|
Packit |
5e46da |
startX = x - offset + arcWidth/2;
|
|
Packit |
5e46da |
endX = x + offset + (w - arcWidth) + arcWidth/2;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
xList[count] = endX;
|
|
Packit |
5e46da |
yList[count] = y + i + h - arcHeight/2;
|
|
Packit |
5e46da |
count++;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// draw bottom box
|
|
Packit |
5e46da |
for (int i = arcHeight / 2; i >= 0; i--) {
|
|
Packit |
5e46da |
offset = (int) Math.sqrt( (1.0 - ((i*i)/bs)) * as );
|
|
Packit |
5e46da |
startX = x - offset + arcWidth/2;
|
|
Packit |
5e46da |
endX = x + offset + (w-arcWidth) + arcWidth/2;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
xList[count] = startX;
|
|
Packit |
5e46da |
yList[count] = y+i+h-arcHeight/2;
|
|
Packit |
5e46da |
count++;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
xList[count] = xList[0];
|
|
Packit |
5e46da |
yList[count] = yList[0];
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
drawPolyline(xList, yList, numPoints);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/** Draws a filled rounded rectangle. */
|
|
Packit |
5e46da |
public void fillRoundRect(int x, int y, int w, int h, int arcWidth, int arcHeight) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
int startX;
|
|
Packit |
5e46da |
int endX;
|
|
Packit |
5e46da |
int offset;
|
|
Packit |
5e46da |
int colour;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (w <= 0 || h <= 0) {
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (arcWidth == 0 || arcHeight == 0) {
|
|
Packit |
5e46da |
fillRect(x,y,w,h);
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (arcWidth < 0) { // matches behaviour of normal java version
|
|
Packit |
5e46da |
arcWidth *= -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (arcHeight < 0) {
|
|
Packit |
5e46da |
arcHeight *= -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
float as = (arcWidth/2.0f) * (arcWidth/2.0f);
|
|
Packit |
5e46da |
float bs = (arcHeight/2.0f) * (arcHeight/2.0f);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
colour = foreground.getRGB();
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// draw top curved half of box
|
|
Packit |
5e46da |
for (int i = -arcHeight/2; i < 0; i++) {
|
|
Packit |
5e46da |
offset = (int) Math.sqrt( (1.0 - ((i*i)/bs)) * as );
|
|
Packit |
5e46da |
startX = x - offset + arcWidth/2;
|
|
Packit |
5e46da |
endX = x + offset + (w - arcWidth) + arcWidth/2;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
drawSpan(startX, y + i + (arcHeight/2), endX - startX + 1, colour);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// draw middle section
|
|
Packit |
5e46da |
for (int i = 0; i < h - arcHeight; i++) {
|
|
Packit |
5e46da |
drawSpan(x, y + i + arcHeight/2, w, colour);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// draw bottom box
|
|
Packit |
5e46da |
for (int i = 0; i <= arcHeight/2; i++) {
|
|
Packit |
5e46da |
offset = (int) Math.sqrt( (1.0 - ((i*i)/bs)) * as );
|
|
Packit |
5e46da |
startX = x - offset + arcWidth/2;
|
|
Packit |
5e46da |
endX = x + offset + (w - arcWidth) + arcWidth/2;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
drawSpan(startX, y + i + h - 1 - arcHeight/2, endX - startX + 1, colour);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
protected native void drawStringN(long ftFace, String string, int x, int y, int rgb);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/** Draws the given string. */
|
|
Packit |
5e46da |
public void drawString(String string, int x, int y) {
|
|
Packit |
5e46da |
getFontMetrics();
|
|
Packit |
5e46da |
if (fontMetrics != null) {
|
|
Packit |
5e46da |
fontMetrics.drawString((BDGraphics)this, string, x, y, foreground.getRGB());
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
logger.error("drawString skipped: no font metrics. string=\"" + string + "\"");
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/** Draws the given character array. */
|
|
Packit |
5e46da |
public void drawChars(char chars[], int offset, int length, int x, int y) {
|
|
Packit |
5e46da |
drawString(new String(chars, offset, length), x, y);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
public void drawString(AttributedCharacterIterator arg0, int arg1, int arg2) {
|
|
Packit |
5e46da |
logger.unimplemented("drawString");
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/**
|
|
Packit |
5e46da |
* Draws an image at x,y in nonblocking mode with a callback object.
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
public boolean drawImage(Image img, int x, int y, ImageObserver observer) {
|
|
Packit |
5e46da |
return drawImage(img, x, y, null, observer);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/**
|
|
Packit |
5e46da |
* Draws an image at x,y in nonblocking mode with a solid background
|
|
Packit |
5e46da |
* color and a callback object.
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
public boolean drawImage(Image img, int x, int y, Color bg,
|
|
Packit |
5e46da |
ImageObserver observer) {
|
|
Packit |
5e46da |
return drawImageN(img, x, y, -1, -1, 0, 0, -1, -1, false, false, bg, observer);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/**
|
|
Packit |
5e46da |
* Draws an image scaled to x,y,w,h in nonblocking mode with a
|
|
Packit |
5e46da |
* callback object.
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
public boolean drawImage(Image img, int x, int y, int w, int h,
|
|
Packit |
5e46da |
ImageObserver observer) {
|
|
Packit |
5e46da |
return drawImage(img, x, y, w, h, null, observer);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/**
|
|
Packit |
5e46da |
* Draws an image scaled to x,y,w,h in nonblocking mode with a
|
|
Packit |
5e46da |
* solid background color and a callback object.
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
public boolean drawImage(Image img, int x, int y, int w, int h,
|
|
Packit |
5e46da |
Color bg, ImageObserver observer) {
|
|
Packit |
5e46da |
return drawImageN(img, x, y, w, h, 0, 0, -1, -1, false, false, bg, observer);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/**
|
|
Packit |
5e46da |
* Draws a subrectangle of an image scaled to a destination rectangle
|
|
Packit |
5e46da |
* in nonblocking mode with a callback object.
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
public boolean drawImage(Image img,
|
|
Packit |
5e46da |
int dx1, int dy1, int dx2, int dy2,
|
|
Packit |
5e46da |
int sx1, int sy1, int sx2, int sy2,
|
|
Packit |
5e46da |
ImageObserver observer) {
|
|
Packit |
5e46da |
return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, observer);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/**
|
|
Packit |
5e46da |
* Draws a subrectangle of an image scaled to a destination rectangle in
|
|
Packit |
5e46da |
* nonblocking mode with a solid background color and a callback object.
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
public boolean drawImage(Image img,
|
|
Packit |
5e46da |
int dx1, int dy1, int dx2, int dy2,
|
|
Packit |
5e46da |
int sx1, int sy1, int sx2, int sy2,
|
|
Packit |
5e46da |
Color bg, ImageObserver observer) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
boolean flipX = false;
|
|
Packit |
5e46da |
boolean flipY = false;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (dx1 > dx2) {
|
|
Packit |
5e46da |
int swap = dx1;
|
|
Packit |
5e46da |
dx1 = dx2;
|
|
Packit |
5e46da |
dx2 = swap;
|
|
Packit |
5e46da |
flipX = !flipX;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (dy1 > dy2) {
|
|
Packit |
5e46da |
int swap = dy1;
|
|
Packit |
5e46da |
dy1 = dy2;
|
|
Packit |
5e46da |
dy2 = swap;
|
|
Packit |
5e46da |
flipY = !flipY;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (sx1 > sx2) {
|
|
Packit |
5e46da |
int swap = sx1;
|
|
Packit |
5e46da |
sx1 = sx2;
|
|
Packit |
5e46da |
sx2 = swap;
|
|
Packit |
5e46da |
flipX = !flipX;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (sy1 > sy2) {
|
|
Packit |
5e46da |
int swap = sy1;
|
|
Packit |
5e46da |
sy1 = sy2;
|
|
Packit |
5e46da |
sy2 = swap;
|
|
Packit |
5e46da |
flipY = !flipY;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return drawImageN(img, dx1, dy1, dx2 - dx1, dy2 - dy1,
|
|
Packit |
5e46da |
sx1, sy1, sx2 - sx1, sy2 - sy1,
|
|
Packit |
5e46da |
flipX, flipY, bg, observer);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/**
|
|
Packit |
5e46da |
* Draws a subrectangle of an image scaled to a destination rectangle in
|
|
Packit |
5e46da |
* nonblocking mode with a solid background color and a callback object.
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
protected boolean drawImageN(Image img,
|
|
Packit |
5e46da |
int dx, int dy, int dw, int dh,
|
|
Packit |
5e46da |
int sx, int sy, int sw, int sh,
|
|
Packit |
5e46da |
boolean flipX, boolean flipY,
|
|
Packit |
5e46da |
Color bg, ImageObserver observer) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if ((sw == 0) || (sh == 0) || (dw == 0) || (dh == 0))
|
|
Packit |
5e46da |
return false;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BDImage bdImage;
|
|
Packit |
5e46da |
if (img instanceof BDImage) {
|
|
Packit |
5e46da |
bdImage = (BDImage)img;
|
|
Packit |
5e46da |
} else if (img instanceof DVBBufferedImage) {
|
|
Packit |
5e46da |
bdImage = (BDImage)getBufferedImagePeer(
|
|
Packit |
5e46da |
(BufferedImage)(((DVBBufferedImage)img).getImage()));
|
|
Packit |
5e46da |
} else if (img instanceof BufferedImage) {
|
|
Packit |
5e46da |
bdImage = (BDImage)getBufferedImagePeer((BufferedImage)img);
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
logger.unimplemented("drawImageN: unsupported image type " + img.getClass().getName());
|
|
Packit |
5e46da |
return false;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (bdImage instanceof BDImageConsumer) {
|
|
Packit |
5e46da |
BDImageConsumer consumer = (BDImageConsumer)bdImage;
|
|
Packit |
5e46da |
if (!consumer.isComplete(observer)) {
|
|
Packit |
5e46da |
return false;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (sw < 0) sw = bdImage.width;
|
|
Packit |
5e46da |
if (sh < 0) sh = bdImage.height;
|
|
Packit |
5e46da |
if (dw < 0) dw = bdImage.width;
|
|
Packit |
5e46da |
if (dh < 0) dh = bdImage.height;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
int stride = bdImage.width;
|
|
Packit |
5e46da |
int[] rgbArray = bdImage.getBdBackBuffer();
|
|
Packit |
5e46da |
int bgColor = 0;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (bg != null) {
|
|
Packit |
5e46da |
bgColor = bg.getRGB();
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// draw background colour
|
|
Packit |
5e46da |
for (int i = 0; i < dh && bg != null; i++) {
|
|
Packit |
5e46da |
drawSpan(dx, dy + i, dw, bgColor);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// resize if needed
|
|
Packit |
5e46da |
if (dw != sw || dh != sh) {
|
|
Packit |
5e46da |
drawResizeBilinear(rgbArray, (sy * stride) + sx, stride, sw, sh,
|
|
Packit |
5e46da |
dx, dy, dw, dh, flipX, flipY);
|
|
Packit |
5e46da |
return true;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// draw actual colour array
|
|
Packit |
5e46da |
if (flipY) {
|
|
Packit |
5e46da |
for (int i = 0; i < dh; i++) {
|
|
Packit |
5e46da |
drawSpan(dx, dy + dh - 1 - i, dw, rgbArray, (stride * (i + sy)) + sx, flipX);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
for (int i = 0; i < dh; i++) {
|
|
Packit |
5e46da |
drawSpan(dx, dy + i, dw, rgbArray, (stride * (i + sy)) + sx, flipX);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return true;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/**
|
|
Packit |
5e46da |
* Bilinear resize ARGB image.
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
* @param pixels Source image pixels.
|
|
Packit |
5e46da |
* @param sw Source image width.
|
|
Packit |
5e46da |
* @param sh Source image height.
|
|
Packit |
5e46da |
* @param dw New width.
|
|
Packit |
5e46da |
* @param dh New height.
|
|
Packit |
5e46da |
* @return New array with size dw * dh.
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
private int[] tmpLine = null;
|
|
Packit |
5e46da |
private void drawResizeBilinear(int[] pixels, int offset, int scansize, int sw, int sh,
|
|
Packit |
5e46da |
int dx, int dy, int dw, int dh, boolean flipX, boolean flipY) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (sh == 1) {
|
|
Packit |
5e46da |
// crop source width if needed for 1d arrays
|
|
Packit |
5e46da |
if (offset + sw > pixels.length) {
|
|
Packit |
5e46da |
sw = (pixels.length - offset);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
// crop source height to prevent possible over reads
|
|
Packit |
5e46da |
if (offset + (scansize*sh) > pixels.length) {
|
|
Packit |
5e46da |
sh = (pixels.length - offset) / scansize;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (sw < 1 || sh < 1 || pixels.length < 1) {
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (sw == 1 && sh == 1) {
|
|
Packit |
5e46da |
for (int Y = dy; Y < (dy + dh); Y++)
|
|
Packit |
5e46da |
drawSpan(dx, Y, dw, pixels[offset]);
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// a quick hack for 1D arrays, stretch them to make them 2D
|
|
Packit |
5e46da |
if (sw == 1) {
|
|
Packit |
5e46da |
int[] temp = new int[2 * sh];
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (int i = 0; i < sw * sh; i++) {
|
|
Packit |
5e46da |
temp[(i * 2) + 0] = pixels[offset + i];
|
|
Packit |
5e46da |
temp[(i * 2) + 1] = pixels[offset + i];
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
scansize = 2;
|
|
Packit |
5e46da |
pixels = temp;
|
|
Packit |
5e46da |
offset = 0;
|
|
Packit |
5e46da |
sw = 2;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
} else if (sh == 1) {
|
|
Packit |
5e46da |
int[] temp = new int[sw * 2];
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
System.arraycopy(pixels, offset, temp, 0, sw);
|
|
Packit |
5e46da |
System.arraycopy(pixels, offset, temp, sw, sw);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
scansize = sw;
|
|
Packit |
5e46da |
pixels = temp;
|
|
Packit |
5e46da |
offset = 0;
|
|
Packit |
5e46da |
sh = 2;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (tmpLine == null || tmpLine.length < dw + 1) {
|
|
Packit |
5e46da |
tmpLine = new int[Math.max(1920, dw + 1)];
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
int a, b, c, d, x, y, index;
|
|
Packit |
5e46da |
float x_ratio = ((float)(sw - 1)) / dw;
|
|
Packit |
5e46da |
float y_ratio = ((float)(sh - 1)) / dh;
|
|
Packit |
5e46da |
float x_diff, y_diff, blue, red, green, alpha;
|
|
Packit |
5e46da |
int position = 0;
|
|
Packit |
5e46da |
for (int i = 0; i < dh; i++) {
|
|
Packit |
5e46da |
for (int j = 0; j < dw; j++) {
|
|
Packit |
5e46da |
x = (int)(x_ratio * j);
|
|
Packit |
5e46da |
y = (int)(y_ratio * i);
|
|
Packit |
5e46da |
x_diff = (x_ratio * j) - x;
|
|
Packit |
5e46da |
y_diff = (y_ratio * i) - y;
|
|
Packit |
5e46da |
index = (y * scansize + x);
|
|
Packit |
5e46da |
index += offset;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
a = pixels[index];
|
|
Packit |
5e46da |
b = pixels[index + 1];
|
|
Packit |
5e46da |
c = pixels[index + scansize];
|
|
Packit |
5e46da |
d = pixels[index + scansize + 1];
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
int aA = a >>> 24;
|
|
Packit |
5e46da |
int bA = b >>> 24;
|
|
Packit |
5e46da |
int cA = c >>> 24;
|
|
Packit |
5e46da |
int dA = d >>> 24;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (aA + bA + cA + dA < 1) {
|
|
Packit |
5e46da |
tmpLine[position++] = 0;
|
|
Packit |
5e46da |
continue;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* calculate areas, weighted with alpha */
|
|
Packit |
5e46da |
float aFactor = (1-x_diff) * (1-y_diff) * aA;
|
|
Packit |
5e46da |
float bFactor = x_diff * (1-y_diff) * bA;
|
|
Packit |
5e46da |
float cFactor = (1-x_diff) * y_diff * cA;
|
|
Packit |
5e46da |
float dFactor = x_diff * y_diff * dA;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// alpha element
|
|
Packit |
5e46da |
// Yr = Ar(1-w)(1-h) + Br(w)(1-h) + Cr(h)(1-w) + Dr(wh)
|
|
Packit |
5e46da |
alpha = aFactor + bFactor + cFactor + dFactor;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// blue element
|
|
Packit |
5e46da |
// Yb = Ab(1-w)(1-h) + Bb(w)(1-h) + Cb(h)(1-w) + Db(wh)
|
|
Packit |
5e46da |
blue = (a & 0xff) * aFactor +
|
|
Packit |
5e46da |
(b & 0xff) * bFactor +
|
|
Packit |
5e46da |
(c & 0xff) * cFactor +
|
|
Packit |
5e46da |
(d & 0xff) * dFactor;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// green element
|
|
Packit |
5e46da |
// Yg = Ag(1-w)(1-h) + Bg(w)(1-h) + Cg(h)(1-w) + Dg(wh)
|
|
Packit |
5e46da |
green = ((a >> 8) & 0xff) * aFactor +
|
|
Packit |
5e46da |
((b >> 8) & 0xff) * bFactor +
|
|
Packit |
5e46da |
((c >> 8) & 0xff) * cFactor +
|
|
Packit |
5e46da |
((d >> 8) & 0xff) * dFactor;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// red element
|
|
Packit |
5e46da |
// Yr = Ar(1-w)(1-h) + Br(w)(1-h) + Cr(h)(1-w) + Dr(wh)
|
|
Packit |
5e46da |
red = ((a >> 16) & 0xff) * aFactor +
|
|
Packit |
5e46da |
((b >> 16) & 0xff) * bFactor +
|
|
Packit |
5e46da |
((c >> 16) & 0xff) * cFactor +
|
|
Packit |
5e46da |
((d >> 16) & 0xff) * dFactor;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
blue /= alpha;
|
|
Packit |
5e46da |
green /= alpha;
|
|
Packit |
5e46da |
red /= alpha;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
tmpLine[position++] =
|
|
Packit |
5e46da |
((((int)alpha) << 24) & 0xff000000) |
|
|
Packit |
5e46da |
((((int)red ) << 16) & 0x00ff0000) |
|
|
Packit |
5e46da |
((((int)green) << 8 ) & 0x0000ff00) |
|
|
Packit |
5e46da |
((((int)blue ) ) & 0x000000ff);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (flipY) {
|
|
Packit |
5e46da |
drawSpan(dx, dy + dh - 1 - i, dw, tmpLine, 0, flipX);
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
drawSpan(dx, dy + i, dw, tmpLine, 0, flipX);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
position = 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
public Stroke getStroke() {
|
|
Packit |
5e46da |
logger.unimplemented("getStroke");
|
|
Packit |
5e46da |
throw new Error();
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
public void setStroke(Stroke stroke) {
|
|
Packit |
5e46da |
logger.unimplemented("setStroke");
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
public void dispose() {
|
|
Packit |
5e46da |
tmpLine = null;
|
|
Packit |
5e46da |
font = null;
|
|
Packit |
5e46da |
fontMetrics = null;
|
|
Packit |
5e46da |
gc = null;
|
|
Packit |
5e46da |
backBuffer = null;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
public String toString() {
|
|
Packit |
5e46da |
return getClass().getName() + "[" + originX + "," + originY + "]";
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
private static Image getBufferedImagePeer(BufferedImage image) {
|
|
Packit |
5e46da |
try {
|
|
Packit |
5e46da |
return (Image)bufferedImagePeer.get(image);
|
|
Packit |
5e46da |
} catch (IllegalArgumentException e) {
|
|
Packit |
5e46da |
logger.error("Failed getting buffered image peer: " + e + "\n" +
|
|
Packit |
5e46da |
Logger.dumpStack(e));
|
|
Packit |
5e46da |
} catch (IllegalAccessException e) {
|
|
Packit |
5e46da |
logger.error("Failed getting buffered image peer: " + e + "\n" +
|
|
Packit |
5e46da |
Logger.dumpStack(e));
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
return null;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
private static Field bufferedImagePeer;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static {
|
|
Packit |
5e46da |
try {
|
|
Packit |
5e46da |
Class c = Class.forName("java.awt.image.BufferedImage");
|
|
Packit |
5e46da |
bufferedImagePeer = c.getDeclaredField("peer");
|
|
Packit |
5e46da |
bufferedImagePeer.setAccessible(true);
|
|
Packit |
5e46da |
} catch (ClassNotFoundException e) {
|
|
Packit |
5e46da |
throw new AWTError("java.awt.image.BufferedImage not found");
|
|
Packit |
5e46da |
} catch (SecurityException e) {
|
|
Packit |
5e46da |
throw new AWTError("java.awt.image.BufferedImage.peer not accessible");
|
|
Packit |
5e46da |
} catch (NoSuchFieldException e) {
|
|
Packit |
5e46da |
throw new AWTError("java.awt.image.BufferedImage.peer not found");
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
private static final Logger logger = Logger.getLogger(BDGraphics.class.getName());
|
|
Packit |
5e46da |
}
|