using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BauzoidNET.math;
using BauzoidNET.graphics.sprite;
using BauzoidNET.graphics.texture;
namespace BauzoidNET
.graphics
{
public class Font
: GraphicsObject
{
public static readonly Vector4 DEFAULT_COLOR
= new Vector4
(1,
1,
1,
1);
public class KerningPair
{
public char first
;
public char second
;
public KerningPair
(char a,
char b
)
{
first
= a
;
second
= b
;
}
public override bool Equals
(Object other
)
{
// Not strictly necessary, but often a good optimization
if (this == other
)
return true;
if (!(other
is KerningPair
))
return false;
KerningPair p
= (KerningPair
)other
;
return ((first
== p
.first) && (second
== p
.second));
}
public override int GetHashCode
()
{
return (first
* 256) + second
;
}
}
public class CharacterInfo
{
private char mCharacter
;
public SpriteInstance mSpriteInstance
= null;
public float offsetX
= 0;
public float offsetY
= 0;
public float width
;
public CharacterInfo
(char c
)
{
mCharacter
= c
;
}
public char getCharacter
()
{
return mCharacter
;
}
public void setSpriteInstance
(SpriteInstance instance
)
{
mSpriteInstance
= instance
;
}
public SpriteInstance getSpriteInstance
()
{
return mSpriteInstance
;
}
public void render
()
{
if (mSpriteInstance
== null)
return;
mSpriteInstance
.render();
}
}
private CharacterInfo
[] mCharacters
= null;
private float mAscent
= 0
.0f
;
private float mGlobalMultiplier
= 2
.0f
;
private Sprite mSprite
= null;
//private Hashtable<KerningPair, Integer> mKernings = new Hashtable<KerningPair, Integer>();
private Dictionary
<KerningPair,
int> mKernings
= new Dictionary
<KerningPair,
int>();
/** The y difference of a line break in multiples of line height. */
private float mLineBreakFactor
= 1
.0f
;
public Font
(Graphics graphics
) :
base(graphics
)
{
}
public void dispose
()
{
mCharacters
= null;
}
public void setAscent
(float ascent
)
{
mAscent
= ascent
;
}
public void setCharacters
(CharacterInfo
[] characters
)
{
mCharacters
= characters
;
}
public void setSprite
(Sprite sprite
)
{
mSprite
= sprite
;
}
public void setGlobalMultiplier
(float multiplier
)
{
mGlobalMultiplier
= multiplier
;
}
public void drawText
(string text,
float x,
float y,
float scale
)
{
drawText
(text, x, y, DEFAULT_COLOR, scale
);
}
public void drawText
(string text,
float x,
float y
)
{
drawText
(text, x, y, DEFAULT_COLOR
);
}
public void drawText
(string text,
float x,
float y, Vector4 color
)
{
drawText
(text, x, y, color, 1
.0f
);
}
public void drawTextDirect
(string text,
float x,
float y, Vector4 color,
float scale
)
{
float posX
= x
;
float posY
= y
;
for (int i
= 0; i
< text
.Length; i
++)
{
if (text
[i
] == '\n')
{
posY
+= mAscent
* mLineBreakFactor
* scale
;
posX
= x
;
continue;
}
int n
= getCharacterIndexNoCase
(text
[i
]);
if (n
== -1)
{
continue;
}
CharacterInfo c
= mCharacters
[n
];
int kerning
= 0;
if (i
< (text
.Length-1))
{
// apply kerning if any
char first
= c
.getCharacter();
char second
= text
[i
+1];
kerning
= getKerning
(first, second
);
}
if (c
.mSpriteInstance != null)
{
c
.mSpriteInstance.transform.x = posX
;
c
.mSpriteInstance.transform.y = posY
;
c
.mSpriteInstance.color = color
;
c
.mSpriteInstance.transform.w = c
.mSpriteInstance.getSpriteRegion().getWidth() * scale
* mGlobalMultiplier
* c
.mSpriteInstance.getSprite().getTextureWidth();
c
.mSpriteInstance.transform.h = c
.mSpriteInstance.getSpriteRegion().getHeight() * scale
* mGlobalMultiplier
* c
.mSpriteInstance.getSprite().getTextureHeight();
//c.mSpriteInstance.param.w = mSprite.getRegionWidth(c.mSpriteInstance.getRegionIndex()) * scale * mGlobalMultiplier;
//c.mSpriteInstance.param.h = mSprite.getRegionHeight(c.mSpriteInstance.getRegionIndex()) * scale * mGlobalMultiplier;
c
.mSpriteInstance.transform.pivotX = 0;
c
.mSpriteInstance.transform.pivotY = 0;
c
.mSpriteInstance.render();
}
posX
+= c
.width * scale
+ kerning
- c
.offsetX;
}
}
public void drawText
(string text,
float x,
float y, Vector4 color,
float scale
)
{
float posX
= x
;
float posY
= y
;
TileBatch batch
= getGraphics
().getBatch();
batch
.begin();
for (int i
= 0; i
< text
.Length; i
++)
{
if (text
[i
] == '\n')
{
posY
+= mAscent
* mLineBreakFactor
* scale
;
posX
= x
;
continue;
}
int n
= getCharacterIndexNoCase
(text
[i
]);
if (n
== -1)
{
continue;
}
CharacterInfo c
= mCharacters
[n
];
int kerning
= 0;
if (i
< (text
.Length-1))
{
// apply kerning if any
char first
= c
.getCharacter();
char second
= text
[i
+1];
kerning
= getKerning
(first, second
);
}
if (c
.mSpriteInstance != null)
{
c
.mSpriteInstance.transform.x = posX
;
c
.mSpriteInstance.transform.y = posY
;
c
.mSpriteInstance.color = color
;
c
.mSpriteInstance.transform.w = c
.mSpriteInstance.getSpriteRegion().getWidth() * scale
* mGlobalMultiplier
* c
.mSpriteInstance.getSprite().getTextureWidth();
c
.mSpriteInstance.transform.h = c
.mSpriteInstance.getSpriteRegion().getHeight() * scale
* mGlobalMultiplier
* c
.mSpriteInstance.getSprite().getTextureHeight();
//c.mSpriteInstance.param.w = mSprite.getRegionWidth(c.mSpriteInstance.getRegionIndex()) * scale * mGlobalMultiplier;
//c.mSpriteInstance.param.h = mSprite.getRegionHeight(c.mSpriteInstance.getRegionIndex()) * scale * mGlobalMultiplier;
c
.mSpriteInstance.transform.pivotX = 0;
c
.mSpriteInstance.transform.pivotY = 0;
batch
.drawSprite(c
.mSpriteInstance);
}
posX
+= c
.width * scale
+ kerning
- c
.offsetX;
}
batch
.end();
}
public float getTextWidth
(string text,
float scale
)
{
float maxWidth
= 0;
float width
= 0;
float posX
= 0;
for (int i
= 0; i
< text
.Length; i
++)
{
if (text
[i
] == '\n')
{
posX
= 0;
continue;
}
int n
= getCharacterIndexNoCase
(text
[i
]);
if (n
== -1)
{
continue;
}
CharacterInfo c
= mCharacters
[n
];
int kerning
= 0;
if (i
< (text
.Length-1))
{
// apply kerning if any
char first
= c
.getCharacter();
char second
= text
[i
+1];
kerning
= getKerning
(first, second
);
}
width
= posX
+ c
.width * scale
;
if (maxWidth
< width
)
{
maxWidth
= width
;
}
posX
+= c
.width * scale
+ kerning
- c
.offsetX;
}
return maxWidth
;
}
public float getTextHeight
(string text,
float scale
)
{
float maxHeight
= 0;
float posY
= 0;
for (int i
= 0; i
< text
.Length; i
++)
{
if (text
[i
] == '\n')
{
posY
+= mAscent
* mLineBreakFactor
* scale
;
continue;
}
int n
= getCharacterIndexNoCase
(text
[i
]);
if (n
== -1)
{
continue;
}
float charHeight
= this.mAscent * scale
;
if ((posY
+ charHeight
) > maxHeight
)
{
maxHeight
= posY
+ charHeight
;
}
}
return maxHeight
;
}
public int getCharacterIndex
(char c
)
{
for (int i
= 0; i
< mCharacters
.Length; i
++)
{
if (mCharacters
[i
].getCharacter() == c
)
return i
;
}
return -1;
}
public int getCharacterIndexNoCase
(char c
)
{
int n
= getCharacterIndex
(c
);
if (n
== -1)
{
n
= getCharacterIndex
(char.ToLower(c
));
if (n
== -1)
{
n
= getCharacterIndex
(char.ToUpper(c
));
}
}
return n
;
}
public CharacterInfo getCharacter
(char c
)
{
int i
= getCharacterIndex
(c
);
if (i
!= -1)
return mCharacters
[i
];
return null;
}
public void setKerning
(char first,
char second,
int value
)
{
//mKernings.put(new KerningPair(first, second), value);
mKernings
.Add(new KerningPair
(first, second
), value
);
}
public int getKerning
(char first,
char second
)
{
//int value = mKernings[new KerningPair(first, second)];
KerningPair key
= new KerningPair
(first, second
);
if (!mKernings
.ContainsKey(key
))
return 0;
return mKernings
[key
];
}
public void setFiltering
(bool filter
)
{
/*
// HACK: should use own texture class
if (filter)
getGraphics().renderStates.getTextureStage(0).setTextureFilter(mSprite.getTexture(), TextureFilter.Linear, TextureFilter.Linear);
else
getGraphics().renderStates.getTextureStage(0).setTextureFilter(mSprite.getTexture(), TextureFilter.Nearest, TextureFilter.Nearest);*/
if (filter
)
mSprite
.getTexture().setFilter(Texture
.Filter.LINEAR, Texture
.Filter.LINEAR);
else
mSprite
.getTexture().setFilter(Texture
.Filter.NEAREST, Texture
.Filter.NEAREST);
}
public void setLineBreak
(float multiple
) { mLineBreakFactor
= multiple
; }
public float getLineBreak
() { return mLineBreakFactor
; }
}
}