1using System.Reflection;
3using SixLabors.ImageSharp.PixelFormats;
15 m_counts =
new short[m_counts.Length * 2];
31 public readonly
char Code = code;
33 public readonly
bool IsBlank = texCoord1 == texCoord2;
41 public readonly
float Width = width;
70 public float Scale {
get;
set; }
82#pragma warning disable CA1416
83 using Stream stream = EngineActivity.m_activity.Assets?.Open(
"Debugfont.png");
84 using Stream stream2 = EngineActivity.m_activity.Assets?.Open(
"Debugfont.lst");
85#pragma warning restore CA1416
87 using Stream stream = typeof(
BitmapFont).GetTypeInfo().Assembly.GetManifestResourceStream(
"Engine.Resources.Debugfont.png");
88 using Stream stream2 = typeof(
BitmapFont).GetTypeInfo().Assembly.GetManifestResourceStream(
"Engine.Resources.Debugfont.lst");
91 throw new FileNotFoundException(
"Debugfont.png");
93 if (stream2 ==
null) {
94 throw new FileNotFoundException(
"Debugfont.lst");
113 char[] splitters = [(char)0x20, (
char)0x09];
115 StreamReader streamReader =
new(GlyphsStream);
116 string firstLine = streamReader.ReadLine();
117 if (firstLine ==
null) {
118 throw new FormatException(
"The first line of the .lst file of the bitmap font can not be founded");
120 int num =
int.Parse(firstLine);
122 for (
int i = 0; i < num; i++) {
123 string line = streamReader.ReadLine();
125 throw new FormatException($
"The {i + 2} line of the .lst file of the bitmap font can not be founded");
127 string[] arr = line.Split(splitters, StringSplitOptions.None);
128 if (arr.Length == 9) {
129 string[] tmp =
new string[8];
131 for (
int j = 2; j < arr.Length; j++) {
136 char code =
char.Parse(arr[0]);
137 Vector2 texCoord =
new(
float.Parse(arr[1]),
float.Parse(arr[2]));
138 Vector2 texCoord2 =
new(
float.Parse(arr[3]),
float.Parse(arr[4]));
139 Vector2 offset =
new(
float.Parse(arr[5]),
float.Parse(arr[6]));
140 if (customGlyphOffset.HasValue) {
141 offset += customGlyphOffset.Value;
143 float width =
float.Parse(arr[7]);
144 array[i] =
new Glyph(code, texCoord, texCoord2, offset, width);
146 string glyphHeightLine = streamReader.ReadLine();
147 if (glyphHeightLine ==
null) {
148 throw new FormatException(
"The height line of the .lst file of the bitmap font can not be founded");
150 float glyphHeight =
float.Parse(glyphHeightLine);
151 string spacingLine = streamReader.ReadLine();
152 if (spacingLine ==
null) {
153 throw new FormatException(
"The spacing line of the .lst file of the bitmap font can not be founded");
155 string[] arr2 = spacingLine.Split(splitters, StringSplitOptions.None);
156 Vector2 spacing =
new(
float.Parse(arr2[0]),
float.Parse(arr2[1]));
157 string scaleLine = streamReader.ReadLine();
158 if (scaleLine ==
null) {
159 throw new FormatException(
"The scale line of the .lst file of the bitmap font can not be founded");
161 float scale =
float.Parse(scaleLine);
162 string fallbackLine = streamReader.ReadLine();
163 if (fallbackLine ==
null) {
164 throw new FormatException(
"The fallback line of the .lst file of the bitmap font can not be founded");
166 char fallbackCode =
char.Parse(fallbackLine);
167 string kerningCountLine = streamReader.ReadLine();
168 if (kerningCountLine !=
null) {
169 int kerningCount =
int.Parse(kerningCountLine);
170 for (
int j = 0; j < kerningCount; j++) {
171 string line = streamReader.ReadLine();
173 throw new FormatException($
"The {j + 7} line of the .lst file of the bitmap font can not be founded");
175 string[] arr = line.Split(splitters, StringSplitOptions.None);
176 if (arr.Length == 3) {
177 char code2 =
char.Parse(arr[0]);
178 char followingCode =
char.Parse(arr[1]);
179 float num3 =
float.Parse(arr[2]);
180 bitmapFont.
SetKerning(code2, followingCode, num3);
195 catch (Exception e) {
226 m_kerningPairs.TryGetValue((
int)(((uint)code << 16) | followingCode), out value);
240 for (
int num2 = start + count; i < num2; i++) {
245 if (vector.
Y > vector2.
Y) {
246 vector2.Y = vector.
Y;
255 float num3 = i < text.Length - 1 ?
GetKerning(c, text[i + 1]) : 0f;
256 vector.X += glyph.Width - num3 + spacing.
X;
257 if (vector.
X > vector2.
X) {
258 vector2.X = vector.
X;
262 return vector2 * scale;
265 public int FitText(
float width,
string text,
float scale,
float spacing) =>
FitText(width, text, 0, text.Length, scale, spacing);
267 public int FitText(
float width,
string text,
int start,
int length,
float scale,
float spacing) {
271 for (
int i = start; i < start + length; i++) {
282 float num2 = i < text.Length - 1 ?
GetKerning(c, text[i + 1]) : 0f;
283 num += (glyph.Width - num2 + spacing) * scale;
293 characterIndex = Math.Clamp(characterIndex, 0, text.Length);
294 return MeasureText(text, 0, characterIndex, scale, spacing).
X;
304 int mipLevelsCount = 1,
325 int mipLevelsCount = 1,
326 bool premultiplyAlpha =
true) =>
Load(
345 int mipLevelsCount = 1,
346 bool premultiplyAlpha =
true) {
363 Display.DeviceReset += delegate {
365 using Stream stream = typeof(
BitmapFont).GetTypeInfo().Assembly.GetManifestResourceStream(
"Engine.Resources.Debugfont.png");
366 using Stream stream2 = typeof(
BitmapFont).GetTypeInfo().Assembly.GetManifestResourceStream(
"Engine.Resources.Debugfont.lst");
382 bool premultiplyAlpha,
383 bool createTexture) {
384 List<Rectangle> list =
new(
FindGlyphs(image));
385 List<Rectangle> list2 =
new(list.Select(r =>
CropGlyph(image, r)));
386 if (list.Count == 0) {
387 throw new InvalidOperationException(
"No glyphs found in BitmapFont image.");
389 int num =
int.MaxValue;
390 int num2 =
int.MaxValue;
391 int num3 =
int.MaxValue;
392 int num4 =
int.MaxValue;
393 for (
int i = 0; i < list2.Count; i++) {
394 if (list2[i].Width > 0
395 && list2[i].Height > 0) {
396 num = Math.Min(num, list2[i].
Left - list[i].
Left);
397 num2 = Math.Min(num2, list2[i].
Top - list[i].
Top);
398 num3 = Math.Min(num3, list[i].
Right - list2[i].
Right);
399 num4 = Math.Min(num4, list[i].
Bottom - list2[i].
Bottom);
402 int num5 = firstCode;
404 List<Glyph> list3 = [];
405 for (
int j = 0; j < list2.Count; j++) {
409 if (list2[j].Width > 0
410 && list2[j].Height > 0) {
413 offset2 =
new Vector2(list2[j].
Left - list[j].
Left - num - 0.5f, list2[j].
Top - list[j].
Top - num2 - 0.5f);
421 float width = list[j].Width - num - num3;
422 num6 = Math.
Max(num6, list[j].Height - num2 - num4);
423 list3.Add(
new Glyph((
char)num5, texCoord, texCoord2, offset2, width));
429 (sourceAccessor, targetAccessor) => {
430 for (int i = 0; i < sourceAccessor.Height; i++) {
431 Span<Rgba32> sourceRow = sourceAccessor.GetRowSpan(i);
432 Span<Rgba32> targetRow = targetAccessor.GetRowSpan(i);
433 for (int x = 0; x < sourceRow.Length; x++) {
434 Rgba32 sourcePixel = sourceRow[x];
435 targetRow[x] = sourcePixel.IsMagenta() ? SixLabors.ImageSharp.Color.Transparent :
436 premultiplyAlpha ? sourcePixel.PremultiplyAlpha() : sourcePixel;
442 Image image3 = createTexture ? null : image2;
453 if (kerningSettings !=
null) {
454 int[][] array =
new int[list.Count][];
455 int[][] array2 =
new int[list.Count][];
456 for (
int l = 0; l < list.Count; l++) {
458 array[l] =
ApplyKerningBulking(array[l], kerningSettings.BulkingRadius, kerningSettings.BulkingGradient);
459 array2[l] =
ApplyKerningBulking(array2[l], kerningSettings.BulkingRadius, kerningSettings.BulkingGradient);
461 Counter counter =
new();
462 for (
int m = 0; m < list.Count; m++) {
463 for (
int n = 0; n < list.Count; n++) {
464 int num7 = list2[m].Top - list[m].Top;
465 int x = list2[m].Bottom - list[m].Top;
466 int num8 = list2[n].Top - list[n].Top;
467 int x2 = list2[n].Bottom - list[n].Top;
471 for (
int num11 = num9; num11 < num10; num11++) {
472 int num12 = num11 - num7;
473 int num13 = num11 - num8;
474 int num14 = array2[m][num12];
475 int num15 = array[n][num13];
476 counter.Increment(num15 + num14);
478 int num16 = Math.Min(kerningSettings.Limit - 1, counter.MaxUsedIndex);
479 int tolerance = kerningSettings.Tolerance;
482 for (num18 = 0; num18 <= num16; num18++) {
483 num17 += counter.Get(num18);
484 if (num17 > tolerance) {
489 bitmapFont.
SetKerning((
char)(m + firstCode), (
char)(n + firstCode), num18);
499 IEnumerable<Glyph> glyphs,
511 IEnumerable<Glyph> enumerable = glyphs as
Glyph[] ?? glyphs.ToArray();
512 foreach (
Glyph glyph
in enumerable) {
513 if (glyph.
Code == fallbackCode) {
525 foreach (
Glyph glyph
in enumerable) {
532 while (y < image.
Height) {
534 for (
int x = 1; x < image.
Width; x = num) {
540 for (; x + i < image.Width && !image.
GetPixelFast(x + i, y).IsMagenta(); i++) { }
541 for (; y + j < image.Height && !image.
GetPixelFast(x, y + j).IsMagenta(); j++) { }
552 int[] array =
new int[depths.Length];
553 for (
int i = 0; i < depths.Length; i++) {
554 array[i] = depths[i];
556 int num2 =
MathUtils.
Min(i + radius, depths.Length - 1);
557 for (
int j = num; j <= num2; j++) {
558 int num3 = Math.Abs(j - i);
559 int x = depths[j] + (int)Math.Round(gradient * num3);
567 leftDepths =
new int[rectangle.
Height];
568 rightDepths =
new int[rectangle.
Height];
569 for (
int i = rectangle.
Top; i < rectangle.
Bottom; i++) {
570 int num = i - rectangle.
Top;
571 leftDepths[num] = rectangle.
Width;
572 rightDepths[num] = rectangle.
Width;
573 for (
int j = rectangle.
Left; j < rectangle.
Right; j++) {
596 int num =
int.MaxValue;
597 int num2 =
int.MaxValue;
598 int num3 =
int.MinValue;
599 int num4 =
int.MinValue;
600 for (
int i = rectangle.
Left; i < rectangle.
Left + rectangle.
Width; i++) {
601 for (
int j = rectangle.
Top; j < rectangle.
Top + rectangle.
Height; j++) {
603 num = Math.Min(num, i);
604 num2 = Math.Min(num2, j);
605 num3 = Math.Max(num3, i);
606 num4 = Math.Max(num4, j);
610 return num == int.MaxValue
612 :
new Rectangle(num, num2, num3 - num + 1, num4 - num2 + 1);
615 public void SetKerning(
char code,
char followingCode,
float kerning) {
617 m_kerningPairs[(int)(((uint)code << 16) | followingCode)] = (short)kerning;
static Texture2D Load(LegacyImage image, int mipLevelsCount=1)
static void Error(object message)
static int Min(int x1, int x2)
static int Max(int x1, int x2)
static Stream OpenFile(string path, OpenFileMode openFileMode)
static readonly Vector2 Zero
static Vector2 Max(Vector2 v, float f)