Subversion Repositories AndroidProjects

Rev

Blame | Last modification | View Log | RSS feed

package com.gebauz.bauzoid.graphics;

import java.io.IOException;
import java.util.Vector;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.gebauz.bauzoid.app.Consts;
import com.gebauz.bauzoid.file.File;
import com.gebauz.bauzoid.file.FileUtil;
import com.gebauz.bauzoid.graphics.sprite.Sprite;
import com.gebauz.bauzoid.graphics.sprite.SpriteRegion;
import com.gebauz.bauzoid.parser.ScanException;
import com.gebauz.bauzoid.parser.Tokenizer;

public class FontUtil
{
        public static final String LOG_TAG = Consts.LOG_TAG + ":FontUtil";
        public static boolean verbose = true;
       
        private static class CharacterRect
        {
                public float x;
                public float y;
                public float w;
                public float h;
               
                public CharacterRect(float _x, float _y, float _w, float _h)
                {
                        x = _x;
                        y = _y;
                        w = _w;
                        h = _h;
                }
        }
       
        private static class CharacterOffset
        {
                public float x;
                public float y;
               
                public CharacterOffset(float _x, float _y)
                {
                        x = _x;
                        y = _y;
                }
        }
       
        private static class KerningPair
        {
                public char first;
                public char second;
                public int value;
               
                public KerningPair(char a, char b, int n)
                {
                        first = a;
                        second = b;
                        value = n;
                }
        }
       
       
        private FontUtil() {}
       
        public static void log(String tag, String msg)
        {
                if (verbose)
                        Gdx.app.log(tag, msg);                 
        }
       
        public static Font createFontFromBinaryFile(Graphics graphics, FileHandle file)
        {
                Vector<Character> charList = new Vector<Character>();
                Vector<Float> widthList = new Vector<Float>();
                Vector<CharacterRect> rectList = new Vector<CharacterRect>();
                Vector<CharacterOffset> offsetList = new Vector<CharacterOffset>();
                Vector<KerningPair> kerningPairs = new Vector<KerningPair>();
       
                //Font font = new Font(graphics);
                //Texture texture = null;
                String textureFileFull = null;
               
                float multiplier = 1.0f;
                float ascent = 10.0f;
               
                try
                {
                        File f = new File(file.read());
                       
                        int version = f.readInt();
                        if (version != 100)
                        {
                                Gdx.app.log(LOG_TAG, "Version mismatch: 100 != " + version);
                                return null;
                        }                      
                       
                        String textureFile = f.readString();
                        textureFileFull = FileUtil.extractPath(file.path()) + "/" + textureFile;
                        //texture = new Texture(Gdx.files.internal(filename));
                       
                        ascent = f.readFloat();
                        multiplier = f.readFloat();
                       
                        // Read character list (char * num)
                        int numChars = f.readInt(); // number of characters
                        for (int i = 0; i < numChars; i++)
                        {
                                Character c = f.readChar();
                                charList.add(c);                               
                        }
                       
                        // Read width list (float * num)
                        int numWidths = f.readInt(); // number of widths
                        for (int i = 0; i < numWidths; i++)
                        {
                                Float width = f.readFloat();
                                widthList.add(width);
                        }
                       
                        // Read rect list (CharRect * num)
                        int numRects = f.readInt(); // number of rects
                        for (int i = 0; i < numRects; i++)
                        {
                                float x = f.readFloat();
                                float y = f.readFloat();
                                float w = f.readFloat();
                                float h = f.readFloat();
                               
                                rectList.add(new CharacterRect(x, y, w, h));
                        }
                       
                        // Read offset list (CharOffset * num)
                        int numOffsets = f.readInt(); // number of offsets
                        for (int i = 0; i < numOffsets; i++)
                        {
                                float x = f.readFloat();
                                float y = f.readFloat();
                               
                                offsetList.add(new CharacterOffset(x, y));                             
                        }
                       
                        // number of kerning pairs
                        int numKerning = f.readInt();
                       
                        // Read kerning pairs + values
                        for (int i = 0; i < numKerning; i++)
                        {
                                char a = f.readChar();
                                char b = f.readChar();
                                int v = f.readInt();
                               
                                kerningPairs.add(new KerningPair(a, b, v));                            
                        }
                       
                        f.close();
                }
                catch (IOException e)
                {
                        Gdx.app.log(LOG_TAG, "Could not read font!");          
                }
               
                return buildFont(graphics, charList, widthList, rectList, offsetList, textureFileFull, multiplier, ascent, kerningPairs);
        }
       
        public static Font createFontFromFile(Graphics graphics, FileHandle file)
        {
                String fileContents = file.readString();
               
                Vector<Character> charList = null;
                Vector<Float> widthList = null;
                Vector<CharacterRect> rectList = null;
                Vector<CharacterOffset> offsetList = null;
                Vector<KerningPair> kerningPairs = null;
                Vector<Integer> kerningValues = null;
       
                //Texture texture = null;
                String textureFile = null;
               
                float ascent = 10.0f;          
                float multiplier = 1.0f;
               
                try
                {
                        Tokenizer tokenizer = new Tokenizer(fileContents);
                        tokenizer.setStringDelimiter(new char[] {'\'', '"'} );
                       
                        while (!tokenizer.checkNoMoreTokens())
                        {
                                String identifier = tokenizer.readIdentifier();
                               
                                if (identifier.equalsIgnoreCase("Define"))
                                {
                                        // Define
                                        String define = tokenizer.readIdentifier();
                                       
                                        if (define.equalsIgnoreCase("CharList"))
                                        {
                                                charList = parseCharList(tokenizer);
                                        }
                                        else if (define.equalsIgnoreCase("WidthList"))
                                        {
                                                widthList = parseWidthList(tokenizer);
                                        }
                                        else if (define.equalsIgnoreCase("RectList"))
                                        {
                                                rectList = parseRectList(tokenizer);
                                        }
                                        else if (define.equalsIgnoreCase("OffsetList"))
                                        {
                                                offsetList = parseOffsetList(tokenizer);
                                        }
                                        else if (define.equalsIgnoreCase("KerningPairs"))
                                        {
                                                kerningPairs = parseKerningPairs(tokenizer);                                           
                                        }
                                        else if (define.equalsIgnoreCase("KerningValues"))
                                        {
                                                kerningValues = parseKerningValues(tokenizer);
                                        }
                                        tokenizer.readToken(";");
                                }
                                else if (identifier.equalsIgnoreCase("CreateLayer"))
                                {
                                        tokenizer.readIdentifier();
                                        tokenizer.readToken(";");
                                }
                                else if (identifier.equalsIgnoreCase("LayerSetImage"))
                                {
                                        tokenizer.readIdentifier();
                                        //String filename = FileUtil.extractPath(file.path()) + "/" + tokenizer.readString() + ".png";
                                        textureFile = FileUtil.extractPath(file.path()) + "/" + tokenizer.readString() + ".png";
                                       
                                        //texture = new Texture(Gdx.files.internal(filename));
                                       
                                        tokenizer.readToken(";");
                                }
                                else if (identifier.equalsIgnoreCase("LayerRegionMultiplier"))
                                {
                                        tokenizer.readIdentifier();
                                       
                                        multiplier = tokenizer.readNumber();
                                        tokenizer.readToken(";");
                                }
                                else if (identifier.equalsIgnoreCase("LayerSetAscent"))
                                {
                                        tokenizer.readIdentifier();
                                        ascent = tokenizer.readNumber();
                                        tokenizer.readToken(";");
                                }
                                else if (identifier.equalsIgnoreCase("LayerSetCharWidths"))
                                {
                                        tokenizer.readIdentifier();
                                        if (tokenizer.checkIdentifier())
                                        {
                                                tokenizer.readIdentifier();
                                                tokenizer.readIdentifier();
                                        }
                                        else if (tokenizer.checkToken("("))
                                        {
                                                Vector<Character> charListExtra = parseCharList(tokenizer);
                                                Vector<Float> widthListExtra = parseWidthList(tokenizer);
                                               
                                                charList.addAll(charListExtra);
                                                widthList.addAll(widthListExtra);
                                        }
                                        tokenizer.readToken(";");
                                }
                                else if (identifier.equalsIgnoreCase("LayerSetImageMap"))
                                {
                                        tokenizer.readIdentifier();
                                        tokenizer.readIdentifier();
                                        tokenizer.readIdentifier();
                                        tokenizer.readToken(";");
                                }
                                else if (identifier.equalsIgnoreCase("LayerSetCharOffsets"))
                                {
                                        tokenizer.readIdentifier();
                                        tokenizer.readIdentifier();
                                        tokenizer.readIdentifier();
                                        tokenizer.readToken(";");
                                }              
                                else if (identifier.equalsIgnoreCase("LayerSetAscentPadding"))
                                {
                                        tokenizer.readIdentifier();
                                        tokenizer.readNumber();
                                        tokenizer.readToken(";");
                                }              
                                else if (identifier.equalsIgnoreCase("LayerSetLineSpacingOffset"))
                                {
                                        tokenizer.readIdentifier();
                                        tokenizer.readNumber();
                                        tokenizer.readToken(";");
                                }              
                                else if (identifier.equalsIgnoreCase("LayerSetPointSize"))
                                {
                                        tokenizer.readIdentifier();
                                        tokenizer.readNumber();
                                        tokenizer.readToken(";");
                                }              
                                else if (identifier.equalsIgnoreCase("SetDefaultPointSize"))
                                {
                                        tokenizer.readNumber();
                                        tokenizer.readToken(";");
                                }
                                else if (identifier.equalsIgnoreCase("LayerSetKerningPairs"))
                                {
                                        tokenizer.readIdentifier();
                                        tokenizer.readIdentifier();
                                        tokenizer.readIdentifier();
                                        tokenizer.readToken(";");
                                       
                                        // set kerning values
                                        for (int i = 0; i < kerningPairs.size(); i++)
                                        {
                                                kerningPairs.elementAt(i).value = kerningValues.elementAt(i);
                                        }
                                }
                                else if (identifier.equalsIgnoreCase("ConvertGreyScaleToAlpha"))
                                {
                                        tokenizer.readNumber();
                                        tokenizer.readToken(";");
                                }
                        }
                       
                }
                catch (ScanException ex)
                {
                        ex.log(LOG_TAG);
                }
               
                return buildFont(graphics, charList, widthList, rectList, offsetList, textureFile, multiplier, ascent, kerningPairs);
        }
       
        private static Font buildFont(Graphics graphics, Vector<Character> charList, Vector<Float> widthList, Vector<CharacterRect> rectList, Vector<CharacterOffset> offsetList,
                        String textureFile, float multiplier, float ascent, Vector<KerningPair> kerningPairs)
        {
                // Build font
                if (textureFile == null)
                {
                        Gdx.app.log(LOG_TAG, "No font file specified!");
                        return null;
                }
               
                Font font = new Font(graphics);
               
                Font.CharacterInfo[] characters = new Font.CharacterInfo[charList.size()];
                SpriteRegion[] regions = new SpriteRegion[rectList.size()];
               
                Sprite sprite = new Sprite(graphics, textureFile);
                sprite.init();
               
                for (int i = 0; i < characters.length; i++)
                {
                        characters[i] = new Font.CharacterInfo(charList.elementAt(i));
                       
                        characters[i].width = widthList.elementAt(i);
                       
                        if (i < offsetList.size())
                        {
                                characters[i].offsetX = offsetList.elementAt(i).x;
                                characters[i].offsetY = offsetList.elementAt(i).y;
                        }
                       
                        if (i < rectList.size())
                        {
                                CharacterRect rect = rectList.elementAt(i);
                               
                                /*characters[i].texX = rectList.elementAt(i).x;
                                characters[i].texY = rectList.elementAt(i).y;
                                characters[i].texW = rectList.elementAt(i).w;
                                characters[i].texH = rectList.elementAt(i).h;*/

                                regions[i] = new SpriteRegion(sprite, i, rect.x / multiplier, rect.y / multiplier, rect.w / multiplier, rect.h / multiplier, true);
                        }
                }
                sprite.setRegions(regions);
               
                //AtlasSprite sprite = new AtlasSprite(graphics, texture, regions);
               
                for (int i = 0; i < regions.length; i++)
                {
                        characters[i].setSpriteInstance(sprite.createSpriteInstance(i));
                }
               
                font.setCharacters(characters);
                font.setSprite(sprite);        
                font.setAscent(ascent);
                font.setGlobalMultiplier(multiplier);
               
                for (int i = 0; i < kerningPairs.size(); i++)
                {
                        KerningPair pair = kerningPairs.elementAt(i);
                        font.setKerning(pair.first, pair.second, pair.value);
                }
               
                return font;
        }
       
        private static Vector<Character> parseCharList(Tokenizer t) throws ScanException
        {
                Vector<Character> charList = new Vector<Character>();
               
                t.readToken("(");
               
                while (!t.checkToken(")"))
                {
                        String character = t.readString();
                       
                        if (character.length() > 1)
                                throw new ScanException("Character can only have length 1!", t.getSurroundings());
                       
                        charList.add(character.charAt(0));
                       
                        if (t.checkToken(")"))
                                break;
                       
                        t.readToken(",");
                }                              
               
                t.readToken(")");
               
                return charList;
        }
       
        private static Vector<Float> parseWidthList(Tokenizer t) throws ScanException
        {
                Vector<Float> widthList = new Vector<Float>();
               
                t.readToken("(");
               
                while (!t.checkToken(")"))
                {
                        float width = t.readNumber();
                       
                        widthList.add(width);
                       
                        if (t.checkToken(")"))
                                break;
                       
                        //Gdx.app.log(LOG_TAG, "[" + width + "]");
                       
                        t.readToken(",");
                }                              
               
                t.readToken(")");
               
                return widthList;
        }
       
        private static Vector<CharacterRect> parseRectList(Tokenizer t) throws ScanException
        {
                Vector<CharacterRect> rectList = new Vector<CharacterRect>();
               
                t.readToken("(");
               
                while (t.checkToken("("))
                {
                        t.readToken("(");
                       
                        float x = t.readNumber();
                        t.readToken(",");
                        float y = t.readNumber();
                        t.readToken(",");
                        float w = t.readNumber();
                        t.readToken(",");
                        float h = t.readNumber();
                       
                        rectList.add(new CharacterRect(x, y, w, h));
                       
                        t.readToken(")");
                       
                        if (!t.checkToken(","))
                                break;
                       
                        t.readToken(",");
                }              
               
                if (!t.checkToken(")"))
                        throw new ScanException("Syntax error in RectList!", t.getSurroundings());
               
                t.readToken(")");
               
                return rectList;
        }
       
        private static Vector<CharacterOffset> parseOffsetList(Tokenizer t) throws ScanException
        {
                Vector<CharacterOffset> offsetList = new Vector<CharacterOffset>();
               
                t.readToken("(");
               
                while (t.checkToken("("))
                {
                        t.readToken("(");
                       
                        float x = t.readNumber();
                        t.readToken(",");
                        float y = t.readNumber();
                       
                        offsetList.add(new CharacterOffset(x, y));
                       
                        t.readToken(")");
                       
                        if (!t.checkToken(","))
                                break;
                       
                        t.readToken(",");
                }              
               
                if (!t.checkToken(")"))
                        throw new ScanException("Syntax error in OffsetList!", t.getSurroundings());
               
                t.readToken(")");
               
                return offsetList;
        }
       
        private static Vector<KerningPair> parseKerningPairs(Tokenizer t) throws ScanException
        {
                Vector<KerningPair> kerningPairs = new Vector<KerningPair>();
               
                t.readToken("(");
               
                while (!t.checkToken(")"))
                {
                        String pair = t.readString();
                       
                        kerningPairs.add(new KerningPair(pair.charAt(0), pair.charAt(1), 0));
                       
                        if (t.checkToken(")"))
                                break;
                       
                        //Gdx.app.log(LOG_TAG, "[" + width + "]");
                       
                        t.readToken(",");
                }                              
               
                t.readToken(")");
               
                return kerningPairs;
        }
       
        private static Vector<Integer> parseKerningValues(Tokenizer t) throws ScanException
        {
                Vector<Integer> kerningValues = new Vector<Integer>();
               
                t.readToken("(");
               
                while (!t.checkToken(")"))
                {
                        int value = (int)t.readNumber();
                       
                        kerningValues.add(value);
                       
                        if (t.checkToken(")"))
                                break;
                       
                        //Gdx.app.log(LOG_TAG, "[" + width + "]");
                       
                        t.readToken(",");
                }                              
               
                t.readToken(")");
               
                return kerningValues;
        }
}