-
-
Save BoarK/9969200 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
//parts of this were inspired by https://github.com/prime31/UIToolkit/blob/master/Assets/Plugins/UIToolkit/UIElements/UIText.cs | |
public class FDFontLabel : FLabel | |
{ | |
protected int dynamicFontSize = 32; | |
protected FontStyle dynamicFontStyle = FontStyle.Normal; | |
public FDFontLabel (string fontName, string text, int fontSize) | |
: this(fontName, text, fontSize, new FTextParams()) | |
{ | |
} | |
public FDFontLabel (string fontName, string text, float fontSize) | |
: this(fontName, text, (int)fontSize, new FTextParams()) | |
{ | |
} | |
public FDFontLabel (string fontName, string text, float fontSize, FTextParams textParams) | |
: this(fontName, text, (int)fontSize, textParams) | |
{ | |
} | |
public FDFontLabel (string fontName, string text, int fontSize, FTextParams textParams) | |
{ | |
dynamicFontSize = fontSize; | |
_fontName = fontName; | |
_text = text; | |
_textParams = textParams; | |
FDynamicFont font = FDynamicFont.dynamicsFonts[fontName]; | |
_font = font; | |
font.dynamicFont.RequestCharactersInTexture(text, dynamicFontSize, dynamicFontStyle); | |
this.shader = FShader.AdditiveColor; | |
Init(FFacetType.Quad, _font.element, 0); | |
CreateTextQuads(); | |
font.labels.Add(this); | |
} | |
~FDFontLabel() | |
{ | |
FDynamicFont font = _font as FDynamicFont; | |
font.labels.Remove(this); | |
} | |
override public void HandleAddedToStage() | |
{ | |
base.HandleAddedToStage(); | |
CreateTextQuads(); //lazily creating the quads was causing too many issues, so just create them when .text is set | |
FDynamicFont font = _font as FDynamicFont; | |
} | |
override public void HandleRemovedFromStage() | |
{ | |
base.HandleRemovedFromStage(); | |
_doesTextNeedUpdate = true; | |
_isMeshDirty = true; | |
FDynamicFont font = _font as FDynamicFont; | |
//font.labels.Remove(this); | |
} | |
public void MarkHasChanged() | |
{ | |
_doesTextNeedUpdate = true; | |
_isMeshDirty = true; | |
FDynamicFont font = _font as FDynamicFont; | |
font.dynamicFont.RequestCharactersInTexture(_text, dynamicFontSize, dynamicFontStyle); | |
CreateTextQuads(); //lazily creating the quads was causing too many issues, so just create them when .text is set | |
} | |
override public string text | |
{ | |
get | |
{ | |
return _text; | |
} | |
set | |
{ | |
if(_text != value) | |
{ | |
_text = value; | |
FDynamicFont font = _font as FDynamicFont; | |
font.dynamicFont.RequestCharactersInTexture(_text, dynamicFontSize, dynamicFontStyle); | |
_doesTextNeedUpdate = true; | |
CreateTextQuads(); //lazily creating the quads was causing too many issues, so just create them when .text is set | |
} | |
} | |
} | |
public FontStyle Style | |
{ | |
get | |
{ | |
return dynamicFontStyle; | |
} | |
set | |
{ | |
dynamicFontStyle = value; | |
MarkHasChanged(); | |
} | |
} | |
override public void CreateTextQuads() | |
{ | |
_doesTextNeedUpdate = false; | |
int oldFacetsNeeded = _numberOfFacetsNeeded; | |
FDynamicFont font = _font as FDynamicFont; | |
_letterQuadLines = font.GetQuadInfoForText(_text, dynamicFontSize, dynamicFontStyle, _textParams); | |
_numberOfFacetsNeeded = 0; | |
int lineCount = _letterQuadLines.Length; | |
for(int i = 0; i< lineCount; i++) | |
{ | |
_numberOfFacetsNeeded += _letterQuadLines[i].quads.Length; | |
} | |
if(_isOnStage) | |
{ | |
int delta = _numberOfFacetsNeeded - oldFacetsNeeded; | |
if(delta != 0) //if the number of letter quads has changed, tell the stage | |
{ | |
_stage.HandleFacetsChanged(); | |
} | |
} | |
UpdateLocalPosition(); //figures out the bounds and alignment, and sets the mesh dirty | |
} | |
public int FontSize | |
{ | |
get | |
{ | |
return dynamicFontSize; | |
} | |
/* // not currently working | |
set | |
{ | |
dynamicFontSize = value; | |
CreateTextQuads(); | |
_doesLocalPositionNeedUpdate = true; | |
} | |
*/ | |
} | |
} | |
public class FDynamicFont : FFont | |
{ | |
public Font dynamicFont; | |
public List<FDFontLabel> labels = new List<FDFontLabel>(); | |
public static Dictionary<string, FDynamicFont> dynamicsFonts = new Dictionary<string, FDynamicFont>(); | |
public static void LoadDynamicFont(string fontName) | |
{ | |
FDynamicFont font; | |
if (!dynamicsFonts.TryGetValue(fontName, out font)) | |
{ | |
Font dynamicFont = Resources.Load<Font>(fontName); | |
Futile.atlasManager.LoadAtlasFromTexture(fontName, dynamicFont.material.mainTexture); | |
FAtlasElement element = Futile.atlasManager.GetElementWithName(fontName); | |
font = new FDynamicFont(fontName, element); | |
font.dynamicFont = dynamicFont; | |
dynamicsFonts.Add(fontName, font); | |
dynamicFont.material.mainTexture.filterMode = FilterMode.Point; | |
font.dynamicFont.textureRebuildCallback += () => { font.OnFontRebuilt(); }; | |
} | |
} | |
public FDynamicFont(string fontname, FAtlasElement element) | |
: base(fontname, element) | |
{ | |
} | |
void OnFontRebuilt() | |
{ | |
foreach(FDFontLabel label in labels) | |
{ | |
label.MarkHasChanged(); | |
} | |
} | |
public FLetterQuadLine[] GetQuadInfoForText(string text, int dynamicFontSize, FontStyle dynamicFontStyle, 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[10]; | |
int lettersLength = letters.Length; | |
for(int c = 0; c<lettersLength; ++c) | |
{ | |
char letter = letters[c]; | |
if(letter == FFont.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; | |
float minX = float.MaxValue; | |
float maxX = float.MinValue; | |
float minY = float.MaxValue; | |
float maxY = float.MinValue; | |
float usableLineHeight = dynamicFontSize + labelTextParams.scaledLineHeightOffset + labelTextParams.scaledLineHeightOffset; | |
for(int c = 0; c<lettersLength; ++c) | |
{ | |
char letter = letters[c]; | |
if(letter == FFont.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 | |
{ | |
//TODO: Reuse letterquads with pooling! | |
FLetterQuad letterQuad = new FLetterQuad(); | |
//v0 v1 are the two corners | |
CharacterInfo charInfo; | |
if (!dynamicFont.GetCharacterInfo(letter, out charInfo, dynamicFontSize, dynamicFontStyle)) | |
{ | |
//blank, character (could consider using the "char not found square") | |
dynamicFont.GetCharacterInfo(' ', out charInfo, dynamicFontSize, dynamicFontStyle); | |
} | |
float totalKern = labelTextParams.scaledKerningOffset + labelTextParams.scaledKerningOffset; | |
/* if(letterCount == 0) | |
{ | |
nextX = -charInfo.offsetX; //don't offset the first character | |
} | |
else*/ | |
{ | |
nextX += totalKern; | |
} | |
letterQuad.charInfo = new FCharInfo(); | |
if (charInfo.flipped) | |
{ | |
letterQuad.charInfo.uvBottomRight = new Vector2(charInfo.uv.xMin, charInfo.uv.yMax); | |
letterQuad.charInfo.uvTopRight = new Vector2(charInfo.uv.xMax, charInfo.uv.yMax); | |
letterQuad.charInfo.uvTopLeft = new Vector2(charInfo.uv.xMax, charInfo.uv.yMin); | |
letterQuad.charInfo.uvBottomLeft = new Vector2(charInfo.uv.xMin, charInfo.uv.yMin); | |
} | |
else | |
{ | |
letterQuad.charInfo.uvTopLeft = new Vector2(charInfo.uv.xMin, charInfo.uv.yMax); | |
letterQuad.charInfo.uvTopRight = new Vector2(charInfo.uv.xMax, charInfo.uv.yMax); | |
letterQuad.charInfo.uvBottomRight = new Vector2(charInfo.uv.xMax, charInfo.uv.yMin); | |
letterQuad.charInfo.uvBottomLeft = new Vector2(charInfo.uv.xMin, charInfo.uv.yMin); | |
} | |
float m = 0.8203215f; | |
float n = 1.0f - m; | |
float offsetY = (int)(m * dynamicFontSize) + n; | |
Rect quadRect = new Rect(nextX + charInfo.vert.x, nextY + charInfo.vert.yMax - offsetY, Mathf.Abs(charInfo.vert.width), Mathf.Abs(charInfo.vert.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.width; | |
letterCount++; | |
} | |
} | |
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; | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment