private void LoadAndParseConfigFile() { TextAsset asset = (TextAsset) Resources.Load(_configPath, typeof(TextAsset)); if(asset == null) { throw new FutileException("Couldn't find font config file " + _configPath); } string[] separators = new string[1]; separators[0] = "\n"; //osx string[] lines = asset.text.Split(separators,StringSplitOptions.RemoveEmptyEntries); if(lines.Length <= 1) //osx line endings didn't work, try windows { separators[0] = "\r\n"; lines = asset.text.Split(separators,StringSplitOptions.RemoveEmptyEntries); } if(lines.Length <= 1) //those line endings didn't work, so we're on a magical OS { separators[0] = "\r"; lines = asset.text.Split(separators,StringSplitOptions.RemoveEmptyEntries); } if(lines.Length <= 1) //WHAT { throw new FutileException("Your font file is messed up"); } int wordCount = 0; int c = 0; int k = 0; _charInfosByID = new Dictionary<uint, FCharInfo>(127); //insert an empty char to be used when a character isn't in the font data file FCharInfo emptyChar = new FCharInfo(); _charInfosByID[0] = emptyChar; float resourceScale = Futile.resourceScale; Vector2 textureSize = _element.atlas.textureSize; bool wasKerningFound = false; int lineCount = lines.Length; for(int n = 0; n<lineCount; ++n) { string line = lines[n]; string [] words = line.Split(new char[] {' '}, StringSplitOptions.RemoveEmptyEntries); /* we don't care about these, or else they could be in the elseif if(words[0] == "info") //info face="Franchise Bold" size=160 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=1,1 { //do nothing } else if(words[0] == "page") //page id=0 file="FranchiseLarge.png" { //do nothing } */ if(words[0] == "common") //common lineHeight=168 base=26 scaleW=1024 scaleH=1024 pages=1 packed=0 { //these are the height and width of the original atlas built by Hiero _configWidth = int.Parse(words[3].Split('=')[1]); //_configHeight = int.Parse(words[4].Split('=')[1]); //this is the ratio of the config vs the size of the actual texture element _configRatio = _element.sourceSize.x/_configWidth; _lineHeight = int.Parse(words[1].Split('=')[1]) * _configRatio; //_lineBase = int.Parse(words[2].Split('=')[1]) * _configRatio; } else if(words[0] == "chars") //chars count=92 { int charCount = int.Parse(words[1].Split('=')[1]); _charInfos = new FCharInfo[charCount+1]; //gotta add 1 because the charCount seems to be off by 1 } else if(words[0] == "char") //char id=32 x=0 y=0 width=0 height=0 xoffset=0 yoffset=120 xadvance=29 page=0 chnl=0 letter=a { FCharInfo charInfo = new FCharInfo(); wordCount = words.Length; for(int w = 1; w<wordCount; ++w) { string[] parts = words[w].Split('='); string partName = parts[0]; if(partName == "letter") { if(parts[1].Length >= 3) { charInfo.letter = parts[1].Substring(1,1); } continue; //we don't care about the letter } if(partName == "\r") continue; //something weird happened with linebreaks, meh! int partValue = int.Parse(parts[1]); if(partName == "id") { charInfo.charID = partValue; } else if(partName == "x") { charInfo.x = partValue*_configRatio - _element.sourceRect.x; //offset to account for the trimmed atlas } else if(partName == "y") { charInfo.y = partValue*_configRatio - _element.sourceRect.y; //offset to account for the trimmed atlas } else if(partName == "width") { charInfo.width = partValue*_configRatio; } else if(partName == "height") { charInfo.height = partValue*_configRatio; } else if(partName == "xoffset") { charInfo.offsetX = partValue*_configRatio; } else if(partName == "yoffset") { charInfo.offsetY = partValue*_configRatio; } else if(partName == "xadvance") { charInfo.xadvance = partValue*_configRatio; } else if(partName == "page") { charInfo.page = partValue; } } Rect uvRect = new Rect ( _element.uvRect.x + charInfo.x/textureSize.x*resourceScale, (textureSize.y-charInfo.y-charInfo.height)/textureSize.y*resourceScale - (1.0f - _element.uvRect.yMax), charInfo.width/textureSize.x*resourceScale, charInfo.height/textureSize.y*resourceScale ); charInfo.uvRect = uvRect; charInfo.uvTopLeft.Set(uvRect.xMin,uvRect.yMax); charInfo.uvTopRight.Set(uvRect.xMax,uvRect.yMax); charInfo.uvBottomRight.Set(uvRect.xMax,uvRect.yMin); charInfo.uvBottomLeft.Set(uvRect.xMin,uvRect.yMin); _charInfosByID[(uint)charInfo.charID] = charInfo; _charInfos[c] = charInfo; c++; } else if(words[0] == "kernings") //kernings count=169 { wasKerningFound = true; int kerningCount = int.Parse(words[1].Split('=')[1]); _kerningInfos = new FKerningInfo[kerningCount+100]; //kerning count can be wrong so just add 100 items of potential fudge factor } else if(words[0] == "kerning") //kerning first=56 second=57 amount=-1 { FKerningInfo kerningInfo = new FKerningInfo(); kerningInfo.first = -1; wordCount = words.Length; for(int w = 1; w<wordCount; w++) { string[] parts = words[w].Split('='); if(parts.Length >= 2) { string partName = parts[0]; int partValue = int.Parse(parts[1]); if(partName == "first") { kerningInfo.first = partValue; } else if(partName == "second") { kerningInfo.second = partValue; } else if(partName == "amount") { kerningInfo.amount = partValue * _configRatio; } } } if(kerningInfo.first != -1) { _kerningInfos[k] = kerningInfo; } k++; } } _kerningCount = k; if(!wasKerningFound) //if there are no kernings at all (like in a pixel font), then make an empty kerning array { _kerningInfos = new FKerningInfo[0]; } //make sure the space character doesn't have offsetY and offsetX if(_charInfosByID[32] != null) { _charInfosByID[32].offsetX = 0; _charInfosByID[32].offsetY = 0; } }
public FLetterQuadLine[] GetQuadInfoForText(string text, FTextParams labelTextParams) { int lineCount = 0; int letterCount = 0; char[] letters = text.ToCharArray(); //at some point these should probably be pooled and reused so we're not allocing new ones all the time //now they're structs though, so it might not be an issue FLetterQuadLine[] lines = new FLetterQuadLine[15]; int lettersLength = letters.Length; for (int c = 0; c < lettersLength; ++c) { char letter = letters[c]; if (letter == ASCII_NEWLINE) { lines[lineCount] = new FLetterQuadLine(); lines[lineCount].letterCount = letterCount; lines[lineCount].quads = new FLetterQuad[letterCount]; lineCount++; letterCount = 0; } else { letterCount++; } } lines[lineCount] = new FLetterQuadLine(); lines[lineCount].letterCount = letterCount; lines[lineCount].quads = new FLetterQuad[letterCount]; FLetterQuadLine[] oldLines = lines; lines = new FLetterQuadLine[lineCount + 1]; for (int c = 0; c < lineCount + 1; ++c) { lines[c] = oldLines[c]; } lineCount = 0; letterCount = 0; float nextX = 0; float nextY = 0; FCharInfo charInfo; char previousLetter = '\0'; float minX = float.MaxValue; float maxX = float.MinValue; float minY = float.MaxValue; float maxY = float.MinValue; float usableLineHeight = _lineHeight + labelTextParams.scaledLineHeightOffset + _textParams.scaledLineHeightOffset; for (int c = 0; c < lettersLength; ++c) { char letter = letters[c]; if (letter == ASCII_NEWLINE) { if (letterCount == 0) { lines[lineCount].bounds = new Rect(0, 0, nextY, nextY - usableLineHeight); } else { lines[lineCount].bounds = new Rect(minX, minY, maxX - minX, maxY - minY); } minX = float.MaxValue; maxX = float.MinValue; minY = float.MaxValue; maxY = float.MinValue; nextX = 0; nextY -= usableLineHeight; lineCount++; letterCount = 0; } else { FKerningInfo foundKerning = _nullKerning; for (int k = 0; k < _kerningCount; k++) { FKerningInfo kerningInfo = _kerningInfos[k]; if (kerningInfo.first == previousLetter && kerningInfo.second == letter) { foundKerning = kerningInfo; } } //TODO: Reuse letterquads with pooling! FLetterQuad letterQuad = new FLetterQuad(); if (_charInfosByID.ContainsKey(letter)) { charInfo = _charInfosByID[letter]; } else //we don't have that character in the font { //blank, character (could consider using the "char not found square") charInfo = _charInfosByID[0]; } float totalKern = foundKerning.amount + labelTextParams.scaledKerningOffset + _textParams.scaledKerningOffset; if (letterCount == 0) { nextX = -charInfo.offsetX; //don't offset the first character } else { nextX += totalKern; } letterQuad.charInfo = charInfo; Rect quadRect = new Rect(nextX + charInfo.offsetX, nextY - charInfo.offsetY - charInfo.height, charInfo.width, charInfo.height); letterQuad.rect = quadRect; lines[lineCount].quads[letterCount] = letterQuad; minX = Math.Min(minX, quadRect.xMin); maxX = Math.Max(maxX, quadRect.xMax); minY = Math.Min(minY, nextY - usableLineHeight); maxY = Math.Max(maxY, nextY); nextX += charInfo.xadvance; letterCount++; } previousLetter = letter; } if (letterCount == 0) //there were no letters, so minX and minY would be crazy if we used them { lines[lineCount].bounds = new Rect(0, 0, nextY, nextY - usableLineHeight); } else { lines[lineCount].bounds = new Rect(minX, minY, maxX - minX, maxY - minY); } return(lines); }
public FLetterQuadLine[] GetQuadInfoForText(string text, FTextParams textParams) { int lineCount = 0; int letterCount = 0; char[] letters = text.ToCharArray(); FLetterQuadLine[] lines = new FLetterQuadLine[10]; for (int c = 0; c < letters.Length; ++c) { char letter = letters[c]; if (letter == ASCII_NEWLINE) { lines[lineCount] = new FLetterQuadLine(); lines[lineCount].letterCount = letterCount; lines[lineCount].quads = new FLetterQuad[letterCount]; lineCount++; letterCount = 0; } else { letterCount++; } } lines[lineCount] = new FLetterQuadLine(); lines[lineCount].letterCount = letterCount; lines[lineCount].quads = new FLetterQuad[letterCount]; FLetterQuadLine[] oldLines = lines; lines = new FLetterQuadLine[lineCount + 1]; for (int c = 0; c < lineCount + 1; ++c) { lines[c] = oldLines[c]; } lineCount = 0; letterCount = 0; float nextX = 0; float nextY = 0; FCharInfo charInfo; char previousLetter = '\0'; float minX = 100000; float maxX = -100000; float minY = 100000; float maxY = -100000; for (int c = 0; c < letters.Length; ++c) { char letter = letters[c]; if (letter == ASCII_NEWLINE) { lines[lineCount].bounds = new Rect(minX, minY, maxX - minX, maxY - minY); minX = 100000; maxX = -100000; minY = 100000; maxY = -100000; nextX = 0; nextY -= _lineHeight + textParams.scaledLineHeightOffset + _fontTextParams.scaledLineHeightOffset; lineCount++; letterCount = 0; } else { FKerningInfo foundKerning = _nullKerning; foreach (FKerningInfo kerningInfo in _kerningInfos) { if (kerningInfo.first == previousLetter && kerningInfo.second == letter) { foundKerning = kerningInfo; } } //TODO: Reuse letterquads with pooling! FLetterQuad letterQuad = new FLetterQuad(); charInfo = _charInfosByID[letter]; float totalKern = foundKerning.amount + textParams.scaledKerningOffset + _fontTextParams.scaledKerningOffset; nextX += totalKern; letterQuad.charInfo = charInfo; // Rect quadRect = new Rect(nextX + charInfo.offsetX, nextY - charInfo.offsetY - charInfo.height, charInfo.width, charInfo.height); letterQuad.rect = quadRect; lines[lineCount].quads[letterCount] = letterQuad; minX = Math.Min(minX, quadRect.xMin); maxX = Math.Max(maxX, quadRect.xMax); minY = Math.Min(minY, quadRect.yMin); maxY = Math.Max(maxY, quadRect.yMax); nextX += charInfo.xadvance; letterCount++; } previousLetter = letter; } lines[lineCount].bounds = new Rect(minX, minY, maxX - minX, maxY - minY); return(lines); }
private void LoadAndParseConfigFile() { TextAsset asset = (TextAsset)Resources.Load(_configPath, typeof(TextAsset)); if (asset == null) { throw new FutileException("Couldn't find font config file " + _configPath); } string[] separators = new string[1]; separators[0] = "\n"; //osx string[] lines = asset.text.Split(separators, StringSplitOptions.RemoveEmptyEntries); if (lines.Length <= 1) //osx line endings didn't work, try windows { separators[0] = "\r\n"; lines = asset.text.Split(separators, StringSplitOptions.RemoveEmptyEntries); } if (lines.Length <= 1) //those line endings didn't work, so we're on a magical OS { separators[0] = "\r"; lines = asset.text.Split(separators, StringSplitOptions.RemoveEmptyEntries); } if (lines.Length <= 1) //WHAT { throw new FutileException("Your font file is messed up"); } int wordCount = 0; int c = 0; int k = 0; _charInfosByID = new Dictionary <uint, FCharInfo>(127); //insert an empty char to be used when a character isn't in the font data file FCharInfo emptyChar = new FCharInfo(); _charInfosByID[0] = emptyChar; float resourceScaleInverse = Futile.resourceScaleInverse; Vector2 textureSize = _element.atlas.textureSize; Debug.Log("texture width " + textureSize.x); bool wasKerningFound = false; int lineCount = lines.Length; for (int n = 0; n < lineCount; ++n) { string line = lines[n]; string [] words = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); /* we don't care about these, or else they could be in the elseif * if(words[0] == "info") //info face="Franchise Bold" size=160 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=1,1 * { * //do nothing * } * else if(words[0] == "page") //page id=0 file="FranchiseLarge" * { * //do nothing * } */ if (words[0] == "common") //common lineHeight=168 base=26 scaleW=1024 scaleH=1024 pages=1 packed=0 { //these are the height and width of the original atlas built by Hiero _configWidth = int.Parse(words[3].Split('=')[1]); //_configHeight = int.Parse(words[4].Split('=')[1]); //this is the ratio of the config vs the size of the actual texture element _configRatio = _element.sourcePixelSize.x / (float)_configWidth; _lineHeight = ((float)int.Parse(words[1].Split('=')[1])) * _configRatio * resourceScaleInverse; //_lineBase = int.Parse(words[2].Split('=')[1]) * _configRatio; } else if (words[0] == "chars") //chars count=92 { int charCount = int.Parse(words[1].Split('=')[1]); _charInfos = new FCharInfo[charCount + 1]; //gotta add 1 because the charCount seems to be off by 1 } else if (words[0] == "char") //char id=32 x=0 y=0 width=0 height=0 xoffset=0 yoffset=120 xadvance=29 page=0 chnl=0 letter=a { FCharInfo charInfo = new FCharInfo(); wordCount = words.Length; for (int w = 1; w < wordCount; ++w) { string[] parts = words[w].Split('='); string partName = parts[0]; if (partName == "letter") { if (parts[1].Length >= 3) { charInfo.letter = parts[1].Substring(1, 1); } continue; //we don't care about the letter } if (partName == "\r") { continue; //something weird happened with linebreaks, meh! } int partIntValue = int.Parse(parts[1]); float partFloatValue = (float)partIntValue; if (partName == "id") { charInfo.charID = partIntValue; } else if (partName == "x") { charInfo.x = partFloatValue * _configRatio - _element.sourceRect.x * Futile.resourceScale; //offset to account for the trimmed atlas } else if (partName == "y") { charInfo.y = partFloatValue * _configRatio - _element.sourceRect.y * Futile.resourceScale; //offset to account for the trimmed atlas } else if (partName == "width") { charInfo.width = partFloatValue * _configRatio; } else if (partName == "height") { charInfo.height = partFloatValue * _configRatio; } else if (partName == "xoffset") { charInfo.offsetX = partFloatValue * _configRatio; } else if (partName == "yoffset") { charInfo.offsetY = partFloatValue * _configRatio; } else if (partName == "xadvance") { charInfo.xadvance = partFloatValue * _configRatio; } else if (partName == "page") { charInfo.page = partIntValue; } } Rect uvRect = new Rect ( _element.uvRect.x + charInfo.x / textureSize.x, (textureSize.y - charInfo.y - charInfo.height) / textureSize.y - (1.0f - _element.uvRect.yMax), charInfo.width / textureSize.x, charInfo.height / textureSize.y ); charInfo.uvRect = uvRect; charInfo.uvTopLeft.Set(uvRect.xMin, uvRect.yMax); charInfo.uvTopRight.Set(uvRect.xMax, uvRect.yMax); charInfo.uvBottomRight.Set(uvRect.xMax, uvRect.yMin); charInfo.uvBottomLeft.Set(uvRect.xMin, uvRect.yMin); //scale them AFTER they've been used for uvs charInfo.width *= resourceScaleInverse; charInfo.height *= resourceScaleInverse; charInfo.offsetX *= resourceScaleInverse; charInfo.offsetY *= resourceScaleInverse; charInfo.xadvance *= resourceScaleInverse; _charInfosByID[(uint)charInfo.charID] = charInfo; _charInfos[c] = charInfo; c++; } else if (words[0] == "kernings") //kernings count=169 { wasKerningFound = true; int kerningCount = int.Parse(words[1].Split('=')[1]); _kerningInfos = new FKerningInfo[kerningCount + 100]; //kerning count can be wrong so just add 100 items of potential fudge factor } else if (words[0] == "kerning") //kerning first=56 second=57 amount=-1 { FKerningInfo kerningInfo = new FKerningInfo(); kerningInfo.first = -1; wordCount = words.Length; for (int w = 1; w < wordCount; w++) { string[] parts = words[w].Split('='); if (parts.Length >= 2) { string partName = parts[0]; int partValue = int.Parse(parts[1]); if (partName == "first") { kerningInfo.first = partValue; } else if (partName == "second") { kerningInfo.second = partValue; } else if (partName == "amount") { kerningInfo.amount = ((float)partValue) * _configRatio * resourceScaleInverse; } } } if (kerningInfo.first != -1) { _kerningInfos[k] = kerningInfo; } k++; } } _kerningCount = k; if (!wasKerningFound) //if there are no kernings at all (like in a pixel font), then make an empty kerning array { _kerningInfos = new FKerningInfo[0]; } //make sure the space character doesn't have offsetY and offsetX if (_charInfosByID.ContainsKey(ASCII_SPACE)) { _charInfosByID[ASCII_SPACE].offsetX = 0; _charInfosByID[ASCII_SPACE].offsetY = 0; } }
private void LoadAndParseConfigFile() { TextAsset asset = (TextAsset)Resources.Load(_configPath, typeof(TextAsset)); if (asset == null) { throw new Exception("Couldn't find font config file " + _configPath); } string[] separators = new string[1]; separators[0] = "\n"; //osx string[] lines = asset.text.Split(separators, StringSplitOptions.RemoveEmptyEntries); if (lines.Length <= 1) //osx line endings didn't work, try windows { separators[0] = "\r\n"; lines = asset.text.Split(separators, StringSplitOptions.RemoveEmptyEntries); } if (lines.Length <= 1) //those line endings didn't work, so we're on a magical OS { separators[0] = "\r"; lines = asset.text.Split(separators, StringSplitOptions.RemoveEmptyEntries); } if (lines.Length <= 1) //WHAT { throw new Exception("Your font file is messed up"); } int wordCount = 0; int c = 0; int k = 0; _charInfosByID = new FCharInfo[127]; float resourceScale = Futile.resourceScale; Vector2 textureSize = _element.atlas.textureSize; bool wasKerningFound = false; int lint = -1; foreach (string line in lines) { lint++; string [] words = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); /* we don't care about these, or else they could be in the elseif * if(words[0] == "info") //info face="Franchise Bold" size=160 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=1,1 * { * //do nothing * } * else if(words[0] == "page") //page id=0 file="FranchiseLarge.png" * { * //do nothing * } */ if (words[0] == "common") //common lineHeight=168 base=26 scaleW=1024 scaleH=1024 pages=1 packed=0 { //these are the height and width of the original atlas built by Hiero _configWidth = int.Parse(words[3].Split('=')[1]); //_configHeight = int.Parse(words[4].Split('=')[1]); //this is the ratio of the config vs the size of the actual texture element _configRatio = _element.sourceSize.x / _configWidth; _lineHeight = int.Parse(words[1].Split('=')[1]) * _configRatio; } else if (words[0] == "chars") //chars count=92 { int charCount = int.Parse(words[1].Split('=')[1]); _charInfos = new FCharInfo[charCount + 1]; //gotta add 1 because the charCount seems to be off by 1 } else if (words[0] == "char") //char id=32 x=0 y=0 width=0 height=0 xoffset=0 yoffset=120 xadvance=29 page=0 chnl=0 letter=a { FCharInfo charInfo = new FCharInfo(); wordCount = words.Length; for (int w = 1; w < wordCount; ++w) { string[] parts = words[w].Split('='); string partName = parts[0]; if (partName == "letter") { if (parts[1].Length >= 3) { charInfo.letter = parts[1].Substring(1, 1); } continue; //we don't care about the letter } if (partName == "\r") { continue; //something weird happened with linebreaks, meh! } int partValue = int.Parse(parts[1]); if (partName == "id") { charInfo.charID = partValue; } else if (partName == "x") { charInfo.x = partValue * _configRatio - _element.sourceRect.x; //offset to account for the trimmed atlas } else if (partName == "y") { charInfo.y = partValue * _configRatio - _element.sourceRect.y; //offset to account for the trimmed atlas } else if (partName == "width") { charInfo.width = partValue * _configRatio; } else if (partName == "height") { charInfo.height = partValue * _configRatio; } else if (partName == "xoffset") { charInfo.offsetX = partValue * _configRatio; } else if (partName == "yoffset") { charInfo.offsetY = partValue * _configRatio; } else if (partName == "xadvance") { charInfo.xadvance = partValue * _configRatio; } else if (partName == "page") { charInfo.page = partValue; } } if (element.isRotated) { Rect uvRect = new Rect ( _element.uvRect.x + _element.uvRect.width - ((charInfo.y + charInfo.height + 0.5f) / textureSize.x * resourceScale), _element.uvRect.y + _element.uvRect.height - ((charInfo.x + charInfo.width + 0.5f) / textureSize.y * resourceScale), charInfo.height / textureSize.x * resourceScale, charInfo.width / textureSize.y * resourceScale ); charInfo.uvRect = uvRect; charInfo.uvBottomLeft.Set(uvRect.xMin, uvRect.yMax); charInfo.uvTopLeft.Set(uvRect.xMax, uvRect.yMax); charInfo.uvTopRight.Set(uvRect.xMax, uvRect.yMin); charInfo.uvBottomRight.Set(uvRect.xMin, uvRect.yMin); } else { Rect uvRect = new Rect ( _element.uvRect.x + charInfo.x / textureSize.x * resourceScale, (textureSize.y - charInfo.y - charInfo.height) / textureSize.y * resourceScale - (1.0f - _element.uvRect.yMax), charInfo.width / textureSize.x * resourceScale, charInfo.height / textureSize.y * resourceScale ); charInfo.uvRect = uvRect; charInfo.uvTopLeft.Set(uvRect.xMin, uvRect.yMax); charInfo.uvTopRight.Set(uvRect.xMax, uvRect.yMax); charInfo.uvBottomRight.Set(uvRect.xMax, uvRect.yMin); charInfo.uvBottomLeft.Set(uvRect.xMin, uvRect.yMin); } _charInfosByID[charInfo.charID] = charInfo; _charInfos[c] = charInfo; c++; } else if (words[0] == "kernings") //kernings count=169 { wasKerningFound = true; int kerningCount = int.Parse(words[1].Split('=')[1]); _kerningInfos = new FKerningInfo[kerningCount + 1]; //gotta add 1 because it's off by 1 } else if (words[0] == "kerning") //kerning first=56 second=57 amount=-1 { FKerningInfo kerningInfo = new FKerningInfo(); wordCount = words.Length; for (int w = 1; w < wordCount; w++) { string[] parts = words[w].Split('='); string partName = parts[0]; int partValue = int.Parse(parts[1]); if (partName == "first") { kerningInfo.first = partValue; } else if (partName == "second") { kerningInfo.second = partValue; } else if (partName == "amount") { kerningInfo.amount = partValue * _configRatio; } } _kerningInfos[k] = kerningInfo; k++; } } if (!wasKerningFound) //if there are no kernings at all (like in a pixel font), then make an empty kerning array { _kerningInfos = new FKerningInfo[0]; } //make sure the space character doesn't have offsetY and offsetX _charInfosByID[32].offsetX = 0; _charInfosByID[32].offsetY = 0; }