0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017: /**
0018: * @author Oleg V. Khaschansky
0019: * @version $Revision$
0020: */package org.apache.harmony.awt.gl.opengl;
0021:
0022: import org.apache.harmony.awt.gl.CommonGraphics2D;
0023: import org.apache.harmony.awt.gl.MultiRectArea;
0024: import org.apache.harmony.awt.gl.Utils;
0025: import org.apache.harmony.awt.gl.Surface;
0026: import org.apache.harmony.awt.gl.font.FontManager;
0027: import org.apache.harmony.awt.gl.render.NullBlitter;
0028: import org.apache.harmony.awt.wtk.NativeWindow;
0029: import org.apache.harmony.awt.nativebridge.Int32Pointer;
0030: import org.apache.harmony.awt.nativebridge.NativeBridge;
0031: import org.apache.harmony.misc.accessors.LockedArray;
0032:
0033: import java.awt.*;
0034: import java.awt.geom.AffineTransform;
0035: import java.awt.geom.Rectangle2D;
0036: import java.awt.geom.Point2D;
0037: import java.awt.font.GlyphVector;
0038: import java.util.Arrays;
0039: import java.math.BigInteger;
0040:
0041: public final class OGLGraphics2D extends CommonGraphics2D {
0042:
0043: private static final int[] BLEND_RULE_MAPPING_SRC_PREMULT = new int[] {
0044: -1, // No rule
0045: GLDefs.GL_ZERO, // 1, Clear
0046: GLDefs.GL_ONE, // 2, Src
0047: GLDefs.GL_ONE, // 3, SrcOver
0048: GLDefs.GL_ONE_MINUS_DST_ALPHA, // 4, DstOver
0049: GLDefs.GL_DST_ALPHA, // 5, SrcIn
0050: GLDefs.GL_ZERO, // 6, DstIn
0051: GLDefs.GL_ONE_MINUS_DST_ALPHA, // 7, SrcOut
0052: GLDefs.GL_ZERO, // 8, DstOut
0053: GLDefs.GL_ZERO, // 9, Dst
0054: GLDefs.GL_DST_ALPHA, // 10, SrcAtop
0055: GLDefs.GL_ONE_MINUS_DST_ALPHA, // 11, DstAtop
0056: GLDefs.GL_ONE_MINUS_DST_ALPHA // 11, Xor
0057: };
0058:
0059: private static final int[] BLEND_RULE_MAPPING_DST = new int[] { -1, // No rule
0060: GLDefs.GL_ZERO, // 1, Clear
0061: GLDefs.GL_ZERO, // 2, Src
0062: GLDefs.GL_ONE_MINUS_SRC_ALPHA, // 3, SrcOver
0063: GLDefs.GL_ONE, // 4, DstOver
0064: GLDefs.GL_ZERO, // 5, SrcIn
0065: GLDefs.GL_SRC_ALPHA, // 6, DstIn
0066: GLDefs.GL_ZERO, // 7, SrcOut
0067: GLDefs.GL_ONE_MINUS_SRC_ALPHA, // 8, DstOut
0068: GLDefs.GL_ONE, // 9, Dst
0069: GLDefs.GL_ONE_MINUS_SRC_ALPHA, // 10, SrcAtop
0070: GLDefs.GL_SRC_ALPHA, // 11, DstAtop
0071: GLDefs.GL_ONE_MINUS_SRC_ALPHA // 11, Xor
0072: };
0073:
0074: private static final boolean[] HAVE_MAPPING_NO_PREMULT = new boolean[] {
0075: false, // No rule
0076: true, // 1, Clear
0077: true, // 2, Src
0078: true, // 3, SrcOver
0079: false, // 4, DstOver
0080: false, // 5, SrcIn
0081: true, // 6, DstIn
0082: false, // 7, SrcOut
0083: true, // 8, DstOut
0084: true, // 9, Dst
0085: false, // 10, SrcAtop
0086: false, // 11, DstAtop
0087: false // 11, Xor
0088: };
0089:
0090: private static final int[] BLEND_RULE_MAPPING_SRC_NO_PREMULT = new int[] {
0091: -1, // No rule
0092: GLDefs.GL_ZERO, // 1, Clear
0093: GLDefs.GL_SRC_ALPHA, // 2, Src
0094: GLDefs.GL_SRC_ALPHA, // 3, SrcOver
0095: -1, // 4, DstOver
0096: -1, // 5, SrcIn
0097: GLDefs.GL_ZERO, // 6, DstIn
0098: -1, // 7, SrcOut
0099: GLDefs.GL_ZERO, // 8, DstOut
0100: GLDefs.GL_ZERO, // 9, Dst
0101: -1, // 10, SrcAtop
0102: -1, // 11, DstAtop
0103: -1 // 11, Xor
0104: };
0105:
0106: private static final int[] BLEND_RULE_MAPPING_DST_NO_ALPHA = new int[] {
0107: -1, // No rule
0108: GLDefs.GL_ZERO, // 1, Clear
0109: GLDefs.GL_ZERO, // 2, Src
0110: GLDefs.GL_ZERO, // 3, SrcOver
0111: GLDefs.GL_ONE, // 4, DstOver
0112: GLDefs.GL_ZERO, // 5, SrcIn
0113: GLDefs.GL_ONE, // 6, DstIn
0114: GLDefs.GL_ZERO, // 7, SrcOut
0115: GLDefs.GL_ZERO, // 8, DstOut
0116: GLDefs.GL_ONE, // 9, Dst
0117: GLDefs.GL_ZERO, // 10, SrcAtop
0118: GLDefs.GL_ONE, // 11, DstAtop
0119: GLDefs.GL_ZERO, // 11, Xor
0120: };
0121:
0122: private static final GL gl = GL.getInstance();
0123:
0124: private final double[] javaTransformMx = new double[6];
0125: private final double[] glTransformMx = new double[16];
0126:
0127: private OGLContextManager ctxmgr;
0128: //private long oglContext;
0129:
0130: private NativeWindow nwin;
0131: Rectangle winBounds; // Cached native window bounds
0132:
0133: // Can't use transform from CommonGraphics, want to get all mra's untransformed
0134: private AffineTransform glTransform = new AffineTransform();
0135:
0136: private final byte fgRgba[] = new byte[4];
0137: boolean opaqueColor = true;
0138: private float acAlpha = 1.0f;
0139:
0140: private boolean oglPaint = true;
0141: private boolean texPaint = false;
0142: private boolean nativeLines = true;
0143: private boolean scalingTransform = false;
0144:
0145: private short stipplePattern;
0146: private int stippleFactor;
0147:
0148: /**
0149: * gradTexName is a 2 pixel 1d texture object, used to draw gradient.
0150: */
0151: private int gradTexName = 0;
0152: /**
0153: * gradObjectPlane is used for 1d texture coordinates generation
0154: * when gradient paint is enabled
0155: */
0156: private double gradObjectPlane[];
0157: private boolean isGPCyclic;
0158:
0159: private long oshdc = 0; // device context for windows offscreen image
0160:
0161: public OGLGraphics2D(NativeWindow nwin, int tx, int ty,
0162: MultiRectArea clip) {
0163: if (nwin instanceof OGLVolatileImage.OGLOffscreenWindow) {
0164: OGLVolatileImage.OGLOffscreenWindow offWin = (OGLVolatileImage.OGLOffscreenWindow) nwin;
0165: oshdc = offWin.getHdc();
0166: }
0167:
0168: this .nwin = nwin;
0169:
0170: ctxmgr = (OGLContextManager) getDeviceConfiguration();
0171: //long oglContext = ctxmgr.getOGLContext();
0172:
0173: // Get the viewport (=native window) width and height
0174: winBounds = nwin.getBounds();
0175:
0176: if (clip != null) {
0177: Rectangle bounds = clip.getBounds();
0178: dstSurf = new OGLSurface(bounds.width, bounds.height, this );
0179: } else {
0180: dstSurf = new OGLSurface(winBounds.width, winBounds.height,
0181: this );
0182: }
0183:
0184: makeCurrent();
0185:
0186: resetBounds();
0187:
0188: // Apply the translation
0189: gl.glLoadIdentity();
0190: glTransform = AffineTransform.getTranslateInstance(tx, ty);
0191: gl.glTranslated(tx, ty, 0);
0192:
0193: // Super class constructor sets untransformed clip
0194: setTransformedClip(clip);
0195:
0196: origPoint = new Point(tx, ty);
0197:
0198: blitter = OGLBlitter.getInstance();
0199:
0200: if (!FontManager.IS_FONTLIB) {
0201: jtr = new OGLTextRenderer();
0202: }
0203: }
0204:
0205: public OGLGraphics2D(NativeWindow nwin, int tx, int ty, int width,
0206: int height) {
0207: this (nwin, tx, ty, new MultiRectArea(new Rectangle(width,
0208: height)));
0209: }
0210:
0211: @Override
0212: public Graphics create() {
0213: OGLGraphics2D res = new OGLGraphics2D(nwin, 0, 0, dstSurf
0214: .getWidth(), dstSurf.getHeight());
0215:
0216: copyInternalFields(res);
0217:
0218: // Have to copy transform and clip explicitly, since we use opengl transforms
0219: res.setTransform(new AffineTransform(glTransform));
0220: if (clip == null) {
0221: res.setTransformedClip(null);
0222: } else {
0223: res.setTransformedClip(new MultiRectArea(clip));
0224: }
0225:
0226: return res;
0227: }
0228:
0229: @Override
0230: public void finalize() {
0231: super .finalize();
0232: try {
0233: EventQueue.invokeAndWait(new Runnable() {
0234: public void run() {
0235: dispose();
0236: }
0237: });
0238: } catch (Exception e) {
0239: e.printStackTrace(); // Something bad happened
0240: }
0241: }
0242:
0243: @Override
0244: public GraphicsConfiguration getDeviceConfiguration() {
0245: GraphicsEnvironment env = GraphicsEnvironment
0246: .getLocalGraphicsEnvironment();
0247: return env.getDefaultScreenDevice().getDefaultConfiguration();
0248: }
0249:
0250: @Override
0251: public void copyArea(int x, int y, int width, int height, int dx,
0252: int dy) {
0253: makeCurrent();
0254:
0255: gl.glPixelZoom(1, 1);
0256:
0257: // Raster position could be outside of the viewport, use glBitmap
0258: gl.glRasterPos2i(0, 0);
0259: gl.glBitmap(0, 0, 0, 0, x + dx, -y - dy - height, 0);
0260:
0261: x += glTransform.getTranslateX() + 0.5;
0262: y += glTransform.getTranslateY() + 0.5;
0263:
0264: gl.glCopyPixels(x, winBounds.height - y - height, width,
0265: height, GLDefs.GL_COLOR);
0266: gl.glFlush();
0267: getSurface().updateScene();
0268: }
0269:
0270: @Override
0271: public void setPaint(Paint paint) {
0272: if (paint == null)
0273: return;
0274:
0275: super .setPaint(paint);
0276:
0277: makeCurrent();
0278:
0279: if (paint instanceof Color) {
0280: deactivateTexturePaint();
0281: deactivateGradientPaint();
0282: setColor((Color) paint);
0283: oglPaint = true;
0284: texPaint = false;
0285: } else if (paint instanceof GradientPaint) {
0286: deactivateTexturePaint();
0287: activateGradientPaint((GradientPaint) paint);
0288: oglPaint = true;
0289: texPaint = false;
0290: } else if (paint instanceof TexturePaint) {
0291: deactivateGradientPaint();
0292: activateTexturePaint((TexturePaint) paint);
0293: oglPaint = true;
0294: texPaint = true;
0295: } else {
0296: deactivateTexturePaint();
0297: deactivateGradientPaint();
0298: oglPaint = false;
0299: texPaint = false;
0300: }
0301: }
0302:
0303: void resetPaint() {
0304: if (gradTexName != 0) {
0305: deactivateTexturePaint();
0306: reactivateGradientPaint();
0307: } else {
0308: setPaint(paint);
0309: }
0310: }
0311:
0312: @Override
0313: public void setColor(Color color) {
0314: if (color == null) {
0315: return;
0316: }
0317:
0318: super .setColor(color);
0319:
0320: makeCurrent();
0321:
0322: // Set gl color
0323: int val = color.getRGB();
0324: fgRgba[0] = (byte) ((val >> 16) & 0xFF);
0325: fgRgba[1] = (byte) ((val >> 8) & 0xFF);
0326: fgRgba[2] = (byte) (val & 0xFF);
0327: fgRgba[3] = (byte) ((val >> 24) & 0xFF);
0328:
0329: // Need to premultiply alpha
0330: if ((fgRgba[3] & 0xFF) != 0xFF || acAlpha != 1.0f) {
0331: float alpha = (fgRgba[3] & 0xFF) / 255.0f;
0332: fgRgba[0] = (byte) ((fgRgba[0] & 0xFF) * acAlpha * alpha + 0.5);
0333: fgRgba[1] = (byte) ((fgRgba[1] & 0xFF) * acAlpha * alpha + 0.5);
0334: fgRgba[2] = (byte) ((fgRgba[2] & 0xFF) * acAlpha * alpha + 0.5);
0335: // Also use acAlpha
0336: fgRgba[3] = (byte) ((fgRgba[3] & 0xFF) * acAlpha + 0.5);
0337: }
0338:
0339: LockedArray lColor = Utils.arraccess.lockArrayShort(fgRgba);
0340: gl.glColor4ubv(lColor.getAddress());
0341: lColor.release();
0342:
0343: // If color becomes translucent, probably need to enable blending
0344: if (opaqueColor != ((fgRgba[3] & 0xFF) == 0xFF)) {
0345: opaqueColor = (fgRgba[3] & 0xFF) == 0xFF;
0346: checkComposite();
0347: }
0348:
0349: // And, finally, update paint
0350: if (texPaint) {
0351: deactivateTexturePaint();
0352: texPaint = false;
0353: } else if (gradTexName != 0) {
0354: deactivateGradientPaint();
0355: }
0356: paint = color;
0357: oglPaint = true;
0358: }
0359:
0360: @Override
0361: public void dispose() {
0362: super .dispose();
0363: /*
0364: if (oglContext != 0) {
0365: ctxmgr.destroyOGLContext(oglContext);
0366: oglContext = 0;
0367: }*/
0368: }
0369:
0370: final void makeCurrent() {
0371: long oglContext = ctxmgr.getOGLContext(nwin.getId(), oshdc);
0372: ctxmgr.makeCurrent(oglContext, nwin.getId(), oshdc);
0373: OGLContextValidator.validateContext(this );
0374: }
0375:
0376: private int[] createVertexArray(MultiRectArea mra) {
0377: int rect[] = mra.rect;
0378: int resSize = (rect[0] - 1) << 1;
0379:
0380: int[] res = null;
0381:
0382: if (resSize > 0) {
0383: //int resSize = nRects*8;
0384: int rectOffset = 1;
0385: res = new int[resSize];
0386: for (int i = 0; i < resSize; i += 8, rectOffset += 4) {
0387: // Left, top
0388: res[i] = rect[rectOffset];
0389: res[i + 1] = rect[rectOffset + 1];
0390: // Right, top
0391: res[i + 2] = rect[rectOffset + 2] + 1;
0392: res[i + 3] = rect[rectOffset + 1];
0393: // Right, bottom
0394: res[i + 4] = rect[rectOffset + 2] + 1;
0395: res[i + 5] = rect[rectOffset + 3] + 1;
0396: // Left, bottom
0397: res[i + 6] = rect[rectOffset];
0398: res[i + 7] = rect[rectOffset + 3] + 1;
0399: }
0400: }
0401:
0402: return res;
0403: }
0404:
0405: @Override
0406: protected void fillMultiRectAreaColor(MultiRectArea mra) {
0407: makeCurrent();
0408:
0409: if (((mra.rect[0] - 1)) > 0) { // Have something to draw
0410: int vertices[] = createVertexArray(mra);
0411: LockedArray lVertices = Utils.arraccess
0412: .lockArrayShort(vertices);
0413:
0414: gl.glVertexPointer(2, GLDefs.GL_INT, 0, lVertices
0415: .getAddress());
0416:
0417: // At least one configuration (ATI MOBILITY FIRE GL T2 card on win32) has
0418: // problems with the large arrays, so workaround is used when
0419: // the number of vertices exceeds 1024
0420: if (vertices.length < 2048) {
0421: gl
0422: .glDrawArrays(GLDefs.GL_QUADS, 0,
0423: vertices.length / 2);
0424: } else {
0425: int iters = vertices.length / 2048;
0426: for (int i = 0; i < iters; i++) {
0427: gl.glDrawArrays(GLDefs.GL_QUADS, i * 1024, 1024);
0428: }
0429: gl.glDrawArrays(GLDefs.GL_QUADS, iters * 1024,
0430: (vertices.length % 2048) / 2);
0431: }
0432:
0433: lVertices.release();
0434: }
0435:
0436: gl.glFlush();
0437: getSurface().updateScene();
0438: }
0439:
0440: @Override
0441: public void drawString(String str, float x, float y) {
0442: makeCurrent();
0443:
0444: if (paint instanceof Color) {
0445: AffineTransform at = (AffineTransform) glTransform.clone();
0446: jtr.drawString(this , str, x, y);
0447: setTransform(at);
0448: } else {
0449: this .fill(font.createGlyphVector(
0450: this .getFontRenderContext(), str).getOutline(x, y));
0451: }
0452:
0453: gl.glFlush();
0454: getSurface().updateScene();
0455: }
0456:
0457: @Override
0458: public void drawGlyphVector(GlyphVector gv, float x, float y) {
0459: makeCurrent();
0460:
0461: if (paint instanceof Color) {
0462: AffineTransform at = (AffineTransform) glTransform.clone();
0463: jtr.drawGlyphVector(this , gv, x, y);
0464: setTransform(at);
0465: } else {
0466: this .fill(gv.getOutline(x, y));
0467: }
0468:
0469: gl.glFlush();
0470: getSurface().updateScene();
0471: }
0472:
0473: @Override
0474: protected void setTransformedClip(MultiRectArea clip) {
0475: super .setTransformedClip(clip);
0476: //if (oglContext != 0) {
0477: if (ctxmgr != null) {
0478: makeCurrent();
0479:
0480: if (clip == null) { // Disable clip
0481: gl.glDisable(GLDefs.GL_STENCIL_TEST);
0482: gl.glDisable(GLDefs.GL_SCISSOR_TEST);
0483:
0484: } else if (clip.rect[0] < 5) { // Emplty clip, no drwing allowed
0485: gl.glDisable(GLDefs.GL_STENCIL_TEST);
0486: gl.glEnable(GLDefs.GL_SCISSOR_TEST);
0487: gl.glScissor(0, 0, 0, 0);
0488:
0489: } else if (clip.rect[0] == 5) { // Define scissor box - have only one clip rect
0490: gl.glDisable(GLDefs.GL_STENCIL_TEST);
0491: gl.glEnable(GLDefs.GL_SCISSOR_TEST);
0492:
0493: // Need to transform clip origin, since ogl transform
0494: // is not applied by glScissor
0495: // Probably should be (int) (glTransform.getTranslateX() + 0.5)
0496: // but this gives a 1 pixel error with swing scrolling
0497: int tx = (int) (glTransform.getTranslateX());
0498: int ty = (int) (glTransform.getTranslateY());
0499:
0500: gl.glScissor(clip.rect[1] + tx, winBounds.height
0501: - clip.rect[4] - 1 - ty, clip.rect[3]
0502: - clip.rect[1] + 1, clip.rect[4] - clip.rect[2]
0503: + 1);
0504: } else { // Several clip rects, use stencil
0505:
0506: gl.glDisable(GLDefs.GL_SCISSOR_TEST);
0507: gl.glEnable(GLDefs.GL_STENCIL_TEST);
0508:
0509: gl.glClear(GLDefs.GL_STENCIL_BUFFER_BIT);
0510:
0511: gl.glColorMask((byte) GLDefs.GL_FALSE,
0512: (byte) GLDefs.GL_FALSE, (byte) GLDefs.GL_FALSE,
0513: (byte) GLDefs.GL_FALSE);
0514: gl.glStencilFunc(GLDefs.GL_ALWAYS, 0x1, 0x1);
0515: gl.glStencilOp(GLDefs.GL_REPLACE, GLDefs.GL_REPLACE,
0516: GLDefs.GL_REPLACE);
0517:
0518: // Draw the clip area into the stencil buffer
0519: fillMultiRectAreaColor(clip);
0520:
0521: gl.glColorMask((byte) GLDefs.GL_TRUE,
0522: (byte) GLDefs.GL_TRUE, (byte) GLDefs.GL_TRUE,
0523: (byte) GLDefs.GL_TRUE);
0524: gl.glStencilFunc(GLDefs.GL_EQUAL, 0x1, 0x1);
0525: gl.glStencilOp(GLDefs.GL_KEEP, GLDefs.GL_KEEP,
0526: GLDefs.GL_KEEP);
0527: }
0528: }
0529: }
0530:
0531: @Override
0532: public void setTransform(AffineTransform transform) {
0533: // If transform is scaling drop native lines and use rasterizer
0534: if ((transform.getType() & AffineTransform.TYPE_MASK_SCALE) != 0) {
0535: scalingTransform = true;
0536: } else {
0537: scalingTransform = false;
0538: }
0539:
0540: //if (oglContext != 0) {
0541: if (ctxmgr != null) {
0542: double clipTranslationX = -transform.getTranslateX()
0543: + glTransform.getTranslateX();
0544: double clipTranslationY = -transform.getTranslateY()
0545: + glTransform.getTranslateY();
0546:
0547: this .glTransform = transform;
0548:
0549: if (clip != null) {
0550: clip.translate(Math.round((float) clipTranslationX),
0551: Math.round((float) clipTranslationY));
0552: }
0553:
0554: makeCurrent();
0555: gl.glLoadIdentity();
0556:
0557: switch (transform.getType()) {
0558: case AffineTransform.TYPE_TRANSLATION: {
0559: gl.glTranslated(transform.getTranslateX(), transform
0560: .getTranslateY(), 0);
0561: break;
0562: }
0563:
0564: case AffineTransform.TYPE_GENERAL_SCALE:
0565: case AffineTransform.TYPE_UNIFORM_SCALE: {
0566: gl.glScaled(transform.getScaleX(), transform
0567: .getScaleY(), 0);
0568: break;
0569: }
0570:
0571: case AffineTransform.TYPE_IDENTITY:
0572: break;
0573:
0574: default: {
0575: transform.getMatrix(javaTransformMx);
0576: Arrays.fill(glTransformMx, 0);
0577: glTransformMx[0] = javaTransformMx[0];
0578: glTransformMx[1] = javaTransformMx[1];
0579: glTransformMx[4] = javaTransformMx[2];
0580: glTransformMx[5] = javaTransformMx[3];
0581: glTransformMx[12] = javaTransformMx[4];
0582: glTransformMx[13] = javaTransformMx[5];
0583: glTransformMx[10] = 1;
0584: glTransformMx[15] = 1;
0585:
0586: LockedArray lMx = Utils.arraccess
0587: .lockArrayShort(glTransformMx);
0588: gl.glLoadMatrixd(lMx.getAddress());
0589: lMx.release();
0590: }
0591: }
0592:
0593: // Fix line rasterization
0594: gl.glTranslated(0.375, 0.375, 0);
0595:
0596: // Update paint if it is TexturePaint or GradientPaint
0597: if (texPaint || gradTexName != 0) {
0598: resetPaint();
0599: }
0600: }
0601: }
0602:
0603: @Override
0604: public Shape getClip() {
0605: if (clip == null) {
0606: return null;
0607: }
0608:
0609: MultiRectArea res = new MultiRectArea(clip);
0610: return res;
0611: }
0612:
0613: @Override
0614: public Rectangle getClipBounds() {
0615: if (clip == null) {
0616: return null;
0617: }
0618:
0619: Rectangle res = (Rectangle) clip.getBounds().clone();
0620: return res;
0621: }
0622:
0623: @Override
0624: public AffineTransform getTransform() {
0625: return (AffineTransform) glTransform.clone();
0626: }
0627:
0628: @Override
0629: public void rotate(double theta) {
0630: glTransform.rotate(theta);
0631: setTransform(glTransform);
0632: }
0633:
0634: @Override
0635: public void rotate(double theta, double x, double y) {
0636: glTransform.rotate(theta, x, y);
0637: setTransform(glTransform);
0638: }
0639:
0640: @Override
0641: public void scale(double sx, double sy) {
0642: glTransform.scale(sx, sy);
0643: setTransform(glTransform);
0644: }
0645:
0646: @Override
0647: public void shear(double shx, double shy) {
0648: glTransform.shear(shx, shy);
0649: setTransform(glTransform);
0650: }
0651:
0652: @Override
0653: public void transform(AffineTransform at) {
0654: AffineTransform newTransform = (AffineTransform) glTransform
0655: .clone();
0656: newTransform.concatenate(at);
0657: setTransform(newTransform);
0658: }
0659:
0660: @Override
0661: public void translate(double tx, double ty) {
0662: AffineTransform newTransform = (AffineTransform) glTransform
0663: .clone();
0664: newTransform.translate(tx, ty);
0665: setTransform(newTransform);
0666: }
0667:
0668: @Override
0669: public void translate(int tx, int ty) {
0670: AffineTransform newTransform = (AffineTransform) glTransform
0671: .clone();
0672: newTransform.translate(tx, ty);
0673: setTransform(newTransform);
0674: }
0675:
0676: @Override
0677: public void clipRect(int x, int y, int width, int height) {
0678: MultiRectArea mra = new MultiRectArea(x, y, x + width - 1, y
0679: + height - 1);
0680:
0681: if (clip == null) {
0682: setTransformedClip(mra);
0683: } else {
0684: clip.intersect(mra);
0685: setTransformedClip(clip);
0686: }
0687: }
0688:
0689: @Override
0690: public void fillRect(int x, int y, int width, int height) {
0691: if (oglPaint) {
0692: makeCurrent();
0693: gl.glRectd(x, y, x + width, y + height);
0694: gl.glFlush();
0695: } else {
0696: super .fillRect(x, y, width, height);
0697: }
0698:
0699: getSurface().updateScene();
0700: }
0701:
0702: @Override
0703: public void drawLine(int x1, int y1, int x2, int y2) {
0704: if (nativeLines && !scalingTransform && oglPaint) {
0705: makeCurrent();
0706:
0707: int vertices[] = new int[4];
0708: vertices[0] = x1;
0709: vertices[1] = y1;
0710: vertices[2] = x2;
0711: vertices[3] = y2;
0712:
0713: LockedArray lVertices = Utils.arraccess
0714: .lockArrayShort(vertices);
0715: gl.glVertexPointer(2, GLDefs.GL_INT, 0, lVertices
0716: .getAddress());
0717: gl.glDrawArrays(GLDefs.GL_LINES, 0, vertices.length / 2);
0718: lVertices.release();
0719:
0720: gl.glFlush();
0721: } else {
0722: super .drawLine(x1, y1, x2, y2);
0723: }
0724:
0725: getSurface().updateScene();
0726: }
0727:
0728: private final void resetClip() {
0729: setTransformedClip(clip);
0730: }
0731:
0732: private final void resetColor() {
0733: setColor(fgColor);
0734: }
0735:
0736: private final void resetTransform() {
0737: setTransform(glTransform);
0738: }
0739:
0740: private final void resetBounds() {
0741: // Set viewport and projection
0742: // Always set the viewport to the whole window
0743: gl.glViewport(0, 0, winBounds.width, winBounds.height);
0744:
0745: gl.glMatrixMode(GLDefs.GL_PROJECTION);
0746: gl.glLoadIdentity();
0747: gl.gluOrtho2D(0, winBounds.width, winBounds.height, 0);
0748:
0749: gl.glMatrixMode(GLDefs.GL_MODELVIEW);
0750: }
0751:
0752: private static class OGLContextValidator {
0753: private static final ThreadLocal<OGLGraphics2D> localCurrentGraphics = new ThreadLocal<OGLGraphics2D>();
0754:
0755: private static final void validateContext(OGLGraphics2D g) {
0756: OGLGraphics2D lastGraphics = localCurrentGraphics.get();
0757:
0758: if (lastGraphics == null) {
0759: // No graphics was used before in the current thread, so
0760: // opengl context of this thread should be initialized first
0761:
0762: // Single-buffered
0763: gl.glDrawBuffer(GLDefs.GL_FRONT);
0764: gl.glReadBuffer(GLDefs.GL_FRONT);
0765:
0766: gl.glEnableClientState(GLDefs.GL_VERTEX_ARRAY);
0767: gl.glDisable(GLDefs.GL_DITHER);
0768:
0769: localCurrentGraphics.set(g);
0770:
0771: if (g.blitter instanceof NullBlitter) {
0772: // Called from constructor, skipping validation.
0773: // Everything will be done in the constructor.
0774: return;
0775: }
0776: // New context in the thread, but old graphics from other thread,
0777: // have to validate all.
0778: g.resetBounds();
0779: g.resetColor();
0780: g.resetTransform();
0781: g.resetClip();
0782: g.checkComposite();
0783: g.resetStroke();
0784: g.resetPaint();
0785: return;
0786: } else if (g == lastGraphics) { // Should have all the attributes in place
0787: return;
0788: }
0789:
0790: localCurrentGraphics.set(g);
0791:
0792: if (!g.winBounds.equals(lastGraphics.winBounds)) {
0793: g.resetBounds();
0794: }
0795:
0796: if (!g.fgColor.equals(lastGraphics.fgColor)) {
0797: g.resetColor();
0798: }
0799:
0800: boolean transformDiffers = !g.glTransform
0801: .equals(lastGraphics.glTransform);
0802: if (transformDiffers) {
0803: g.resetTransform();
0804: }
0805:
0806: if (g.clip == null) {
0807: if (lastGraphics.clip != null) {
0808: g.resetClip();
0809: }
0810: } else if (!g.clip.equals(lastGraphics.clip)
0811: || transformDiffers) {
0812: g.resetClip();
0813: }
0814:
0815: if (!g.composite.equals(lastGraphics.composite)) {
0816: g.checkComposite();
0817: }
0818:
0819: if (!g.stroke.equals(lastGraphics.stroke)) {
0820: g.resetStroke();
0821: }
0822:
0823: if (!g.paint.equals(lastGraphics.paint)) {
0824: g.resetPaint();
0825: }
0826: }
0827: }
0828:
0829: @Override
0830: public void setComposite(Composite composite) {
0831: super .setComposite(composite);
0832:
0833: makeCurrent();
0834: checkComposite();
0835: }
0836:
0837: /**
0838: * NOTE - caller should call makeCurrent() before calling this method
0839: */
0840: final void checkComposite() {
0841: if (composite instanceof AlphaComposite) {
0842: AlphaComposite ac = (AlphaComposite) composite;
0843: acAlpha = ac.getAlpha();
0844:
0845: if (ac.getAlpha() == 1
0846: && opaqueColor
0847: && (ac.getRule() == AlphaComposite.SRC_OVER || ac
0848: .getRule() == AlphaComposite.SRC)) {
0849: gl.glDisable(GLDefs.GL_BLEND);
0850: } else {
0851: enableAlphaComposite(ac, true, true);
0852: //gl.glEnable(GLDefs.GL_BLEND);
0853: }
0854:
0855: if (ac.getAlpha() != 1) {
0856: setColor(bgColor);
0857: }
0858: } else {
0859: acAlpha = 1.0f;
0860: }
0861: }
0862:
0863: /**
0864: * NOTE - caller should call makeCurrent() before calling this method
0865: * @param ac
0866: * @param srcPremult
0867: * @param srcHasAlpha
0868: * @return true if caller should not premultiply the source, false otherwise
0869: */
0870: final static boolean enableAlphaComposite(AlphaComposite ac,
0871: boolean srcPremult, boolean srcHasAlpha) {
0872: float acAlpha = ac.getAlpha();
0873: int acRule = ac.getRule();
0874:
0875: int srcFactor;
0876: int dstFactor;
0877: int alphaFactor = BLEND_RULE_MAPPING_SRC_PREMULT[acRule];
0878:
0879: boolean needPremultiply = false;
0880:
0881: if (srcHasAlpha) {
0882: if (srcPremult || !HAVE_MAPPING_NO_PREMULT[acRule]) {
0883: srcFactor = BLEND_RULE_MAPPING_SRC_PREMULT[acRule];
0884: if (!srcPremult) { // Caller should premultiply the source
0885: needPremultiply = true;
0886: }
0887: } else {
0888: srcFactor = BLEND_RULE_MAPPING_SRC_NO_PREMULT[acRule];
0889: }
0890: dstFactor = BLEND_RULE_MAPPING_DST[acRule];
0891: } else {
0892: srcFactor = BLEND_RULE_MAPPING_SRC_PREMULT[acRule];
0893:
0894: if (srcFactor == GLDefs.GL_ONE && acAlpha == 1) {
0895: gl.glDisable(GLDefs.GL_BLEND);
0896: return true;
0897: }
0898:
0899: dstFactor = BLEND_RULE_MAPPING_DST_NO_ALPHA[acRule];
0900: }
0901:
0902: gl.glEnable(GLDefs.GL_BLEND);
0903:
0904: if (srcFactor == alphaFactor) {
0905: gl.glBlendFunc(srcFactor, dstFactor);
0906: } else {
0907: gl.glBlendFuncSeparate(srcFactor, dstFactor, alphaFactor,
0908: dstFactor);
0909: }
0910:
0911: // Setup alpha scaling for the case when alpha in AlphaComposite != 1
0912: gl.glPixelTransferf(GLDefs.GL_ALPHA_SCALE, acAlpha);
0913: if (srcPremult || needPremultiply) {
0914: gl.glPixelTransferf(GLDefs.GL_RED_SCALE, acAlpha);
0915: gl.glPixelTransferf(GLDefs.GL_GREEN_SCALE, acAlpha);
0916: gl.glPixelTransferf(GLDefs.GL_BLUE_SCALE, acAlpha);
0917: } else {
0918: gl.glPixelTransferf(GLDefs.GL_RED_SCALE, 1);
0919: gl.glPixelTransferf(GLDefs.GL_GREEN_SCALE, 1);
0920: gl.glPixelTransferf(GLDefs.GL_BLUE_SCALE, 1);
0921: }
0922:
0923: return needPremultiply;
0924: }
0925:
0926: final OGLSurface getSurface() {
0927: return (OGLSurface) dstSurf;
0928: }
0929:
0930: void readPixels(int x, int y, int w, int h, Object buffer,
0931: boolean topToBottom) {
0932: // Save current graphics to restore current context after returning pixels
0933: OGLGraphics2D currGraphics = OGLContextValidator.localCurrentGraphics
0934: .get();
0935: makeCurrent();
0936: /*
0937: x += glTransform.getTranslateX() + 0.5;
0938: y += glTransform.getTranslateY() + 0.5;
0939: */
0940: LockedArray lBuffer = Utils.arraccess.lockArrayShort(buffer);
0941:
0942: if (topToBottom) {
0943: // Need to read scanlines one-by-one to make them go from top to bottom.
0944: // OpenGL allows to read from bottom to top only.
0945: int sourceRow = winBounds.height - y - 1;
0946: for (int i = 0; i < h; i++, sourceRow--) {
0947: gl.glPixelStorei(GLDefs.GL_PACK_SKIP_ROWS, i);
0948: gl.glReadPixels(x, sourceRow, w, 1, GLDefs.GL_BGRA,
0949: GLDefs.GL_UNSIGNED_INT_8_8_8_8_REV, lBuffer
0950: .getAddress());
0951: }
0952: } else {
0953: gl.glReadPixels(x, winBounds.height - y - h, w, h,
0954: GLDefs.GL_BGRA, GLDefs.GL_UNSIGNED_INT_8_8_8_8_REV,
0955: lBuffer.getAddress());
0956: }
0957:
0958: lBuffer.release();
0959:
0960: gl.glPixelStorei(GLDefs.GL_PACK_SKIP_ROWS, 0);
0961:
0962: if (currGraphics != null && currGraphics != this ) {
0963: currGraphics.makeCurrent();
0964: }
0965: }
0966:
0967: @Override
0968: public void setStroke(Stroke stroke) {
0969: super .setStroke(stroke);
0970: if (stroke instanceof BasicStroke) {
0971: BasicStroke bs = (BasicStroke) stroke;
0972: if (bs.getLineWidth() <= 1.) {
0973: if (bs.getDashArray() != null) {
0974: if (setLineStipplePattern(bs.getDashArray(), bs
0975: .getDashPhase())) {
0976: nativeLines = true;
0977: resetStroke();
0978: return;
0979: }
0980: } else {
0981: nativeLines = true;
0982: stipplePattern = 0;
0983: resetStroke();
0984: return;
0985: }
0986: }
0987: }
0988:
0989: nativeLines = false;
0990: stipplePattern = 0;
0991: }
0992:
0993: /**
0994: * Calculates opengl line stipple parameters from dashArray and dashPhase taken from
0995: * BasicStroke.
0996: * @param dashArray - array, taken from BasicStroke
0997: * @param dashPhase - phase, taken from BasicStroke
0998: * @return fasle if it is impossible to use glLineStipple, true otherwise.
0999: */
1000: private boolean setLineStipplePattern(float dashArray[],
1001: float dashPhase) {
1002: // if there's odd number of elements in the dash array, we repeat it twice
1003: int longArrLength = dashArray.length % 2 == 0 ? dashArray.length
1004: : dashArray.length * 2;
1005: long longArray[] = new long[longArrLength];
1006: long longPhase = Math.round(dashPhase);
1007: BigInteger gcd = BigInteger.valueOf(Math.round(dashArray[0]));
1008: int sum = 0;
1009: for (int i = 0; i < longArrLength; i++) {
1010: longArray[i] = Math.round(dashArray[i % dashArray.length]);
1011: gcd = gcd.gcd(BigInteger.valueOf(longArray[i]));
1012: sum += longArray[i];
1013: }
1014:
1015: if (dashPhase != 0) {
1016: gcd = gcd.gcd(BigInteger.valueOf(longPhase));
1017: longPhase /= gcd.longValue();
1018: }
1019:
1020: sum /= gcd.longValue();
1021:
1022: if (sum > 16) {
1023: return false;
1024: }
1025:
1026: int repeatNum;
1027:
1028: switch (sum) {
1029: case 1:
1030: repeatNum = 16;
1031: break;
1032: case 2:
1033: repeatNum = 8;
1034: break;
1035: case 4:
1036: repeatNum = 4;
1037: break;
1038: case 8:
1039: repeatNum = 2;
1040: break;
1041: case 16:
1042: repeatNum = 1;
1043: break;
1044: default:
1045: return false;
1046: }
1047:
1048: int intPattern = 0;
1049: stippleFactor = (int) gcd.longValue();
1050:
1051: for (int i = 0; i < repeatNum; i++) {
1052: for (int j = longArray.length - 1; j >= 0; j--) {
1053: long currPatternLen = longArray[j] / stippleFactor;
1054: intPattern <<= currPatternLen;
1055: if ((j & 0x1) == 0) {
1056: intPattern |= (1 << currPatternLen) - 1;
1057: }
1058: }
1059: }
1060:
1061: if (longPhase != 0) { // cyclic shift
1062: intPattern = (intPattern >>> longPhase)
1063: | (intPattern << (16 - longPhase));
1064: }
1065:
1066: stipplePattern = (short) (intPattern & 0xFFFF);
1067:
1068: return true;
1069: }
1070:
1071: /**
1072: * Validates stroke.
1073: */
1074: void resetStroke() {
1075: if (nativeLines) {
1076: // Use opengl only for 1-width lines, don't need to set width
1077: if (stipplePattern == 0) {
1078: gl.glDisable(GLDefs.GL_LINE_STIPPLE);
1079: } else {
1080: gl.glEnable(GLDefs.GL_LINE_STIPPLE);
1081: gl.glLineStipple(stippleFactor, stipplePattern);
1082: }
1083: } else {
1084: gl.glDisable(GLDefs.GL_LINE_STIPPLE);
1085: }
1086: }
1087:
1088: @Override
1089: public void drawPolygon(Polygon polygon) {
1090: drawPolygon(polygon.xpoints, polygon.ypoints, polygon.npoints);
1091: }
1092:
1093: @Override
1094: public void drawPolygon(int[] xpoints, int[] ypoints, int npoints) {
1095: drawPoly(xpoints, ypoints, npoints, true);
1096: }
1097:
1098: @Override
1099: public void drawPolyline(int[] xpoints, int[] ypoints, int npoints) {
1100: drawPoly(xpoints, ypoints, npoints, false);
1101: }
1102:
1103: private final void drawPoly(int[] xpoints, int[] ypoints,
1104: int npoints, boolean closed) {
1105: if (nativeLines && !scalingTransform && oglPaint) {
1106: makeCurrent();
1107:
1108: int vertices[] = new int[npoints << 1];
1109: for (int i = 0; i < npoints; i++) {
1110: vertices[i << 1] = xpoints[i];
1111: vertices[(i << 1) + 1] = ypoints[i];
1112: }
1113:
1114: LockedArray lVertices = Utils.arraccess
1115: .lockArrayShort(vertices);
1116: gl.glVertexPointer(2, GLDefs.GL_INT, 0, lVertices
1117: .getAddress());
1118: gl.glDrawArrays(closed ? GLDefs.GL_LINE_LOOP
1119: : GLDefs.GL_LINE_STRIP, 0, vertices.length / 2);
1120: lVertices.release();
1121:
1122: gl.glFlush();
1123: } else {
1124: if (closed) {
1125: super .drawPolygon(xpoints, ypoints, npoints);
1126: } else {
1127: super .drawPolyline(xpoints, ypoints, npoints);
1128: }
1129: }
1130:
1131: getSurface().updateScene();
1132: }
1133:
1134: @Override
1135: public void draw(Shape s) {
1136: // To get proper rasterization quality need to
1137: // perform scaling before rasterization
1138: if (scalingTransform) {
1139: s = stroke.createStrokedShape(s);
1140: s = glTransform.createTransformedShape(s);
1141: gl.glPushMatrix();
1142: gl.glLoadIdentity();
1143: fillMultiRectArea(jsr.rasterize(s, 0.5));
1144: gl.glPopMatrix();
1145: } else {
1146: super .draw(s);
1147: }
1148: }
1149:
1150: void activateTexturePaint(TexturePaint p) {
1151: Rectangle2D r = p.getAnchorRect();
1152: /*
1153: if (r.getX() != 0 || r.getY() != 0) {
1154: gl.glPixelStoref(GLDefs.GL_UNPACK_SKIP_PIXELS, (float)r.getX());
1155: gl.glPixelStoref(GLDefs.GL_UNPACK_SKIP_ROWS, (float)r.getY());
1156: }
1157: */
1158: Surface srcSurf = Surface.getImageSurface(p.getImage());
1159:
1160: int width = (int) r.getWidth();
1161: int height = (int) r.getHeight();
1162:
1163: OGLBlitter oglBlitter = (OGLBlitter) blitter;
1164:
1165: OGLBlitter.OGLTextureParams tp = oglBlitter
1166: .blitImg2OGLTexCached(srcSurf, srcSurf.getWidth(),
1167: srcSurf.getHeight(), true);
1168:
1169: gl.glTexParameteri(GLDefs.GL_TEXTURE_2D,
1170: GLDefs.GL_TEXTURE_WRAP_S, GLDefs.GL_REPEAT);
1171: gl.glTexParameteri(GLDefs.GL_TEXTURE_2D,
1172: GLDefs.GL_TEXTURE_WRAP_T, GLDefs.GL_REPEAT);
1173:
1174: gl.glTexGeni(GLDefs.GL_S, GLDefs.GL_TEXTURE_GEN_MODE,
1175: GLDefs.GL_OBJECT_LINEAR);
1176: gl.glTexGeni(GLDefs.GL_T, GLDefs.GL_TEXTURE_GEN_MODE,
1177: GLDefs.GL_OBJECT_LINEAR);
1178:
1179: double sObjPlane[] = new double[4];
1180: double tObjPlane[] = new double[4];
1181:
1182: // If texture is power of two, take [0;1]x[0;1] square - this is the texture
1183: // coordinates range. Then create mapping of anchor rect onto it.
1184: // For NPOT texture take [0;size/p2size]x[0;size/p2size] square.
1185: double widthFactor = (double) width / tp.width * tp.p2w;
1186: double heightFactor = (double) height / tp.height * tp.p2h;
1187:
1188: sObjPlane[0] = 1. / widthFactor;
1189: sObjPlane[1] = 0;
1190: sObjPlane[2] = 0;
1191: sObjPlane[3] = -r.getX() / widthFactor;
1192:
1193: tObjPlane[0] = 0;
1194: tObjPlane[1] = 1. / heightFactor;
1195: tObjPlane[2] = 0;
1196: tObjPlane[3] = -r.getY() / heightFactor;
1197:
1198: LockedArray la = Utils.arraccess.lockArrayShort(sObjPlane);
1199: gl.glTexGendv(GLDefs.GL_S, GLDefs.GL_OBJECT_PLANE, la
1200: .getAddress());
1201: la.release();
1202: la = Utils.arraccess.lockArrayShort(tObjPlane);
1203: gl.glTexGendv(GLDefs.GL_T, GLDefs.GL_OBJECT_PLANE, la
1204: .getAddress());
1205: la.release();
1206:
1207: gl.glEnable(GLDefs.GL_TEXTURE_GEN_S);
1208: gl.glEnable(GLDefs.GL_TEXTURE_GEN_T);
1209:
1210: gl.glEnable(GLDefs.GL_TEXTURE_2D);
1211: }
1212:
1213: /*
1214: static final void reactivateTexturePaint() {
1215: gl.glEnable(GLDefs.GL_TEXTURE_GEN_S);
1216: gl.glEnable(GLDefs.GL_TEXTURE_GEN_T);
1217: gl.glEnable(GLDefs.GL_TEXTURE_2D);
1218: }
1219: */
1220: static final void deactivateTexturePaint() {
1221: gl.glDisable(GLDefs.GL_TEXTURE_GEN_S);
1222: gl.glDisable(GLDefs.GL_TEXTURE_GEN_T);
1223: gl.glDisable(GLDefs.GL_TEXTURE_2D);
1224: }
1225:
1226: @Override
1227: protected void fillMultiRectAreaPaint(MultiRectArea mra) {
1228: if (oglPaint) {
1229: fillMultiRectAreaColor(mra);
1230: } else {
1231: super .fillMultiRectAreaPaint(mra);
1232: }
1233: }
1234:
1235: private final void activateGradientPaint(GradientPaint gp) {
1236: byte twoPixels[] = new byte[8];
1237: int val1 = gp.getColor1().getRGB();
1238: int val2 = gp.getColor2().getRGB();
1239: twoPixels[0] = (byte) ((val1 >> 16) & 0xFF);
1240: twoPixels[1] = (byte) ((val1 >> 8) & 0xFF);
1241: twoPixels[2] = (byte) (val1 & 0xFF);
1242: twoPixels[3] = (byte) ((val1 >> 24) & 0xFF);
1243: twoPixels[4] = (byte) ((val2 >> 16) & 0xFF);
1244: twoPixels[5] = (byte) ((val2 >> 8) & 0xFF);
1245: twoPixels[6] = (byte) (val2 & 0xFF);
1246: twoPixels[7] = (byte) ((val2 >> 24) & 0xFF);
1247:
1248: // Get gradient endpoints in the device space
1249: Point2D p1 = gp.getPoint1();
1250: Point2D p2 = gp.getPoint2();
1251: double x1 = p1.getX();
1252: double y1 = p1.getY();
1253: double x2 = p2.getX();
1254: double y2 = p2.getY();
1255: /**
1256: * Let us denote by a1, a2 and a3 object plane coefficients for texture s coordinate:
1257: * s = a1*x + a2*y + a3
1258: * Want to create following mapping for the texture s coordinate:
1259: * x1,y1 -> 0,25
1260: * x2,y2 -> 0,75
1261: * x3,y3 -> 0,25
1262: * where (x3-x1,y3-y1) is perpendicular to (x2-x1,y2-y1).
1263: * 0,25 and 0,75 are centers of the first and second pixels, where
1264: * the color should have the full intensity.
1265: * From this have 3 equations for a1, a2 and a3.
1266: * They are solved, using cramer's rule in the code below.
1267: */
1268: double x3 = x1 + y2 - y1;
1269: double y3 = y1 + x1 - x2;
1270: double d1 = (y3 - y1) * 0.5;
1271: double d2 = (x1 - x3) * 0.5;
1272: double d = -((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
1273: double a1 = d1 / d;
1274: double a2 = d2 / d;
1275: double a3 = 0.25 - a1 * x1 - a2 * y1;
1276:
1277: gradObjectPlane = new double[4];
1278: gradObjectPlane[0] = a1;
1279: gradObjectPlane[1] = a2;
1280: gradObjectPlane[2] = 0;
1281: gradObjectPlane[3] = a3;
1282:
1283: // Create 1D texture object
1284: Int32Pointer texPtr = NativeBridge.getInstance()
1285: .createInt32Pointer(1, true);
1286: gl.glGenTextures(1, texPtr);
1287: gradTexName = texPtr.get(0);
1288: gl.glBindTexture(GLDefs.GL_TEXTURE_1D, gradTexName);
1289: texPtr.free();
1290: gl.glTexParameteri(GLDefs.GL_TEXTURE_1D,
1291: GLDefs.GL_TEXTURE_MAG_FILTER, GLDefs.GL_LINEAR);
1292: gl.glTexParameteri(GLDefs.GL_TEXTURE_1D,
1293: GLDefs.GL_TEXTURE_MIN_FILTER, GLDefs.GL_LINEAR);
1294: gl.glTexEnvf(GLDefs.GL_TEXTURE_ENV, GLDefs.GL_TEXTURE_ENV_MODE,
1295: GLDefs.GL_REPLACE);
1296:
1297: // Setup texture coordinates generation
1298: isGPCyclic = gp.isCyclic();
1299: gl.glTexParameteri(GLDefs.GL_TEXTURE_1D,
1300: GLDefs.GL_TEXTURE_WRAP_S, isGPCyclic ? GLDefs.GL_REPEAT
1301: : GLDefs.GL_CLAMP_TO_EDGE);
1302: gl.glTexGeni(GLDefs.GL_S, GLDefs.GL_TEXTURE_GEN_MODE,
1303: GLDefs.GL_OBJECT_LINEAR);
1304: LockedArray la = Utils.arraccess
1305: .lockArrayShort(gradObjectPlane);
1306: gl.glTexGendv(GLDefs.GL_S, GLDefs.GL_OBJECT_PLANE, la
1307: .getAddress());
1308: la.release();
1309: gl.glEnable(GLDefs.GL_TEXTURE_GEN_S);
1310:
1311: // Load data into texture
1312: la = Utils.arraccess.lockArrayShort(twoPixels);
1313: gl.glTexImage1D(GLDefs.GL_TEXTURE_1D, 0, GLDefs.GL_RGBA, 2, 0,
1314: GLDefs.GL_RGBA, GLDefs.GL_UNSIGNED_BYTE, la
1315: .getAddress());
1316: la.release();
1317:
1318: // Enable 1D texture
1319: gl.glEnable(GLDefs.GL_TEXTURE_1D);
1320: }
1321:
1322: private final void reactivateGradientPaint() {
1323: gl.glBindTexture(GLDefs.GL_TEXTURE_1D, gradTexName);
1324: LockedArray la = Utils.arraccess
1325: .lockArrayShort(gradObjectPlane);
1326: gl.glTexGendv(GLDefs.GL_S, GLDefs.GL_OBJECT_PLANE, la
1327: .getAddress());
1328: la.release();
1329: gl.glTexParameteri(GLDefs.GL_TEXTURE_1D,
1330: GLDefs.GL_TEXTURE_WRAP_S, isGPCyclic ? GLDefs.GL_REPEAT
1331: : GLDefs.GL_CLAMP_TO_EDGE);
1332: gl.glEnable(GLDefs.GL_TEXTURE_1D);
1333: }
1334:
1335: private final void deactivateGradientPaint() {
1336: gl.glDisable(GLDefs.GL_TEXTURE_1D);
1337: if (gradTexName != 0) {
1338: OGLBlitter.OGLTextureParams.deleteTexture(gradTexName);
1339: gradTexName = 0;
1340: }
1341: }
1342:
1343: /**
1344: * This method supposes that context is already current and validated.
1345: * It only changes current read drawable to the drawable of other
1346: * OGLGraphics2D object. It returnes false if contexts of this OGLGraphics2D
1347: * and OGLGraphics2D passed in read parameter differs. To provide normal operation
1348: * after using read drawable caller should restore state by calling makeCurrent().
1349: * @param read - OGLGraphics2D which provides read drawable
1350: * @return true on success
1351: */
1352: private final boolean setCurrentRead(OGLGraphics2D read) {
1353: long oglContext = ctxmgr.getOGLContext(nwin.getId(), oshdc);
1354: if (read.ctxmgr.getOGLContext(read.nwin.getId(), read.oshdc) != oglContext)
1355: return false;
1356:
1357: ctxmgr.makeContextCurrent(oglContext, nwin.getId(), read.nwin
1358: .getId(), oshdc, read.oshdc);
1359: return true;
1360: }
1361:
1362: boolean copyArea(int x, int y, int width, int height, int dx,
1363: int dy, OGLGraphics2D read, boolean texture) {
1364: if (!setCurrentRead(read)) {
1365: return false;
1366: }
1367:
1368: gl.glPixelStoref(GLDefs.GL_UNPACK_SKIP_PIXELS, 0);
1369: gl.glPixelStoref(GLDefs.GL_UNPACK_SKIP_ROWS, 0);
1370:
1371: gl.glPixelZoom(1, 1);
1372:
1373: // Raster position could be outside of the viewport, use glBitmap
1374: gl.glRasterPos2i(0, 0);
1375: gl.glBitmap(0, 0, 0, 0, dx, -dy - height, 0);
1376:
1377: x += read.glTransform.getTranslateX() + 0.5;
1378: y += read.glTransform.getTranslateY() + 0.5;
1379:
1380: if (!texture) {
1381: gl.glCopyPixels(x, read.winBounds.height - y - height,
1382: width, height, GLDefs.GL_COLOR);
1383: gl.glFlush();
1384:
1385: } else {
1386: gl.glCopyTexSubImage2D(GLDefs.GL_TEXTURE_2D, 0, 0, 0, x,
1387: read.winBounds.height - y - height, width, height);
1388: }
1389:
1390: getSurface().updateScene();
1391:
1392: makeCurrent();
1393: return true;
1394: }
1395: }
|