use of com.badlogic.gdx.graphics.g2d.BitmapFont.BitmapFontData in project libgdx by libgdx.
the class Skin method getJsonLoader.
protected Json getJsonLoader(final FileHandle skinFile) {
final Skin skin = this;
final Json json = new Json() {
public <T> T readValue(Class<T> type, Class elementType, JsonValue jsonData) {
// If the JSON is a string but the type is not, look up the actual value by name.
if (jsonData.isString() && !ClassReflection.isAssignableFrom(CharSequence.class, type))
return get(jsonData.asString(), type);
return super.readValue(type, elementType, jsonData);
}
};
json.setTypeName(null);
json.setUsePrototypes(false);
json.setSerializer(Skin.class, new ReadOnlySerializer<Skin>() {
public Skin read(Json json, JsonValue typeToValueMap, Class ignored) {
for (JsonValue valueMap = typeToValueMap.child; valueMap != null; valueMap = valueMap.next) {
try {
readNamedObjects(json, ClassReflection.forName(valueMap.name()), valueMap);
} catch (ReflectionException ex) {
throw new SerializationException(ex);
}
}
return skin;
}
private void readNamedObjects(Json json, Class type, JsonValue valueMap) {
Class addType = type == TintedDrawable.class ? Drawable.class : type;
for (JsonValue valueEntry = valueMap.child; valueEntry != null; valueEntry = valueEntry.next) {
Object object = json.readValue(type, valueEntry);
if (object == null)
continue;
try {
add(valueEntry.name, object, addType);
if (addType != Drawable.class && ClassReflection.isAssignableFrom(Drawable.class, addType))
add(valueEntry.name, object, Drawable.class);
} catch (Exception ex) {
throw new SerializationException("Error reading " + ClassReflection.getSimpleName(type) + ": " + valueEntry.name, ex);
}
}
}
});
json.setSerializer(BitmapFont.class, new ReadOnlySerializer<BitmapFont>() {
public BitmapFont read(Json json, JsonValue jsonData, Class type) {
String path = json.readValue("file", String.class, jsonData);
int scaledSize = json.readValue("scaledSize", int.class, -1, jsonData);
Boolean flip = json.readValue("flip", Boolean.class, false, jsonData);
Boolean markupEnabled = json.readValue("markupEnabled", Boolean.class, false, jsonData);
FileHandle fontFile = skinFile.parent().child(path);
if (!fontFile.exists())
fontFile = Gdx.files.internal(path);
if (!fontFile.exists())
throw new SerializationException("Font file not found: " + fontFile);
// Use a region with the same name as the font, else use a PNG file in the same directory as the FNT file.
String regionName = fontFile.nameWithoutExtension();
try {
BitmapFont font;
Array<TextureRegion> regions = skin.getRegions(regionName);
if (regions != null)
font = new BitmapFont(new BitmapFontData(fontFile, flip), regions, true);
else {
TextureRegion region = skin.optional(regionName, TextureRegion.class);
if (region != null)
font = new BitmapFont(fontFile, region, flip);
else {
FileHandle imageFile = fontFile.parent().child(regionName + ".png");
if (imageFile.exists())
font = new BitmapFont(fontFile, imageFile, flip);
else
font = new BitmapFont(fontFile, flip);
}
}
font.getData().markupEnabled = markupEnabled;
// Scaled size is the desired cap height to scale the font to.
if (scaledSize != -1)
font.getData().setScale(scaledSize / font.getCapHeight());
return font;
} catch (RuntimeException ex) {
throw new SerializationException("Error loading bitmap font: " + fontFile, ex);
}
}
});
json.setSerializer(Color.class, new ReadOnlySerializer<Color>() {
public Color read(Json json, JsonValue jsonData, Class type) {
if (jsonData.isString())
return get(jsonData.asString(), Color.class);
String hex = json.readValue("hex", String.class, (String) null, jsonData);
if (hex != null)
return Color.valueOf(hex);
float r = json.readValue("r", float.class, 0f, jsonData);
float g = json.readValue("g", float.class, 0f, jsonData);
float b = json.readValue("b", float.class, 0f, jsonData);
float a = json.readValue("a", float.class, 1f, jsonData);
return new Color(r, g, b, a);
}
});
json.setSerializer(TintedDrawable.class, new ReadOnlySerializer() {
public Object read(Json json, JsonValue jsonData, Class type) {
String name = json.readValue("name", String.class, jsonData);
Color color = json.readValue("color", Color.class, jsonData);
Drawable drawable = newDrawable(name, color);
if (drawable instanceof BaseDrawable) {
BaseDrawable named = (BaseDrawable) drawable;
named.setName(jsonData.name + " (" + name + ", " + color + ")");
}
return drawable;
}
});
return json;
}
use of com.badlogic.gdx.graphics.g2d.BitmapFont.BitmapFontData in project libgdx by libgdx.
the class TextField method paste.
void paste(String content, boolean fireChangeEvent) {
if (content == null)
return;
StringBuilder buffer = new StringBuilder();
int textLength = text.length();
if (hasSelection)
textLength -= Math.abs(cursor - selectionStart);
BitmapFontData data = style.font.getData();
for (int i = 0, n = content.length(); i < n; i++) {
if (!withinMaxLength(textLength + buffer.length()))
break;
char c = content.charAt(i);
if (!(writeEnters && (c == ENTER_ANDROID || c == ENTER_DESKTOP))) {
if (c == '\r' || c == '\n')
continue;
if (onlyFontChars && !data.hasGlyph(c))
continue;
if (filter != null && !filter.acceptChar(this, c))
continue;
}
buffer.append(c);
}
content = buffer.toString();
if (hasSelection)
cursor = delete(fireChangeEvent);
if (fireChangeEvent)
changeText(text, insert(cursor, content, text));
else
text = insert(cursor, content, text);
updateDisplayText();
cursor += content.length();
}
use of com.badlogic.gdx.graphics.g2d.BitmapFont.BitmapFontData in project libgdx by libgdx.
the class GlyphPage method renderGlyph.
/** Loads a single glyph to the backing texture, if it fits. */
private boolean renderGlyph(Glyph glyph, int pageX, int pageY, int width, int height) {
scratchGraphics.setComposite(AlphaComposite.Clear);
scratchGraphics.fillRect(0, 0, MAX_GLYPH_SIZE, MAX_GLYPH_SIZE);
scratchGraphics.setComposite(AlphaComposite.SrcOver);
ByteBuffer glyphPixels = scratchByteBuffer;
int format;
if (unicodeFont.getRenderType() == RenderType.FreeType && unicodeFont.bitmapFont != null) {
BitmapFontData data = unicodeFont.bitmapFont.getData();
BitmapFont.Glyph g = data.getGlyph((char) glyph.getCodePoint());
Pixmap fontPixmap = unicodeFont.bitmapFont.getRegions().get(g.page).getTexture().getTextureData().consumePixmap();
int fontWidth = fontPixmap.getWidth();
int padTop = unicodeFont.getPaddingTop(), padBottom = unicodeFont.getPaddingBottom();
int padLeftBytes = unicodeFont.getPaddingLeft() * 4;
int padXBytes = padLeftBytes + unicodeFont.getPaddingRight() * 4;
int glyphRowBytes = width * 4, fontRowBytes = g.width * 4;
ByteBuffer fontPixels = fontPixmap.getPixels();
byte[] row = new byte[glyphRowBytes];
glyphPixels.position(0);
for (int i = 0; i < padTop; i++) glyphPixels.put(row);
glyphPixels.position((height - padBottom) * glyphRowBytes);
for (int i = 0; i < padBottom; i++) glyphPixels.put(row);
glyphPixels.position(padTop * glyphRowBytes);
for (int y = 0, n = g.height; y < n; y++) {
fontPixels.position(((g.srcY + y) * fontWidth + g.srcX) * 4);
fontPixels.get(row, padLeftBytes, fontRowBytes);
glyphPixels.put(row);
}
fontPixels.position(0);
glyphPixels.position(height * glyphRowBytes);
glyphPixels.flip();
format = GL11.GL_RGBA;
} else {
// Draw the glyph to the scratch image using Java2D.
if (unicodeFont.getRenderType() == RenderType.Native) {
for (Iterator iter = unicodeFont.getEffects().iterator(); iter.hasNext(); ) {
Effect effect = (Effect) iter.next();
if (effect instanceof ColorEffect)
scratchGraphics.setColor(((ColorEffect) effect).getColor());
}
scratchGraphics.setColor(java.awt.Color.white);
scratchGraphics.setFont(unicodeFont.getFont());
scratchGraphics.drawString("" + (char) glyph.getCodePoint(), 0, unicodeFont.getAscent());
} else if (unicodeFont.getRenderType() == RenderType.Java) {
scratchGraphics.setColor(java.awt.Color.white);
for (Iterator iter = unicodeFont.getEffects().iterator(); iter.hasNext(); ) ((Effect) iter.next()).draw(scratchImage, scratchGraphics, unicodeFont, glyph);
// The shape will never be needed again.
glyph.setShape(null);
}
width = Math.min(width, texture.getWidth());
height = Math.min(height, texture.getHeight());
WritableRaster raster = scratchImage.getRaster();
int[] row = new int[width];
for (int y = 0; y < height; y++) {
raster.getDataElements(0, y, width, 1, row);
scratchIntBuffer.put(row);
}
format = GL12.GL_BGRA;
}
// Simple deduplication, doesn't work across pages of course.
String hash = "";
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(glyphPixels);
BigInteger bigInt = new BigInteger(1, md.digest());
hash = bigInt.toString(16);
} catch (NoSuchAlgorithmException ex) {
}
scratchByteBuffer.clear();
scratchIntBuffer.clear();
try {
for (int i = 0, n = hashes.size(); i < n; i++) {
String other = hashes.get(i);
if (other.equals(hash)) {
Glyph dupe = pageGlyphs.get(i);
glyph.setTexture(dupe.texture, dupe.u, dupe.v, dupe.u2, dupe.v2);
return false;
}
}
} finally {
hashes.add(hash);
pageGlyphs.add(glyph);
}
Gdx.gl.glTexSubImage2D(texture.glTarget, 0, pageX, pageY, width, height, format, GL11.GL_UNSIGNED_BYTE, glyphPixels);
float u = pageX / (float) texture.getWidth();
float v = pageY / (float) texture.getHeight();
float u2 = (pageX + width) / (float) texture.getWidth();
float v2 = (pageY + height) / (float) texture.getHeight();
glyph.setTexture(texture, u, v, u2, v2);
return true;
}
use of com.badlogic.gdx.graphics.g2d.BitmapFont.BitmapFontData in project libgdx by libgdx.
the class GlyphLayout method setText.
/** @param color The default color to use for the text (the BitmapFont {@link BitmapFont#getColor() color} is not used). If
* {@link BitmapFontData#markupEnabled} is true, color markup tags in the specified string may change the color for
* portions of the text.
* @param halign Horizontal alignment of the text, see {@link Align}.
* @param targetWidth The width used for alignment, line wrapping, and truncation. May be zero if those features are not used.
* @param truncate If not null and the width of the glyphs exceed targetWidth, the glyphs are truncated and the glyphs for the
* specified truncate string are placed at the end. Empty string can be used to truncate without adding glyphs.
* Truncate should not be used with text that contains multiple lines. Wrap is ignored if truncate is not null. */
public void setText(BitmapFont font, CharSequence str, int start, int end, Color color, float targetWidth, int halign, boolean wrap, String truncate) {
if (truncate != null)
// Causes truncate code to run, doesn't actually cause wrapping.
wrap = true;
else if (//
targetWidth <= font.data.spaceWidth)
// Avoid one line per character, which is very inefficient.
wrap = false;
BitmapFontData fontData = font.data;
boolean markupEnabled = fontData.markupEnabled;
Pool<GlyphRun> glyphRunPool = Pools.get(GlyphRun.class);
Array<GlyphRun> runs = this.runs;
glyphRunPool.freeAll(runs);
runs.clear();
float x = 0, y = 0, width = 0;
int lines = 0, blankLines = 0;
Array<Color> colorStack = this.colorStack;
Color nextColor = color;
colorStack.add(color);
Pool<Color> colorPool = Pools.get(Color.class);
int runStart = start;
outer: while (true) {
// Each run is delimited by newline or left square bracket.
int runEnd = -1;
boolean newline = false, colorRun = false;
if (start == end) {
// End of string with no run to process, we're done.
if (runStart == end)
break;
// End of string, process last run.
runEnd = end;
} else {
switch(str.charAt(start++)) {
case '\n':
// End of line.
runEnd = start - 1;
newline = true;
break;
case '[':
// Possible color tag.
if (markupEnabled) {
int length = parseColorMarkup(str, start, end, colorPool);
if (length >= 0) {
runEnd = start - 1;
start += length + 1;
nextColor = colorStack.peek();
colorRun = true;
} else if (length == -2) {
// Skip first of "[[" escape sequence.
start++;
continue outer;
}
}
break;
}
}
if (runEnd != -1) {
if (runEnd != runStart) {
// Can happen (eg) when a color tag is at text start or a line is "\n".
// Store the run that has ended.
GlyphRun run = glyphRunPool.obtain();
run.color.set(color);
run.x = x;
run.y = y;
fontData.getGlyphs(run, str, runStart, runEnd, colorRun);
if (run.glyphs.size == 0)
glyphRunPool.free(run);
else {
runs.add(run);
// Compute the run width, wrap if necessary, and position the run.
float[] xAdvances = run.xAdvances.items;
for (int i = 0, n = run.xAdvances.size; i < n; i++) {
float xAdvance = xAdvances[i];
x += xAdvance;
// Don't wrap if the glyph would fit with just its width (no xadvance or kerning).
if (wrap && x > targetWidth && i > 1 && x - xAdvance + (run.glyphs.get(i - 1).xoffset + run.glyphs.get(i - 1).width) * fontData.scaleX - 0.0001f > targetWidth) {
if (truncate != null) {
truncate(fontData, run, targetWidth, truncate, i, glyphRunPool);
x = run.x + run.width;
break outer;
}
int wrapIndex = fontData.getWrapIndex(run.glyphs, i);
if (// Require at least one glyph per line.
(run.x == 0 && wrapIndex == 0) || wrapIndex >= run.glyphs.size) {
// Wrap at least the glyph that didn't fit.
wrapIndex = i - 1;
}
GlyphRun next;
if (wrapIndex == 0)
// No wrap index, move entire run to next line.
next = run;
else {
next = wrap(fontData, run, glyphRunPool, wrapIndex, i);
runs.add(next);
}
// Start the loop over with the new run on the next line.
width = Math.max(width, run.x + run.width);
x = 0;
y += fontData.down;
lines++;
next.x = 0;
next.y = y;
i = -1;
n = next.xAdvances.size;
xAdvances = next.xAdvances.items;
run = next;
} else
run.width += xAdvance;
}
}
}
if (newline) {
// Next run will be on the next line.
width = Math.max(width, x);
x = 0;
float down = fontData.down;
if (runEnd == runStart) {
// Blank line.
down *= fontData.blankLineScale;
blankLines++;
} else
lines++;
y += down;
}
runStart = start;
color = nextColor;
}
}
width = Math.max(width, x);
for (int i = 1, n = colorStack.size; i < n; i++) colorPool.free(colorStack.get(i));
colorStack.clear();
// Align runs to center or right of targetWidth.
if ((halign & Align.left) == 0) {
// Not left aligned, so must be center or right aligned.
boolean center = (halign & Align.center) != 0;
float lineWidth = 0, lineY = Integer.MIN_VALUE;
int lineStart = 0, n = runs.size;
for (int i = 0; i < n; i++) {
GlyphRun run = runs.get(i);
if (run.y != lineY) {
lineY = run.y;
float shift = targetWidth - lineWidth;
if (center)
shift /= 2;
while (lineStart < i) runs.get(lineStart++).x += shift;
lineWidth = 0;
}
lineWidth += run.width;
}
float shift = targetWidth - lineWidth;
if (center)
shift /= 2;
while (lineStart < n) runs.get(lineStart++).x += shift;
}
this.width = width;
this.height = fontData.capHeight + lines * fontData.lineHeight + blankLines * fontData.lineHeight * fontData.blankLineScale;
}
use of com.badlogic.gdx.graphics.g2d.BitmapFont.BitmapFontData in project libgdx by libgdx.
the class FreeTypePackTest method createFonts.
protected int createFonts() {
// //////////////////////////////////////////////////////////////////////////////////////////////////////
// //////Steps to use multiple FreeTypeFontGenerators with a single texture atlas://////////////////////
// 1. Create a new PixmapPacker big enough to fit all your desired glyphs
// 2. Create a new FreeTypeFontGenerator for each file (i.e. font styles/families)
// 3. Pack the data by specifying the PixmapPacker parameter to generateData
// Keep hold of the returned BitmapFontData for later
// 4. Repeat for other sizes.
// 5. Dispose the generator and repeat for other font styles/families
// 6. Get the TextureRegion(s) from the packer using packer.updateTextureRegions()
// 7. Dispose the PixmapPacker
// 8. Use each BitmapFontData to construct a new BitmapFont, and specify your TextureRegion(s) to the font constructor
// 9. Dispose of the Texture upon application exit or when you are done using the font atlas
// //////////////////////////////////////////////////////////////////////////////////////////////////////
// create the pixmap packer
PixmapPacker packer = new PixmapPacker(FONT_ATLAS_WIDTH, FONT_ATLAS_HEIGHT, Format.RGBA8888, 2, false);
// we need to load all the BitmapFontDatas before we can start loading BitmapFonts
FontMap<BitmapFontData> dataMap = new FontMap<BitmapFontData>();
// for each style...
for (FontStyle style : FontStyle.values()) {
// get the file for this style
FreeTypeFontGenerator gen = new FreeTypeFontGenerator(Gdx.files.internal(style.path));
// For each size...
for (FontSize size : FontSize.values()) {
// pack the glyphs into the atlas using the default chars
FreeTypeFontGenerator.FreeTypeFontParameter fontParameter = new FreeTypeFontGenerator.FreeTypeFontParameter();
fontParameter.size = size.size;
fontParameter.packer = packer;
fontParameter.characters = CHARACTERS;
BitmapFontData data = gen.generateData(fontParameter);
// store the info for later, when we generate the texture
dataMap.get(style).put(size, data);
}
// dispose of the generator once we're finished with this family
gen.dispose();
}
// Get regions from our packer
regions = new Array<TextureRegion>();
packer.updateTextureRegions(regions, TextureFilter.Nearest, TextureFilter.Nearest, false);
// No more need for our CPU-based pixmap packer, as our textures are now on GPU
packer.dispose();
// Now we can create our fonts...
fontMap = new FontMap<BitmapFont>();
int fontCount = 0;
// for each style...
for (FontStyle style : FontStyle.values()) {
// For each size...
for (FontSize size : FontSize.values()) {
// get the data for this style/size pair
BitmapFontData data = dataMap.get(style).get(size);
// create a BitmapFont from the data and shared texture
BitmapFont bmFont = new BitmapFont(data, regions, INTEGER);
// place the font into our map of loaded fonts
fontMap.get(style).put(size, bmFont);
fontCount++;
}
}
// for the demo, show how many glyphs we loaded
return fontCount * CHARACTERS.length();
}
Aggregations