Beispiel #1
0
    // ------------------------------------------------------------------
    // Desc:
    // ------------------------------------------------------------------

    Rect MapCharInfo(Rect _atlasRect, exBitmapFont.CharInfo _charInfo)
    {
        Rect rect = new Rect(_charInfo.x * curEdit.scale,
                             _charInfo.y * curEdit.scale,
                             _charInfo.rotatedWidth * curEdit.scale,
                             _charInfo.rotatedHeight * curEdit.scale);

        rect.x = _atlasRect.x + rect.x;
        rect.y = _atlasRect.y + _atlasRect.height - rect.y - rect.height;
        rect   = exGeometryUtility.Rect_FloorToInt(rect);

        return(rect);
    }
Beispiel #2
0
    ///////////////////////////////////////////////////////////////////////////////
    // Functions
    ///////////////////////////////////////////////////////////////////////////////

    /*public CharInfo GetCharInfo ( char _symbol ) {
     *  if (bitmapFont_ != null) {
     *      return bitmapFont_.GetCharInfo(_symbol);
     *  }
     *  if (dynamicFont_ != null) {
     *      //// yes, Unity's GetCharacterInfo have y problem, you should get lowest character j's y-offset adjust it.
     *      CharacterInfo jCharInfo;
     *      dynamicFont_.RequestCharactersInTexture("j", dynamicFontSize_, dynamicFontStyle_);
     *      dynamicFont_.GetCharacterInfo('j', out jCharInfo, dynamicFontSize_, dynamicFontStyle_);
     *      int ttf_offset = (int)(dynamicFontSize_ + jCharInfo.vert.yMax);
     *
     *      CharacterInfo dynamicCharInfo;
     *      dynamicFont_.GetCharacterInfo(_symbol, out dynamicCharInfo, dynamicFontSize_, dynamicFontStyle_);
     *
     *      Texture texture = dynamicFont_.material.mainTexture;
     *      CharInfo charInfo = new CharInfo(); // TODO: use static char info
     *      charInfo.id = _symbol;
     *      charInfo.trim_x = 0;
     *      charInfo.trim_y = 0;
     *      charInfo.x = (int)(dynamicCharInfo.uv.x * texture.width);
     *      charInfo.y = (int)(dynamicCharInfo.uv.yMax * texture.height);
     *      charInfo.width = (int)dynamicCharInfo.vert.width;
     *      charInfo.height = - (int)dynamicCharInfo.vert.height;
     *      charInfo.xoffset = (int)dynamicCharInfo.vert.x;
     *      charInfo.yoffset = - (int)dynamicCharInfo.vert.y;
     *      charInfo.xadvance = (int)dynamicCharInfo.width;
     *      charInfo.rotated = dynamicCharInfo.flipped;
     *      return charInfo;
     *  }
     *  return null;
     * }*/

    public bool GetCharInfo(char _symbol, out CharacterInfo _charInfo)
    {
        if (bitmapFont_ != null)
        {
            exBitmapFont.CharInfo bitmapCharInfo = bitmapFont_.GetCharInfo(_symbol);
            if (bitmapCharInfo != null)
            {
                _charInfo.flipped = bitmapCharInfo.rotated;
                _charInfo.index   = bitmapCharInfo.id;
                _charInfo.size    = 0;
                _charInfo.style   = FontStyle.Normal;
                if (bitmapFont_.texture != null)
                {
                    Vector2 texelSize = bitmapFont_.texture.texelSize;
                    if (bitmapCharInfo.rotated)
                    {
                        _charInfo.uv = new Rect((bitmapCharInfo.x + bitmapCharInfo.rotatedWidth) * texelSize.x,
                                                bitmapCharInfo.y * texelSize.y,
                                                -bitmapCharInfo.rotatedWidth * texelSize.x,
                                                bitmapCharInfo.rotatedHeight * texelSize.y);
                    }
                    else
                    {
                        _charInfo.uv = new Rect(bitmapCharInfo.x * texelSize.x,
                                                bitmapCharInfo.y * texelSize.y,
                                                bitmapCharInfo.rotatedWidth * texelSize.x,
                                                bitmapCharInfo.rotatedHeight * texelSize.y);
                    }
                }
                else
                {
                    _charInfo.uv = new Rect();
                }
                _charInfo.vert = new Rect(bitmapCharInfo.xoffset, -bitmapCharInfo.yoffset, bitmapCharInfo.width, -bitmapCharInfo.height);
                float baselineOffset = bitmapFont_.size - bitmapFont_.baseLine;
                _charInfo.vert.y += baselineOffset;
                _charInfo.width   = bitmapCharInfo.xadvance;
                return(true);
            }
        }
        else if (dynamicFont_ != null)
        {
            if (dynamicFont_.GetCharacterInfo(_symbol, out _charInfo, dynamicFontSize_, dynamicFontStyle_))
            {
                _charInfo.vert.y -= baseline;
                return(true);
            }
        }
        _charInfo = new CharacterInfo();
        return(false);
    }
Beispiel #3
0
    // ------------------------------------------------------------------
    // Desc:
    // ------------------------------------------------------------------

    protected Element AddFontElement(exBitmapFont _srcFontInfo, exBitmapFont _destFontInfo, exBitmapFont.CharInfo _charInfo)
    {
        exAtlasInfo.Element el = new exAtlasInfo.Element();
        el.isFontElement = true;

        el.srcFontInfo  = _srcFontInfo;
        el.destFontInfo = _destFontInfo;
        el.charInfo     = _charInfo;

        el.trimRect  = new Rect(_charInfo.x, _charInfo.y, _charInfo.width, _charInfo.height);
        el.rotated   = false;
        el.trim      = true;
        el.atlasInfo = this;
        el.texture   = _srcFontInfo.pageInfos[0].texture;
        el.coord[0]  = 0;
        el.coord[1]  = 0;

        exBitmapFont.CharInfo destCharInfo = el.destFontInfo.GetCharInfo(el.charInfo.id);
        if (destCharInfo != null)
        {
            destCharInfo.id       = el.charInfo.id;
            destCharInfo.x        = el.charInfo.x;
            destCharInfo.y        = el.charInfo.y;
            destCharInfo.width    = el.charInfo.width;
            destCharInfo.height   = el.charInfo.height;
            destCharInfo.xoffset  = el.charInfo.xoffset;
            destCharInfo.yoffset  = el.charInfo.yoffset;
            destCharInfo.xadvance = el.charInfo.xadvance;
            destCharInfo.page     = el.charInfo.page;
            destCharInfo.uv0      = el.charInfo.uv0;
        }
        else
        {
            Debug.LogError("can't not find char info with ID " + el.charInfo.id);
        }

        elements.Add(el);

        needRebuild = true;
        EditorUtility.SetDirty(this);

        return(el);
    }
Beispiel #4
0
    public int GetAdvance(char _symbol)
    {
        if (bitmapFont_ != null)
        {
            exBitmapFont.CharInfo charInfo = bitmapFont_.GetCharInfo(_symbol);
            if (charInfo != null)
            {
                return((int)charInfo.xadvance);
            }
        }
        else if (dynamicFont_ != null)
        {
            CharacterInfo charInfo;
            if (dynamicFont_.GetCharacterInfo(_symbol, out charInfo, dynamicFontSize_, dynamicFontStyle_))
            {
                return((int)charInfo.width);
            }
        }

        return(0);
    }
Beispiel #5
0
    // ------------------------------------------------------------------
    // Desc:
    // ------------------------------------------------------------------

    public static bool Parse(exBitmapFont _bitmapFont, Object _fontInfo)
    {
        _bitmapFont.Reset();

        string fontInfoPath = AssetDatabase.GetAssetPath(_fontInfo);
        string dirname      = Path.GetDirectoryName(fontInfoPath);

        string       line;
        FileInfo     fileInfo      = new FileInfo(fontInfoPath);
        StreamReader reader        = fileInfo.OpenText();
        int          textureHeight = -1;

        while ((line = reader.ReadLine()) != null)
        {
            string[] words = line.Split(' ');
            if (words[0] == "info")
            {
                _bitmapFont.size = int.Parse(ParseValue(words, "size"));
            }
            else if (words[0] == "common")
            {
                _bitmapFont.lineHeight = int.Parse(ParseValue(words, "lineHeight"));
                _bitmapFont.baseLine   = int.Parse(ParseValue(words, "base"));
                // _bitmapFont.width = int.Parse ( ParseValue( words, "scaleW" ) );
                // _bitmapFont.height = int.Parse ( ParseValue( words, "scaleH" ) );

                int pages = int.Parse(ParseValue(words, "pages"));
                if (pages != 1)
                {
                    Debug.LogError("Parse Error: only support one page");
                    return(false);
                }
            }
            else if (words[0] == "page")
            {
                // load texture from file
                string filename = ParseValue(words, "file");
                filename = filename.Substring(1, filename.Length - 2); // remove the "" in "foobar.png"
                string    texturePath = Path.Combine(dirname, filename);
                Texture2D texture     = (Texture2D)AssetDatabase.LoadAssetAtPath(texturePath, typeof(Texture2D));
                if (texture == null)
                {
                    Debug.LogError("Parse Failed: The texture " + filename + " not found.");
                    return(false);
                }
                if (exEditorUtility.IsValidForBitmapFont(texture) == false)
                {
                    exEditorUtility.ImportTextureForBitmapFont(texture);
                }
                textureHeight = texture.height;

                // add page info
                _bitmapFont.texture = texture;
            }
            else if (words[0] == "char")
            {
                exBitmapFont.CharInfo charInfo = new exBitmapFont.CharInfo();
                charInfo.id       = int.Parse(ParseValue(words, "id"));
                charInfo.width    = int.Parse(ParseValue(words, "width"));
                charInfo.height   = int.Parse(ParseValue(words, "height"));
                charInfo.trim_x   = int.Parse(ParseValue(words, "x"));
                charInfo.trim_y   = int.Parse(ParseValue(words, "y"));
                charInfo.xoffset  = int.Parse(ParseValue(words, "xoffset"));
                charInfo.yoffset  = int.Parse(ParseValue(words, "yoffset"));
                charInfo.xadvance = int.Parse(ParseValue(words, "xadvance"));
                charInfo.rotated  = false;
                // charInfo.page = int.Parse ( ParseValue( words, "page" ) );

                // add char info
                _bitmapFont.charInfos.Add(charInfo);
            }
            else if (words[0] == "kerning")
            {
                exBitmapFont.KerningInfo kerningInfo = new exBitmapFont.KerningInfo();
                kerningInfo.first  = int.Parse(ParseValue(words, "first"));
                kerningInfo.second = int.Parse(ParseValue(words, "second"));
                kerningInfo.amount = int.Parse(ParseValue(words, "amount"));
                _bitmapFont.kernings.Add(kerningInfo);
            }
        }
        reader.Close();
        _bitmapFont.rawFontGUID    = exEditorUtility.AssetToGUID(_fontInfo);
        _bitmapFont.rawTextureGUID = exEditorUtility.AssetToGUID(_bitmapFont.texture);

        // revert charInfo uv-y to fit the Unity's uv-coordination.
        foreach (exBitmapFont.CharInfo charInfo in _bitmapFont.charInfos)
        {
            charInfo.trim_y = textureHeight - (charInfo.trim_y + charInfo.height);
            charInfo.x      = charInfo.trim_x;
            charInfo.y      = charInfo.trim_y;
        }

        EditorUtility.SetDirty(_bitmapFont);

        return(true);
    }
Beispiel #6
0
    // ------------------------------------------------------------------
    /// \param _objects
    /// get the Texture2D and exBitmapFont from a list of objects, import them into atlas
    // ------------------------------------------------------------------

    public void ImportObjects(Object[] _objects)
    {
        bool dirty = false;

        foreach (Object o in _objects)
        {
            if (o is Texture2D)
            {
                Texture2D             t      = o as Texture2D;
                exAtlasDB.ElementInfo elInfo = exAtlasDB.GetElementInfo(t);
                if (elInfo == null)
                {
                    AddElement(t, trimElements);
                    dirty = true;
                }
                else
                {
                    Debug.LogError("The texture [" + t.name + "]" +
                                   " has already been added in atlas: " +
                                   AssetDatabase.GUIDToAssetPath(elInfo.guidAtlasInfo));
                }
            }
            else if (o is exBitmapFont)
            {
                exBitmapFont f = o as exBitmapFont;
                if (f.inAtlas)
                {
                    // NOTE: it is still possible we have atlas font in the obj list since we use Selection.GetFiltered().
                    continue;
                }

                // multi-page atlas font is forbit
                if (f.pageInfos.Count > 1)
                {
                    Debug.LogError("Can't not create atlas font from " + f.name + ", it has multiple page info.");
                    continue;
                }

                // check if we have resource in the project
                string       assetPath      = AssetDatabase.GetAssetPath(texture);
                string       dirname        = Path.GetDirectoryName(assetPath);
                string       filename       = Path.GetFileNameWithoutExtension(assetPath);
                string       bitmapFontPath = Path.Combine(dirname, filename + " - " + f.name + ".asset");
                exBitmapFont f2             = (exBitmapFont)AssetDatabase.LoadAssetAtPath(bitmapFontPath,
                                                                                          typeof(exBitmapFont));
                if (f2 == null)
                {
                    f2            = (exBitmapFont)ScriptableObject.CreateInstance(typeof(exBitmapFont));
                    f2.inAtlas    = true;
                    f2.name       = f.name;
                    f2.lineHeight = f.lineHeight;

                    // add page info
                    exBitmapFont.PageInfo pageInfo = new exBitmapFont.PageInfo();
                    pageInfo.texture  = texture;
                    pageInfo.material = material;
                    f2.pageInfos.Add(pageInfo);

                    // add char info
                    foreach (exBitmapFont.CharInfo c in f.charInfos)
                    {
                        exBitmapFont.CharInfo c2 = new exBitmapFont.CharInfo(c);
                        f2.charInfos.Add(c2);
                    }

                    // add kerning info
                    foreach (exBitmapFont.KerningInfo k in f.kernings)
                    {
                        f2.kernings.Add(k);
                    }

                    AssetDatabase.CreateAsset(f2, bitmapFontPath);

                    //
                    foreach (exBitmapFont.CharInfo c in f2.charInfos)
                    {
                        if (c.id == -1)
                        {
                            continue;
                        }
                        AddFontElement(f, f2, c);
                    }
                }
                else
                {
                    Debug.LogError("You already add the BitmapFont in this Atlas");
                }

                //
                if (bitmapFonts.IndexOf(f2) == -1)
                {
                    bitmapFonts.Add(f2);
                }

                dirty = true;
            }
            if (dirty)
            {
                EditorUtility.SetDirty(this);
            }
        }
    }
Beispiel #7
0
    // ------------------------------------------------------------------
    /// \param _objects 
    /// get the Texture2D and exBitmapFont from a list of objects, import them into atlas
    // ------------------------------------------------------------------
    public void ImportObjects( Object[] _objects )
    {
        bool dirty = false;
        foreach ( Object o in _objects ) {
            if ( o is Texture2D ) {
                Texture2D t = o as Texture2D;
                exAtlasDB.ElementInfo elInfo = exAtlasDB.GetElementInfo(t);
                if ( elInfo == null ) {
                    AddElement( t, trimElements );
                    dirty = true;
                }
                else {
                    Debug.LogError( "The texture [" + t.name + "]" +
                                    " has already been added in atlas: " +
                                    AssetDatabase.GUIDToAssetPath(elInfo.guidAtlasInfo) );
                }
            }
            else if ( o is exBitmapFont ) {
                exBitmapFont f = o as exBitmapFont;
                if ( f.inAtlas ) {
                    // NOTE: it is still possible we have atlas font in the obj list since we use Selection.GetFiltered().
                    continue;
                }

                // multi-page atlas font is forbit
                if ( f.pageInfos.Count > 1 ) {
                    Debug.LogError("Can't not create atlas font from " + f.name + ", it has multiple page info.");
                    continue;
                }

                // check if we have resource in the project
                string assetPath = AssetDatabase.GetAssetPath(texture);
                string dirname = Path.GetDirectoryName(assetPath);
                string filename = Path.GetFileNameWithoutExtension(assetPath);
                string bitmapFontPath = Path.Combine( dirname, filename + " - " + f.name + ".asset" );
                exBitmapFont f2 = (exBitmapFont)AssetDatabase.LoadAssetAtPath( bitmapFontPath,
                                                                               typeof(exBitmapFont) );
                if ( f2 == null ) {
                    f2 = (exBitmapFont)ScriptableObject.CreateInstance(typeof(exBitmapFont));
                    f2.inAtlas = true;
                    f2.name = f.name;
                    f2.lineHeight = f.lineHeight;

                    // add page info
                    exBitmapFont.PageInfo pageInfo = new exBitmapFont.PageInfo();
                    pageInfo.texture = texture;
                    pageInfo.material = material;
                    f2.pageInfos.Add(pageInfo);

                    // add char info
                    foreach ( exBitmapFont.CharInfo c in f.charInfos ) {
                        exBitmapFont.CharInfo c2 = new exBitmapFont.CharInfo(c);
                        f2.charInfos.Add(c2);
                    }

                    // add kerning info
                    foreach ( exBitmapFont.KerningInfo k in f.kernings ) {
                        f2.kernings.Add(k);
                    }

                    AssetDatabase.CreateAsset ( f2, bitmapFontPath );

                    //
                    foreach ( exBitmapFont.CharInfo c in f2.charInfos ) {
                        if ( c.id == -1 )
                            continue;
                        AddFontElement( f, f2, c );
                    }
                }
                else {
                    Debug.LogError("You already add the BitmapFont in this Atlas");
                }

                //
                if ( bitmapFonts.IndexOf(f2) == -1 ) {
                    bitmapFonts.Add(f2);
                }

                dirty = true;
            }
            if ( dirty ) {
                EditorUtility.SetDirty(this);
            }
        }
    }
Beispiel #8
0
    // ------------------------------------------------------------------
    // Desc: This only calculate result in one line
    // ------------------------------------------------------------------

    public static void BuildTextLine(Vector3[] _vertices, Vector2[] _uvs,
                                     string _text,
                                     exBitmapFont _font,
                                     int _lineHeight,
                                     int _fontSize,
                                     int _wordSpacing,
                                     int _letterSpacing)
    {
        int cur_x = 0;
        int cur_y = 0;

        //
        for (int i = 0; i < _text.Length; ++i)
        {
            char cur_char = _text[i];

            // NOTE: we skip new-line operation, since we believe this function only have one-line text
            if (cur_char == '\n')
            {
                continue;
            }

            // generate mesh
            exBitmapFont.CharInfo charInfo = _font.GetCharInfo(cur_char);
            if (charInfo != null)
            {
                int   idx = 4 * i;
                float x   = cur_x + charInfo.xoffset;
                float y   = cur_y + charInfo.yoffset;

                Vector2 texelSize = _font.texture.texelSize;
                Vector2 start     = new Vector2(charInfo.x * texelSize.x,
                                                charInfo.y * texelSize.y);
                Vector2 end = new Vector2((charInfo.x + charInfo.rotatedWidth) * texelSize.x,
                                          (charInfo.y + charInfo.rotatedHeight) * texelSize.y);

                // build vertices
                _vertices[idx + 0] = new Vector3(x, y, 0.0f);
                _vertices[idx + 1] = new Vector3(x + charInfo.width, y, 0.0f);
                _vertices[idx + 2] = new Vector3(x + charInfo.width, y + charInfo.height, 0.0f);
                _vertices[idx + 3] = new Vector3(x, y + charInfo.height, 0.0f);

                // build uv
                if (charInfo.rotated)
                {
                    _uvs[idx + 0] = new Vector2(end.x, start.y);
                    _uvs[idx + 1] = new Vector2(end.x, end.y);
                    _uvs[idx + 2] = new Vector2(start.x, end.y);
                    _uvs[idx + 3] = new Vector2(start.x, start.y);
                }
                else
                {
                    _uvs[idx + 0] = new Vector2(start.x, end.y);
                    _uvs[idx + 1] = new Vector2(end.x, end.y);
                    _uvs[idx + 2] = new Vector2(end.x, start.y);
                    _uvs[idx + 3] = new Vector2(start.x, start.y);
                }

                // advance x
                cur_x += (int)charInfo.xadvance + _letterSpacing;
                if (cur_char == ' ')
                {
                    cur_x += _wordSpacing;
                }
            }
        }
    }
Beispiel #9
0
    // ------------------------------------------------------------------
    // Desc:
    // ------------------------------------------------------------------

    static void FillAtlasTexture(Texture2D _tex, exAtlasInfo _atlasInfo, bool _noImport)
    {
        foreach (exAtlasInfo.Element el in _atlasInfo.elements)
        {
            // DISABLE: it is too slow {
            // EditorUtility.DisplayProgressBar( "Building Atlas...",
            //                                   "Building Texture " + el.texture.name,
            //                                   (float)i/(float)_atlasInfo.elements.Count - 0.1f );
            // } DISABLE end

            Texture2D srcTexture = el.texture;
            int       destX      = el.coord[0];
            if (el.isFontElement)
            {
                // build the font
                exBitmapFont.CharInfo charInfo = el.destFontInfo.GetCharInfo(el.charInfo.id);
                if (charInfo != null)
                {
                    charInfo.uv0 = new Vector2((float)destX / _tex.width,
                                               (_tex.height - (float)el.coord[1] - charInfo.height) / _tex.height);
                    EditorUtility.SetDirty(el.destFontInfo);
                }
            }

            // make the src texture readable
            if (exTextureHelper.IsValidForAtlas(srcTexture) == false)
            {
                if (_noImport)
                {
                    Debug.LogError("The texture import settings of [" + AssetDatabase.GetAssetPath(srcTexture) + "] is invalid for atlas build");
                    continue;
                }
                else
                {
                    exTextureHelper.ImportTextureForAtlas(srcTexture);
                }
            }

            // apply contour bleed
            if (_atlasInfo.useContourBleed)
            {
                srcTexture = exTextureHelper.ApplyContourBleed(srcTexture);
            }

            // copy element's texture into atlas texture
            int destY = _tex.height - el.coord[1] - el.Height();
            exTextureHelper.Fill(_tex,
                                 new Vector2(destX, destY),
                                 srcTexture,
                                 el.trimRect,
                                 el.rotated ? exTextureHelper.RotateDirection.RotRight : exTextureHelper.RotateDirection.None,
                                 _atlasInfo.useBuildColor,
                                 _atlasInfo.buildColor);

            // apply padding bleed
            if (_atlasInfo.usePaddingBleed)
            {
                exTextureHelper.ApplyPaddingBleed(_tex,
                                                  new Rect(destX, destY, el.trimRect.width, el.trimRect.height));
            }

            // TODO {
            // Color32[] colors = srcTexture.GetPixels32();
            // Color32[] colors_d = new Color32[_tex.width * _tex.height];
            // for ( int r = 0; r < srcTexture.width; ++r ) {
            //     for ( int c = 0; c < srcTexture.height; ++c ) {
            //         colors_d[r+c*_tex.width] = colors[r+c*srcTexture.width];
            //     }
            // }
            // _tex.SetPixels32( colors_d );
            // } TODO end
        }

#if EX2D_EVALUATE
        // ========================================================
        // Add water mark
        // ========================================================

        // NOTE: onlly open it in evaluate version {
        // Make Water Make {
        // Texture2D texWaterMark = (Texture2D)AssetDatabase.LoadAssetAtPath("Assets/ex2D/Editor/Resource/water_mark.png", typeof(Texture2D));
        // exTextureHelper.ImportTextureForAtlas(texWaterMark);
        // Color[] colors = texWaterMark.GetPixels();
        // StreamWriter sw = new StreamWriter("Assets/TestFile.txt");
        // Color32[] colors32 = texWaterMark.GetPixels32();
        // for ( int r = 0; r < texWaterMark.height; ++r ) {
        //     for ( int c = 0; c < texWaterMark.width; ++c ) {
        //         Color32 cc = colors32[r*texWaterMark.width+c];
        //         sw.Write( "0x" + cc.r.ToString("X2")
        //                   + ", 0x" + cc.g.ToString("X2")
        //                   + ", 0x" + cc.b.ToString("X2")
        //                   + ", 0x" + cc.a.ToString("X2")
        //                   + ", " );
        //     }
        //     sw.WriteLine("");
        // }
        // sw.Close();
        // } Make Water Make end

        int     wa_width  = 392;
        int     wa_height = 40;
        Color[] colors    = new Color[wa_width * wa_height];
        for (int r = 0; r < wa_height; ++r)
        {
            for (int c = 0; c < wa_width; ++c)
            {
                colors[r * wa_width + c] = new Color(waterMark[(r * wa_width + c) * 4] / 255.0f,
                                                     waterMark[(r * wa_width + c) * 4 + 1] / 255.0f,
                                                     waterMark[(r * wa_width + c) * 4 + 2] / 255.0f,
                                                     waterMark[(r * wa_width + c) * 4 + 3] / 255.0f);
            }
        }
        Color[] colors_d = _tex.GetPixels();
        for (int r = 0; r < wa_height; ++r)
        {
            for (int c = 0; c < wa_width; ++c)
            {
                Color color_d = colors_d[r * _tex.width + c];
                Color color   = colors[r * wa_width + c];
                // colors_d[r*_tex.width+(c+_tex.height-wa_height)] =
                colors_d[r * _tex.width + c] = color_d * (1.0f - color.a) + color * color.a;
            }
        }
        _tex.SetPixels(colors_d);
        // } NOTE end
#endif // EX2D_EVALUATE

        _tex.Apply(false);
    }
Beispiel #10
0
    // ------------------------------------------------------------------
    /// \param _mesh the mesh to update
    ///
    /// Update the _mesh depends on the exPlane.updateFlags
    // ------------------------------------------------------------------

    public void UpdateMesh(Mesh _mesh)
    {
        // pre check fontInfo
        if (fontInfo_ == null)
        {
            _mesh.Clear();
            return;
        }

        // ========================================================
        // init value
        // ========================================================

        int numVerts    = text_.Length * 4;
        int numIndices  = text_.Length * 6;
        int vertexCount = 0;
        int indexCount  = 0;

        // first shadow
        int shadowVertexStartAt = -1;
        int shadowIndexStartAt  = -1;

        if (useShadow_)
        {
            shadowVertexStartAt = vertexCount;
            vertexCount        += numVerts;

            shadowIndexStartAt = indexCount;
            indexCount        += numIndices;
        }

        // second outline
        int outlineVertexStartAt = -1;
        int outlineIndexStartAt  = -1;

        if (useOutline_)
        {
            outlineVertexStartAt = vertexCount;
            vertexCount         += 8 * numVerts;

            outlineIndexStartAt = indexCount;
            indexCount         += 8 * numIndices;
        }

        // finally normal
        int vertexStartAt = vertexCount;

        vertexCount += numVerts;

        int indexStartAt = indexCount;

        indexCount += numIndices;

        // ========================================================
        // Update Vertex, UV and Indices
        // ========================================================

        if ((updateFlags & UpdateFlags.Text) != 0)
        {
            updateFlags &= ~UpdateFlags.Vertex; // remove vertex update, if we have

            _mesh.Clear();

            float[] lineWidths;
            float[] kernings;
            float   halfWidthScaled;
            float   halfHeightScaled;
            float   offsetX;
            float   offsetY;
            CalculateSize(out lineWidths,
                          out kernings,
                          out halfWidthScaled,
                          out halfHeightScaled,
                          out offsetX,
                          out offsetY);

            //
            Vector3[] vertices   = new Vector3[vertexCount];
            Vector2[] uvs        = new Vector2[vertexCount];
            int[]     indices    = new int[indexCount];
            Vector2   finalScale = new Vector2(scale_.x * ppfScale_.x, scale_.y * ppfScale_.y);

            //
            int   curLine = 0;
            float curX    = 0.0f;
            if (useMultiline_)
            {
                switch (textAlign_)
                {
                case TextAlign.Left:
                    curX = 0.0f;
                    break;

                case TextAlign.Center:
                    curX = halfWidthScaled - lineWidths[curLine] * 0.5f * finalScale.x;
                    break;

                case TextAlign.Right:
                    curX = halfWidthScaled * 2.0f - lineWidths[curLine] * finalScale.x;
                    break;
                }
            }
            float curY = 0.0f;
            for (int i = 0; i < text_.Length; ++i)
            {
                int id = text_[i];

                // if next line
                if (id == '\n')
                {
                    if (useMultiline_)
                    {
                        ++curLine;
                        switch (textAlign_)
                        {
                        case TextAlign.Left:
                            curX = 0.0f;
                            break;

                        case TextAlign.Center:
                            curX = halfWidthScaled - lineWidths[curLine] * 0.5f * finalScale.x;
                            break;

                        case TextAlign.Right:
                            curX = halfWidthScaled * 2.0f - lineWidths[curLine] * finalScale.x;
                            break;
                        }
                        curY = curY + (fontInfo_.lineHeight + lineSpacing_) * finalScale.y;
                    }
                    continue;
                }

                int vert_id = vertexStartAt + 4 * i;
                int idx_id  = indexStartAt + 6 * i;
                // if we don't have the character, it will become space.
                exBitmapFont.CharInfo charInfo = fontInfo_.GetCharInfo(id);

                //
                if (charInfo != null)
                {
                    // build vertices & normals
                    for (int r = 0; r < 2; ++r)
                    {
                        for (int c = 0; c < 2; ++c)
                        {
                            int j = r * 2 + c;

                            // calculate the base pos
                            float x = curX - halfWidthScaled + c * charInfo.width * finalScale.x + charInfo.xoffset * finalScale.x;
                            float y = -curY + halfHeightScaled - r * charInfo.height * finalScale.y - charInfo.yoffset * finalScale.y;

                            // calculate the pos affect by anchor
                            x -= offsetX;
                            y += offsetY;

                            // calculate the shear
                            float old_x = x;
                            x += y * shear_.x;
                            y += old_x * shear_.y;

                            // build vertices and normals
                            vertices[vert_id + j] = new Vector3(x, y, 0.0f);
                            // normals[vert_id+j] = new Vector3( 0.0f, 0.0f, -1.0f );
                        }
                    }

                    // build uv
                    float textureWidth  = fontInfo_.pageInfos[0].texture.width;
                    float textureHeight = fontInfo_.pageInfos[0].texture.height;
                    float charUVWidth   = (float)charInfo.width / (float)textureWidth;
                    float charUVHeight  = (float)charInfo.height / (float)textureHeight;

                    float xStart = charInfo.uv0.x;
                    float yStart = charInfo.uv0.y;
                    float xEnd   = xStart + charUVWidth;
                    float yEnd   = yStart + charUVHeight;

                    //
                    uvs[vert_id + 0] = new Vector2(xStart, yEnd);
                    uvs[vert_id + 1] = new Vector2(xEnd, yEnd);
                    uvs[vert_id + 2] = new Vector2(xStart, yStart);
                    uvs[vert_id + 3] = new Vector2(xEnd, yStart);

                    // build indices
                    indices[idx_id + 0] = vert_id + 0;
                    indices[idx_id + 1] = vert_id + 1;
                    indices[idx_id + 2] = vert_id + 2;
                    indices[idx_id + 3] = vert_id + 2;
                    indices[idx_id + 4] = vert_id + 1;
                    indices[idx_id + 5] = vert_id + 3;

                    //
                    curX = curX + (charInfo.xadvance + tracking_) * finalScale.x;
                    if (useKerning_)
                    {
                        if (i < text_.Length - 1)
                        {
                            curX += kernings[i] * finalScale.x;
                        }
                    }
                }
            }

            // update outline
            if (useOutline_)
            {
                UpdateOutline(outlineVertexStartAt,
                              outlineIndexStartAt,
                              vertexStartAt,
                              vertices,
                              uvs,
                              indices);
            }

            // update shadow
            if (useShadow_)
            {
                UpdateShadow(shadowVertexStartAt,
                             shadowIndexStartAt,
                             vertexStartAt,
                             vertices,
                             uvs,
                             indices);
            }

            //
            _mesh.vertices = vertices;
            // _mesh.normals = normals;
            _mesh.uv        = uvs;
            _mesh.triangles = indices;
            _mesh.bounds    = GetMeshBounds(offsetX, offsetY, halfWidthScaled * 2.0f, halfHeightScaled * 2.0f);

            // update box-collider if we have
            UpdateBoundRect(offsetX, offsetY, halfWidthScaled * 2.0f, halfHeightScaled * 2.0f);
            if (collisionHelper)
            {
                collisionHelper.UpdateCollider();
            }

// #if UNITY_EDITOR
//             _mesh.RecalculateBounds();
// #endif
        }

        // ========================================================
        // Update Vertex Only
        // ========================================================

        else if ((updateFlags & UpdateFlags.Vertex) != 0)
        {
            float[] lineWidths;
            float[] kernings;
            float   halfWidthScaled;
            float   halfHeightScaled;
            float   offsetX;
            float   offsetY;
            CalculateSize(out lineWidths,
                          out kernings,
                          out halfWidthScaled,
                          out halfHeightScaled,
                          out offsetX,
                          out offsetY);

            //
            Vector3[] vertices   = new Vector3[vertexCount];
            Vector2   finalScale = new Vector2(scale_.x * ppfScale_.x, scale_.y * ppfScale_.y);

            //
            int   curLine = 0;
            float curX    = 0.0f;
            if (useMultiline_)
            {
                switch (textAlign_)
                {
                case TextAlign.Left:
                    curX = 0.0f;
                    break;

                case TextAlign.Center:
                    curX = halfWidthScaled - lineWidths[curLine] * 0.5f * finalScale.x;
                    break;

                case TextAlign.Right:
                    curX = halfWidthScaled * 2.0f - lineWidths[curLine] * finalScale.x;
                    break;
                }
            }
            float curY = 0.0f;
            for (int i = 0; i < text_.Length; ++i)
            {
                int id = text_[i];

                // if next line
                if (id == '\n')
                {
                    if (useMultiline_)
                    {
                        ++curLine;
                        switch (textAlign_)
                        {
                        case TextAlign.Left:
                            curX = 0.0f;
                            break;

                        case TextAlign.Center:
                            curX = halfWidthScaled - lineWidths[curLine] * 0.5f * finalScale.x;
                            break;

                        case TextAlign.Right:
                            curX = halfWidthScaled * 2.0f - lineWidths[curLine] * finalScale.x;
                            break;
                        }
                        curY = curY + (fontInfo_.lineHeight + lineSpacing_) * finalScale.y;
                    }
                    continue;
                }

                int vert_id = vertexStartAt + 4 * i;
                // if we don't have the character, it will become space.
                exBitmapFont.CharInfo charInfo = fontInfo_.GetCharInfo(id);

                if (charInfo != null)
                {
                    // build vertices & normals
                    for (int r = 0; r < 2; ++r)
                    {
                        for (int c = 0; c < 2; ++c)
                        {
                            int j = r * 2 + c;

                            // calculate the base pos
                            float x = curX - halfWidthScaled + c * charInfo.width * finalScale.x + charInfo.xoffset * finalScale.x;
                            float y = -curY + halfHeightScaled - r * charInfo.height * finalScale.y - charInfo.yoffset * finalScale.y;

                            // calculate the pos affect by anchor
                            x -= offsetX;
                            y += offsetY;

                            // calculate the shear
                            x += y * shear_.x;
                            y += x * shear_.y;

                            // build vertices
                            vertices[vert_id + j] = new Vector3(x, y, 0.0f);
                        }
                    }

                    //
                    curX = curX + (charInfo.xadvance + tracking_) * finalScale.x;
                    if (useKerning_)
                    {
                        if (i < text_.Length - 1)
                        {
                            curX += kernings[i] * finalScale.x;
                        }
                    }
                }
            }

            // update outline
            if (useOutline_)
            {
                UpdateOutline(outlineVertexStartAt,
                              -1,
                              vertexStartAt,
                              vertices,
                              null,
                              null);
            }

            // update shadow
            if (useShadow_)
            {
                UpdateShadow(shadowVertexStartAt,
                             -1,
                             vertexStartAt,
                             vertices,
                             null,
                             null);
            }

            _mesh.vertices = vertices;
            _mesh.bounds   = GetMeshBounds(offsetX, offsetY, halfWidthScaled * 2.0f, halfHeightScaled * 2.0f);

            // update collider if we have
            UpdateBoundRect(offsetX, offsetY, halfWidthScaled * 2.0f, halfHeightScaled * 2.0f);
            if (collisionHelper)
            {
                collisionHelper.UpdateCollider();
            }

// #if UNITY_EDITOR
//             _mesh.RecalculateBounds();
// #endif
        }

        // ========================================================
        // Update Color
        // ========================================================

        if ((updateFlags & UpdateFlags.Color) != 0 ||
            (updateFlags & UpdateFlags.Text) != 0)
        {
            Color[] colors = new Color[vertexCount];
            for (int i = 0; i < text_.Length; ++i)
            {
                int vert_id = vertexStartAt + 4 * i;
                colors[vert_id + 0] = colors[vert_id + 1] = topColor_;
                colors[vert_id + 2] = colors[vert_id + 3] = botColor_;


                if (outlineVertexStartAt != -1)
                {
                    vert_id = 4 * i;
                    int[] vi = new int[] {
                        outlineVertexStartAt + vert_id + 0 * numVerts,
                        outlineVertexStartAt + vert_id + 1 * numVerts,
                        outlineVertexStartAt + vert_id + 2 * numVerts,
                        outlineVertexStartAt + vert_id + 3 * numVerts,
                        outlineVertexStartAt + vert_id + 4 * numVerts,
                        outlineVertexStartAt + vert_id + 5 * numVerts,
                        outlineVertexStartAt + vert_id + 6 * numVerts,
                        outlineVertexStartAt + vert_id + 7 * numVerts
                    };
                    for (int k = 0; k < vi.Length; ++k)
                    {
                        colors[vi[k] + 0]             =
                            colors[vi[k] + 1]         =
                                colors[vi[k] + 2]     =
                                    colors[vi[k] + 3] = outlineColor_;
                    }
                }
                if (shadowVertexStartAt != -1)
                {
                    vert_id                         = shadowVertexStartAt + 4 * i;
                    colors[vert_id + 0]             =
                        colors[vert_id + 1]         =
                            colors[vert_id + 2]     =
                                colors[vert_id + 3] = shadowColor_;
                }
            }
            _mesh.colors = colors;
        }

        // NOTE: though we set updateFlags to None at exPlane::LateUpdate,
        //       the Editor still need this or it will caused editor keep dirty
        updateFlags = UpdateFlags.None;
    }
Beispiel #11
0
    ///////////////////////////////////////////////////////////////////////////////
    // mesh building functions
    ///////////////////////////////////////////////////////////////////////////////

    // ------------------------------------------------------------------
    // Desc:
    // ------------------------------------------------------------------

    public void CalculateSize(out float[] _lineWidths,
                              out float[] _kernings,
                              out float _halfWidthScaled,
                              out float _halfHeightScaled,
                              out float _offsetX,
                              out float _offsetY)
    {
        if (useMultiline_)
        {
            long lines = exStringHelper.CountLinesInString(text_);
            _lineWidths = new float[lines];
        }
        else
        {
            _lineWidths = new float[0];
        }
        _kernings = new float[Mathf.Max(text_.Length - 1, 0)];
        float maxWidth = 0.0f;
        float curWidth = 0.0f;
        float height   = fontInfo_.lineHeight;

        int curLine = 0;

        for (int i = 0; i < text_.Length; ++i)
        {
            char c = text_[i];
            if (c == '\n')
            {
                if (useMultiline_)
                {
                    if (curWidth > maxWidth)
                    {
                        maxWidth = curWidth;
                    }
                    _lineWidths[curLine] = curWidth;
                    curWidth             = 0.0f;
                    height = height + fontInfo_.lineHeight + lineSpacing_;
                    ++curLine;
                }
                continue;
            }

            // if we don't have the character, it will become space.
            exBitmapFont.CharInfo charInfo = fontInfo_.GetCharInfo(c);
            if (charInfo != null)
            {
                curWidth = curWidth + charInfo.xadvance + tracking_;
                if (useKerning_)
                {
                    if (i < text_.Length - 1)
                    {
                        for (int idx = 0; idx < fontInfo_.kernings.Count; ++idx)
                        {
                            exBitmapFont.KerningInfo k = fontInfo_.kernings[idx];
                            if (k.first == c && k.second == text_[i + 1])
                            {
                                curWidth    += k.amount;
                                _kernings[i] = k.amount;
                                break;
                            }
                        }
                    }
                }
            }
        }
        if (curWidth > maxWidth)
        {
            maxWidth = curWidth;
        }
        if (useMultiline_)
        {
            _lineWidths[curLine] = curWidth;
        }

        Vector2 finalScale = new Vector2(scale_.x * ppfScale_.x, scale_.y * ppfScale_.y);

        _halfWidthScaled  = maxWidth * finalScale.x * 0.5f;
        _halfHeightScaled = height * finalScale.y * 0.5f;
        _offsetX          = 0.0f;
        _offsetY          = 0.0f;

        // calculate anchor offset
        switch (anchor_)
        {
        case Anchor.TopLeft: _offsetX = -_halfWidthScaled;  _offsetY = -_halfHeightScaled; break;

        case Anchor.TopCenter: _offsetX = 0.0f;               _offsetY = -_halfHeightScaled; break;

        case Anchor.TopRight: _offsetX = _halfWidthScaled;   _offsetY = -_halfHeightScaled; break;

        case Anchor.MidLeft: _offsetX = -_halfWidthScaled;  _offsetY = 0.0f;               break;

        case Anchor.MidCenter: _offsetX = 0.0f;               _offsetY = 0.0f;               break;

        case Anchor.MidRight: _offsetX = _halfWidthScaled;   _offsetY = 0.0f;               break;

        case Anchor.BotLeft: _offsetX = -_halfWidthScaled;  _offsetY = _halfHeightScaled;  break;

        case Anchor.BotCenter: _offsetX = 0.0f;               _offsetY = _halfHeightScaled;  break;

        case Anchor.BotRight: _offsetX = _halfWidthScaled;   _offsetY = _halfHeightScaled;  break;

        default: _offsetX = 0.0f;               _offsetY = 0.0f;               break;
        }
        _offsetX -= offset_.x;
        _offsetY += offset_.y;
    }
Beispiel #12
0
    // ------------------------------------------------------------------
    // Desc:
    // ------------------------------------------------------------------
    static void ParseFontInfo( exBitmapFont _bitmapFont, Object _fontInfo )
    {
        EditorUtility.DisplayProgressBar( "Building BitmapFont...",
                                          "Parsing font info...",
                                          0.1f );

        string fontInfoPath = AssetDatabase.GetAssetPath(_fontInfo);
        string dirname = Path.GetDirectoryName(fontInfoPath);

        // TODO {
        // _bitmapFont.fontInfoGUIDs.Add(exEditorHelper.AssetToGUID(_fontInfo));
        // } TODO end

        // DELME {
        // string[] lines = _textAsset.text.Split ('\n');
        // foreach ( string line in lines ) {
        // } DELME end
        string line;
        FileInfo fileInfo = new FileInfo(fontInfoPath);
        StreamReader reader = fileInfo.OpenText();
        while ( (line = reader.ReadLine()) != null ) {

            // DISABLE: it is too slow {
            // EditorUtility.DisplayProgressBar( "Building BitmapFont...",
            //                                   "Parsing line " + i,
            //                                   (float)i/(float)lines.Length );
            // } DISABLE end
            string[] words = line.Split(' ');
            if ( words[0] == "info" ) {
                _bitmapFont.size = int.Parse ( ParseValue( words, "size" ) );
            }
            else if ( words[0] == "common" ) {
                _bitmapFont.lineHeight = int.Parse ( ParseValue( words, "lineHeight" ) );
                // _bitmapFont.width = int.Parse ( ParseValue( words, "scaleW" ) );
                // _bitmapFont.height = int.Parse ( ParseValue( words, "scaleH" ) );
                int pages = int.Parse( ParseValue( words, "pages" ) );
                _bitmapFont.pageInfos = new List<exBitmapFont.PageInfo>(pages);
                for ( int i = 0; i < pages; ++i ) {
                    _bitmapFont.pageInfos.Add(new exBitmapFont.PageInfo());
                }
                // DISABLE {
                // if ( pages != 1 ) {
                //     Debug.LogError ( "Parse Error: only support one page" );
                //     return;
                // }
                // } DISABLE end
            }
            else if ( words[0] == "page" ) {
                // check if id is valid
                int id = int.Parse ( ParseValue( words, "id" ) );
                if ( id >= _bitmapFont.pageInfos.Count ) {
                    Debug.LogError("Parse Failed: The page id is exceed the page number");
                    return;
                }

                // load texture from file
                string filename = ParseValue( words, "file" );
                filename = filename.Substring( 1, filename.Length-2 ); // remove the "" in "foobar.png"
                string texturePath = Path.Combine( dirname, filename );
                Texture2D texture = (Texture2D)AssetDatabase.LoadAssetAtPath( texturePath, typeof(Texture2D) );
                if ( texture == null ) {
                    Debug.LogError("Parse Failed: The texture " + filename + " not found.");
                    return;
                }

                // load material, if not exists, create a new one.
                string filenameNoExt = Path.GetFileNameWithoutExtension(texturePath);
                string materialPath = Path.Combine( dirname, filenameNoExt ) + ".mat";
                Material material = (Material)AssetDatabase.LoadAssetAtPath( materialPath, typeof(Material) );
                if ( material == null ) {
                    material = new Material( Shader.Find("ex2D/Alpha Blended") );
                    material.mainTexture = texture;
                    AssetDatabase.CreateAsset( material, materialPath );
                }

                // add page info
                _bitmapFont.pageInfos[id].texture = texture;
                _bitmapFont.pageInfos[id].material = material;
            }
            else if ( words[0] == "char" ) {
                exBitmapFont.CharInfo charInfo = new exBitmapFont.CharInfo();
                charInfo.id = int.Parse ( ParseValue( words, "id" ) );
                charInfo.x = int.Parse ( ParseValue( words, "x" ) );
                charInfo.y = int.Parse ( ParseValue( words, "y" ) );
                charInfo.width = int.Parse ( ParseValue( words, "width" ) );
                charInfo.height = int.Parse ( ParseValue( words, "height" ) );
                charInfo.xoffset = int.Parse ( ParseValue( words, "xoffset" ) );
                charInfo.yoffset = int.Parse ( ParseValue( words, "yoffset" ) );
                charInfo.xadvance = int.Parse ( ParseValue( words, "xadvance" ) );
                charInfo.page = int.Parse ( ParseValue( words, "page" ) );

                exBitmapFont.PageInfo pageInfo = _bitmapFont.pageInfos[charInfo.page];
                charInfo.uv0 = new Vector2 ( (float)charInfo.x / pageInfo.texture.width,
                                             (pageInfo.texture.height - (float)charInfo.y - charInfo.height) / pageInfo.texture.height );

                _bitmapFont.charInfos.Add(charInfo);
            }
            else if ( words[0] == "kerning" ) {
                exBitmapFont.KerningInfo kerningInfo = new exBitmapFont.KerningInfo();
                kerningInfo.first = int.Parse ( ParseValue( words, "first" ) );
                kerningInfo.second = int.Parse ( ParseValue( words, "second" ) );
                kerningInfo.amount = int.Parse ( ParseValue( words, "amount" ) );
                _bitmapFont.kernings.Add(kerningInfo);
            }
        }
        _bitmapFont.RebuildIdToCharInfoTable();
    }
Beispiel #13
0
    // ------------------------------------------------------------------
    // Desc:
    // ------------------------------------------------------------------

    static void ParseFontInfo(exBitmapFont _bitmapFont, Object _fontInfo)
    {
        EditorUtility.DisplayProgressBar("Building BitmapFont...",
                                         "Parsing font info...",
                                         0.1f);

        string fontInfoPath = AssetDatabase.GetAssetPath(_fontInfo);
        string dirname      = Path.GetDirectoryName(fontInfoPath);

        // TODO {
        // _bitmapFont.fontInfoGUIDs.Add(exEditorHelper.AssetToGUID(_fontInfo));
        // } TODO end

        // DELME {
        // string[] lines = _textAsset.text.Split ('\n');
        // foreach ( string line in lines ) {
        // } DELME end
        string       line;
        FileInfo     fileInfo = new FileInfo(fontInfoPath);
        StreamReader reader   = fileInfo.OpenText();

        while ((line = reader.ReadLine()) != null)
        {
            // DISABLE: it is too slow {
            // EditorUtility.DisplayProgressBar( "Building BitmapFont...",
            //                                   "Parsing line " + i,
            //                                   (float)i/(float)lines.Length );
            // } DISABLE end
            string[] words = line.Split(' ');
            if (words[0] == "info")
            {
                _bitmapFont.size = int.Parse(ParseValue(words, "size"));
            }
            else if (words[0] == "common")
            {
                _bitmapFont.lineHeight = int.Parse(ParseValue(words, "lineHeight"));
                // _bitmapFont.width = int.Parse ( ParseValue( words, "scaleW" ) );
                // _bitmapFont.height = int.Parse ( ParseValue( words, "scaleH" ) );
                int pages = int.Parse(ParseValue(words, "pages"));
                _bitmapFont.pageInfos = new List <exBitmapFont.PageInfo>(pages);
                for (int i = 0; i < pages; ++i)
                {
                    _bitmapFont.pageInfos.Add(new exBitmapFont.PageInfo());
                }
                // DISABLE {
                // if ( pages != 1 ) {
                //     Debug.LogError ( "Parse Error: only support one page" );
                //     return;
                // }
                // } DISABLE end
            }
            else if (words[0] == "page")
            {
                // check if id is valid
                int id = int.Parse(ParseValue(words, "id"));
                if (id >= _bitmapFont.pageInfos.Count)
                {
                    Debug.LogError("Parse Failed: The page id is exceed the page number");
                    return;
                }

                // load texture from file
                string filename = ParseValue(words, "file");
                filename = filename.Substring(1, filename.Length - 2); // remove the "" in "foobar.png"
                string    texturePath = Path.Combine(dirname, filename);
                Texture2D texture     = (Texture2D)AssetDatabase.LoadAssetAtPath(texturePath, typeof(Texture2D));
                if (texture == null)
                {
                    Debug.LogError("Parse Failed: The texture " + filename + " not found.");
                    return;
                }

                // load material, if not exists, create a new one.
                string   filenameNoExt = Path.GetFileNameWithoutExtension(texturePath);
                string   materialPath  = Path.Combine(dirname, filenameNoExt) + ".mat";
                Material material      = (Material)AssetDatabase.LoadAssetAtPath(materialPath, typeof(Material));
                if (material == null)
                {
                    material             = new Material(Shader.Find("ex2D/Alpha Blended"));
                    material.mainTexture = texture;
                    AssetDatabase.CreateAsset(material, materialPath);
                }

                // add page info
                _bitmapFont.pageInfos[id].texture  = texture;
                _bitmapFont.pageInfos[id].material = material;
            }
            else if (words[0] == "char")
            {
                exBitmapFont.CharInfo charInfo = new exBitmapFont.CharInfo();
                charInfo.id       = int.Parse(ParseValue(words, "id"));
                charInfo.x        = int.Parse(ParseValue(words, "x"));
                charInfo.y        = int.Parse(ParseValue(words, "y"));
                charInfo.width    = int.Parse(ParseValue(words, "width"));
                charInfo.height   = int.Parse(ParseValue(words, "height"));
                charInfo.xoffset  = int.Parse(ParseValue(words, "xoffset"));
                charInfo.yoffset  = int.Parse(ParseValue(words, "yoffset"));
                charInfo.xadvance = int.Parse(ParseValue(words, "xadvance"));
                charInfo.page     = int.Parse(ParseValue(words, "page"));

                exBitmapFont.PageInfo pageInfo = _bitmapFont.pageInfos[charInfo.page];
                charInfo.uv0 = new Vector2((float)charInfo.x / pageInfo.texture.width,
                                           (pageInfo.texture.height - (float)charInfo.y - charInfo.height) / pageInfo.texture.height);

                _bitmapFont.charInfos.Add(charInfo);
            }
            else if (words[0] == "kerning")
            {
                exBitmapFont.KerningInfo kerningInfo = new exBitmapFont.KerningInfo();
                kerningInfo.first  = int.Parse(ParseValue(words, "first"));
                kerningInfo.second = int.Parse(ParseValue(words, "second"));
                kerningInfo.amount = int.Parse(ParseValue(words, "amount"));
                _bitmapFont.kernings.Add(kerningInfo);
            }
        }
        _bitmapFont.RebuildIdToCharInfoTable();
    }
    // ------------------------------------------------------------------
    // Desc:
    // ------------------------------------------------------------------
    public static bool Parse( exBitmapFont _bitmapFont, Object _fontInfo )
    {
        _bitmapFont.Reset();

        string fontInfoPath = AssetDatabase.GetAssetPath(_fontInfo);
        string dirname = Path.GetDirectoryName(fontInfoPath);

        string line;
        FileInfo fileInfo = new FileInfo(fontInfoPath);
        StreamReader reader = fileInfo.OpenText();
        int textureHeight = -1;
        while ( (line = reader.ReadLine()) != null ) {

            string[] words = line.Split(' ');
            if ( words[0] == "info" ) {
                _bitmapFont.size = int.Parse ( ParseValue( words, "size" ) );
            }
            else if ( words[0] == "common" ) {
                _bitmapFont.lineHeight = int.Parse ( ParseValue( words, "lineHeight" ) );
                _bitmapFont.baseLine = int.Parse ( ParseValue( words, "base" ) );
                // _bitmapFont.width = int.Parse ( ParseValue( words, "scaleW" ) );
                // _bitmapFont.height = int.Parse ( ParseValue( words, "scaleH" ) );

                int pages = int.Parse( ParseValue( words, "pages" ) );
                if ( pages != 1 ) {
                    Debug.LogError ( "Parse Error: only support one page" );
                    return false;
                }
            }
            else if ( words[0] == "page" ) {
                // load texture from file
                string filename = ParseValue( words, "file" );
                filename = filename.Substring( 1, filename.Length-2 ); // remove the "" in "foobar.png"
                string texturePath = Path.Combine( dirname, filename );
                Texture2D texture = (Texture2D)AssetDatabase.LoadAssetAtPath( texturePath, typeof(Texture2D) );
                if ( texture == null ) {
                    Debug.LogError("Parse Failed: The texture " + filename + " not found.");
                    return false;
                }
                if ( exEditorUtility.IsValidForBitmapFont(texture) == false ) {
                    exEditorUtility.ImportTextureForBitmapFont(texture);
                }
                textureHeight = texture.height;

                // add page info
                _bitmapFont.texture = texture;
            }
            else if ( words[0] == "char" ) {
                exBitmapFont.CharInfo charInfo = new exBitmapFont.CharInfo();
                charInfo.id = int.Parse ( ParseValue( words, "id" ) );
                charInfo.width = int.Parse ( ParseValue( words, "width" ) );
                charInfo.height = int.Parse ( ParseValue( words, "height" ) );
                charInfo.trim_x = int.Parse ( ParseValue( words, "x" ) );
                charInfo.trim_y = int.Parse ( ParseValue( words, "y" ) );
                charInfo.xoffset = int.Parse ( ParseValue( words, "xoffset" ) );
                charInfo.yoffset = int.Parse ( ParseValue( words, "yoffset" ) );
                charInfo.xadvance = int.Parse ( ParseValue( words, "xadvance" ) );
                charInfo.rotated = false;
                // charInfo.page = int.Parse ( ParseValue( words, "page" ) );

                // add char info
                _bitmapFont.charInfos.Add(charInfo);
            }
            else if ( words[0] == "kerning" ) {
                exBitmapFont.KerningInfo kerningInfo = new exBitmapFont.KerningInfo();
                kerningInfo.first = int.Parse ( ParseValue( words, "first" ) );
                kerningInfo.second = int.Parse ( ParseValue( words, "second" ) );
                kerningInfo.amount = int.Parse ( ParseValue( words, "amount" ) );
                _bitmapFont.kernings.Add(kerningInfo);
            }
        }
        reader.Close();
        _bitmapFont.rawFontGUID = exEditorUtility.AssetToGUID(_fontInfo);
        _bitmapFont.rawTextureGUID = exEditorUtility.AssetToGUID(_bitmapFont.texture);

        // revert charInfo uv-y to fit the Unity's uv-coordination.
        foreach ( exBitmapFont.CharInfo charInfo in _bitmapFont.charInfos ) {
            charInfo.trim_y = textureHeight - (charInfo.trim_y + charInfo.height);
            charInfo.x = charInfo.trim_x;
            charInfo.y = charInfo.trim_y;
        }

        EditorUtility.SetDirty(_bitmapFont);

        return true;
    }