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

Source Code of org.apache.harmony.awt.gl.opengl.OGLTextRenderer$DLInfo

/*
*  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.
*/

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

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.font.GlyphMetrics;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.IndexColorModel;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.lang.ref.SoftReference;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;

import org.apache.harmony.awt.gl.Surface;
import org.apache.harmony.awt.gl.TextRenderer;
import org.apache.harmony.awt.gl.font.CommonGlyphVector;
import org.apache.harmony.awt.gl.font.FontPeerImpl;
import org.apache.harmony.awt.gl.font.Glyph;

import org.apache.harmony.misc.HashCode;

import org.apache.harmony.awt.internal.nls.Messages;

public class OGLTextRenderer extends TextRenderer {   

    private static final TextureCache tx = TextureCache.getInstance();
    private static final GL gl = GL.getInstance();
   
    private static final HashSet ESCAPE = new HashSet<Character>();
    static {
        ESCAPE.add(new Character('\n'));
        ESCAPE.add(new Character('\r'));
        ESCAPE.add(new Character('\t'));
    }
   
    private static final Hashtable intHash2glyphHash = new SoftHashtable();  
   
    private static final Vector toDel = new Vector<Integer>();
   
    private static final Color INVISIBLE_COLOR = new Color(0,0,0,(float)0);
   
    public static final BufferedImage getBufImg(byte[] pixels, int width, int height, Color color) {       
        if (pixels == null) {           
            return new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_BINARY);
        }

        WritableRaster wr = Raster.createPackedRaster(
                new DataBufferByte(pixels, pixels.length),
                (pixels.length / height) << 3,
                height,
                1,
                null
        );
       
        int[] masColors = new int[]{ (int)0x000000, color.getRGB()};
       
        IndexColorModel colorModel = new IndexColorModel(1, 2, masColors, 0,true,0,DataBuffer.TYPE_BYTE)

        BufferedImage bim = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_INDEXED, colorModel);
       
        bim.setData( wr.createWritableChild(0, 0, width, height, 0, 0, null));
       
        return bim;
    }
   
    /**
     * Draws string on specified Graphics at desired position.
     *
     * @param g specified Graphics2D object
     * @param str String object to draw
     * @param x start X position to draw
     * @param y start Y position to draw
     */
    public void drawString(Graphics2D g, String str, float x, float y) {       
        char[] input = str.toCharArray();
        Character ch;
        Glyph glyph;
        DLInfo info;
        GlyphMetrics glMetrics;
        Color col = g.getColor();
        Font font = g.getFont();       
        int lenght = str.length();
        FontPeerImpl peer = ((FontPeerImpl)font.getPeer());
        AffineTransform fontAT = (AffineTransform)font.getTransform().clone();
        Point.Float pos = new Point.Float();
        Paint paint = g.getPaint();
        boolean isAntialias = g.getRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING) == RenderingHints.VALUE_TEXT_ANTIALIAS_ON;
       
        try {
            fontAT.inverseTransform(new Point.Double(x + fontAT.getTranslateX(), y + fontAT.getTranslateY()), pos);
        } catch (NoninvertibleTransformException e) {  
//          TODO determinant equals 0 => point or line
            g.fill(font.createGlyphVector(g.getFontRenderContext(), str).getOutline(x, y));
            return;
        }
       
        fontAT.translate(pos.x,pos.y);
        g.transform(fontAT);
       
        HashCode hash = new HashCode();
        hash.append(peer);
        hash.append(getFactor(g.getTransform()));
        hash.append(paint);
        hash.append(isAntialias);
        Integer intHash = new Integer(hash.hashCode());
       
        GlyphHashtable glyphHash =
            intHash2glyphHash.containsKey(intHash) ?
                    (GlyphHashtable) intHash2glyphHash.get(intHash) : null;
        if ( glyphHash == null) {
            glyphHash = new GlyphHashtable();
            intHash2glyphHash. put(intHash, glyphHash);
        }
       
        activateVars();       
       
        for (int i = 0; i - lenght < 0; i ++) {
            ch = new Character(input[i]);
            if (ESCAPE.contains(ch)) continue;
            glyph = peer.getGlyph(input[i]);
           
            if (ch == ' ') {
                glMetrics = glyph.getGlyphPointMetrics();
                gl.glTranslated(
                        glMetrics.getAdvanceX(),
                        glMetrics.getAdvanceY(),
                        0
                );
                continue;
            }
           
            info = glyphHash.containsKey(ch) ? (DLInfo)glyphHash.get(ch) : null;
           
            if (info == null || !info.isValid()) {
                createColorGlyphDL(g, glyph, glyphHash, font, ch, col, isAntialias);
            } else {
                gl.glCallList(info.getDL());
            }           
           
            glMetrics = glyph.getGlyphPointMetrics();
            gl.glTranslated(
                    glMetrics.getAdvanceX(),
                    glMetrics.getAdvanceY(),
                    0
            );           
           
        }
        deactivateVars();
        cleanLists();
       
    }

    /**
     * Draws GlyphVector on specified Graphics at desired position.
     *
     * @param g specified Graphics2D object
     * @param glyphVector GlyphVector object to draw
     * @param x start X position to draw
     * @param y start Y position to draw
     */
    public void drawGlyphVector(Graphics2D g, GlyphVector gv, float x, float y) {
        Character ch;
        DLInfo info;
        Color col = g.getColor();
        Glyph[] input = ((CommonGlyphVector)gv).vector;       
        Font font = gv.getFont();
        int lenght = gv.getNumGlyphs();
        FontPeerImpl peer = ((FontPeerImpl)font.getPeer());
        AffineTransform fontAT = (AffineTransform)font.getTransform().clone();
        Point.Float pos = new Point.Float();
        boolean isAntialias = g.getRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING) == RenderingHints.VALUE_TEXT_ANTIALIAS_ON;  
       
        try {
            fontAT.inverseTransform(new Point.Double(x + fontAT.getTranslateX(), y + fontAT.getTranslateY()), pos);
        } catch (NoninvertibleTransformException e) {
            //TODO determinant equals 0 => point or line
            g.fill(gv.getOutline(x, y));
            return;
        }
       
        fontAT.translate(pos.getX(), pos.getY());
        g.transform(fontAT);       
       
        HashCode hash = new HashCode();
        hash.append(peer);
        hash.append(getFactor(g.getTransform()));
        hash.append(g.getPaint());
        hash.append(isAntialias);       
        Integer intHash = new Integer(hash.hashCode());
       
        GlyphHashtable glyphHash =
            intHash2glyphHash.containsKey(intHash) ?
                    (GlyphHashtable) intHash2glyphHash.get(intHash) : null;
        if ( glyphHash == null) {
            glyphHash = new GlyphHashtable();
            intHash2glyphHash. put(intHash, glyphHash);
        }       
       
        fontAT = (AffineTransform) font.getTransform().clone();
        activateVars();
        for (int i = 0; i - lenght < 0; i ++) {
            ch = new Character(input[i].getChar());
           
            if (ch == ' ') continue;
           
            info = glyphHash.containsKey(ch) ? (DLInfo)glyphHash.get(ch) : null;           
            try {
                fontAT.inverseTransform(gv.getGlyphPosition(i), pos);
            } catch (NoninvertibleTransformException e) {               
            }
           
            gl.glTranslated(pos.x, pos.y, 0);
            if (info == null || !info.isValid()) {               
                createColorGlyphDL(g, input[i], glyphHash, font, ch, col, isAntialias);               
            } else {               
                gl.glCallList(info.getDL());    
            }                  
            gl.glTranslated(-pos.x, -pos.y, 0);
        }    
        deactivateVars();       
        cleanLists();
    }   
   
    /**
     * @param ogl
     * @param glyph
     * @param glyphHash
     * @param font
     */
    private void createColorGlyphDL(Graphics2D g, Glyph glyph, GlyphHashtable glyphHash, Font font, Character ch, Color col, boolean isAntialias) {
        int base = gl.glGenLists(1);
        if (base == 0) {
            //awt.296 can't allocate memory on video card to create new display list
            throw new NullPointerException(Messages.getString("awt.296"));
        }       
            
        double texSize = getFactor(g.getTransform());
       
        Glyph newGlyph = ((FontPeerImpl)(font.deriveFont(
                (float)(font.getSize2D() * texSize))).getPeer())
                .getGlyph(ch.charValue());
       
        byte[] pixels = newGlyph.getBitmap();
       
        BufferedImage bim = getBufImg(
                pixels,
                newGlyph.getPointWidth(),
                newGlyph.getPointHeight(),
                col
                );
       
        Rectangle.Double rect = new Rectangle.Double(
                Math.round(glyph.getGlyphPointMetrics().getLSB()),
                Math.round(-newGlyph.bmp_top  / texSize),
                glyph.getPointWidth(),
                glyph.getPointHeight()
                );       
       
        Surface sur = Surface.getImageSurface(bim);
       
        OGLBlitter.OGLTextureParams tp =  OGLBlitter.getInstance().blitImg2OGLTexCached(
                sur,
                bim.getWidth(),
                bim.getHeight(),
                true
        );
       
        gl.glTexParameteri(GLDefs.GL_TEXTURE_2D, GLDefs.GL_TEXTURE_WRAP_S, GLDefs.GL_CLAMP_TO_EDGE);
        gl.glTexParameteri(GLDefs.GL_TEXTURE_2D, GLDefs.GL_TEXTURE_WRAP_T, GLDefs.GL_CLAMP_TO_EDGE);
       
        if (isAntialias) {
                gl.glTexParameteri(GLDefs.GL_TEXTURE_2D, GLDefs.GL_TEXTURE_MAG_FILTER, GLDefs.GL_LINEAR);
                gl.glTexParameteri(GLDefs.GL_TEXTURE_2D, GLDefs.GL_TEXTURE_MIN_FILTER, GLDefs.GL_LINEAR);
        } else {
                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);
        }
       
        double widthFactor = rect.getWidth() / tp.width * tp.p2w;
        double heightFactor = rect.getHeight() / tp.height * tp.p2h;
       
        gl.glNewList(base, GLDefs.GL_COMPILE_AND_EXECUTE);
       
        g.setColor(INVISIBLE_COLOR);       
       
        gl.glBindTexture(GLDefs.GL_TEXTURE_2D, tp.textureName);

        gl.glBegin(GLDefs.GL_QUADS);

        gl.glTexCoord2d(0.0, 0.0);
        gl.glVertex2d(rect.getX(), rect.getY());
        gl.glTexCoord2d(0.0, rect.getHeight()/heightFactor);
        gl.glVertex2d(rect.getX(), rect.getY() + rect.getHeight());
        gl.glTexCoord2d(rect.getWidth()/widthFactor,rect.getHeight()/heightFactor);
        gl.glVertex2d(rect.getWidth() + rect.getX(), rect.getY() + rect.getHeight());
        gl.glTexCoord2d(rect.getWidth()/widthFactor,0.0);
        gl.glVertex2d(rect.getWidth() + rect.getX(), rect.getY());

        gl.glEnd();
       
        g.setColor(col);       
       
        gl.glEndList();
       
        glyphHash.put(ch, new DLInfo(base, sur));       
       
//        System.out.println("create new dl - " + base);       
    }
   
    private double getFactor(AffineTransform at) {       
        return Math.max(at.getScaleX(), at.getScaleY());
    }
   
    private void cleanLists() {
        synchronized(toDel) {
            if (!toDel.isEmpty()) {           
                 for (Iterator iter = toDel.iterator(); iter.hasNext();) {
                    int element = ((Integer)iter.next()).intValue();               
                    if (gl.glIsList(element) == GLDefs.GL_TRUE) {   

                        gl.glDeleteLists(element, 1);   
//                        System.err.println("delete dl - " + element);
                    }
                }          
                toDel.clear();
            }
        }
    }   
   
    private void activateVars() {
//        gl.glPixelStorei(GLDefs.GL_UNPACK_ALIGNMENT, 1);     
        gl.glTexEnvf(GLDefs.GL_TEXTURE_ENV, GLDefs.GL_TEXTURE_ENV_MODE, GLDefs.GL_REPLACE);
       
        gl.glTexParameteri(GLDefs.GL_TEXTURE_2D, GLDefs.GL_TEXTURE_WRAP_S, GLDefs.GL_CLAMP_TO_EDGE);
        gl.glTexParameteri(GLDefs.GL_TEXTURE_2D, GLDefs.GL_TEXTURE_WRAP_T, GLDefs.GL_CLAMP_TO_EDGE);

        gl.glTexGeni(GLDefs.GL_S, GLDefs.GL_TEXTURE_GEN_MODE, GLDefs.GL_OBJECT_LINEAR);
        gl.glTexGeni(GLDefs.GL_T, GLDefs.GL_TEXTURE_GEN_MODE, GLDefs.GL_OBJECT_LINEAR);       
       
        gl.glDisable(GLDefs.GL_TEXTURE_GEN_S);
        gl.glDisable(GLDefs.GL_TEXTURE_GEN_T);

        gl.glEnable(GLDefs.GL_TEXTURE_2D);
    }
   
    private void deactivateVars() {
        gl.glDisable(GLDefs.GL_TEXTURE_2D);
    }
   
    private static final class SoftHashtable extends Hashtable {

        public Object put(Object key,Object obj) {
            SoftReference ref = (SoftReference)super.put(key,new SoftReference(obj));
            return ref == null ? null : ref.get();
        }

        public Object get(Object key) {
            SoftReference ref = (SoftReference)super.get(key);
            return ref == null ? null : ref.get();
        }

        public Object remove(Object key) {
            SoftReference ref = (SoftReference)super.remove(key);
            return ref == null ? null : ref.get();
        }
    }
   
    private static final class GlyphHashtable extends Hashtable {
        public void finalize() throws Throwable {
            super.finalize();
            synchronized(toDel) {
                for (Iterator i = this.values().iterator(); i.hasNext();) {
                    toDel.add(new Integer(((DLInfo) i.next()).getDL()));               
                }
            }
        }       
    }
   
    private static final class DLInfo {
        private int dl;
        private Surface srf;
        public DLInfo(int dl, Surface srf) {
            this.dl = dl;
            this.srf = srf;
        }     
       
        public int getDL() {
            return dl;
        }
       
        public Surface getSrf() {
            return srf;
        }
       
        public boolean isValid() {               
            if (tx.findTexture(srf) == null) {
                synchronized (toDel) {
                    toDel.add(new Integer(dl));
                }
                return false;
            }
           
            return gl.glIsList(dl) == GLDefs.GL_TRUE;           
        }
    }

}
TOP

Related Classes of org.apache.harmony.awt.gl.opengl.OGLTextRenderer$DLInfo

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.