Package org.apache.harmony.awt.gl.opengl

Source Code of org.apache.harmony.awt.gl.opengl.OGLBlitter$OGLImageParams

/*
*  Licensed to the Apache Software Foundation (ASF) under one or more
*  contributor license agreements.  See the NOTICE file distributed with
*  this work for additional information regarding copyright ownership.
*  The ASF licenses this file to You under the Apache License, Version 2.0
*  (the "License"); you may not use this file except in compliance with
*  the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
/**
* @author Oleg V. Khaschansky
* @version $Revision$
*/

package org.apache.harmony.awt.gl.opengl;

import org.apache.harmony.awt.gl.render.Blitter;
import org.apache.harmony.awt.gl.*;
import org.apache.harmony.awt.nativebridge.NativeBridge;
import org.apache.harmony.awt.nativebridge.Int32Pointer;
import org.apache.harmony.misc.accessors.LockedArray;

import java.awt.geom.AffineTransform;
import java.awt.*;
import java.awt.image.ColorModel;
import java.awt.image.BufferedImage;

public class OGLBlitter implements Blitter {
    private static final GL gl = GL.getInstance();

    private static final OGLBlitter inst = new OGLBlitter();

    private static final class OGLImageParams {
        OGLImageParams(
                int format, int intFormat,
                int type, int alignment,
                boolean requiresConversion
        ) {
            oglFormat = format;
            oglIntFormat = intFormat;
            oglType = type;
            oglAlignment = alignment;
            this.requiresConversion = requiresConversion;
        }

        int oglFormat;
        int oglIntFormat;
        int oglType;
        int oglAlignment;
        boolean requiresConversion;
    }

    static final class OGLTextureParams {
        OGLTextureParams(int tName, int p2w, int p2h, int w, int h) {
            textureName = tName;
            this.p2w = p2w;
            this.p2h = p2h;
            width = w;
            height = h;
        }

        int textureName;

        // Actual texture width and height
        int p2w;
        int p2h;

        // Size of the used part of the texture
        int width;
        int height;

        final void deleteTexture() {
            deleteTexture(textureName);
            textureName = 0;
        }

        static final void deleteTexture(int textureName) {
            if (textureName != 0) {
                Int32Pointer texPtr =
                        NativeBridge.getInstance().createInt32Pointer(1, true);
                texPtr.set(0, textureName);
                gl.glDeleteTextures(1, texPtr);
                texPtr.free();
            }
        }
    };

    private static final OGLImageParams IMAGE_TYPE_MAPPING[] = new OGLImageParams [] {
        new OGLImageParams(GLDefs.GL_BGRA, 4, GLDefs.GL_UNSIGNED_INT_8_8_8_8_REV, 4, true), // TYPE_CUSTOM = 0
        new OGLImageParams(GLDefs.GL_BGR, 3, GLDefs.GL_UNSIGNED_INT_8_8_8_8_REV, 4, false), // TYPE_INT_RGB = 1
        new OGLImageParams(GLDefs.GL_BGRA, 4, GLDefs.GL_UNSIGNED_INT_8_8_8_8_REV, 4, false), // TYPE_INT_ARGB = 2
        new OGLImageParams(GLDefs.GL_BGRA, 4, GLDefs.GL_UNSIGNED_INT_8_8_8_8_REV, 4, false), // TYPE_INT_ARGB_PRE = 3
        new OGLImageParams(GLDefs.GL_RGB, 3, GLDefs.GL_UNSIGNED_INT_8_8_8_8_REV, 4, false), // TYPE_INT_BGR = 4
        new OGLImageParams(GLDefs.GL_BGR, 3, GLDefs.GL_UNSIGNED_BYTE, 1, false), // TYPE_3BYTE_BGR = 5
        new OGLImageParams(GLDefs.GL_RGBA, 4, GLDefs.GL_UNSIGNED_INT_8_8_8_8_REV, 4, false), // TYPE_4BYTE_ABGR = 6
        new OGLImageParams(GLDefs.GL_RGBA, 4, GLDefs.GL_UNSIGNED_INT_8_8_8_8_REV, 4, false), // TYPE_4BYTE_ABGR_PRE = 7
        new OGLImageParams(GLDefs.GL_RGB, 3, GLDefs.GL_UNSIGNED_SHORT_5_6_5, 2, false), // TYPE_USHORT_565_RGB = 8
        new OGLImageParams(GLDefs.GL_BGR, 3, GLDefs.GL_UNSIGNED_SHORT_1_5_5_5_REV, 2, false), // TYPE_USHORT_555_RGB = 9
        new OGLImageParams(GLDefs.GL_LUMINANCE, 1, GLDefs.GL_UNSIGNED_BYTE, 1, false), // TYPE_BYTE_GRAY = 10
        new OGLImageParams(GLDefs.GL_LUMINANCE, 1, GLDefs.GL_UNSIGNED_SHORT, 2, false), // TYPE_USHORT_GRAY = 11
        new OGLImageParams(GLDefs.GL_BGR, 3, GLDefs.GL_UNSIGNED_INT_8_8_8_8_REV, 4, true), // TYPE_BYTE_BINARY = 12
        new OGLImageParams(GLDefs.GL_BGRA, 4, GLDefs.GL_UNSIGNED_INT_8_8_8_8_REV, 4, true) // TYPE_BYTE_INDEXED = 13
    };

    public static OGLBlitter getInstance(){
        return inst;
    }

    public void blit(
            int srcX, int srcY, Surface srcSurf,
            int dstX, int dstY, Surface dstSurf,
            int width, int height,
            AffineTransform sysxform, AffineTransform xform,
            Composite comp, Color bgcolor, MultiRectArea clip
    ) {
        int type = xform.getType();
        switch (type) {
            case AffineTransform.TYPE_TRANSLATION:
                dstX += xform.getTranslateX();
                dstY += xform.getTranslateY();
            case AffineTransform.TYPE_IDENTITY:
                 blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf,
                         width, height, sysxform, comp, bgcolor, clip);
                break;
            default:
                AffineTransform at = (AffineTransform) sysxform.clone();
                at.concatenate(xform);
                blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf,
                        width, height, at, comp, bgcolor, clip);
        }
    }

    public void blit(
            int srcX, int srcY, Surface srcSurf,
            int dstX, int dstY, Surface dstSurf,
            int width, int height,
            AffineTransform sysxform,
            Composite comp, Color bgcolor, MultiRectArea clip
    ) {
        int type = sysxform.getType();
        switch (type) {
            case AffineTransform.TYPE_TRANSLATION:
                dstX += sysxform.getTranslateX();
                dstY += sysxform.getTranslateY();
            case AffineTransform.TYPE_IDENTITY:
                blitImpl(
                        srcX, srcY, srcSurf,
                        dstX, dstY, dstSurf,
                        width, height,
                        comp, bgcolor, clip,
                        null
                );
                break;
            default:
                blitImpl(
                        srcX, srcY, srcSurf,
                        dstX, dstY, dstSurf,
                        width, height,
                        comp, bgcolor, clip,
                        sysxform
                );
        }
    }

    public void blit(
            int srcX, int srcY, Surface srcSurf,
            int dstX, int dstY, Surface dstSurf,
            int width, int height,
            Composite comp, Color bgcolor, MultiRectArea clip
    ) {
        blitImpl(
            srcX, srcY, srcSurf,
            dstX, dstY, dstSurf,
            width, height,
            comp, bgcolor, clip,
            null
        );
    }

    private final void blitImpl(
            int srcX, int srcY, Surface srcSurf,
            int dstX, int dstY, Surface dstSurf,
            int width, int height,
            Composite comp, Color bgcolor, MultiRectArea clip,
            AffineTransform xform
    ) {
        OGLSurface oglDstSurf = (OGLSurface) dstSurf;
        OGLGraphics2D oglg = oglDstSurf.oglg;
        oglg.makeCurrent();

        // Set the requested clip, saving current clip
        MultiRectArea oldClip = (MultiRectArea) oglg.getClip();
        boolean needRestoreClip = false;
        if ((clip == null && oldClip != null) || !clip.equals(oldClip)) {
            oglg.setTransformedClip(clip);
            needRestoreClip = true;
        } else {
            oldClip = null;
        }

        // Fill the background if needed
        if (
                srcSurf.getColorModel().getTransparency() != Transparency.OPAQUE &&
                bgcolor != null
        ) {
            if (xform == null) {
                oglg.fillRect(dstX, dstY, width, height);
            } else {
                Rectangle bounds = new Rectangle(srcX, srcY, width, height);
                Shape tBounds = xform.createTransformedShape(bounds);
                AffineTransform dstT = AffineTransform.getTranslateInstance(dstX, dstY);
                tBounds = dstT.createTransformedShape(tBounds);
                Color savedc = oglg.getColor();
                oglg.setColor(bgcolor);
                oglg.fill(tBounds);
                oglg.setColor(savedc);
            }
        }

        if (srcX != 0 || srcY != 0) {
            gl.glPixelStoref(GLDefs.GL_UNPACK_SKIP_PIXELS, srcX);
            gl.glPixelStoref(GLDefs.GL_UNPACK_SKIP_ROWS, srcY);
        }

        ColorModel srcCM = srcSurf.getColorModel();

        boolean needRestoreComposite = false;
        boolean needPremultiply = false;
        if (comp instanceof AlphaComposite) {
            if (
                    !oglg.getComposite().equals(comp) ||
                    !srcCM.isAlphaPremultiplied() ||
                    srcCM.hasAlpha() == oglg.opaqueColor
            ) {
                needPremultiply =
                        OGLGraphics2D.enableAlphaComposite(
                                (AlphaComposite) comp,
                                srcCM.isAlphaPremultiplied(),
                                srcCM.hasAlpha()
                        );
                needRestoreComposite = true;
            }
        } else {
            // XXX - todo - custom composite
        }

        boolean oglSrc = false; //srcSurf instanceof OGLSurface;

        if (xform == null && !oglSrc) {
            // glCopyPixels works very slow on some NV GPU's.
            /*
            boolean copied = (srcSurf instanceof OGLSurface) &&
                oglg.copyArea(
                        srcX, srcY,
                        width, height,
                        dstX, dstY,
                        ((OGLSurface) srcSurf).oglg
                );

            if(!copied) {
            */
            blitImg2OGL(
                    srcSurf,
                    width, height,
                    dstX, dstY,
                    needPremultiply
            );
            //}
        } else {
            OGLTextureParams tp;
            if (oglSrc) { // We have opengl source with or w/o transform
                tp = blitOGL2OGLTexCached(
                        (OGLSurface) srcSurf,
                        oglDstSurf,
                        srcX, srcY,
                        dstX, dstY,
                        width, height
                );

                if (tp == null) { // Can't copy texture, use readPixels
                    oglSrc = false;
                    tp = blitImg2OGLTexCached(
                            srcSurf,
                            width, height,
                            needPremultiply
                    );
                }
            } else { // Non opengl source
                tp = blitImg2OGLTexCached(
                        srcSurf,
                        width, height,
                        needPremultiply
                );
            }

            double xCoord = (double)width/tp.p2w;
            double yCoord = (double)height/tp.p2h;

            double vertices[] = new double[8];
            if (!oglSrc) {
                vertices[0] = srcX;
                vertices[1] = srcY;
                vertices[2] = srcX + width;
                vertices[3] = srcY;
                vertices[4] = srcX + width;
                vertices[5] = srcY + height;
                vertices[6] = srcX;
                vertices[7] = srcY + height;
            } else {
                vertices[6] = srcX;
                vertices[7] = srcY;
                vertices[4] = srcX + width;
                vertices[5] = srcY;
                vertices[2] = srcX + width;
                vertices[3] = srcY + height;
                vertices[0] = srcX;
                vertices[1] = srcY + height;
            }

            if (xform != null) {
                xform.transform(vertices, 0, vertices, 0, 4);
            }

            for (int i = 0; i < vertices.length; i++) {
                vertices[i] += (i%2 == 0) ? dstX : dstY;
            }

            gl.glEnable(GLDefs.GL_TEXTURE_2D);
            gl.glBegin(GLDefs.GL_QUADS);

            gl.glTexCoord2d(0.0, 0.0);
            gl.glVertex2d(vertices[0], vertices[1]);
            gl.glTexCoord2d(xCoord, 0.0);
            gl.glVertex2d(vertices[2], vertices[3]);
            gl.glTexCoord2d(xCoord, yCoord);
            gl.glVertex2d(vertices[4], vertices[5]);
            gl.glTexCoord2d(0.0, yCoord);
            gl.glVertex2d(vertices[6], vertices[7]);

            gl.glEnd();
            gl.glFlush();
            gl.glDisable(GLDefs.GL_TEXTURE_2D);

            //tp.deleteTexture();
        }

        if (needRestoreClip) {
            oglg.setTransformedClip(oldClip);
        }

        if (needRestoreComposite) {
            oglg.checkComposite();
        }
    }

    private void blitImg2OGL(
            Surface srcSurf,
            int width, int height,
            int dstX, int dstY,
            boolean needPremultiply
    ) {
        OGLImageParams imageParams = IMAGE_TYPE_MAPPING[srcSurf.getSurfaceType()];
        boolean requiresConversion = imageParams.requiresConversion;
        if (requiresConversion || needPremultiply) {
            imageParams = IMAGE_TYPE_MAPPING[BufferedImage.TYPE_INT_ARGB_PRE];
        }

        gl.glPixelStorei(GLDefs.GL_UNPACK_ALIGNMENT, imageParams.oglAlignment);

        ColorModel srcCM = srcSurf.getColorModel();

        // Obtain image data in opengl-compatible format and draw the image
        if (requiresConversion || needPremultiply) {
            // Set the raster position to the destination point
            gl.glRasterPos2i(0, 0);
            gl.glBitmap(0, 0, 0, 0, dstX, -dstY, 0);

            gl.glPixelZoom(1, -1);

            // needPremultiply should be always false for OGLSurface, type cast is safe
            gl.glDrawPixels(
                    width, height,
                    imageParams.oglFormat, imageParams.oglType,
                    ((ImageSurface) srcSurf).getCachedData(
                            srcCM.isAlphaPremultiplied() || needPremultiply
                    )
            );
        } else {
            Object data;
            if (srcSurf instanceof OGLSurface) {
                data = ((OGLSurface) srcSurf).getBottomToTopData();

                // Set the raster position to the destination point
                gl.glRasterPos2i(0, 0);
                gl.glBitmap(0, 0, 0, 0, dstX, -dstY-height, 0);

                gl.glPixelZoom(1, 1);
            } else {
                data = srcSurf.getData();

                // Set the raster position to the destination point
                gl.glRasterPos2i(0, 0);
                gl.glBitmap(0, 0, 0, 0, dstX, -dstY, 0);

                gl.glPixelZoom(1, -1);
            }

            LockedArray ldata = Utils.arraccess.lockArrayShort(data);
            gl.glDrawPixels(
                    width, height,
                    imageParams.oglFormat, imageParams.oglType,
                    ldata.getAddress()
            );
            ldata.release();
        }
    }

    /**
     * Calculates the next power of 2 from the size
     * @param size - arbitrary positive integer
     * @return next to the size power of 2
     */
    private final static int p2(int size) {
        size--;
        size |= size >> 1;
        size |= size >> 2;
        size |= size >> 4;
        size |= size >> 8;
        size |= size >> 16;
        return ++size;
    }

    private final OGLTextureParams blitImg2OGLTex(
            Surface srcSurf,
            int width, int height,
            boolean needPremultiply,
            OGLTextureParams tp
    ) {
        OGLImageParams imageParams = IMAGE_TYPE_MAPPING[srcSurf.getSurfaceType()];
        boolean requiresConversion = imageParams.requiresConversion;
        if (requiresConversion || needPremultiply) {
            imageParams = IMAGE_TYPE_MAPPING[BufferedImage.TYPE_INT_ARGB_PRE];
        }

        gl.glPixelStorei(GLDefs.GL_UNPACK_ALIGNMENT, imageParams.oglAlignment);

        ColorModel srcCM = srcSurf.getColorModel();

        int p2w = p2(width);
        int p2h = p2(height);

        if (tp == null) {
            Int32Pointer texPtr =
                    NativeBridge.getInstance().createInt32Pointer(1, true);

            gl.glGenTextures(1, texPtr);
            int texName = texPtr.get(0);
            gl.glBindTexture(GLDefs.GL_TEXTURE_2D, texName);
            texPtr.free();

            gl.glTexParameteri(GLDefs.GL_TEXTURE_2D, GLDefs.GL_TEXTURE_MAG_FILTER, GLDefs.GL_NEAREST);
            gl.glTexParameteri(GLDefs.GL_TEXTURE_2D, GLDefs.GL_TEXTURE_MIN_FILTER, GLDefs.GL_NEAREST);

            tp = new OGLTextureParams(texName, p2w, p2h, width, height);
        } else {
            gl.glBindTexture(GLDefs.GL_TEXTURE_2D, tp.textureName);
            tp.width = width;
            tp.height = height;
            tp.p2w = p2w;
            tp.p2h = p2h;
        }

        // XXX - todo - check for texture non p2 extension
        gl.glTexImage2D(
                GLDefs.GL_TEXTURE_2D, 0,
                imageParams.oglIntFormat,
                p2w, p2h, 0,
                imageParams.oglFormat, imageParams.oglType,
                0
        );

        // Obtain image data in opengl-compatible format and draw the image
        if (requiresConversion || needPremultiply) {
            // needPremultiply should be always false for OGLSurface, type cast is safe
            gl.glTexSubImage2D(
                    GLDefs.GL_TEXTURE_2D, 0, 0, 0,
                    //imageParams.oglIntFormat,
                    width, height, // 0,
                    imageParams.oglFormat, imageParams.oglType,
                    ((ImageSurface) srcSurf).getCachedData(
                            srcCM.isAlphaPremultiplied() || needPremultiply
                    )
            );
        } else {
            Object data = srcSurf.getData();
            LockedArray ldata = Utils.arraccess.lockArrayShort(data);
            gl.glTexSubImage2D(
                    GLDefs.GL_TEXTURE_2D, 0, 0, 0,
                    //imageParams.oglIntFormat,
                    width, height, //0,
                    imageParams.oglFormat, imageParams.oglType,
                    ldata.getAddress()
            );

            ldata.release();
        }

        return tp;
    }

    final OGLTextureParams blitImg2OGLTexCached(
            Surface srcSurf,
            int width, int height,
            boolean needPremultiply
    ) {
        TextureCache tc = TextureCache.getInstance();
        OGLTextureParams tp = tc.findTexture(srcSurf);

        if (tp != null) {
            if (width > tp.width || height > tp.height || !srcSurf.isCaheValid(tp)) {
                tp = blitImg2OGLTex(
                        srcSurf,
                        width, height,
                        needPremultiply,
                        tp
                );
                srcSurf.addValidCache(tp);
            } else {
                gl.glBindTexture(GLDefs.GL_TEXTURE_2D, tp.textureName);
            }
        } else {
            tp = blitImg2OGLTex(
                    srcSurf,
                    width, height,
                    needPremultiply,
                    null
            );
            tc.add(srcSurf, tp);
            srcSurf.addValidCache(tp);
            tc.cleanupTextures();
        }

        gl.glTexEnvf(GLDefs.GL_TEXTURE_ENV, GLDefs.GL_TEXTURE_ENV_MODE, GLDefs.GL_REPLACE);

        return tp;
    }

    private final OGLTextureParams blitOGL2OGLTexCached(
            OGLSurface srcSurf,
            OGLSurface dstSurf,
            int srcX, int srcY,
            int dstX, int dstY,
            int width, int height
    ) {
        TextureCache tc = TextureCache.getInstance();
        OGLTextureParams tp = tc.findTexture(srcSurf);

        if (tp != null) {
            if (width > tp.width || height > tp.height || !srcSurf.isCaheValid(tp)) {
                tp = blitOGL2OGLTex(
                        srcSurf,
                        dstSurf,
                        srcX, srcY,
                        dstX, dstY,
                        width, height,
                        tp
                );
                srcSurf.addValidCache(tp);
            } else {
                gl.glBindTexture(GLDefs.GL_TEXTURE_2D, tp.textureName);
            }
        } else {
            tp = blitOGL2OGLTex(
                    srcSurf,
                    dstSurf,
                    srcX, srcY,
                    dstX, dstY,
                    width, height,
                    null
            );
            tc.add(srcSurf, tp);
            srcSurf.addValidCache(tp);
            tc.cleanupTextures();
        }

        gl.glTexEnvf(GLDefs.GL_TEXTURE_ENV, GLDefs.GL_TEXTURE_ENV_MODE, GLDefs.GL_REPLACE);

        return tp;
    }

    private final OGLTextureParams blitOGL2OGLTex(
            OGLSurface srcSurf,
            OGLSurface dstSurf,
            int srcX, int srcY,
            int dstX, int dstY,
            int width, int height,
            OGLTextureParams tp
    ) {
        OGLImageParams imageParams = IMAGE_TYPE_MAPPING[BufferedImage.TYPE_INT_ARGB_PRE];
        gl.glPixelStorei(GLDefs.GL_UNPACK_ALIGNMENT, imageParams.oglAlignment);

        int p2w = p2(width);
        int p2h = p2(height);

        if (tp == null) {
            Int32Pointer texPtr =
                    NativeBridge.getInstance().createInt32Pointer(1, true);

            gl.glGenTextures(1, texPtr);
            int texName = texPtr.get(0);
            gl.glBindTexture(GLDefs.GL_TEXTURE_2D, texName);
            texPtr.free();

            gl.glTexParameteri(GLDefs.GL_TEXTURE_2D, GLDefs.GL_TEXTURE_MAG_FILTER, GLDefs.GL_NEAREST);
            gl.glTexParameteri(GLDefs.GL_TEXTURE_2D, GLDefs.GL_TEXTURE_MIN_FILTER, GLDefs.GL_NEAREST);

            tp = new OGLTextureParams(texName, p2w, p2h, width, height);
        } else {
            gl.glBindTexture(GLDefs.GL_TEXTURE_2D, tp.textureName);
            tp.width = width;
            tp.height = height;
            tp.p2w = p2w;
            tp.p2h = p2h;
        }

        // XXX - todo - check for texture non p2 extension
        gl.glTexImage2D(
                GLDefs.GL_TEXTURE_2D, 0,
                imageParams.oglIntFormat,
                p2w, p2h, 0,
                imageParams.oglFormat, imageParams.oglType,
                0
        );

        // Obtain image data in opengl-compatible format and draw the image
        boolean copied = dstSurf.oglg.copyArea(
                srcX, srcY,
                width, height,
                dstX, dstY,
                (srcSurf).oglg,
                true
        );

        return copied ? tp : null;
    }

}
TOP

Related Classes of org.apache.harmony.awt.gl.opengl.OGLBlitter$OGLImageParams

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.
div>