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