Search in sources :

Example 1 with GlyphSlot

use of com.badlogic.gdx.graphics.g2d.freetype.FreeType.GlyphSlot in project libgdx by libgdx.

the class FreeTypeFontGenerator method createGlyph.

/** @return null if glyph was not found. */
Glyph createGlyph(char c, FreeTypeBitmapFontData data, FreeTypeFontParameter parameter, Stroker stroker, float baseLine, PixmapPacker packer) {
    boolean missing = face.getCharIndex(c) == 0 && c != 0;
    if (missing)
        return null;
    if (!loadChar(c, getLoadingFlags(parameter)))
        return null;
    GlyphSlot slot = face.getGlyph();
    FreeType.Glyph mainGlyph = slot.getGlyph();
    try {
        mainGlyph.toBitmap(parameter.mono ? FreeType.FT_RENDER_MODE_MONO : FreeType.FT_RENDER_MODE_NORMAL);
    } catch (GdxRuntimeException e) {
        mainGlyph.dispose();
        Gdx.app.log("FreeTypeFontGenerator", "Couldn't render char: " + c);
        return null;
    }
    Bitmap mainBitmap = mainGlyph.getBitmap();
    Pixmap mainPixmap = mainBitmap.getPixmap(Format.RGBA8888, parameter.color, parameter.gamma);
    if (mainBitmap.getWidth() != 0 && mainBitmap.getRows() != 0) {
        int offsetX = 0, offsetY = 0;
        if (parameter.borderWidth > 0) {
            // execute stroker; this generates a glyph "extended" along the outline
            int top = mainGlyph.getTop(), left = mainGlyph.getLeft();
            FreeType.Glyph borderGlyph = slot.getGlyph();
            borderGlyph.strokeBorder(stroker, false);
            borderGlyph.toBitmap(parameter.mono ? FreeType.FT_RENDER_MODE_MONO : FreeType.FT_RENDER_MODE_NORMAL);
            offsetX = left - borderGlyph.getLeft();
            offsetY = -(top - borderGlyph.getTop());
            // Render border (pixmap is bigger than main).
            Bitmap borderBitmap = borderGlyph.getBitmap();
            Pixmap borderPixmap = borderBitmap.getPixmap(Format.RGBA8888, parameter.borderColor, parameter.borderGamma);
            // Draw main glyph on top of border.
            for (int i = 0, n = parameter.renderCount; i < n; i++) borderPixmap.drawPixmap(mainPixmap, offsetX, offsetY);
            mainPixmap.dispose();
            mainGlyph.dispose();
            mainPixmap = borderPixmap;
            mainGlyph = borderGlyph;
        }
        if (parameter.shadowOffsetX != 0 || parameter.shadowOffsetY != 0) {
            int mainW = mainPixmap.getWidth(), mainH = mainPixmap.getHeight();
            int shadowOffsetX = Math.max(parameter.shadowOffsetX, 0), shadowOffsetY = Math.max(parameter.shadowOffsetY, 0);
            int shadowW = mainW + Math.abs(parameter.shadowOffsetX), shadowH = mainH + Math.abs(parameter.shadowOffsetY);
            Pixmap shadowPixmap = new Pixmap(shadowW, shadowH, mainPixmap.getFormat());
            Color shadowColor = parameter.shadowColor;
            float a = shadowColor.a;
            if (a != 0) {
                byte r = (byte) (shadowColor.r * 255), g = (byte) (shadowColor.g * 255), b = (byte) (shadowColor.b * 255);
                ByteBuffer mainPixels = mainPixmap.getPixels();
                ByteBuffer shadowPixels = shadowPixmap.getPixels();
                for (int y = 0; y < mainH; y++) {
                    int shadowRow = shadowW * (y + shadowOffsetY) + shadowOffsetX;
                    for (int x = 0; x < mainW; x++) {
                        int mainPixel = (mainW * y + x) * 4;
                        byte mainA = mainPixels.get(mainPixel + 3);
                        if (mainA == 0)
                            continue;
                        int shadowPixel = (shadowRow + x) * 4;
                        shadowPixels.put(shadowPixel, r);
                        shadowPixels.put(shadowPixel + 1, g);
                        shadowPixels.put(shadowPixel + 2, b);
                        shadowPixels.put(shadowPixel + 3, (byte) ((mainA & 0xff) * a));
                    }
                }
            }
            // Draw main glyph (with any border) on top of shadow.
            for (int i = 0, n = parameter.renderCount; i < n; i++) shadowPixmap.drawPixmap(mainPixmap, Math.max(-parameter.shadowOffsetX, 0), Math.max(-parameter.shadowOffsetY, 0));
            mainPixmap.dispose();
            mainPixmap = shadowPixmap;
        } else if (parameter.borderWidth == 0) {
            // No shadow and no border, draw glyph additional times.
            for (int i = 0, n = parameter.renderCount - 1; i < n; i++) mainPixmap.drawPixmap(mainPixmap, 0, 0);
        }
    }
    GlyphMetrics metrics = slot.getMetrics();
    Glyph glyph = new Glyph();
    glyph.id = c;
    glyph.width = mainPixmap.getWidth();
    glyph.height = mainPixmap.getHeight();
    glyph.xoffset = mainGlyph.getLeft();
    glyph.yoffset = parameter.flip ? -mainGlyph.getTop() + (int) baseLine : -(glyph.height - mainGlyph.getTop()) - (int) baseLine;
    glyph.xadvance = FreeType.toInt(metrics.getHoriAdvance()) + (int) parameter.borderWidth + parameter.spaceX;
    if (bitmapped) {
        mainPixmap.setColor(Color.CLEAR);
        mainPixmap.fill();
        ByteBuffer buf = mainBitmap.getBuffer();
        int whiteIntBits = Color.WHITE.toIntBits();
        int clearIntBits = Color.CLEAR.toIntBits();
        for (int h = 0; h < glyph.height; h++) {
            int idx = h * mainBitmap.getPitch();
            for (int w = 0; w < (glyph.width + glyph.xoffset); w++) {
                int bit = (buf.get(idx + (w / 8)) >>> (7 - (w % 8))) & 1;
                mainPixmap.drawPixel(w, h, ((bit == 1) ? whiteIntBits : clearIntBits));
            }
        }
    }
    Rectangle rect = packer.pack(mainPixmap);
    // Glyph is always packed into the last page for now.
    glyph.page = packer.getPages().size - 1;
    glyph.srcX = (int) rect.x;
    glyph.srcY = (int) rect.y;
    // If a page was added, create a new texture region for the incrementally added glyph.
    if (parameter.incremental && data.regions != null && data.regions.size <= glyph.page)
        packer.updateTextureRegions(data.regions, parameter.minFilter, parameter.magFilter, parameter.genMipMaps);
    mainPixmap.dispose();
    mainGlyph.dispose();
    return glyph;
}
Also used : GlyphSlot(com.badlogic.gdx.graphics.g2d.freetype.FreeType.GlyphSlot) GlyphMetrics(com.badlogic.gdx.graphics.g2d.freetype.FreeType.GlyphMetrics) Color(com.badlogic.gdx.graphics.Color) Rectangle(com.badlogic.gdx.math.Rectangle) ByteBuffer(java.nio.ByteBuffer) GdxRuntimeException(com.badlogic.gdx.utils.GdxRuntimeException) Bitmap(com.badlogic.gdx.graphics.g2d.freetype.FreeType.Bitmap) Glyph(com.badlogic.gdx.graphics.g2d.BitmapFont.Glyph) Pixmap(com.badlogic.gdx.graphics.Pixmap)

Example 2 with GlyphSlot

use of com.badlogic.gdx.graphics.g2d.freetype.FreeType.GlyphSlot in project libgdx by libgdx.

the class FreeTypeFontGenerator method generateGlyphAndBitmap.

/** Returns null if glyph was not found. If there is nothing to render, for example with various space characters, then bitmap
	 * is null. */
public GlyphAndBitmap generateGlyphAndBitmap(int c, int size, boolean flip) {
    setPixelSizes(0, size);
    SizeMetrics fontMetrics = face.getSize().getMetrics();
    int baseline = FreeType.toInt(fontMetrics.getAscender());
    // 0 means 'undefined character code'
    if (face.getCharIndex(c) == 0) {
        return null;
    }
    // Try to load character
    if (!loadChar(c)) {
        throw new GdxRuntimeException("Unable to load character!");
    }
    GlyphSlot slot = face.getGlyph();
    // Try to render to bitmap
    Bitmap bitmap;
    if (bitmapped) {
        bitmap = slot.getBitmap();
    } else if (!slot.renderGlyph(FreeType.FT_RENDER_MODE_NORMAL)) {
        bitmap = null;
    } else {
        bitmap = slot.getBitmap();
    }
    GlyphMetrics metrics = slot.getMetrics();
    Glyph glyph = new Glyph();
    if (bitmap != null) {
        glyph.width = bitmap.getWidth();
        glyph.height = bitmap.getRows();
    } else {
        glyph.width = 0;
        glyph.height = 0;
    }
    glyph.xoffset = slot.getBitmapLeft();
    glyph.yoffset = flip ? -slot.getBitmapTop() + baseline : -(glyph.height - slot.getBitmapTop()) - baseline;
    glyph.xadvance = FreeType.toInt(metrics.getHoriAdvance());
    glyph.srcX = 0;
    glyph.srcY = 0;
    glyph.id = c;
    GlyphAndBitmap result = new GlyphAndBitmap();
    result.glyph = glyph;
    result.bitmap = bitmap;
    return result;
}
Also used : GdxRuntimeException(com.badlogic.gdx.utils.GdxRuntimeException) GlyphSlot(com.badlogic.gdx.graphics.g2d.freetype.FreeType.GlyphSlot) Bitmap(com.badlogic.gdx.graphics.g2d.freetype.FreeType.Bitmap) GlyphMetrics(com.badlogic.gdx.graphics.g2d.freetype.FreeType.GlyphMetrics) Glyph(com.badlogic.gdx.graphics.g2d.BitmapFont.Glyph) SizeMetrics(com.badlogic.gdx.graphics.g2d.freetype.FreeType.SizeMetrics)

Aggregations

Glyph (com.badlogic.gdx.graphics.g2d.BitmapFont.Glyph)2 Bitmap (com.badlogic.gdx.graphics.g2d.freetype.FreeType.Bitmap)2 GlyphMetrics (com.badlogic.gdx.graphics.g2d.freetype.FreeType.GlyphMetrics)2 GlyphSlot (com.badlogic.gdx.graphics.g2d.freetype.FreeType.GlyphSlot)2 GdxRuntimeException (com.badlogic.gdx.utils.GdxRuntimeException)2 Color (com.badlogic.gdx.graphics.Color)1 Pixmap (com.badlogic.gdx.graphics.Pixmap)1 SizeMetrics (com.badlogic.gdx.graphics.g2d.freetype.FreeType.SizeMetrics)1 Rectangle (com.badlogic.gdx.math.Rectangle)1 ByteBuffer (java.nio.ByteBuffer)1