Rev 1456 | Details | Compare with Previous | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 1454 | chris | 1 | using System; |
| 2 | using System.Collections.Generic; |
||
| 3 | using System.Linq; |
||
| 4 | using System.Text; |
||
| 5 | using System.Threading.Tasks; |
||
| 6 | using System.IO; |
||
| 1489 | chris | 7 | using System.Drawing; |
| 1454 | chris | 8 | |
| 9 | using BauzoidNET.file; |
||
| 10 | using BauzoidNET.graphics.sprite; |
||
| 11 | |||
| 1456 | chris | 12 | using EndianHandling; |
| 1454 | chris | 13 | |
| 14 | namespace BauzoidNET.graphics |
||
| 15 | { |
||
| 16 | public class FontUtil |
||
| 17 | { |
||
| 18 | public static readonly string LOG_TAG = "FontUtil"; |
||
| 19 | public static bool verbose = true; |
||
| 20 | |||
| 21 | private class CharacterRect |
||
| 22 | { |
||
| 23 | public float x; |
||
| 24 | public float y; |
||
| 25 | public float w; |
||
| 26 | public float h; |
||
| 27 | |||
| 28 | public CharacterRect(float _x, float _y, float _w, float _h) |
||
| 29 | { |
||
| 30 | x = _x; |
||
| 31 | y = _y; |
||
| 32 | w = _w; |
||
| 33 | h = _h; |
||
| 34 | } |
||
| 35 | } |
||
| 36 | |||
| 37 | private class CharacterOffset |
||
| 38 | { |
||
| 39 | public float x; |
||
| 40 | public float y; |
||
| 41 | |||
| 42 | public CharacterOffset(float _x, float _y) |
||
| 43 | { |
||
| 44 | x = _x; |
||
| 45 | y = _y; |
||
| 46 | } |
||
| 47 | } |
||
| 48 | |||
| 49 | private class KerningPair |
||
| 50 | { |
||
| 51 | public char first; |
||
| 52 | public char second; |
||
| 53 | public int value; |
||
| 54 | |||
| 55 | public KerningPair(char a, char b, int n) |
||
| 56 | { |
||
| 57 | first = a; |
||
| 58 | second = b; |
||
| 59 | value = n; |
||
| 60 | } |
||
| 61 | } |
||
| 62 | |||
| 63 | |||
| 64 | private FontUtil() {} |
||
| 65 | |||
| 66 | public static void log(String msg) |
||
| 67 | { |
||
| 68 | log(LOG_TAG, msg); |
||
| 69 | } |
||
| 70 | |||
| 71 | public static void log(String tag, String msg) |
||
| 72 | { |
||
| 73 | if (verbose) |
||
| 74 | System.Console.WriteLine(tag + ": " + msg); |
||
| 75 | } |
||
| 1489 | chris | 76 | |
| 77 | public static Font createFontFromBinaryResource(Graphics graphics, byte[] file, Bitmap bmOverride) |
||
| 78 | { |
||
| 79 | MemoryStream stream = new MemoryStream(file); |
||
| 80 | Font font = createFontFromBinaryStream(graphics, stream, null, bmOverride); |
||
| 81 | stream.Close(); |
||
| 82 | return font; |
||
| 83 | } |
||
| 84 | |||
| 85 | public static Font createFontFromBinaryFile(Graphics graphics, string filename, Stream input, Bitmap bmOverride = null) |
||
| 86 | { |
||
| 87 | FileStream stream = File.Open(filename, FileMode.Open); |
||
| 88 | Font font = createFontFromBinaryStream(graphics, stream, Path.GetDirectoryName(filename), bmOverride); |
||
| 89 | stream.Close(); |
||
| 90 | return font; |
||
| 91 | } |
||
| 1454 | chris | 92 | |
| 1489 | chris | 93 | public static Font createFontFromBinaryStream(Graphics graphics, Stream input, string bmDirectory, Bitmap bmOverride = null) |
| 1454 | chris | 94 | { |
| 95 | List<char> charList = new List<char>(); |
||
| 96 | List<float> widthList = new List<float>(); |
||
| 97 | List<CharacterRect> rectList = new List<CharacterRect>(); |
||
| 98 | List<CharacterOffset> offsetList = new List<CharacterOffset>(); |
||
| 99 | List<KerningPair> kerningPairs = new List<KerningPair>(); |
||
| 100 | |||
| 101 | //Font font = new Font(graphics); |
||
| 102 | //Texture texture = null; |
||
| 103 | String textureFileFull = null; |
||
| 104 | |||
| 105 | float multiplier = 1.0f; |
||
| 106 | float ascent = 10.0f; |
||
| 107 | |||
| 108 | try |
||
| 109 | { |
||
| 110 | //File f = new File(file.read()); |
||
| 1489 | chris | 111 | EndianBinaryReader reader = new EndianBinaryReader(input, Encoding.Default, true); |
| 1454 | chris | 112 | |
| 113 | //int version = f.readInt(); |
||
| 1456 | chris | 114 | int version = 0; |
| 115 | reader.ReadInt32(out version); |
||
| 1454 | chris | 116 | if (version != 100) |
| 117 | { |
||
| 118 | //Gdx.app.log(LOG_TAG, "Version mismatch: 100 != " + version); |
||
| 119 | log("Version mismatch: 100 != " + version); |
||
| 120 | return null; |
||
| 121 | } |
||
| 122 | |||
| 123 | //String textureFile = f.readString(); |
||
| 1456 | chris | 124 | string textureFile = FileUtil.readString(reader); |
| 1454 | chris | 125 | |
| 126 | //textureFileFull = FileUtil.extractPath(file.path()) + "/" + textureFile; |
||
| 1489 | chris | 127 | if (bmDirectory != null) |
| 128 | textureFileFull = bmDirectory + "\\" + textureFile; |
||
| 129 | else |
||
| 130 | textureFileFull = textureFile; |
||
| 1454 | chris | 131 | |
| 132 | |||
| 133 | //ascent = f.readFloat(); |
||
| 1456 | chris | 134 | //ascent = reader.ReadSingle(); |
| 135 | reader.ReadSingle(out ascent); |
||
| 1454 | chris | 136 | //multiplier = f.readFloat(); |
| 1456 | chris | 137 | //multiplier = reader.ReadSingle(); |
| 138 | reader.ReadSingle(out multiplier); |
||
| 1454 | chris | 139 | |
| 140 | // Read character list (char * num) |
||
| 141 | //int numChars = f.readInt(); // number of characters |
||
| 1456 | chris | 142 | int numChars; |
| 143 | reader.ReadInt32(out numChars); |
||
| 1454 | chris | 144 | for (int i = 0; i < numChars; i++) |
| 145 | { |
||
| 146 | //Character c = f.readChar(); |
||
| 1456 | chris | 147 | char c; |
| 148 | reader.ReadChar(out c); |
||
| 1454 | chris | 149 | charList.Add(c); |
| 150 | } |
||
| 151 | |||
| 152 | // Read width list (float * num) |
||
| 153 | //int numWidths = f.readInt(); // number of widths |
||
| 1456 | chris | 154 | int numWidths; |
| 155 | reader.ReadInt32(out numWidths); |
||
| 1454 | chris | 156 | for (int i = 0; i < numWidths; i++) |
| 157 | { |
||
| 158 | //Float width = f.readFloat(); |
||
| 1456 | chris | 159 | float width; |
| 160 | reader.ReadSingle(out width); |
||
| 1454 | chris | 161 | widthList.Add(width); |
| 162 | } |
||
| 163 | |||
| 164 | // Read rect list (CharRect * num) |
||
| 165 | //int numRects = f.readInt(); // number of rects |
||
| 1456 | chris | 166 | int numRects; |
| 167 | reader.ReadInt32(out numRects); |
||
| 1454 | chris | 168 | for (int i = 0; i < numRects; i++) |
| 169 | { |
||
| 1456 | chris | 170 | float x; |
| 171 | reader.ReadSingle(out x); |
||
| 172 | float y; |
||
| 173 | reader.ReadSingle(out y); |
||
| 174 | float w; |
||
| 175 | reader.ReadSingle(out w); |
||
| 176 | float h; |
||
| 177 | reader.ReadSingle(out h); |
||
| 1454 | chris | 178 | |
| 179 | rectList.Add(new CharacterRect(x, y, w, h)); |
||
| 180 | } |
||
| 181 | |||
| 182 | // Read offset list (CharOffset * num) |
||
| 1456 | chris | 183 | int numOffsets; |
| 184 | reader.ReadInt32(out numOffsets); // number of offsets |
||
| 1454 | chris | 185 | for (int i = 0; i < numOffsets; i++) |
| 186 | { |
||
| 1456 | chris | 187 | float x; |
| 188 | reader.ReadSingle(out x); |
||
| 189 | float y; |
||
| 190 | reader.ReadSingle(out y); |
||
| 1454 | chris | 191 | |
| 192 | offsetList.Add(new CharacterOffset(x, y)); |
||
| 193 | } |
||
| 194 | |||
| 195 | // number of kerning pairs |
||
| 1456 | chris | 196 | int numKerning; |
| 197 | reader.ReadInt32(out numKerning); |
||
| 1454 | chris | 198 | |
| 199 | // Read kerning pairs + values |
||
| 200 | for (int i = 0; i < numKerning; i++) |
||
| 201 | { |
||
| 1456 | chris | 202 | char a; |
| 203 | reader.ReadChar(out a); |
||
| 204 | char b; |
||
| 205 | reader.ReadChar(out b); |
||
| 206 | int v; |
||
| 207 | reader.ReadInt32(out v); |
||
| 1454 | chris | 208 | |
| 209 | kerningPairs.Add(new KerningPair(a, b, v)); |
||
| 210 | } |
||
| 211 | |||
| 212 | //f.close(); |
||
| 1456 | chris | 213 | reader.Close(); |
| 1454 | chris | 214 | } |
| 1456 | chris | 215 | catch |
| 1454 | chris | 216 | { |
| 217 | //Gdx.app.log(LOG_TAG, "Could not read font!"); |
||
| 218 | log("Could not read font!"); |
||
| 219 | } |
||
| 1489 | chris | 220 | |
| 221 | Sprite sprite = null; |
||
| 222 | if (bmOverride == null) |
||
| 223 | { |
||
| 224 | sprite = new Sprite(graphics, textureFileFull); |
||
| 225 | } |
||
| 226 | else |
||
| 227 | { |
||
| 228 | sprite = new Sprite(graphics, bmOverride); |
||
| 229 | } |
||
| 230 | |||
| 231 | return buildFont(graphics, sprite, charList, widthList, rectList, offsetList, multiplier, ascent, kerningPairs); |
||
| 1454 | chris | 232 | } |
| 1456 | chris | 233 | |
| 1489 | chris | 234 | private static Font buildFont(Graphics graphics, Sprite sprite, List<char> charList, List<float> widthList, List<CharacterRect> rectList, List<CharacterOffset> offsetList, |
| 235 | float multiplier, float ascent, List<KerningPair> kerningPairs) |
||
| 1454 | chris | 236 | { |
| 237 | // Build font |
||
| 1489 | chris | 238 | if (sprite == null) |
| 1454 | chris | 239 | { |
| 1489 | chris | 240 | log("No sprite specified!"); |
| 1454 | chris | 241 | return null; |
| 242 | } |
||
| 243 | |||
| 244 | Font font = new Font(graphics); |
||
| 245 | |||
| 1456 | chris | 246 | Font.CharacterInfo[] characters = new Font.CharacterInfo[charList.Count]; |
| 247 | SpriteRegion[] regions = new SpriteRegion[rectList.Count]; |
||
| 1454 | chris | 248 | |
| 1489 | chris | 249 | //Sprite sprite = new Sprite(graphics, textureFile); |
| 1454 | chris | 250 | sprite.init(); |
| 251 | |||
| 1456 | chris | 252 | for (int i = 0; i < characters.Length; i++) |
| 1454 | chris | 253 | { |
| 1456 | chris | 254 | characters[i] = new Font.CharacterInfo(charList.ElementAt(i)); |
| 255 | |||
| 256 | characters[i].width = widthList.ElementAt(i); |
||
| 1454 | chris | 257 | |
| 1456 | chris | 258 | if (i < offsetList.Count) |
| 1454 | chris | 259 | { |
| 1456 | chris | 260 | characters[i].offsetX = offsetList.ElementAt(i).x; |
| 261 | characters[i].offsetY = offsetList.ElementAt(i).y; |
||
| 1454 | chris | 262 | } |
| 263 | |||
| 1456 | chris | 264 | if (i < rectList.Count) |
| 1454 | chris | 265 | { |
| 1456 | chris | 266 | CharacterRect rect = rectList.ElementAt(i); |
| 1454 | chris | 267 | |
| 268 | /*characters[i].texX = rectList.elementAt(i).x; |
||
| 269 | characters[i].texY = rectList.elementAt(i).y; |
||
| 270 | characters[i].texW = rectList.elementAt(i).w; |
||
| 271 | characters[i].texH = rectList.elementAt(i).h;*/ |
||
| 272 | regions[i] = new SpriteRegion(sprite, i, rect.x / multiplier, rect.y / multiplier, rect.w / multiplier, rect.h / multiplier, true); |
||
| 273 | } |
||
| 274 | } |
||
| 275 | sprite.setRegions(regions); |
||
| 276 | |||
| 277 | //AtlasSprite sprite = new AtlasSprite(graphics, texture, regions); |
||
| 278 | |||
| 1456 | chris | 279 | for (int i = 0; i < regions.Length; i++) |
| 1454 | chris | 280 | { |
| 281 | characters[i].setSpriteInstance(sprite.createSpriteInstance(i)); |
||
| 282 | } |
||
| 283 | |||
| 284 | font.setCharacters(characters); |
||
| 285 | font.setSprite(sprite); |
||
| 286 | font.setAscent(ascent); |
||
| 287 | font.setGlobalMultiplier(multiplier); |
||
| 288 | |||
| 1456 | chris | 289 | for (int i = 0; i < kerningPairs.Count; i++) |
| 1454 | chris | 290 | { |
| 1456 | chris | 291 | KerningPair pair = kerningPairs.ElementAt(i); |
| 1454 | chris | 292 | font.setKerning(pair.first, pair.second, pair.value); |
| 293 | } |
||
| 294 | |||
| 295 | return font; |
||
| 296 | } |
||
| 297 | |||
| 1456 | chris | 298 | /* private static Vector<Character> parseCharList(Tokenizer t) throws ScanException |
| 1454 | chris | 299 | { |
| 300 | Vector<Character> charList = new Vector<Character>(); |
||
| 301 | |||
| 302 | t.readToken("("); |
||
| 303 | |||
| 304 | while (!t.checkToken(")")) |
||
| 305 | { |
||
| 306 | String character = t.readString(); |
||
| 307 | |||
| 308 | if (character.length() > 1) |
||
| 309 | throw new ScanException("Character can only have length 1!", t.getSurroundings()); |
||
| 310 | |||
| 311 | charList.add(character.charAt(0)); |
||
| 312 | |||
| 313 | if (t.checkToken(")")) |
||
| 314 | break; |
||
| 315 | |||
| 316 | t.readToken(","); |
||
| 317 | } |
||
| 318 | |||
| 319 | t.readToken(")"); |
||
| 320 | |||
| 321 | return charList; |
||
| 322 | } |
||
| 323 | |||
| 324 | private static Vector<Float> parseWidthList(Tokenizer t) throws ScanException |
||
| 325 | { |
||
| 326 | Vector<Float> widthList = new Vector<Float>(); |
||
| 327 | |||
| 328 | t.readToken("("); |
||
| 329 | |||
| 330 | while (!t.checkToken(")")) |
||
| 331 | { |
||
| 332 | float width = t.readNumber(); |
||
| 333 | |||
| 334 | widthList.add(width); |
||
| 335 | |||
| 336 | if (t.checkToken(")")) |
||
| 337 | break; |
||
| 338 | |||
| 339 | //Gdx.app.log(LOG_TAG, "[" + width + "]"); |
||
| 340 | |||
| 341 | t.readToken(","); |
||
| 342 | } |
||
| 343 | |||
| 344 | t.readToken(")"); |
||
| 345 | |||
| 346 | return widthList; |
||
| 347 | } |
||
| 348 | |||
| 349 | private static Vector<CharacterRect> parseRectList(Tokenizer t) throws ScanException |
||
| 350 | { |
||
| 351 | Vector<CharacterRect> rectList = new Vector<CharacterRect>(); |
||
| 352 | |||
| 353 | t.readToken("("); |
||
| 354 | |||
| 355 | while (t.checkToken("(")) |
||
| 356 | { |
||
| 357 | t.readToken("("); |
||
| 358 | |||
| 359 | float x = t.readNumber(); |
||
| 360 | t.readToken(","); |
||
| 361 | float y = t.readNumber(); |
||
| 362 | t.readToken(","); |
||
| 363 | float w = t.readNumber(); |
||
| 364 | t.readToken(","); |
||
| 365 | float h = t.readNumber(); |
||
| 366 | |||
| 367 | rectList.add(new CharacterRect(x, y, w, h)); |
||
| 368 | |||
| 369 | t.readToken(")"); |
||
| 370 | |||
| 371 | if (!t.checkToken(",")) |
||
| 372 | break; |
||
| 373 | |||
| 374 | t.readToken(","); |
||
| 375 | } |
||
| 376 | |||
| 377 | if (!t.checkToken(")")) |
||
| 378 | throw new ScanException("Syntax error in RectList!", t.getSurroundings()); |
||
| 379 | |||
| 380 | t.readToken(")"); |
||
| 381 | |||
| 382 | return rectList; |
||
| 383 | } |
||
| 384 | |||
| 385 | private static Vector<CharacterOffset> parseOffsetList(Tokenizer t) throws ScanException |
||
| 386 | { |
||
| 387 | Vector<CharacterOffset> offsetList = new Vector<CharacterOffset>(); |
||
| 388 | |||
| 389 | t.readToken("("); |
||
| 390 | |||
| 391 | while (t.checkToken("(")) |
||
| 392 | { |
||
| 393 | t.readToken("("); |
||
| 394 | |||
| 395 | float x = t.readNumber(); |
||
| 396 | t.readToken(","); |
||
| 397 | float y = t.readNumber(); |
||
| 398 | |||
| 399 | offsetList.add(new CharacterOffset(x, y)); |
||
| 400 | |||
| 401 | t.readToken(")"); |
||
| 402 | |||
| 403 | if (!t.checkToken(",")) |
||
| 404 | break; |
||
| 405 | |||
| 406 | t.readToken(","); |
||
| 407 | } |
||
| 408 | |||
| 409 | if (!t.checkToken(")")) |
||
| 410 | throw new ScanException("Syntax error in OffsetList!", t.getSurroundings()); |
||
| 411 | |||
| 412 | t.readToken(")"); |
||
| 413 | |||
| 414 | return offsetList; |
||
| 415 | } |
||
| 416 | |||
| 417 | private static Vector<KerningPair> parseKerningPairs(Tokenizer t) throws ScanException |
||
| 418 | { |
||
| 419 | Vector<KerningPair> kerningPairs = new Vector<KerningPair>(); |
||
| 420 | |||
| 421 | t.readToken("("); |
||
| 422 | |||
| 423 | while (!t.checkToken(")")) |
||
| 424 | { |
||
| 425 | String pair = t.readString(); |
||
| 426 | |||
| 427 | kerningPairs.add(new KerningPair(pair.charAt(0), pair.charAt(1), 0)); |
||
| 428 | |||
| 429 | if (t.checkToken(")")) |
||
| 430 | break; |
||
| 431 | |||
| 432 | //Gdx.app.log(LOG_TAG, "[" + width + "]"); |
||
| 433 | |||
| 434 | t.readToken(","); |
||
| 435 | } |
||
| 436 | |||
| 437 | t.readToken(")"); |
||
| 438 | |||
| 439 | return kerningPairs; |
||
| 440 | } |
||
| 441 | |||
| 442 | private static Vector<Integer> parseKerningValues(Tokenizer t) throws ScanException |
||
| 443 | { |
||
| 444 | Vector<Integer> kerningValues = new Vector<Integer>(); |
||
| 445 | |||
| 446 | t.readToken("("); |
||
| 447 | |||
| 448 | while (!t.checkToken(")")) |
||
| 449 | { |
||
| 450 | int value = (int)t.readNumber(); |
||
| 451 | |||
| 452 | kerningValues.add(value); |
||
| 453 | |||
| 454 | if (t.checkToken(")")) |
||
| 455 | break; |
||
| 456 | |||
| 457 | //Gdx.app.log(LOG_TAG, "[" + width + "]"); |
||
| 458 | |||
| 459 | t.readToken(","); |
||
| 460 | } |
||
| 461 | |||
| 462 | t.readToken(")"); |
||
| 463 | |||
| 464 | return kerningValues; |
||
| 1456 | chris | 465 | }*/ |
| 1454 | chris | 466 | } |
| 467 | } |