diff options
author | Julien Gouesse <[email protected]> | 2015-11-19 20:45:53 +0100 |
---|---|---|
committer | Julien Gouesse <[email protected]> | 2015-11-19 20:45:53 +0100 |
commit | a18c3b0789bfc24b49dbaf41c2390159bc683afc (patch) | |
tree | b5236ff2570178de356eab569225108948eb4d30 /src/javax/media/j3d/J3DGraphics2DImpl.java | |
parent | 264608060948a634b53a13ee96ed07527eb07340 (diff) | |
parent | 7a2e20caac9db6f789a7b3fab344b9758af45335 (diff) |
Gets Harvey's changes
Diffstat (limited to 'src/javax/media/j3d/J3DGraphics2DImpl.java')
-rw-r--r-- | src/javax/media/j3d/J3DGraphics2DImpl.java | 1214 |
1 files changed, 1214 insertions, 0 deletions
diff --git a/src/javax/media/j3d/J3DGraphics2DImpl.java b/src/javax/media/j3d/J3DGraphics2DImpl.java new file mode 100644 index 0000000..0d55383 --- /dev/null +++ b/src/javax/media/j3d/J3DGraphics2DImpl.java @@ -0,0 +1,1214 @@ +/* + * 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; + } + } +} |