0001: /*
0002: * $RCSfile: J3DGraphics2DImpl.java,v $
0003: *
0004: * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved.
0005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0006: *
0007: * This code is free software; you can redistribute it and/or modify it
0008: * under the terms of the GNU General Public License version 2 only, as
0009: * published by the Free Software Foundation. Sun designates this
0010: * particular file as subject to the "Classpath" exception as provided
0011: * by Sun in the LICENSE file that accompanied this code.
0012: *
0013: * This code is distributed in the hope that it will be useful, but WITHOUT
0014: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0015: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0016: * version 2 for more details (a copy is included in the LICENSE file that
0017: * accompanied this code).
0018: *
0019: * You should have received a copy of the GNU General Public License version
0020: * 2 along with this work; if not, write to the Free Software Foundation,
0021: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0022: *
0023: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0024: * CA 95054 USA or visit www.sun.com if you need additional information or
0025: * have any questions.
0026: *
0027: * $Revision: 1.7 $
0028: * $Date: 2008/02/28 20:17:25 $
0029: * $State: Exp $
0030: */
0031:
0032: package javax.media.j3d;
0033:
0034: import java.io.*;
0035: import java.util.*;
0036: import java.awt.*;
0037: import java.awt.event.*;
0038: import java.text.AttributedCharacterIterator;
0039: import java.awt.RenderingHints.Key;
0040: import java.awt.geom.*;
0041: import java.awt.image.*;
0042: import java.awt.image.renderable.RenderableImage;
0043: import java.awt.font.*;
0044:
0045: /**
0046: * Implementation class for J3DGraphics2D
0047: */
0048:
0049: final class J3DGraphics2DImpl extends J3DGraphics2D {
0050: private boolean hasBeenDisposed = false;
0051: private Graphics2D offScreenGraphics2D;
0052: private BufferedImage g3dImage = null;
0053: private byte[] data = null;
0054: private boolean isFlushed = true;
0055: private Canvas3D canvas3d;
0056: private int width, height;
0057: private int texWidth, texHeight;
0058: private int xmin, ymin, xmax, ymax;
0059: private Object extentLock = new Object();
0060: private boolean abgr;
0061: private boolean initTexMap = false;
0062: private boolean strokeSet = false;
0063: private Point2D.Float ptSrc = new Point2D.Float();
0064: private Point2D.Float ptDst1 = new Point2D.Float();
0065: private Point2D.Float ptDst2 = new Point2D.Float();
0066: private Color xOrModeColor = null;
0067: private volatile boolean initCtx = false;
0068: private volatile boolean threadWaiting = false;
0069: static final Color blackTransparent = new Color(0, 0, 0, 0);
0070: int objectId = -1;
0071:
0072: // Package scope contructor
0073: J3DGraphics2DImpl(Canvas3D c) {
0074: canvas3d = c;
0075:
0076: synchronized (VirtualUniverse.mc.contextCreationLock) {
0077: if (c.ctx == null) {
0078: // create a dummy bufferImage
0079: width = 1;
0080: height = 1;
0081: g3dImage = new BufferedImage(width, height,
0082: BufferedImage.TYPE_INT_ARGB);
0083: offScreenGraphics2D = g3dImage.createGraphics();
0084: } else {
0085: init();
0086: }
0087: }
0088:
0089: }
0090:
0091: // This is invoke from Renderer callback when the first
0092: // time createContext() finish which set
0093: // canvas3d.extensionSupported correctly.
0094: void init() {
0095: // if ABGR extension is supported, we want to use
0096: // TYPE_4BYTE_ABGR to make a fast copy
0097: if (!initCtx) {
0098: abgr = ((canvas3d.extensionsSupported & Canvas3D.EXT_ABGR) != 0);
0099:
0100: width = canvas3d.getWidth();
0101: height = canvas3d.getHeight();
0102: initTexMap = false;
0103:
0104: if (width <= 0) {
0105: width = 1;
0106: }
0107: if (height <= 0) {
0108: height = 1;
0109: }
0110:
0111: synchronized (extentLock) {
0112: xmax = width;
0113: ymax = height;
0114: xmin = 0;
0115: ymin = 0;
0116: }
0117: g3dImage = new BufferedImage(width, height,
0118: (abgr ? BufferedImage.TYPE_4BYTE_ABGR
0119: : BufferedImage.TYPE_INT_ARGB));
0120: offScreenGraphics2D = g3dImage.createGraphics();
0121: clearOffScreen();
0122: if (!abgr) {
0123: data = new byte[width * height * 4];
0124: }
0125:
0126: // should be the last flag to set
0127: initCtx = true;
0128: }
0129: }
0130:
0131: /**
0132: * Flushes all previously executed rendering operations to the
0133: * drawing buffer for this 2D graphics object.
0134: *
0135: * @param wait flag indicating whether or not to wait for the
0136: * rendering to be complete before returning from this call.
0137: */
0138: public void flush(boolean waiting) {
0139:
0140: if (hasBeenDisposed) {
0141: throw new IllegalStateException(J3dI18N
0142: .getString("J3DGraphics2D0"));
0143: }
0144:
0145: if (!isFlushed) {
0146: // Composite g3dImage into Canvas3D
0147: if (Thread.currentThread() == canvas3d.screen.renderer) {
0148: if (!initCtx) {
0149: return;
0150: }
0151: doFlush();
0152: } else {
0153: if (!initCtx) {
0154: if (waiting && (canvas3d.pendingView != null)
0155: && canvas3d.pendingView.activeStatus) {
0156: // wait until Renderer init() this context
0157:
0158: while (!initCtx) {
0159: MasterControl.threadYield();
0160: }
0161: } else {
0162: return;
0163: }
0164: }
0165: // Behavior Scheduler or other threads
0166: // XXXX: may not be legal for behaviorScheduler
0167: // May cause deadlock if it is in behaviorScheduler
0168: // and we wait for Renderer to finish
0169: boolean renderRun = (Thread.currentThread() != canvas3d.view.universe.behaviorScheduler);
0170: // This must put before sendRenderMessage()
0171: threadWaiting = true;
0172: sendRenderMessage(renderRun, GraphicsContext3D.FLUSH2D,
0173: null, null, null);
0174: if (waiting) {
0175: // It is possible that thread got notify BEFORE
0176: // the following runMonitor invoke.
0177: runMonitor(J3dThread.WAIT);
0178: }
0179: }
0180: isFlushed = true;
0181:
0182: }
0183: }
0184:
0185: // copy the data into a byte buffer that will be passed to opengl
0186: void doFlush() {
0187: assert !hasBeenDisposed;
0188:
0189: // clip to offscreen buffer size
0190: if (canvas3d.ctx == null) {
0191: canvas3d.getGraphicsContext3D().doClear();
0192: }
0193:
0194: synchronized (extentLock) {
0195: if (xmin < 0) {
0196: xmin = 0;
0197: }
0198: if (xmax > width) {
0199: xmax = width;
0200: }
0201: if (ymin < 0) {
0202: ymin = 0;
0203: }
0204: if (ymax > height) {
0205: ymax = height;
0206: }
0207:
0208: if ((xmax - xmin > 0) && (ymax - ymin > 0)) {
0209: if (abgr) {
0210: data = ((DataBufferByte) g3dImage.getRaster()
0211: .getDataBuffer()).getData();
0212: } else {
0213: copyImage(g3dImage, data, width, height, xmin,
0214: ymin, xmax, ymax);
0215: }
0216: copyDataToCanvas(0, 0, xmin, ymin, xmax, ymax, width,
0217: height);
0218: } else {
0219:
0220: runMonitor(J3dThread.NOTIFY);
0221: }
0222: // this define an empty region
0223: xmax = 0;
0224: ymax = 0;
0225: xmin = width;
0226: ymin = height;
0227: }
0228:
0229: }
0230:
0231: // borrowed from ImageComponentRetained since ImageComponent2D
0232: // seems to do stuff we don't need to
0233: final void copyImage(BufferedImage bi, byte[] image, int width,
0234: int height, int x1, int y1, int x2, int y2) {
0235:
0236: assert !hasBeenDisposed;
0237:
0238: int biType = bi.getType();
0239: int w, h, i, j;
0240: int row, rowBegin, rowInc, dstBegin;
0241:
0242: dstBegin = 0;
0243: rowInc = 1;
0244: rowBegin = 0;
0245:
0246: // convert format to RGBA for underlying OGL use
0247: if ((biType == BufferedImage.TYPE_INT_ARGB)
0248: || (biType == BufferedImage.TYPE_INT_RGB)) {
0249: // optimized cases
0250: rowBegin = y1;
0251:
0252: int colBegin = x1;
0253:
0254: int[] intData = ((DataBufferInt) bi.getRaster()
0255: .getDataBuffer()).getData();
0256: int rowOffset = rowInc * width;
0257: int intPixel;
0258:
0259: rowBegin = rowBegin * width + colBegin;
0260: dstBegin = rowBegin * 4;
0261:
0262: if (biType == BufferedImage.TYPE_INT_ARGB) {
0263: for (h = y1; h < y2; h++) {
0264: i = rowBegin;
0265: j = dstBegin;
0266: for (w = x1; w < x2; w++, i++) {
0267: intPixel = intData[i];
0268: image[j++] = (byte) ((intPixel >> 16) & 0xff);
0269: image[j++] = (byte) ((intPixel >> 8) & 0xff);
0270: image[j++] = (byte) (intPixel & 0xff);
0271: image[j++] = (byte) ((intPixel >> 24) & 0xff);
0272: }
0273: rowBegin += rowOffset;
0274: dstBegin += (rowOffset * 4);
0275: }
0276: } else {
0277: for (h = y1; h < y2; h++) {
0278: i = rowBegin;
0279: j = dstBegin;
0280: for (w = x1; w < x2; w++, i++) {
0281: intPixel = intData[i];
0282: image[j++] = (byte) ((intPixel >> 16) & 0xff);
0283: image[j++] = (byte) ((intPixel >> 8) & 0xff);
0284: image[j++] = (byte) (intPixel & 0xff);
0285: image[j++] = (byte) 255;
0286: }
0287: rowBegin += rowOffset;
0288: dstBegin += (rowOffset * 4);
0289: }
0290: }
0291: } else {
0292: // non-optimized cases
0293: WritableRaster ras = bi.getRaster();
0294: ColorModel cm = bi.getColorModel();
0295: Object pixel = ImageComponentRetained
0296: .getDataElementBuffer(ras);
0297:
0298: j = (y1 * width + x1) * 4;
0299: for (h = y1; h < y2; h++) {
0300: i = j;
0301: for (w = x1; w < x2; w++) {
0302: ras.getDataElements(w, h, pixel);
0303: image[j++] = (byte) cm.getRed(pixel);
0304: image[j++] = (byte) cm.getGreen(pixel);
0305: image[j++] = (byte) cm.getBlue(pixel);
0306: image[j++] = (byte) cm.getAlpha(pixel);
0307:
0308: }
0309: j = i + width * 4;
0310: }
0311: }
0312: }
0313:
0314: void sendRenderMessage(boolean renderRun, int command, Object arg1,
0315: Object arg2, Object arg3) {
0316: // send a message to the request renderer
0317: J3dMessage renderMessage = new J3dMessage();
0318: renderMessage.threads = J3dThread.RENDER_THREAD;
0319: renderMessage.type = J3dMessage.RENDER_IMMEDIATE;
0320: renderMessage.universe = null;
0321: renderMessage.view = null;
0322: renderMessage.args[0] = canvas3d;
0323: renderMessage.args[1] = new Integer(command);
0324: renderMessage.args[2] = arg1;
0325: renderMessage.args[3] = arg2;
0326: renderMessage.args[4] = arg3;
0327:
0328: while (!canvas3d.view.inRenderThreadData) {
0329: // wait until the renderer thread data in added in
0330: // MC:RenderThreadData array ready to receive message
0331: MasterControl.threadYield();
0332: }
0333:
0334: canvas3d.screen.renderer.rendererStructure
0335: .addMessage(renderMessage);
0336:
0337: if (renderRun) {
0338: // notify mc that there is work to do
0339: VirtualUniverse.mc.sendRunMessage(canvas3d.view,
0340: J3dThread.RENDER_THREAD);
0341: } else {
0342: // notify mc that there is work for the request renderer
0343: VirtualUniverse.mc.setWorkForRequestRenderer();
0344: }
0345: }
0346:
0347: final void validate() {
0348: validate(0, 0, width, height);
0349: }
0350:
0351: void validate(float x1, float y1, float x2, float y2,
0352: AffineTransform xform) {
0353: float t;
0354:
0355: if (xform == null) {
0356: validate(x1, y1, x2, y2);
0357: } else {
0358: ptSrc.x = x1;
0359: ptSrc.y = y1;
0360: xform.transform(ptSrc, ptDst1);
0361: ptSrc.x = x2;
0362: ptSrc.y = y2;
0363: xform.transform(ptSrc, ptDst2);
0364:
0365: if (ptDst1.x > ptDst2.x) {
0366: t = ptDst1.x;
0367: ptDst1.x = ptDst2.x;
0368: ptDst2.x = t;
0369: }
0370: if (ptDst1.y > ptDst2.y) {
0371: t = ptDst1.y;
0372: ptDst1.y = ptDst2.y;
0373: ptDst2.y = t;
0374: }
0375: // take care of numerical error by adding 1
0376: validate(ptDst1.x - 1, ptDst1.y - 1, ptDst2.x + 1,
0377: ptDst2.y + 1);
0378: }
0379: }
0380:
0381: void validate(float x1, float y1, float x2, float y2) {
0382: boolean doResize = false;
0383: isFlushed = false;
0384:
0385: synchronized (canvas3d) {
0386: if (initCtx && canvas3d.resizeGraphics2D) {
0387: doResize = true;
0388: canvas3d.resizeGraphics2D = false;
0389: }
0390: }
0391: if (doResize) {
0392: synchronized (VirtualUniverse.mc.contextCreationLock) {
0393: Graphics2D oldOffScreenGraphics2D = offScreenGraphics2D;
0394: initCtx = false;
0395: init();
0396: copyGraphics2D(oldOffScreenGraphics2D);
0397: }
0398: } else {
0399: AffineTransform tr = getTransform();
0400: ptSrc.x = x1;
0401: ptSrc.y = y1;
0402: tr.transform(ptSrc, ptDst1);
0403: ptSrc.x = x2;
0404: ptSrc.y = y2;
0405: tr.transform(ptSrc, ptDst2);
0406:
0407: synchronized (extentLock) {
0408: if (ptDst1.x < xmin) {
0409: xmin = (int) ptDst1.x;
0410: }
0411: if (ptDst1.y < ymin) {
0412: ymin = (int) ptDst1.y;
0413: }
0414: if (ptDst2.x > xmax) {
0415: xmax = (int) ptDst2.x;
0416: }
0417: if (ptDst2.y > ymax) {
0418: ymax = (int) ptDst2.y;
0419: }
0420: }
0421: }
0422: }
0423:
0424: void copyGraphics2D(Graphics2D oldg) {
0425: // restore the original setting of Graphics2D when resizing the windows
0426: setColor(oldg.getColor());
0427: setFont(oldg.getFont());
0428: setClip(oldg.getClip());
0429: setComposite(oldg.getComposite());
0430: setTransform(oldg.getTransform());
0431: setPaint(oldg.getPaint());
0432: setStroke(oldg.getStroke());
0433: if (xOrModeColor != null) {
0434: setXORMode(xOrModeColor);
0435: }
0436:
0437: }
0438:
0439: // Implementation of Graphics2D methods
0440: public final void clip(Shape s) {
0441: offScreenGraphics2D.clip(s);
0442: }
0443:
0444: public FontMetrics getFontMetrics() {
0445: return offScreenGraphics2D.getFontMetrics();
0446: }
0447:
0448: public Rectangle getClipBounds(Rectangle r) {
0449: return offScreenGraphics2D.getClipBounds(r);
0450: }
0451:
0452: public Rectangle getClipRect() {
0453: return offScreenGraphics2D.getClipRect();
0454: }
0455:
0456: public String toString() {
0457: return offScreenGraphics2D.toString();
0458:
0459: }
0460:
0461: public final AffineTransform getTransform() {
0462: return offScreenGraphics2D.getTransform();
0463: }
0464:
0465: public final Color getColor() {
0466: return offScreenGraphics2D.getColor();
0467: }
0468:
0469: public final Composite getComposite() {
0470: return offScreenGraphics2D.getComposite();
0471: }
0472:
0473: public final Font getFont() {
0474: return offScreenGraphics2D.getFont();
0475: }
0476:
0477: public final FontMetrics getFontMetrics(Font f) {
0478: return offScreenGraphics2D.getFontMetrics(f);
0479: }
0480:
0481: public final FontRenderContext getFontRenderContext() {
0482: return offScreenGraphics2D.getFontRenderContext();
0483: }
0484:
0485: public final GraphicsConfiguration getDeviceConfiguration() {
0486: return offScreenGraphics2D.getDeviceConfiguration();
0487: }
0488:
0489: public final Object getRenderingHint(Key hintKey) {
0490: return offScreenGraphics2D.getRenderingHint(hintKey);
0491: }
0492:
0493: public final Paint getPaint() {
0494: return offScreenGraphics2D.getPaint();
0495: }
0496:
0497: public final Rectangle getClipBounds() {
0498: return offScreenGraphics2D.getClipBounds();
0499: }
0500:
0501: public final RenderingHints getRenderingHints() {
0502: return offScreenGraphics2D.getRenderingHints();
0503: }
0504:
0505: public final Shape getClip() {
0506: return offScreenGraphics2D.getClip();
0507: }
0508:
0509: public final Stroke getStroke() {
0510: return offScreenGraphics2D.getStroke();
0511: }
0512:
0513: public final boolean drawImage(Image img, AffineTransform xform,
0514: ImageObserver obs) {
0515:
0516: validate(0, 0, img.getWidth(obs), img.getHeight(obs), xform);
0517: return offScreenGraphics2D.drawImage(img, xform, obs);
0518: }
0519:
0520: public final void drawImage(BufferedImage img, BufferedImageOp op,
0521: int x, int y) {
0522: if (op != null) {
0523: img = op.filter(img, null);
0524: }
0525: validate(x, y, x + img.getWidth(), y + img.getHeight());
0526: offScreenGraphics2D.drawImage(img, null, x, y);
0527: }
0528:
0529: public final boolean drawImage(Image img, int x, int y,
0530: ImageObserver observer) {
0531:
0532: validate(x, y, x + img.getWidth(observer), y
0533: + img.getWidth(observer));
0534: return offScreenGraphics2D.drawImage(img, x, y, observer);
0535: }
0536:
0537: public final boolean drawImage(Image img, int x, int y, int width,
0538: int height, ImageObserver observer) {
0539: validate(x, y, x + width, y + height);
0540: return offScreenGraphics2D.drawImage(img, x, y, width, height,
0541: observer);
0542: }
0543:
0544: public final boolean drawImage(Image img, int x, int y, int width,
0545: int height, Color bgcolor, ImageObserver observer) {
0546: validate(x, y, x + width, y + height);
0547: return offScreenGraphics2D.drawImage(img, x, y, width, height,
0548: bgcolor, observer);
0549: }
0550:
0551: public final void drawImage(BufferedImage img, int dx1, int dy1,
0552: int dx2, int dy2, int sx1, int sy1, int sx2, int sy2,
0553: ImageObserver observer) {
0554: validate(dx1, dy1, dx2, dy2);
0555: offScreenGraphics2D.drawImage(img, dx1, dy1, dx2, dy2, sx1,
0556: sy1, sx2, sy2, observer);
0557: }
0558:
0559: public final boolean drawImage(Image img, int dx1, int dy1,
0560: int dx2, int dy2, int sx1, int sy1, int sx2, int sy2,
0561: ImageObserver observer) {
0562: validate(dx1, dy1, dx2, dy2);
0563: return offScreenGraphics2D.drawImage(img, dx1, dy1, dx2, dy2,
0564: sx1, sy1, sx2, sy2, observer);
0565: }
0566:
0567: public final boolean drawImage(Image img, int dx1, int dy1,
0568: int dx2, int dy2, int sx1, int sy1, int sx2, int sy2,
0569: Color bgcolor, ImageObserver observer) {
0570: validate(dx1, dy1, dx2, dy2);
0571: return offScreenGraphics2D.drawImage(img, dx1, dy1, dx2, dy2,
0572: sx1, sy1, sx2, sy2, bgcolor, observer);
0573: }
0574:
0575: public final boolean drawImage(Image img, int x, int y,
0576: Color bgcolor, ImageObserver observer) {
0577: validate(x, y, x + img.getWidth(observer), y
0578: + img.getHeight(observer));
0579: return offScreenGraphics2D.drawImage(img, x, y, bgcolor,
0580: observer);
0581: }
0582:
0583: public final boolean hit(Rectangle rect, Shape s, boolean onStroke) {
0584: return offScreenGraphics2D.hit(rect, s, onStroke);
0585: }
0586:
0587: public final void addRenderingHints(Map hints) {
0588: offScreenGraphics2D.addRenderingHints(hints);
0589: }
0590:
0591: public final void clipRect(int x, int y, int width, int height) {
0592: offScreenGraphics2D.clipRect(x, y, width, height);
0593: }
0594:
0595: public final void copyArea(int x, int y, int width, int height,
0596: int dx, int dy) {
0597: validate(x + dx, y + dy, x + dx + width, y + dy + height);
0598: offScreenGraphics2D.copyArea(x, y, width, height, dx, dy);
0599: }
0600:
0601: public final void draw(Shape s) {
0602: Rectangle rect = s.getBounds();
0603: validate(rect.x, rect.y, rect.x + rect.width, rect.y
0604: + rect.height);
0605: offScreenGraphics2D.draw(s);
0606: }
0607:
0608: public final void drawArc(int x, int y, int width, int height,
0609: int startAngle, int arcAngle) {
0610: // XXXX: call validate with bounding box of primitive
0611: validate();
0612: offScreenGraphics2D.drawArc(x, y, width, height, startAngle,
0613: arcAngle);
0614: }
0615:
0616: public final void drawGlyphVector(GlyphVector g, float x, float y) {
0617: // XXXX: call validate with bounding box of primitive
0618: validate();
0619: offScreenGraphics2D.drawGlyphVector(g, x, y);
0620: }
0621:
0622: public final void drawLine(int x1, int y1, int x2, int y2) {
0623: int minx, miny, maxx, maxy;
0624: if (!strokeSet) {
0625: if (x1 > x2) {
0626: minx = x2;
0627: maxx = x1;
0628: } else {
0629: minx = x1;
0630: maxx = x2;
0631: }
0632: if (y1 > y2) {
0633: miny = y2;
0634: maxy = y1;
0635: } else {
0636: miny = y1;
0637: maxy = y2;
0638: }
0639: validate(minx, miny, maxx, maxy);
0640: } else {
0641: // XXXX: call validate with bounding box of primitive
0642: // XXXX: Need to consider Stroke width
0643: validate();
0644: }
0645: offScreenGraphics2D.drawLine(x1, y1, x2, y2);
0646: }
0647:
0648: public final void drawOval(int x, int y, int width, int height) {
0649: // XXXX: call validate with bounding box of primitive
0650: validate();
0651: offScreenGraphics2D.drawOval(x, y, width, height);
0652: }
0653:
0654: public final void drawPolygon(int xPoints[], int yPoints[],
0655: int nPoints) {
0656: // XXXX: call validate with bounding box of primitive
0657: validate();
0658: offScreenGraphics2D.drawPolygon(xPoints, yPoints, nPoints);
0659: }
0660:
0661: public final void drawPolyline(int xPoints[], int yPoints[],
0662: int nPoints) {
0663: // XXXX: call validate with bounding box of primitive
0664: validate();
0665: offScreenGraphics2D.drawPolyline(xPoints, yPoints, nPoints);
0666: }
0667:
0668: public final void drawRenderableImage(RenderableImage img,
0669: AffineTransform xform) {
0670:
0671: validate(0, 0, img.getWidth(), img.getHeight(), xform);
0672: offScreenGraphics2D.drawRenderableImage(img, xform);
0673: }
0674:
0675: public final void drawRenderedImage(RenderedImage img,
0676: AffineTransform xform) {
0677: validate(0, 0, img.getWidth(), img.getHeight(), xform);
0678: offScreenGraphics2D.drawRenderedImage(img, xform);
0679: }
0680:
0681: public final void drawRoundRect(int x, int y, int width,
0682: int height, int arcWidth, int arcHeight) {
0683: // XXXX: call validate with bounding box of primitive
0684: validate();
0685: offScreenGraphics2D.drawRoundRect(x, y, width, height,
0686: arcWidth, arcHeight);
0687: }
0688:
0689: public final void drawString(AttributedCharacterIterator iterator,
0690: int x, int y) {
0691: // XXXX: call validate with bounding box of primitive
0692: validate();
0693: offScreenGraphics2D.drawString(iterator, x, y);
0694: }
0695:
0696: public final void drawString(AttributedCharacterIterator iterator,
0697: float x, float y) {
0698: // XXXX: call validate with bounding box of primitive
0699: validate();
0700: offScreenGraphics2D.drawString(iterator, x, y);
0701: }
0702:
0703: public final void drawString(String s, float x, float y) {
0704: TextLayout layout = new TextLayout(s, getFont(),
0705: getFontRenderContext());
0706: Rectangle2D bounds = layout.getBounds();
0707: float x1 = (float) bounds.getX();
0708: float y1 = (float) bounds.getY();
0709: validate(x1 + x, y1 + y, x1 + x + (float) bounds.getWidth(), y1
0710: + y + (float) bounds.getHeight());
0711: offScreenGraphics2D.drawString(s, x, y);
0712:
0713: }
0714:
0715: public final void drawString(String s, int x, int y) {
0716: drawString(s, (float) x, (float) y);
0717: }
0718:
0719: public final void fill(Shape s) {
0720: Rectangle rect = s.getBounds();
0721: validate(rect.x, rect.y, rect.x + rect.width, rect.y
0722: + rect.height);
0723: offScreenGraphics2D.fill(s);
0724: }
0725:
0726: public final void fillArc(int x, int y, int width, int height,
0727: int startAngle, int arcAngle) {
0728: // XXXX: call validate with bounding box of primitive
0729: validate();
0730: offScreenGraphics2D.fillArc(x, y, width, height, startAngle,
0731: arcAngle);
0732: }
0733:
0734: public final void fillOval(int x, int y, int width, int height) {
0735: // XXXX: call validate with bounding box of primitive
0736: validate();
0737: offScreenGraphics2D.fillOval(x, y, width, height);
0738: }
0739:
0740: public final void fillRoundRect(int x, int y, int width,
0741: int height, int arcWidth, int arcHeight) {
0742: // XXXX: call validate with bounding box of primitive
0743: validate();
0744: offScreenGraphics2D.fillRoundRect(x, y, width, height,
0745: arcWidth, arcHeight);
0746: }
0747:
0748: public final void rotate(double theta) {
0749: offScreenGraphics2D.rotate(theta);
0750: }
0751:
0752: public final void rotate(double theta, double x, double y) {
0753: offScreenGraphics2D.rotate(theta, x, y);
0754: }
0755:
0756: public final void scale(double sx, double sy) {
0757: offScreenGraphics2D.scale(sx, sy);
0758: }
0759:
0760: public final void setClip(Shape clip) {
0761: offScreenGraphics2D.setClip(clip);
0762: }
0763:
0764: public final void setClip(int x, int y, int width, int height) {
0765: offScreenGraphics2D.setClip(x, y, width, height);
0766: }
0767:
0768: public final void setColor(Color c) {
0769: offScreenGraphics2D.setColor(c);
0770: }
0771:
0772: public final void setComposite(Composite comp) {
0773: offScreenGraphics2D.setComposite(comp);
0774: }
0775:
0776: public final void setFont(Font font) {
0777: offScreenGraphics2D.setFont(font);
0778: }
0779:
0780: public final void setPaint(Paint paint) {
0781: offScreenGraphics2D.setPaint(paint);
0782: }
0783:
0784: public final void setPaintMode() {
0785: xOrModeColor = null;
0786: offScreenGraphics2D.setPaintMode();
0787: }
0788:
0789: public final void setRenderingHint(Key hintKey, Object hintValue) {
0790: offScreenGraphics2D.setRenderingHint(hintKey, hintValue);
0791: }
0792:
0793: public final void setRenderingHints(Map hints) {
0794: offScreenGraphics2D.setRenderingHints(hints);
0795: }
0796:
0797: public final void setStroke(Stroke s) {
0798: strokeSet = (s != null);
0799: offScreenGraphics2D.setStroke(s);
0800: }
0801:
0802: public final void setTransform(AffineTransform Tx) {
0803: offScreenGraphics2D.setTransform(Tx);
0804: }
0805:
0806: public final void setXORMode(Color c1) {
0807: xOrModeColor = c1;
0808: offScreenGraphics2D.setXORMode(c1);
0809: }
0810:
0811: public final void shear(double shx, double shy) {
0812: offScreenGraphics2D.shear(shx, shy);
0813: }
0814:
0815: public final void transform(AffineTransform Tx) {
0816: offScreenGraphics2D.transform(Tx);
0817: }
0818:
0819: public final void translate(double tx, double ty) {
0820: offScreenGraphics2D.translate(tx, ty);
0821: }
0822:
0823: public final void translate(int x, int y) {
0824: offScreenGraphics2D.translate(x, y);
0825: }
0826:
0827: public boolean hitClip(int x, int y, int width, int height) {
0828: return offScreenGraphics2D.hitClip(x, y, width, height);
0829: }
0830:
0831: public void draw3DRect(int x, int y, int width, int height,
0832: boolean raised) {
0833: // XXXX: call validate with bounding box of primitive
0834: validate();
0835: offScreenGraphics2D.draw3DRect(x, y, width, height, raised);
0836: }
0837:
0838: public void drawBytes(byte data[], int offset, int length, int x,
0839: int y) {
0840: // XXXX: call validate with bounding box of primitive
0841: validate();
0842: offScreenGraphics2D.drawBytes(data, offset, length, x, y);
0843: }
0844:
0845: public void drawChars(char data[], int offset, int length, int x,
0846: int y) {
0847: // XXXX: call validate with bounding box of primitive
0848: validate();
0849: offScreenGraphics2D.drawChars(data, offset, length, x, y);
0850: }
0851:
0852: public void drawPolygon(Polygon p) {
0853: // XXXX: call validate with bounding box of primitive
0854: validate();
0855: offScreenGraphics2D.drawPolygon(p);
0856: }
0857:
0858: public void drawRect(int x, int y, int width, int height) {
0859: // XXXX: call validate with bounding box of primitive
0860: // XXXX: need to consider Stroke width
0861: validate();
0862: offScreenGraphics2D.drawRect(x, y, width, height);
0863: }
0864:
0865: public void fill3DRect(int x, int y, int width, int height,
0866: boolean raised) {
0867: // XXXX: call validate with bounding box of primitive
0868: // XXXX: need to consider Stroke width
0869: validate();
0870: offScreenGraphics2D.fill3DRect(x, y, width, height, raised);
0871: }
0872:
0873: public void fillPolygon(Polygon p) {
0874: // XXXX: call validate with bounding box of primitive
0875: validate();
0876: offScreenGraphics2D.fillPolygon(p);
0877: }
0878:
0879: public final void fillPolygon(int xPoints[], int yPoints[],
0880: int nPoints) {
0881: // XXXX: call validate with bounding box of primitive
0882: validate();
0883: offScreenGraphics2D.fillPolygon(xPoints, yPoints, nPoints);
0884: }
0885:
0886: public final void fillRect(int x, int y, int width, int height) {
0887: // XXXX: call validate with bounding box of primitive
0888: validate();
0889: offScreenGraphics2D.fillRect(x, y, width, height);
0890: }
0891:
0892: // Issue 121 - release all resources, mark as disposed
0893: public void dispose() {
0894:
0895: if (Thread.currentThread() == canvas3d.screen.renderer) {
0896: doDispose();
0897: } else {
0898: // Behavior Scheduler or other threads
0899: // XXXX: may not be legal for behaviorScheduler
0900: // May cause deadlock if it is in behaviorScheduler
0901: // and we wait for Renderer to finish
0902: boolean renderRun = (Thread.currentThread() != canvas3d.view.universe.behaviorScheduler);
0903: sendRenderMessage(renderRun, GraphicsContext3D.DISPOSE2D,
0904: null, null, null);
0905: }
0906:
0907: }
0908:
0909: public void doDispose() {
0910:
0911: if (hasBeenDisposed) {
0912: return;
0913: }
0914:
0915: if (objectId != -1) {
0916: canvas3d.freeTexture(canvas3d.ctx, objectId);
0917: VirtualUniverse.mc.freeTexture2DId(objectId);
0918: objectId = -1;
0919: }
0920:
0921: // Dispose of the underlying Graphics2D
0922: offScreenGraphics2D.dispose();
0923:
0924: // Mark as disposed
0925: hasBeenDisposed = true;
0926: }
0927:
0928: public void drawAndFlushImage(BufferedImage img, int x, int y,
0929: ImageObserver observer) {
0930:
0931: if (hasBeenDisposed) {
0932: throw new IllegalStateException(J3dI18N
0933: .getString("J3DGraphics2D0"));
0934: }
0935:
0936: if (!(initCtx && abgr && (img.getType() == BufferedImage.TYPE_4BYTE_ABGR))) {
0937: drawImage(img, x, y, observer);
0938: flush(false);
0939: return;
0940: }
0941:
0942: if (Thread.currentThread() == canvas3d.screen.renderer) {
0943: doDrawAndFlushImage(img, x, y, observer);
0944: } else {
0945: // Behavior Scheduler or other threads
0946: // XXXX: may not be legal for behaviorScheduler
0947: // May cause deadlock if it is in behaviorScheduler
0948: // and we wait for Renderer to finish
0949: boolean renderRun = (Thread.currentThread() != canvas3d.view.universe.behaviorScheduler);
0950: sendRenderMessage(renderRun,
0951: GraphicsContext3D.DRAWANDFLUSH2D, img, new Point(x,
0952: y), observer);
0953: }
0954: }
0955:
0956: void doDrawAndFlushImage(BufferedImage img, int x, int y,
0957: ImageObserver observer) {
0958:
0959: assert !hasBeenDisposed;
0960:
0961: int imgWidth = img.getWidth(observer);
0962: int imgHeight = img.getHeight(observer);
0963: int px, py, x1, y1, x2, y2;
0964:
0965: if (canvas3d.ctx == null) {
0966: canvas3d.getGraphicsContext3D().doClear();
0967: }
0968:
0969: // format needs to be 4BYTE_ABGR and abgr needs to be supported
0970: // also must be in canvas callback
0971: data = ((DataBufferByte) img.getRaster().getDataBuffer())
0972: .getData();
0973:
0974: // Transform the affine transform,
0975: // note we do not handle scale/rotate etc.
0976: AffineTransform tr = getTransform();
0977: ptSrc.x = x;
0978: ptSrc.y = y;
0979: tr.transform(ptSrc, ptDst1);
0980: px = (int) ptDst1.x;
0981: py = (int) ptDst1.y;
0982:
0983: // clip to offscreen buffer size
0984:
0985: if (px + imgWidth > width) {
0986: x2 = width - px;
0987: } else {
0988: x2 = imgWidth;
0989: }
0990:
0991: if (px < 0) {
0992: x1 = -px;
0993: px = 0;
0994: } else {
0995: x1 = 0;
0996: }
0997:
0998: if (py + imgHeight > height) {
0999: y2 = height - py;
1000: } else {
1001: y2 = imgHeight;
1002: }
1003:
1004: if (py < 0) {
1005: y1 = -py;
1006: py = 0;
1007: } else {
1008: y1 = 0;
1009: }
1010:
1011: if ((y2 - y1 > 0) && (x2 - x1 > 0)) {
1012: copyDataToCanvas(px, py, x1, y1, x2, y2, imgWidth,
1013: imgHeight);
1014: }
1015:
1016: }
1017:
1018: void copyDataToCanvas(int px, int py, int x1, int y1, int x2,
1019: int y2, int w, int h) {
1020: try {
1021: if (!canvas3d.drawingSurfaceObject.renderLock()) {
1022: return;
1023: }
1024:
1025: if (!initTexMap) {
1026: if (objectId == -1) {
1027: objectId = VirtualUniverse.mc.getTexture2DId();
1028: }
1029: texWidth = getGreaterPowerOf2(w);
1030: texHeight = getGreaterPowerOf2(h);
1031:
1032: // Canvas got resize, need to init texture map again
1033: // in Renderer thread
1034: if (!canvas3d.initTexturemapping(canvas3d.ctx,
1035: texWidth, texHeight, objectId)) {
1036: // Fail to get the texture surface, most likely
1037: // there is not enough texture memory
1038: initTexMap = false;
1039: VirtualUniverse.mc.freeTexture2DId(objectId);
1040: objectId = -1;
1041: // TODO : Need to find a better way to report no resource problem --- Chien.
1042: System.err
1043: .println("J3DGraphics2DImpl.copyDataToCanvas() : Fail to get texture resources ...");
1044:
1045: } else {
1046: initTexMap = true;
1047: }
1048: }
1049: if (initTexMap) {
1050: canvas3d
1051: .texturemapping(
1052: canvas3d.ctx,
1053: px,
1054: py,
1055: x1,
1056: y1,
1057: x2,
1058: y2,
1059: texWidth,
1060: texHeight,
1061: w,
1062: (abgr ? ImageComponentRetained.TYPE_BYTE_ABGR
1063: : ImageComponentRetained.TYPE_BYTE_RGBA),
1064: objectId, data, width, height);
1065: }
1066:
1067: canvas3d.drawingSurfaceObject.unLock();
1068: } catch (NullPointerException ne) {
1069: canvas3d.drawingSurfaceObject.unLock();
1070: throw ne;
1071: }
1072:
1073: clearOffScreen();
1074: runMonitor(J3dThread.NOTIFY);
1075: }
1076:
1077: void clearOffScreen() {
1078: Composite comp = offScreenGraphics2D.getComposite();
1079: Color c = offScreenGraphics2D.getColor();
1080: offScreenGraphics2D.setComposite(AlphaComposite.Src);
1081: offScreenGraphics2D.setColor(blackTransparent);
1082: offScreenGraphics2D.fillRect(xmin, ymin, (xmax - xmin),
1083: (ymax - ymin));
1084: offScreenGraphics2D.setComposite(comp);
1085: offScreenGraphics2D.setColor(c);
1086: }
1087:
1088: /**
1089: * Return an integer of power 2 greater than x
1090: */
1091: static int getGreaterPowerOf2(int x) {
1092: int i = -1;
1093: if (x >= 0) {
1094: for (i = 1; i < x; i <<= 1)
1095: ;
1096: }
1097: return i;
1098: }
1099:
1100: /**
1101: * MC may not scheduler Renderer thread or Renderer thread
1102: * may not process message FLUSH. This will hang user
1103: * thread.
1104: */
1105: synchronized void runMonitor(int action) {
1106: if (action == J3dThread.WAIT) {
1107: // Issue 279 - loop until ready
1108: while (threadWaiting) {
1109: try {
1110: wait();
1111: } catch (InterruptedException e) {
1112: }
1113: }
1114: } else if (action == J3dThread.NOTIFY) {
1115: notify();
1116: threadWaiting = false;
1117: }
1118: }
1119: }
|