![JAR search and dependency download from the Maven repository](/logo.png)
javax.media.j3d.J3DGraphics2DImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of j3dcore Show documentation
Show all versions of j3dcore Show documentation
3D Graphics API for the Java Platform
/*
* Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
package javax.media.j3d;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.Paint;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.RenderingHints.Key;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ColorModel;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.awt.image.ImageObserver;
import java.awt.image.RenderedImage;
import java.awt.image.WritableRaster;
import java.awt.image.renderable.RenderableImage;
import java.text.AttributedCharacterIterator;
import java.util.Map;
/**
* Implementation class for J3DGraphics2D
*/
final class J3DGraphics2DImpl extends J3DGraphics2D {
private boolean hasBeenDisposed = false;
private Graphics2D offScreenGraphics2D;
private BufferedImage g3dImage = null;
private byte[] data = null;
private boolean isFlushed = true;
private Canvas3D canvas3d;
private int width, height;
private int texWidth, texHeight;
private int xmin, ymin, xmax, ymax;
private Object extentLock = new Object();
private boolean abgr;
private boolean initTexMap = false;
private boolean strokeSet=false;
private Point2D.Float ptSrc = new Point2D.Float();
private Point2D.Float ptDst1 = new Point2D.Float();
private Point2D.Float ptDst2 = new Point2D.Float();
private Color xOrModeColor = null;
private volatile boolean initCtx = false;
private volatile boolean threadWaiting = false;
static final Color blackTransparent = new Color(0,0,0,0);
int objectId = -1;
// Package scope contructor
J3DGraphics2DImpl(Canvas3D c) {
canvas3d = c;
synchronized (VirtualUniverse.mc.contextCreationLock) {
if (c.ctx == null) {
// create a dummy bufferImage
width = 1;
height = 1;
g3dImage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
offScreenGraphics2D = g3dImage.createGraphics();
} else {
init();
}
}
}
// This is invoke from Renderer callback when the first
// time createContext() finish which set
// canvas3d.extensionSupported correctly.
void init() {
// if ABGR extension is supported, we want to use
// TYPE_4BYTE_ABGR to make a fast copy
if (!initCtx) {
abgr = ((canvas3d.extensionsSupported & Canvas3D.EXT_ABGR) != 0);
width = canvas3d.getWidth();
height = canvas3d.getHeight();
initTexMap = false;
if (width <= 0) {
width = 1;
}
if (height <= 0) {
height = 1;
}
synchronized (extentLock) {
xmax = width;
ymax = height;
xmin = 0;
ymin = 0;
}
g3dImage = new BufferedImage(width, height,
(abgr ? BufferedImage.TYPE_4BYTE_ABGR:
BufferedImage.TYPE_INT_ARGB));
offScreenGraphics2D = g3dImage.createGraphics();
clearOffScreen();
if (!abgr) {
data = new byte[width*height*4];
}
// should be the last flag to set
initCtx = true;
}
}
/**
* Flushes all previously executed rendering operations to the
* drawing buffer for this 2D graphics object.
*
* @param wait flag indicating whether or not to wait for the
* rendering to be complete before returning from this call.
*/
@Override
public void flush(boolean waiting) {
if (hasBeenDisposed) {
throw new IllegalStateException(J3dI18N.getString("J3DGraphics2D0"));
}
if (!isFlushed) {
// Composite g3dImage into Canvas3D
if (Thread.currentThread() == canvas3d.screen.renderer) {
if (!initCtx) {
return;
}
doFlush();
} else {
if (!initCtx) {
if (waiting &&
(canvas3d.pendingView != null) &&
canvas3d.pendingView.activeStatus) {
// wait until Renderer init() this context
while (!initCtx) {
MasterControl.threadYield();
}
} else {
return;
}
}
// Behavior Scheduler or other threads
// XXXX: may not be legal for behaviorScheduler
// May cause deadlock if it is in behaviorScheduler
// and we wait for Renderer to finish
boolean renderRun = (Thread.currentThread() !=
canvas3d.view.universe.behaviorScheduler);
// This must put before sendRenderMessage()
threadWaiting = true;
sendRenderMessage(renderRun, GraphicsContext3D.FLUSH2D, null,
null, null);
if (waiting) {
// It is possible that thread got notify BEFORE
// the following runMonitor invoke.
runMonitor(J3dThread.WAIT);
}
}
isFlushed = true;
}
}
// copy the data into a byte buffer that will be passed to opengl
void doFlush() {
assert !hasBeenDisposed;
// clip to offscreen buffer size
if (canvas3d.ctx == null) {
canvas3d.getGraphicsContext3D().doClear();
}
synchronized (extentLock) {
if (xmin < 0) {
xmin = 0;
}
if (xmax > width) {
xmax = width;
}
if (ymin < 0) {
ymin = 0;
}
if (ymax > height) {
ymax = height;
}
if ((xmax - xmin > 0) &&
(ymax - ymin > 0)) {
if (abgr) {
data = ((DataBufferByte)g3dImage.getRaster().getDataBuffer()).getData();
} else {
copyImage(g3dImage, data, width, height, xmin, ymin, xmax, ymax);
}
copyDataToCanvas(0, 0, xmin, ymin, xmax, ymax, width, height);
} else {
runMonitor(J3dThread.NOTIFY);
}
// this define an empty region
xmax = 0;
ymax = 0;
xmin = width;
ymin = height;
}
}
// borrowed from ImageComponentRetained since ImageComponent2D
// seems to do stuff we don't need to
final void copyImage(BufferedImage bi, byte[] image,
int width, int height,
int x1, int y1, int x2, int y2) {
assert !hasBeenDisposed;
int biType = bi.getType();
int w, h, i, j;
int row, rowBegin, rowInc, dstBegin;
dstBegin = 0;
rowInc = 1;
rowBegin = 0;
// convert format to RGBA for underlying OGL use
if ((biType == BufferedImage.TYPE_INT_ARGB) ||
(biType == BufferedImage.TYPE_INT_RGB)) {
// optimized cases
rowBegin = y1;
int colBegin = x1;
int[] intData =
((DataBufferInt)bi.getRaster().getDataBuffer()).getData();
int rowOffset = rowInc * width;
int intPixel;
rowBegin = rowBegin*width + colBegin;
dstBegin = rowBegin*4;
if (biType == BufferedImage.TYPE_INT_ARGB) {
for (h = y1; h < y2; h++) {
i = rowBegin;
j = dstBegin;
for (w = x1; w < x2; w++, i++) {
intPixel = intData[i];
image[j++] = (byte)((intPixel >> 16) & 0xff);
image[j++] = (byte)((intPixel >> 8) & 0xff);
image[j++] = (byte)(intPixel & 0xff);
image[j++] = (byte)((intPixel >> 24) & 0xff);
}
rowBegin += rowOffset;
dstBegin += (rowOffset*4);
}
} else {
for (h = y1; h < y2; h++) {
i = rowBegin;
j = dstBegin;
for (w = x1; w < x2; w++, i++) {
intPixel = intData[i];
image[j++] = (byte)((intPixel >> 16) & 0xff);
image[j++] = (byte)((intPixel >> 8) & 0xff);
image[j++] = (byte)(intPixel & 0xff);
image[j++] = (byte)255;
}
rowBegin += rowOffset;
dstBegin += (rowOffset*4);
}
}
} else {
// non-optimized cases
WritableRaster ras = bi.getRaster();
ColorModel cm = bi.getColorModel();
Object pixel = ImageComponentRetained.getDataElementBuffer(ras);
j = (y1*width + x1)*4;
for (h = y1; h < y2; h++) {
i = j;
for (w = x1; w < x2; w++) {
ras.getDataElements(w, h, pixel);
image[j++] = (byte)cm.getRed(pixel);
image[j++] = (byte)cm.getGreen(pixel);
image[j++] = (byte)cm.getBlue(pixel);
image[j++] = (byte)cm.getAlpha(pixel);
}
j = i+ width*4;
}
}
}
void sendRenderMessage(boolean renderRun, int command,
Object arg1, Object arg2, Object arg3) {
// send a message to the request renderer
J3dMessage renderMessage = new J3dMessage();
renderMessage.threads = J3dThread.RENDER_THREAD;
renderMessage.type = J3dMessage.RENDER_IMMEDIATE;
renderMessage.universe = null;
renderMessage.view = null;
renderMessage.args[0] = canvas3d;
renderMessage.args[1] = new Integer(command);
renderMessage.args[2] = arg1;
renderMessage.args[3] = arg2;
renderMessage.args[4] = arg3;
while (!canvas3d.view.inRenderThreadData) {
// wait until the renderer thread data in added in
// MC:RenderThreadData array ready to receive message
MasterControl.threadYield();
}
canvas3d.screen.renderer.rendererStructure.addMessage(renderMessage);
if (renderRun) {
// notify mc that there is work to do
VirtualUniverse.mc.sendRunMessage(canvas3d.view, J3dThread.RENDER_THREAD);
} else {
// notify mc that there is work for the request renderer
VirtualUniverse.mc.setWorkForRequestRenderer();
}
}
final void validate() {
validate(0, 0, width, height);
}
void validate(float x1, float y1, float x2, float y2,
AffineTransform xform) {
float t;
if (xform == null) {
validate(x1, y1, x2, y2);
} else {
ptSrc.x = x1;
ptSrc.y = y1;
xform.transform(ptSrc, ptDst1);
ptSrc.x = x2;
ptSrc.y = y2;
xform.transform(ptSrc, ptDst2);
if (ptDst1.x > ptDst2.x) {
t = ptDst1.x;
ptDst1.x = ptDst2.x;
ptDst2.x = t;
}
if (ptDst1.y > ptDst2.y) {
t = ptDst1.y;
ptDst1.y = ptDst2.y;
ptDst2.y = t;
}
// take care of numerical error by adding 1
validate(ptDst1.x-1, ptDst1.y-1, ptDst2.x+1, ptDst2.y+1);
}
}
void validate(float x1, float y1, float x2, float y2) {
boolean doResize = false;
isFlushed = false;
synchronized(canvas3d) {
if (initCtx && canvas3d.resizeGraphics2D) {
doResize = true;
canvas3d.resizeGraphics2D = false;
}
}
if (doResize) {
synchronized (VirtualUniverse.mc.contextCreationLock) {
Graphics2D oldOffScreenGraphics2D = offScreenGraphics2D;
initCtx = false;
init();
copyGraphics2D(oldOffScreenGraphics2D);
}
} else {
AffineTransform tr = getTransform();
ptSrc.x = x1;
ptSrc.y = y1;
tr.transform(ptSrc, ptDst1);
ptSrc.x = x2;
ptSrc.y = y2;
tr.transform(ptSrc, ptDst2);
synchronized (extentLock) {
if (ptDst1.x < xmin) {
xmin = (int) ptDst1.x;
}
if (ptDst1.y < ymin) {
ymin = (int) ptDst1.y;
}
if (ptDst2.x > xmax) {
xmax = (int) ptDst2.x;
}
if (ptDst2.y > ymax) {
ymax = (int) ptDst2.y;
}
}
}
}
void copyGraphics2D(Graphics2D oldg) {
// restore the original setting of Graphics2D when resizing the windows
setColor(oldg.getColor());
setFont(oldg.getFont());
setClip(oldg.getClip());
setComposite(oldg.getComposite());
setTransform(oldg.getTransform());
setPaint(oldg.getPaint());
setStroke(oldg.getStroke());
if (xOrModeColor != null) {
setXORMode(xOrModeColor);
}
}
// Implementation of Graphics2D methods
@Override
public final void clip(Shape s) {
offScreenGraphics2D.clip(s);
}
@Override
public FontMetrics getFontMetrics() {
return offScreenGraphics2D.getFontMetrics();
}
@Override
public Rectangle getClipBounds(Rectangle r) {
return offScreenGraphics2D.getClipBounds(r);
}
@Override
public Rectangle getClipRect() {
return offScreenGraphics2D.getClipRect();
}
@Override
public String toString() {
return offScreenGraphics2D.toString();
}
@Override
public final AffineTransform getTransform() {
return offScreenGraphics2D.getTransform();
}
@Override
public final Color getColor() {
return offScreenGraphics2D.getColor();
}
@Override
public final Composite getComposite() {
return offScreenGraphics2D.getComposite();
}
@Override
public final Font getFont() {
return offScreenGraphics2D.getFont();
}
@Override
public final FontMetrics getFontMetrics(Font f) {
return offScreenGraphics2D.getFontMetrics(f);
}
@Override
public final FontRenderContext getFontRenderContext() {
return offScreenGraphics2D.getFontRenderContext();
}
@Override
public final GraphicsConfiguration getDeviceConfiguration() {
return offScreenGraphics2D.getDeviceConfiguration();
}
@Override
public final Object getRenderingHint(Key hintKey) {
return offScreenGraphics2D.getRenderingHint(hintKey);
}
@Override
public final Paint getPaint() {
return offScreenGraphics2D.getPaint();
}
@Override
public final Rectangle getClipBounds() {
return offScreenGraphics2D.getClipBounds();
}
@Override
public final RenderingHints getRenderingHints() {
return offScreenGraphics2D.getRenderingHints();
}
@Override
public final Shape getClip() {
return offScreenGraphics2D.getClip();
}
@Override
public final Stroke getStroke() {
return offScreenGraphics2D.getStroke();
}
@Override
public final boolean drawImage(Image img, AffineTransform xform,
ImageObserver obs) {
validate(0, 0, img.getWidth(obs), img.getHeight(obs), xform);
return offScreenGraphics2D.drawImage(img, xform, obs);
}
@Override
public final void drawImage(BufferedImage img, BufferedImageOp op,
int x, int y) {
if (op != null) {
img = op.filter(img, null);
}
validate(x, y, x+img.getWidth(), y+img.getHeight());
offScreenGraphics2D.drawImage(img, null, x, y);
}
@Override
public final boolean drawImage(Image img,
int x, int y,
ImageObserver observer) {
validate(x, y,
x + img.getWidth(observer),
y + img.getWidth(observer));
return offScreenGraphics2D.drawImage(img, x, y, observer);
}
@Override
public final boolean drawImage(Image img, int x, int y,
int width, int height,
ImageObserver observer) {
validate(x, y, x+width, y+height);
return offScreenGraphics2D.drawImage(img, x, y, width, height,
observer);
}
@Override
public final boolean drawImage(Image img, int x, int y,
int width, int height,
Color bgcolor,
ImageObserver observer) {
validate(x, y, x+width, y+height);
return offScreenGraphics2D.drawImage(img, x, y, width, height, bgcolor,
observer);
}
public final void drawImage(BufferedImage img,
int dx1, int dy1, int dx2, int dy2,
int sx1, int sy1, int sx2, int sy2,
ImageObserver observer) {
validate(dx1, dy1, dx2, dy2);
offScreenGraphics2D.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1,
sx2, sy2, observer);
}
@Override
public final boolean drawImage(Image img,
int dx1, int dy1, int dx2, int dy2,
int sx1, int sy1, int sx2, int sy2,
ImageObserver observer) {
validate(dx1, dy1, dx2, dy2);
return offScreenGraphics2D.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1,
sx2, sy2, observer);
}
@Override
public final boolean drawImage(Image img,
int dx1, int dy1, int dx2, int dy2,
int sx1, int sy1, int sx2, int sy2,
Color bgcolor,
ImageObserver observer) {
validate(dx1, dy1, dx2, dy2);
return offScreenGraphics2D.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1,
sx2, sy2, bgcolor, observer);
}
@Override
public final boolean drawImage(Image img, int x, int y,
Color bgcolor,
ImageObserver observer) {
validate(x, y, x+img.getWidth(observer), y+img.getHeight(observer));
return offScreenGraphics2D.drawImage(img, x, y, bgcolor, observer);
}
@Override
public final boolean hit(Rectangle rect, Shape s, boolean onStroke) {
return offScreenGraphics2D.hit(rect, s, onStroke);
}
@Override
public final void addRenderingHints(Map hints) {
offScreenGraphics2D.addRenderingHints(hints);
}
@Override
public final void clipRect(int x, int y, int width, int height) {
offScreenGraphics2D.clipRect(x, y, width, height);
}
@Override
public final void copyArea(int x, int y, int width, int height,
int dx, int dy) {
validate(x+dx, y+dy, x+dx+width, y+dy+height);
offScreenGraphics2D.copyArea(x, y, width, height, dx, dy);
}
@Override
public final void draw(Shape s) {
Rectangle rect = s.getBounds();
validate(rect.x, rect.y,
rect.x + rect.width,
rect.y + rect.height);
offScreenGraphics2D.draw(s);
}
@Override
public final void drawArc(int x, int y, int width, int height,
int startAngle, int arcAngle) {
// XXXX: call validate with bounding box of primitive
validate();
offScreenGraphics2D.drawArc(x, y, width, height, startAngle, arcAngle);
}
@Override
public final void drawGlyphVector(GlyphVector g, float x, float y) {
// XXXX: call validate with bounding box of primitive
validate();
offScreenGraphics2D.drawGlyphVector(g, x, y);
}
@Override
public final void drawLine(int x1, int y1, int x2, int y2) {
int minx, miny, maxx, maxy;
if (!strokeSet) {
if (x1 > x2) {
minx = x2;
maxx = x1;
} else {
minx = x1;
maxx = x2;
}
if (y1 > y2) {
miny = y2;
maxy = y1;
} else {
miny = y1;
maxy = y2;
}
validate(minx, miny, maxx, maxy);
} else {
// XXXX: call validate with bounding box of primitive
// XXXX: Need to consider Stroke width
validate();
}
offScreenGraphics2D.drawLine(x1, y1, x2, y2);
}
@Override
public final void drawOval(int x, int y, int width, int height) {
// XXXX: call validate with bounding box of primitive
validate();
offScreenGraphics2D.drawOval(x, y, width, height);
}
@Override
public final void drawPolygon(int xPoints[], int yPoints[],
int nPoints) {
// XXXX: call validate with bounding box of primitive
validate();
offScreenGraphics2D.drawPolygon(xPoints, yPoints, nPoints);
}
@Override
public final void drawPolyline(int xPoints[], int yPoints[],
int nPoints) {
// XXXX: call validate with bounding box of primitive
validate();
offScreenGraphics2D.drawPolyline(xPoints, yPoints, nPoints);
}
@Override
public final void drawRenderableImage(RenderableImage img,
AffineTransform xform) {
validate(0, 0, img.getWidth(), img.getHeight(), xform);
offScreenGraphics2D.drawRenderableImage(img, xform);
}
@Override
public final void drawRenderedImage(RenderedImage img,
AffineTransform xform) {
validate(0, 0, img.getWidth(), img.getHeight(), xform);
offScreenGraphics2D.drawRenderedImage(img, xform);
}
@Override
public final void drawRoundRect(int x, int y, int width, int height,
int arcWidth, int arcHeight) {
// XXXX: call validate with bounding box of primitive
validate();
offScreenGraphics2D.drawRoundRect(x, y, width, height, arcWidth,
arcHeight);
}
@Override
public final void drawString(AttributedCharacterIterator iterator,
int x, int y) {
// XXXX: call validate with bounding box of primitive
validate();
offScreenGraphics2D.drawString(iterator, x, y);
}
@Override
public final void drawString(AttributedCharacterIterator iterator,
float x, float y) {
// XXXX: call validate with bounding box of primitive
validate();
offScreenGraphics2D.drawString(iterator, x, y);
}
@Override
public final void drawString(String s, float x, float y) {
TextLayout layout = new TextLayout(s, getFont(),
getFontRenderContext());
Rectangle2D bounds = layout.getBounds();
float x1 = (float) bounds.getX();
float y1 = (float) bounds.getY();
validate(x1+x, y1+y,
x1 + x + (float) bounds.getWidth(),
y1 + y + (float) bounds.getHeight());
offScreenGraphics2D.drawString(s, x, y);
}
@Override
public final void drawString(String s, int x, int y) {
drawString(s, (float) x, (float) y);
}
@Override
public final void fill(Shape s) {
Rectangle rect = s.getBounds();
validate(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height);
offScreenGraphics2D.fill(s);
}
@Override
public final void fillArc(int x, int y, int width, int height,
int startAngle, int arcAngle) {
// XXXX: call validate with bounding box of primitive
validate();
offScreenGraphics2D.fillArc(x, y, width, height, startAngle, arcAngle);
}
@Override
public final void fillOval(int x, int y, int width, int height) {
// XXXX: call validate with bounding box of primitive
validate();
offScreenGraphics2D.fillOval(x, y, width, height);
}
@Override
public final void fillRoundRect(int x, int y, int width, int height,
int arcWidth, int arcHeight) {
// XXXX: call validate with bounding box of primitive
validate();
offScreenGraphics2D.fillRoundRect(x, y, width, height, arcWidth,
arcHeight);
}
@Override
public final void rotate(double theta) {
offScreenGraphics2D.rotate(theta);
}
@Override
public final void rotate(double theta, double x, double y) {
offScreenGraphics2D.rotate(theta, x, y);
}
@Override
public final void scale(double sx, double sy) {
offScreenGraphics2D.scale(sx, sy);
}
@Override
public final void setClip(Shape clip) {
offScreenGraphics2D.setClip(clip);
}
@Override
public final void setClip(int x, int y, int width, int height) {
offScreenGraphics2D.setClip(x, y, width, height);
}
@Override
public final void setColor(Color c) {
offScreenGraphics2D.setColor(c);
}
@Override
public final void setComposite(Composite comp) {
offScreenGraphics2D.setComposite(comp);
}
@Override
public final void setFont(Font font) {
offScreenGraphics2D.setFont(font);
}
@Override
public final void setPaint( Paint paint ) {
offScreenGraphics2D.setPaint(paint);
}
@Override
public final void setPaintMode() {
xOrModeColor = null;
offScreenGraphics2D.setPaintMode();
}
@Override
public final void setRenderingHint(Key hintKey, Object hintValue) {
offScreenGraphics2D.setRenderingHint(hintKey, hintValue);
}
@Override
public final void setRenderingHints(Map hints) {
offScreenGraphics2D.setRenderingHints(hints);
}
@Override
public final void setStroke(Stroke s) {
strokeSet = (s != null);
offScreenGraphics2D.setStroke(s);
}
@Override
public final void setTransform(AffineTransform Tx) {
offScreenGraphics2D.setTransform(Tx);
}
@Override
public final void setXORMode(Color c1) {
xOrModeColor = c1;
offScreenGraphics2D.setXORMode(c1);
}
@Override
public final void shear(double shx, double shy) {
offScreenGraphics2D.shear(shx, shy);
}
@Override
public final void transform(AffineTransform Tx) {
offScreenGraphics2D.transform(Tx);
}
@Override
public final void translate(double tx, double ty) {
offScreenGraphics2D.translate(tx, ty);
}
@Override
public final void translate(int x, int y) {
offScreenGraphics2D.translate(x, y);
}
@Override
public boolean hitClip(int x, int y, int width, int height) {
return offScreenGraphics2D.hitClip(x, y, width, height);
}
@Override
public void draw3DRect(int x, int y, int width, int height,
boolean raised) {
// XXXX: call validate with bounding box of primitive
validate();
offScreenGraphics2D.draw3DRect(x, y, width, height, raised);
}
@Override
public void drawBytes(byte data[], int offset, int length, int x, int y) {
// XXXX: call validate with bounding box of primitive
validate();
offScreenGraphics2D.drawBytes(data, offset, length, x, y);
}
@Override
public void drawChars(char data[], int offset, int length, int x, int y) {
// XXXX: call validate with bounding box of primitive
validate();
offScreenGraphics2D.drawChars(data, offset, length, x, y);
}
@Override
public void drawPolygon(Polygon p) {
// XXXX: call validate with bounding box of primitive
validate();
offScreenGraphics2D.drawPolygon(p);
}
@Override
public void drawRect(int x, int y, int width, int height) {
// XXXX: call validate with bounding box of primitive
// XXXX: need to consider Stroke width
validate();
offScreenGraphics2D.drawRect(x, y, width, height);
}
@Override
public void fill3DRect(int x, int y, int width, int height,
boolean raised) {
// XXXX: call validate with bounding box of primitive
// XXXX: need to consider Stroke width
validate();
offScreenGraphics2D.fill3DRect(x, y, width, height, raised);
}
@Override
public void fillPolygon(Polygon p) {
// XXXX: call validate with bounding box of primitive
validate();
offScreenGraphics2D.fillPolygon(p);
}
@Override
public final void fillPolygon(int xPoints[], int yPoints[],
int nPoints) {
// XXXX: call validate with bounding box of primitive
validate();
offScreenGraphics2D.fillPolygon(xPoints, yPoints, nPoints);
}
@Override
public final void fillRect(int x, int y, int width, int height) {
// XXXX: call validate with bounding box of primitive
validate();
offScreenGraphics2D.fillRect(x, y, width, height);
}
// Issue 121 - release all resources, mark as disposed
@Override
public void dispose() {
// Issue 583 - do nothing if graphics has already been disposed
if (hasBeenDisposed) {
return;
}
if (Thread.currentThread() == canvas3d.screen.renderer) {
doDispose();
} else {
// Behavior Scheduler or other threads
// XXXX: may not be legal for behaviorScheduler
// May cause deadlock if it is in behaviorScheduler
// and we wait for Renderer to finish
boolean renderRun = (Thread.currentThread() !=
canvas3d.view.universe.behaviorScheduler);
sendRenderMessage(renderRun, GraphicsContext3D.DISPOSE2D,
null, null, null);
}
}
public void doDispose() {
if (hasBeenDisposed) {
return;
}
if (objectId != -1) {
Canvas3D.freeTexture(canvas3d.ctx, objectId);
objectId = -1;
}
// Dispose of the underlying Graphics2D
offScreenGraphics2D.dispose();
// Mark as disposed
hasBeenDisposed = true;
// Issue 583 - set graphics2D field to null so it will get recreated
canvas3d.graphics2D = null;
}
@Override
public void drawAndFlushImage(BufferedImage img, int x, int y,
ImageObserver observer) {
if (hasBeenDisposed) {
throw new IllegalStateException(J3dI18N.getString("J3DGraphics2D0"));
}
if (!(initCtx && abgr &&
(img.getType() == BufferedImage.TYPE_4BYTE_ABGR))) {
drawImage(img, x, y, observer);
flush(false);
return;
}
if (Thread.currentThread() == canvas3d.screen.renderer) {
doDrawAndFlushImage(img, x, y, observer);
} else {
// Behavior Scheduler or other threads
// XXXX: may not be legal for behaviorScheduler
// May cause deadlock if it is in behaviorScheduler
// and we wait for Renderer to finish
boolean renderRun = (Thread.currentThread() !=
canvas3d.view.universe.behaviorScheduler);
sendRenderMessage(renderRun, GraphicsContext3D.DRAWANDFLUSH2D,
img, new Point(x, y), observer);
}
}
void doDrawAndFlushImage(BufferedImage img, int x, int y,
ImageObserver observer) {
assert !hasBeenDisposed;
int imgWidth = img.getWidth(observer);
int imgHeight = img.getHeight(observer);
int px, py, x1, y1, x2, y2;
if (canvas3d.ctx == null) {
canvas3d.getGraphicsContext3D().doClear();
}
// format needs to be 4BYTE_ABGR and abgr needs to be supported
// also must be in canvas callback
data = ((DataBufferByte)img.getRaster().getDataBuffer()).getData();
// Transform the affine transform,
// note we do not handle scale/rotate etc.
AffineTransform tr = getTransform();
ptSrc.x = x;
ptSrc.y = y;
tr.transform(ptSrc, ptDst1);
px = (int) ptDst1.x;
py = (int) ptDst1.y;
// clip to offscreen buffer size
if (px + imgWidth > width) {
x2 = width - px;
} else {
x2 = imgWidth;
}
if (px < 0) {
x1 = -px;
px = 0;
} else {
x1 = 0;
}
if (py + imgHeight > height) {
y2 = height - py;
} else {
y2 = imgHeight;
}
if (py < 0) {
y1 = -py;
py = 0;
} else {
y1 = 0;
}
if ((y2 - y1 > 0) && (x2 - x1 > 0)) {
copyDataToCanvas(px, py, x1,y1, x2, y2,imgWidth, imgHeight);
}
}
void copyDataToCanvas(int px, int py, int x1, int y1,
int x2, int y2, int w, int h) {
try {
if (!canvas3d.drawingSurfaceObject.renderLock()) {
return;
}
if (!initTexMap) {
if (objectId == -1) {
objectId = Canvas3D.generateTexID(canvas3d.ctx);
}
texWidth = getGreaterPowerOf2(w);
texHeight = getGreaterPowerOf2(h);
// Canvas got resize, need to init texture map again
// in Renderer thread
if (!canvas3d.initTexturemapping(canvas3d.ctx,
texWidth, texHeight,
objectId)) {
// Fail to get the texture surface, most likely
// there is not enough texture memory
initTexMap = false;
Canvas3D.freeTexture(canvas3d.ctx, objectId);
objectId = -1;
// TODO : Need to find a better way to report no resource problem --- Chien.
System.err.println("J3DGraphics2DImpl.copyDataToCanvas() : Fail to get texture resources ...");
} else {
initTexMap = true;
}
}
if (initTexMap) {
canvas3d.texturemapping(canvas3d.ctx, px, py,
x1, y1, x2, y2,
texWidth, texHeight, w,
(abgr ? ImageComponentRetained.TYPE_BYTE_ABGR:
ImageComponentRetained.TYPE_BYTE_RGBA),
objectId, data, width, height);
}
canvas3d.drawingSurfaceObject.unLock();
} catch (NullPointerException ne) {
canvas3d.drawingSurfaceObject.unLock();
throw ne;
}
clearOffScreen();
runMonitor(J3dThread.NOTIFY);
}
void clearOffScreen() {
Composite comp = offScreenGraphics2D.getComposite();
Color c = offScreenGraphics2D.getColor();
offScreenGraphics2D.setComposite(AlphaComposite.Src);
offScreenGraphics2D.setColor(blackTransparent);
offScreenGraphics2D.fillRect(xmin, ymin, (xmax-xmin), (ymax-ymin));
offScreenGraphics2D.setComposite(comp);
offScreenGraphics2D.setColor(c);
}
/**
* Return an integer of power 2 greater than x
*/
static int getGreaterPowerOf2(int x) {
int i = -1;
if (x >= 0) {
for (i = 1; i < x; i <<= 1);
}
return i;
}
/**
* MC may not scheduler Renderer thread or Renderer thread
* may not process message FLUSH. This will hang user
* thread.
*/
synchronized void runMonitor(int action) {
if (action == J3dThread.WAIT) {
// Issue 279 - loop until ready
while (threadWaiting) {
try {
wait();
} catch (InterruptedException e){}
}
} else if (action == J3dThread.NOTIFY) {
notify();
threadWaiting = false;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy