True Type font module
Monkey Archive Forums/Monkey Projects/True Type font module
| ||
Loads and parses a true type file at runtime within monkey![]() Download Link Here Currently supports ttf files with true type outlines only. Features * Set colour of font at load point * Set additional letter spacing at drawtext * Set additional line spacing at drawtext * Center text x and y * TextWidth and TextHeight method * Uses characters advance width and left side bearing * SHOULD work on all targets - Tested on html5, flash, desktop and android * Supports "~n" as a new line (horizontal squiggle (asciitidal))n Still to do: * ttf files with open type layout * OpenType file support * Compound glyfs * Oriental character support * Speed up android somehow Methods 'Import module Import tfont 'Declaration of your font Global MyFont:TFont 'Load font file MyFont = New TFont(Path:String, PixelHeight,[R, G, B]) 'Draw text MyFont.DrawText(Text:String, X, Y, CenterX=0, CenterY=0, AdditionalLetterSpace=0, AdditionalLineSpace=0) 'Return text width of a given text (multi line included) MyFont.TextWidth(Text:String, AdditionalLetterSpace=0) 'Return text Height of a given text (multi line included) MyFont.TextHeight(Text:String, AdditionalLineSpace = 0) |
| ||
| Top job! I'll have a play tonight. |
| ||
| Was following this like a ninja in the other thread, ill check it out. |
| ||
| Exellent! Really usefull. Feel free to take a look at http://www.monkey-x.com/Community/posts.php?topic=8035 to see if there's anything you can use. (I'm looking forward to maybe experimenting with a vector only version of this.) |
| ||
| So does this works on all targets? So cool! Have anyone done some speed tests to see how fast is it? Can you change font color on the fly? Maybe it could use native HTML5 functions on that TARGET... I know it is possible there, because I've done it in the past Here, found my html5 loading code 'hack', from my own HTML engine: Then you just do something like this to write it: |
| ||
| @SLotman This *Should* work on all targets, ive tested and is working on html,flash,desktop,and android. Speedwise, loading times are aroung the 40ms per font mark - apart from android, which I have been unable to speed up loading more than 500ms per font :( Rendering time will be around the same as other bitmap font modules as it converts it to bitmaps. Setting the colour is done when you load the font, so not on the fly unfortunatly. I did have a look at trying to use external libraries for each target, although started with android as html5 runs fast as is, but I was getting nowhere as I could not work out androids api combined with extern etc. I tried for a couple of days to understand opentype table formats to (that would allow opentype and truetype with postscript outline files), but was just not intelligent enough to get it! So unfortunately unless a genius comes along, and takes this a couple more steps further I am at a dead end :( Incidenty if anyone can further this, please do! Full Truetype/opentype support is a massive hole missing in monkey, and you have my unconditional consent to use copy etc any of my source! |
| ||
| If you're using WritePixel on Android, take a look at Danilo's post here: http://www.monkey-x.com/Community/posts.php?topic=8505&post=87728 | Changing Bind to Bind2 seemed to solve the horrendous speed issues. So unfortunately unless a genius comes along, and takes this a couple more steps further I am at a dead end :( Don't put yourself down. You did a good job having never worked with fonts before. I don't think a genius is needed, more like someone knowledgeable in vector graphics and fonts is needed to further it. Either that or someone really dedicated to just keep pushing until they solve it. |
| ||
| I agree, don't put yourself down - you have done a super job! I've been meaning look into integrating my TTF module for Android and your version, but like always I don't find the time. My TTF module uses the native Android function to load a TTF in, draw it to the screen via native functions and from there I capture it as a bitmap font, so it should be possible and because it is using native functions it is really quick to load. http://www.monkey-x.com/Community/posts.php?topic=8190 @Slotman, in my TTF module I added a prototype TTF loader for HTML5 and it works with IE 10 & 11. |
| ||
| Never mind, I sorted it out.. :) EDIT: Actually.. While trying to find a good font for a console, I noticed that many fonts are missing the capital letter "i" (comes out as a square)...? Also, there's no way to turn anti-aliasing off, which is sad with pixelated fonts.... But ...any updates soon? |
| ||
| Just having a play with this, I get an Array index out of range error when loading the Impact TTF. The fonts included with the module work fine though. |
| ||
| The link doesn't work. Could you please fix? I can mirror! |
| ||
| Also i made an online monkey font generator. http://www.monkey-x.com/Community/posts.php?topic=8897 direct link to the font generator http://vigilsoft.net/monkeyfonts/monkeyfontgen.php |
| ||
| @Alex Here's my copy of it: https://dl.dropboxusercontent.com/u/35103024/tfont.zip Also I've created a GoogleCode Repo here. this work is too good to go missing: https://code.google.com/p/monkey-ttf-module/ @Chris - If you want me to remove this repo please say so, also if you want to be the owner let me know and I'll add you to the project. @Landon This isn't quite the same, this module loads in true TTF files into Monkey to render them. |
| ||
| Thank you for mirroring it! I agree that the work is too good to have vanish. |
| ||
| @therevills Thank you! Great job, works like a charm! The outline and shadow would be great ;) |
| ||
| I've added my own little "smooth font" flag which by default is true, but can be turned off to use a much sharper scaling method. It's very handy when using smaller fonts that would otherwise turn out blurry. Here's an example: ![]() So the new load function works like this: MyFont = New TFont(font, size,[r,g,b],smooth)Where "smooth" set to "False" obviously will produce the sharp edges. Also! #TEXT_FILES+="*.ttf"Doesn't actually append to TEXT_FILES, it replaces it entirely, causing a few issues. So you'll want to place that in "Example.monkey" instead. Here's the new tfont.monkey (With "HEZKORE" marking changes) '#TEXT_FILES+="*.ttf" 'HEZKORE: This does not append, it replaces it
Import mojo
Import tfontdatastream
Import tfontpoly
Class TFont
Field Stream:DataStream
Field Size
Field Color:Int[]
Field Smooth:Bool 'HEZKORE: Smooth font
Field Path:String
Field OutlineType:String ' "TT" or "OT"
Field GlyphNumber
Field FontLimits[4]
Field FontScale:Float
Field LineHeight
Field GlyphId:Int[]
Field Glyph:TFont_Glyph[]
Field ImagesLoaded:Bool = False
Field FontClockwise:Bool
Field ClockwiseFound:Bool = False
'Load a new Font HEZKORE: Added smooth font flag
Method New(Path:String, Size, Color:Int[] =[0, 0, 0],Smooth:Bool=True)
Stream = New DataStream("monkey://data/" + Path, True)
Self.Size = Size
Self.Color = Color
Self.Smooth = Smooth 'HEZKORE: Store smooth flag
Self.Path = Path
If Stream.Buffer = Null Then Error Path + " : Font file not found"
'===== Read Offset Table =====
Local sfntVersion = Stream.ReadFixed32()
Local numTables = Stream.ReadUInt(2)
Local searchRange = Stream.ReadUInt(2)
Local entrySelector = Stream.ReadUInt(2)
Local rangeShift = Stream.ReadUInt(2)
If Int(sfntVersion) = 1 Then
OutlineType = "TT"
Else
OutlineType = "OT"
End If
'===== Load Offset Table Records and get offsets =====
Local cmapOffset, headOffset, hheaOffset, hmtxOffset, maxpOffset, nameOffset, glyfOffset, locaOffset, CFFOffset, VORGOffset
For Local i = 0 To numTables - 1
Local tag:String = Stream.ReadString(4)
Local checksum = Stream.ReadUInt(4)
Local offset = Stream.ReadUInt(4)
Local length = Stream.ReadUInt(4)
Select tag
Case "cmap"
cmapOffset = offset
Case "head"
headOffset = offset
Case "hhea"
hheaOffset = offset
Case "hmtx"
hmtxOffset = offset
Case "maxp"
maxpOffset = offset
Case "name"
nameOffset = offset
Case "glyf"
glyfOffset = offset
Case "loca"
locaOffset = offset
Case "CFF "
CFFOffset = offset
Case "VORG"
VORGOffset = offset
End Select
Next
'===== Peek some font data =====
GlyphNumber = Stream.PeekUInt(2, maxpOffset + 4)
FontLimits[0] = Stream.PeekInt(2, headOffset + 36) 'xMin
FontLimits[1] = Stream.PeekInt(2, headOffset + 38) 'yMin
FontLimits[2] = Stream.PeekInt(2, headOffset + 40) 'xMax
FontLimits[3] = Stream.PeekInt(2, headOffset + 42) 'yMax
FontScale = (Size * 1.0) / (FontLimits[3])' - FontLimits[1])
LineHeight = Size
Local LocaFormat = Stream.PeekInt(2, headOffset + 50)
Local HMetricsNumber = Stream.PeekUInt(2, hheaOffset + 34)
'===== Setup Glyph Arrays =====
GlyphId = New Int[1000]
Glyph = New TFont_Glyph[GlyphNumber]
For Local i = 0 To GlyphNumber - 1
Glyph[i] = New TFont_Glyph
Next
'===== Load Big Data =====
LoadMetrics(hmtxOffset, HMetricsNumber)
LoadCmapData(cmapOffset)
LoadLoca(locaOffset, LocaFormat, glyfOffset)
'Load glyph data
For Local g = 0 To GlyphNumber - 1
'Load Points
LoadGlyfData(g, Glyph[g].FileAddress)
QuadGlyph(g)
SmoothGlyph(g)
Next
'Make Poly
For Local g = 0 To GlyphNumber - 1
Glyph[g].Poly = New TFont_Poly[Glyph[g].ContourNumber]
For Local c = 0 To Glyph[g].ContourNumber - 1
Glyph[g].Poly[c] = New TFont_Poly(Glyph[g].xyList[c], FontScale)
If Glyph[g].ContourNumber = 1 And Not ClockwiseFound Then
FontClockwise = Glyph[g].Poly[0].Clockwise
ClockwiseFound = True
EndIf
Next
Next
End Method
Method DrawText(Text:String, x, y, CenterX = 0, CenterY = 0, AdditionalLetterSpace = 0, AdditionalLineSpace = 0)
'Load Font
If ImagesLoaded = False Then
LoadGlyphImages()
ImagesLoaded = True
End If
'Draw Lines of Text
Local X = x
Local Y = y
If CenterY = 1 Then
Y = Y - Self.TextHeight(Text, AdditionalLineSpace) / 2
End If
For Local L:String = EachIn Text.Split("~n")
For Local c = EachIn L
Local Id = GlyphId[c]
Local tx = X + Glyph[Id].xMin * FontScale
Local ty = Y - (Glyph[Id].yMax * FontScale) + LineHeight
If CenterX = 1 Then
tx = tx - (Self.TextWidth(L, AdditionalLetterSpace)) / 2
End If
If c > 32 Then
If Glyph[Id].Img <> Null Then DrawImage(Glyph[Id].Img, tx, ty)
End If
X = X + Glyph[Id].Adv * FontScale + AdditionalLetterSpace
Next
X = x
Y = Y + LineHeight + AdditionalLineSpace
Next
End Method
Method TextWidth(Text:String, AdditionalLetterSpace = 0)
Local Width = 0
For Local L:String = EachIn Text.Split("~n")
Local TempWidth = 0
For Local c = EachIn L
Local Id = GlyphId[c]
TempWidth = TempWidth + (Glyph[Id].Adv * FontScale) + AdditionalLetterSpace
Next
If TempWidth > Width Then Width = TempWidth
Next
Return Width
End Method
Method TextHeight(Text:String, AdditionalLineSpace = 0)
Local Height = 0
Local Lines = (Text.Split("~n")).Length
Return (Lines * LineHeight) + (Lines * AdditionalLineSpace)
End Method
Method LoadMetrics(Offset, HMetricsCount)
Stream.SetPointer(Offset)
Local Count = 0, LastAdv
For Local i = 0 To GlyphNumber - 1
If Count < HMetricsCount - 1 Then
Glyph[i].Adv = Stream.ReadUInt(2)
'HEZKORE: Quick fix for some FontScale
If Glyph[i].Adv<=0 then Glyph[i].Adv=1024
Glyph[i].Lsb = Stream.ReadInt(2)
LastAdv = Glyph[i].Adv
Else
Glyph[i].Adv = LastAdv
Glyph[i].Lsb = Stream.ReadInt(2)
End If
Count = Count + 1
Next
End Method
Method LoadCmapData(Offset)
Stream.SetPointer(Offset)
Stream.ReadUInt(2)
Local numTables = Stream.ReadUInt(2)
Local PlatformId[numTables]
Local EncodingId[numTables]
Local TableOffset[numTables]
'Load all tables and select windows format
For Local t = 0 To numTables - 1
PlatformId[t] = Stream.ReadUInt(2)
EncodingId[t] = Stream.ReadUInt(2)
TableOffset[t] = Stream.ReadUInt(4) + Offset
Next
'Load 3-1 first then other tables
Local WindowsFontFound:Bool = False
For Local t = 0 To numTables - 1
If PlatformId[t] = 3 And EncodingId[t] = 1 Then
WindowsFontFound = True
Local Format = Stream.PeekUInt(2, TableOffset[t])
If Format = 0 Then LoadCmapTable0(TableOffset[t] + 2)
If Format = 4 Then LoadCmapTable4(TableOffset[t] + 2)
If Format = 6 Then LoadCmapTable6(TableOffset[t] + 2)
End If
Next
'Load 3 - Any first Then other tables
For Local t = 0 To numTables - 1
If PlatformId[t] = 3 And EncodingId[t] <> 1 Then
Local Format = Stream.PeekUInt(2, TableOffset[t])
If Format = 0 Then LoadCmapTable0(TableOffset[t] + 2)
If Format = 4 Then LoadCmapTable4(TableOffset[t] + 2)
If Format = 6 Then LoadCmapTable6(TableOffset[t] + 2)
End If
Next
'Load Any first Then other tables
For Local t = 0 To numTables - 1
If PlatformId[t] <> 3 Then
Local Format = Stream.PeekUInt(2, TableOffset[t])
If Format = 0 Then LoadCmapTable0(TableOffset[t] + 2)
If Format = 4 Then LoadCmapTable4(TableOffset[t] + 2)
If Format = 6 Then LoadCmapTable6(TableOffset[t] + 2)
End If
Next
'Revert additional to 0 - Just to make Sure
For Local i = 0 To GlyphId.Length - 1
If GlyphId[i] > GlyphNumber - 1 Then GlyphId[i] = 0
Next
End Method
Method LoadCmapTable0(Offset)
Stream.SetPointer(Offset)
Stream.ReadUInt(2); Stream.ReadUInt(2)
For Local g = 0 To 254
Local GId = Stream.ReadUInt(1)
If GlyphId[g] = 0 Then GlyphId[g] = GId
Next
End Method
Method LoadCmapTable4(Offset)
Local OffCount = Offset
Stream.SetPointer(Offset)
Stream.ReadUInt(2); Stream.ReadUInt(2)
Local SegCount = Stream.ReadUInt(2) / 2
Local SearchRange = Stream.ReadUInt(2)
Local EntrySelector = Stream.ReadUInt(2)
Local RangeShift = Stream.ReadUInt(2)
OffCount = OffCount + 12
Local EndCount[SegCount]
For Local s = 0 To SegCount - 1
EndCount[s] = Stream.ReadUInt(2)
OffCount = OffCount + 2
Next
Local Reserved = Stream.ReadUInt(2); OffCount = OffCount + 2
Local StartCount[SegCount]
For Local s = 0 To SegCount - 1
StartCount[s] = Stream.ReadUInt(2)
OffCount = OffCount + 2
Next
Local IdDelta[SegCount]
For Local s = 0 To SegCount - 1
IdDelta[s] = Stream.ReadInt(2)
OffCount = OffCount + 2
Next
Local IdRangeOffset[SegCount]
Local IdRangeOffsetOffset[SegCount]
For Local s = 0 To SegCount - 1
IdRangeOffset[s] = Stream.ReadUInt(2)
IdRangeOffsetOffset[s] = OffCount
OffCount = OffCount + 2
Next
'Get Glyph Id
For Local Char = 0 To GlyphNumber - 1
Local NullFlag = 1
'GetSegment
Local CharSeg
For Local s = 0 To SegCount - 1
If EndCount[s] >= Char Then
CharSeg = s
If Char >= StartCount[s] Then NullFlag = 0
Exit
End If
Next
If NullFlag = 1 Then
GlyphId[Char] = 0
Continue
End If
If IdRangeOffset[CharSeg] = 0 Then
If GlyphId[Char] = 0 Then GlyphId[Char] = IdDelta[CharSeg] + Char
Else
Local Location = (2 * (Char - StartCount[CharSeg])) + (IdRangeOffset[CharSeg] - IdRangeOffset[0]) + OffCount + (CharSeg * 2)
If GlyphId[Char] = 0 Then GlyphId[Char] = Stream.PeekUInt(2, Location)
End If
Next
End Method
Method LoadCmapTable6(Offset)
Stream.SetPointer(Offset)
Stream.ReadUInt(2); Stream.ReadUInt(2)
Local FirstCode = Stream.ReadUInt(2)
Local EntryCount = Stream.ReadUInt(2)
For Local g = FirstCode To EntryCount - 1
Local GId = Stream.ReadUInt(2)
If GlyphId[g] = 0 Then GlyphId[g] = GId
Next
End Method
Method LoadLoca(Offset, Format, GlyfOffset)
Stream.SetPointer(Offset)
For Local i = 0 To GlyphNumber - 1
If Format = 0 Then
Glyph[i].FileAddress = (Stream.ReadUInt(2) * 2) + GlyfOffset
Else
Glyph[i].FileAddress = (Stream.ReadUInt(4)) + GlyfOffset
End If
Next
End Method
Method LoadGlyfData(Id, Offset)
Stream.SetPointer(Offset)
'Load contour Number and Position
Local ContourNumber = Stream.ReadInt(2)
If ContourNumber < 1 Then Return 0
Glyph[Id].ContourNumber = ContourNumber
Glyph[Id].xMin = Stream.ReadInt(2)
Glyph[Id].yMin = Stream.ReadInt(2)
Glyph[Id].xMax = Stream.ReadInt(2)
Glyph[Id].yMax = Stream.ReadInt(2)
Glyph[Id].W = Glyph[Id].xMax - Glyph[Id].xMin
Glyph[Id].H = Glyph[Id].yMax - Glyph[Id].yMin
'End Points
Local EndPoints:Int[ContourNumber]
For Local i = 0 To ContourNumber - 1
EndPoints[i] = Stream.ReadUInt(2)
Next
Local PointNumber = EndPoints[ContourNumber - 1] + 1
'Instructions
Local insLen = Stream.ReadUInt(2)
Stream.ReadString(insLen)
'Flags
Local Flags:Int[][] = New Int[PointNumber][]
Local ContinueNumber = 0
For Local i = 0 To PointNumber - 1
'Is The Same
If ContinueNumber > 0 Then
Flags[i] = Flags[i - 1]
ContinueNumber = ContinueNumber - 1
Continue
End If
'Load in new flag
Flags[i] = Stream.ReadBits(1)
If Flags[i][3] = 1 Then ContinueNumber = Stream.ReadUInt(1)
Next
'XCoords
Local XCoords:Int[PointNumber]
For Local i = 0 To PointNumber - 1
'Is the same as last
If Flags[i][1] = 0 And Flags[i][4] = 1 Then
If i > 0 Then XCoords[i] = XCoords[i - 1] Else XCoords[i] = -Glyph[Id].xMin
Continue
End If
'XisByte
If Flags[i][1] = 1 Then
Local tmp = Stream.ReadUInt(1)
If Flags[i][4] = 0 Then tmp = tmp * -1
If i > 0 Then XCoords[i] = XCoords[i - 1] + tmp Else XCoords[i] = tmp - Glyph[Id].xMin
Continue
End If
If Flags[i][1] = 0 And Flags[i][4] = 0 Then
If i > 0 Then XCoords[i] = XCoords[i - 1] + Stream.ReadInt(2) Else XCoords[i] = Stream.ReadInt(2) - Glyph[Id].xMin
Continue
End If
Next
'YCoords
Local YCoords:Int[PointNumber]
For Local i = 0 To PointNumber - 1
'Is the same as last
If Flags[i][2] = 0 And Flags[i][5] = 1 Then
If i > 0 Then YCoords[i] = YCoords[i - 1] Else YCoords[i] = Glyph[Id].yMax
Continue
End If
'YisByte
If Flags[i][2] = 1 Then
Local tmp = Stream.ReadUInt(1)
If Flags[i][5] = 0 Then tmp = tmp * -1
If i > 0 Then YCoords[i] = YCoords[i - 1] - tmp Else YCoords[i] = Glyph[Id].yMax - tmp
Continue
End If
If Flags[i][2] = 0 And Flags[i][5] = 0 Then
If i > 0 Then YCoords[i] = YCoords[i - 1] - Stream.ReadInt(2) Else YCoords[i] = Glyph[Id].yMax - Stream.ReadInt(2)
Continue
End If
Next
'Transpose to xyList
Glyph[Id].xyList = New Float[ContourNumber][]
Local p1 = 0, Pend
For Local i = 0 To ContourNumber - 1
If i > 0 Then
p1 = EndPoints[i - 1] + 1
End If
Pend = EndPoints[i]
Glyph[Id].xyList[i] = New Float[ ( (Pend - p1 + 1) * 3)]
Local Count = 0
For Local j = p1 To Pend
'HEZKORE: Sharper scaling for fonts that aren't smooth
If Not Smooth Then
Glyph[Id].xyList[i][Count] = XCoords[j] * FontScale
Glyph[Id].xyList[i][Count + 1] = YCoords[j] * FontScale
Else
Glyph[Id].xyList[i][Count] = XCoords[j]
Glyph[Id].xyList[i][Count + 1] = YCoords[j]
EndIf
Glyph[Id].xyList[i][Count + 2] = Flags[j][0]
Count = Count + 3
Next
Next
End Method
Method QuadGlyph(Id)
For Local c = 0 To Glyph[Id].ContourNumber - 1
Local xyStack:Stack<Float> = New Stack<Float>
For Local p0 = 0 To Glyph[Id].xyList[c].Length - 1 Step 3
Local p1 = p0 + 3 If p1 > Glyph[Id].xyList[c].Length - 1 Then p1 = 0
'Add p0
'HEZKORE: Use Ints for fonts that aren't smooth
If Not Smooth Then
xyStack.Push(Floor(Glyph[Id].xyList[c][p0]))
xyStack.Push(Floor(Glyph[Id].xyList[c][p0 + 1]))
xyStack.Push(Floor(Glyph[Id].xyList[c][p0 + 2]))
Else
xyStack.Push(Glyph[Id].xyList[c][p0])
xyStack.Push(Glyph[Id].xyList[c][p0 + 1])
xyStack.Push(Glyph[Id].xyList[c][p0 + 2])
Endif
'If Double add a middle point
If Glyph[Id].xyList[c][p0 + 2] = 0 And Glyph[Id].xyList[c][p1 + 2] = 0 Then
Local tx:Float = (Glyph[Id].xyList[c][p0] + Glyph[Id].xyList[c][p1]) / 2.0
Local ty:Float = (Glyph[Id].xyList[c][p0 + 1] + Glyph[Id].xyList[c][p1 + 1]) / 2.0
xyStack.Push(tx)
xyStack.Push(ty)
xyStack.Push(1)
End If
Next
Glyph[Id].xyList[c] = xyStack.ToArray()
Next
End Method
Method SmoothGlyph(Id)
For Local c = 0 To Glyph[Id].ContourNumber - 1
Local xyStack:Stack<Float> = New Stack<Float>
For Local p0 = 0 To Glyph[Id].xyList[c].Length - 1 Step 3
Local p1 = p0 + 3 If p1 > Glyph[Id].xyList[c].Length - 1 Then p1 = 0
Local p2 = p1 + 3 If p2 > Glyph[Id].xyList[c].Length - 1 Then p2 = 0
If Glyph[Id].xyList[c][p0 + 2] = 0 Then Continue
'Straight Line
If Glyph[Id].xyList[c][p0 + 2] = 1 And Glyph[Id].xyList[c][p1 + 2] = 1
xyStack.Push(Glyph[Id].xyList[c][p0])
xyStack.Push(Glyph[Id].xyList[c][p0 + 1])
Else
'Bexier curve
Local T:Float[] = CalculateCurve(Glyph[Id].xyList[c][p0], Glyph[Id].xyList[c][p0 + 1], Glyph[Id].xyList[c][p1], Glyph[Id].xyList[c][p1 + 1], Glyph[Id].xyList[c][p2], Glyph[Id].xyList[c][p2 + 1])
For Local tt:Float = EachIn T
xyStack.Push(tt)
Next
End If
Next
Glyph[Id].xyList[c] = xyStack.ToArray()
Next
End Method
Method CalculateCurve:Float[] (x1, y1, x2, y2, x3, y3)
Local Lst:Float[10]
Local Counter = 0
For Local t:Float = 0 To 0.8 Step 0.2
Local tx:Float = (Pow(1.0 - t, 2) * x1) + (2 * ( (1.0 - t) * t * x2)) + (Pow(t, 2) * x3)
Local ty:Float = (Pow(1.0 - t, 2) * y1) + (2 * ( (1.0 - t) * t * y2)) + (Pow(t, 2) * y3)
Lst[Counter] = tx
Lst[Counter + 1] = ty
Counter = Counter + 2
Next
Return Lst
End Method
Method LoadGlyphImages()
Local OrigColor:Float[] = GetColor()
'Copy BG
Local BW = ( (FontLimits[2] - FontLimits[0]) * FontScale) + 2
Local BH = ( (FontLimits[3] - FontLimits[1]) * FontScale) + 2
Local BG:Image = CreateImage(BW, BH)
Local BGPixels:Int[BW * BH]
ReadPixels(BGPixels, 0, 0, BW, BH)
BG.WritePixels(BGPixels, 0, 0, BW, BH)
'HEZKORE: Only scale here if it's a smooth font
If Smooth Then
PushMatrix
Scale(FontScale, FontScale)
EndIf
For Local g = 0 To GlyphNumber - 1
If Glyph[g].ContourNumber < 1 Then Continue
Local W = Glyph[g].W * FontScale + 4
Local H = Glyph[g].H * FontScale + 4
If W < 1 Or H < 1 Then Continue
'DrawBG
SetColor(255, 255, 255)
DrawRect(0, 0, W/FontScale, H/FontScale)
'Draw solids
SetColor(0, 0, 0)
For Local i = 0 To Glyph[g].ContourNumber - 1
If Glyph[g].Poly[i].Clockwise = FontClockwise Then
Glyph[g].Poly[i].Draw()
End If
Next
'Draw Cutouts
SetColor(255, 255, 255)
For Local i = 0 To Glyph[g].ContourNumber - 1
If Glyph[g].Poly[i].Clockwise <> FontClockwise Then
Glyph[g].Poly[i].Draw()
End If
Next
'SaveImage
Local pixels:Int[W * H]
ReadPixels(pixels, 0, 0, W, H)
'Set Alpha & Color
For Local i:Int = 0 Until pixels.Length
Local argb:Int = pixels[i]
Local a:Int = (argb Shr 24) & $ff
Local r:Int = (argb Shr 16) & $ff
Local g:Int = (argb Shr 8) & $ff
Local b:Int = argb & $ff
a = 255 - r
r = Color[0]
g = Color[1]
b = Color[2]
argb = (a Shl 24) | (r Shl 16) | (g Shl 8) | b
pixels[i] = argb
Next
Glyph[g].Img = CreateImage(W, H)
Glyph[g].Img.WritePixels(pixels, 0, 0, W, H)
Next
If Smooth Then PopMatrix 'HEZKORE: Only needed for smooth fonts
SetColor(255, 255, 255)
DrawImage(BG, 0, 0)
ImagesLoaded = True
SetColor(OrigColor[0], OrigColor[1], OrigColor[2])
End Method
End
Class TFont_Glyph
Field Adv, Lsb
Field FileAddress
Field xMin, yMin, xMax, yMax, W, H
Field ContourNumber
Field Points:Int[][]
Field xyList:Float[][]
Field Poly:TFont_Poly[]
Field Img:Image
End |
| ||
| This is a great module, its a shame there is no anti-alias on Android/iOS, but looks nice on HTML5 |
| ||
| Guys, why doesn't this module support non-latin characters? Or do I do something wrong? |
| ||
| I just stumbled upon this module and started using it. I downloaded the code therevills hosted on Google Code. The module has some serious bugs and visualization glitches. I've been able to fix (or so I think) some of them, but I suspect more will come. Does anyone have an updated version of the module? Or an alternative one which can load TTF fonts and display them correctly? Otherwise, we could maybe have the code hosted on GitHub to work on it together. |
| ||
| @itto my version (posted above) is "newer", and has the "sharp" way of loading TTF files which has worked great in my tests. |
| ||
| @Hezkore tried it already, but I don't see any improvements over the original one using the smooth feature (only tested with the bundled Helvetica on a HTML5 target). And disabling the smooth feature renders them even worse than the original module, especially small fonts are illegible. Additionally, the rendering is still not great. For small fonts the letters are all misplaced on the Y axis :( |

