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 :( |