;| ;| Pure Basic Module ;| ;| Title : Typeface ;| Version : 1.4.2-0018 (2018-09-24) ;| Copyright : UnionBytes ;| (Martin Guttmann alias STARGĊTE) ;| PureBasic : 5.30+ ;| String-Format : Ascii, Unicode ;| Operating-System : Windows, Linux (PB 5.20+) ;| Processor : x86, x64 ;| Description : Display of bitmap fonts on the screen. ;| Various styling options As color, size, rotation, bending, word wrap And more. ;| ;| Change-Log : 2018-09-24 : Written as a module DeclareModule Typeface ; Public Constants #Typeface_Ignore = -$100010000 #Typeface_Default = -$100000000 ; Public Constants: Formats Enumeration 1 #Typeface_Format_TF #Typeface_Format_XML EndEnumeration ; Public Procedures: Management Declare.i CopyTypeface(SourceTypeface.i, Typeface.i) Declare FreeTypeface(Typeface.i) Declare.i IsTypeface(Typeface.i) Declare.i LoadTypeface(Typeface.i, FileName.s) Declare.i TypefaceID(Typeface.i) Declare.i CatchTypeface(Typeface.i, *Memory) Declare.i SaveTypeface(Typeface.i, FileName.s, Format.i=#Typeface_Format_TF) ; Public Procedures: Styling Declare PopTypefaceStyles(Typeface.i) Declare PushTypefaceStyles(Typeface.i) Declare ResetTypefaceStyles(Typeface.i) Declare TypefaceAlignment(Typeface.i, AlignmentH.f=#Typeface_Ignore, AlignmentV.f=#Typeface_Ignore) Declare TypefaceBendRadius(Typeface.i, BendRadius.f=0.0) Declare TypefaceClipping(Typeface.i, State.i, X.f=0.0, Y.f=0.0, Width.f=0.0, Height.f=0.0) Declare TypefaceColor(Typeface.i, Color.q=#Typeface_Default) Declare TypefaceItalic(Typeface.i, InclinationAngle.f=0.0) Declare TypefaceKerning(Typeface.i, State.i=#True) Declare TypefaceOpacity(Typeface.i, Opacity.f=1.0) Declare TypefaceOrigin(Typeface.i, X.f=0, Y.f=0, Z.f=#Typeface_Ignore) Declare TypefaceRotation(Typeface.i, AxisZ.f, AxisY.f=0.0, AxisX.f=0.0) Declare TypefaceSize(Typeface.i, Size.f=1.0, Mode.i=#PB_Relative) Declare TypefaceSpacing(Typeface.i, LetterSpacing.f=#Typeface_Ignore, WordSpacing.f=#Typeface_Ignore) Declare TypefaceWordWrap(Typeface.i, Width.f=0.0) ; Public Procedures: Display Declare DisplayTypeface(Typeface.i, X.f, Y.f, Text.s, Opacity.f=#Typeface_Ignore, Color.q=#Typeface_Ignore, Size.f=#Typeface_Ignore, Italic.f=#Typeface_Ignore) Declare.i TypefaceDimension(Typeface.i, *StringCharacters, *Width.Float=#Null, *Height.Float=#Null, Size.f=#Typeface_Ignore) Declare.f TypefaceWidth(Typeface.i, Text.s, Size.f=#Typeface_Ignore) Declare.f TypefaceHeight(Typeface.i, Text.s, Size.f=#Typeface_Ignore) EndDeclareModule Module Typeface ;-> Constants ;ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ ; General #TypefaceInclude_IndexNumber = $FFFF ; Maximale Indexnummer für eine 'Typeface' #TypefaceInclude_AnyNumber = ~#TypefaceInclude_IndexNumber ; Nummer wurde durch '#PB_Any' erzeugt #TypefaceInclude_KerningSlots = 701 ; Anzahl der Slots bei aktiver Unterscheidung (Primzahl) #TypefaceInclude_MagicNumber = $7C30342E317C8354 ; Magische Zahl zum identifizieren der Typefacedatei #NUL = 0 ; Compilation modes Enumeration #TypefaceCompilation_Normal = %0000 #TypefaceCompilation_UBEngine = %1000 EndEnumeration CompilerIf Defined(UBE_VERSION, #PB_Constant) #TypefaceCompilation = #TypefaceCompilation_UBEngine CompilerElse #TypefaceCompilation = #TypefaceCompilation_Normal CompilerEndIf ; Chunks Enumeration 0 #TypefaceChunk_End ; Ende der Datei #TypefaceChunk_Image ; Bild (Image/Sprite) mit den Zeichen #TypefaceChunk_Characters ; Liste aller Zeichen mit deren Abmessungen #TypefaceChunk_KerningPairs ; Liste aller Unterscheidungen #TypefaceChunk_Info ; Sonstige Infos (Schriftart die als Quelle diente) EndEnumeration ;-> Structures ;ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ ; General Structure Typeface_CharacterArray C.c[0] EndStructure ; Typeface Structure Typeface_Vertex X.f Y.f Z.f W.f U.f V.f EndStructure Structure Typeface_Vertices I.Typeface_Vertex[4] EndStructure Structure Typeface_Matrix A11.f : A12.f : A13.f A21.f : A22.f : A23.f A31.f : A32.f : A33.f EndStructure Structure Typeface_Region X.f Y.f Width.f Height.f EndStructure Structure Typeface_Style Size.f ; Größe (relativ zur Originalgröße) Opacity.f ; Transparenzwert [0, 255] Color.q ; Farbe (in RGB) BendRadius.f ; Biegeradius (in Pixel) AlignH.f ; Ausrichtung (hozizontal) [0.0 (links), 1.0 (rechts)] AlignV.f ; Ausrichtung (vertikal) [0.0 (oben), 1.0 (unten)] Italic.f ; Kursiv-Grad (in Grad) LetterSpace.f ; (zusätzlicher) Buchstabenabstand (in Pixel) WordSpace.f ; (zusätzlicher) Wortabstand (in Pixel) Translation.Typeface_Vertex ; Koordinatenursprung (im 3D-Raum) (in Pixel) Rotation.Typeface_Matrix ; Rotation (im 3D-Raum) (in Grad) WordWrap.f AccentColor.i AccentCharacter.u Kerning.i ; Unterscheidung EnabledRegion.i Region.Typeface_Region EndStructure Structure Typeface_CharacterArea X.i Y.i Width.i Height.i EndStructure Structure Typeface_Character Index.i Outlay.Typeface_CharacterArea Source.Typeface_CharacterArea EndStructure Structure Typeface_KerningPair StructureUnion CharacterPair.q ; Zeichenpaar Character.w[2] ; Zeichen EndStructureUnion Amount.i ; Versatz *NextPair.Typeface_KerningPair ; nächstes Unterscheidungspaar EndStructure Structure Typeface_CharacterSet_Elements List Character.Typeface_Character() ; Zeichen List KerningPair.Typeface_KerningPair() ; Unterscheidungspaare EndStructure Structure Typeface_CharacterSet CompilerIf #TypefaceCompilation & #TypefaceCompilation_UBEngine *Material.UBE_MATERIAL CompilerElse Sprite.i ; Sprite-Nummer CompilerEndIf MirroredSprite.i ; Gespiegeltes Sprite MirroredSpriteHeight.i ; Höhe des gespiegelten Sprites Image.i ; Image-Nummer Copys.i ; Anzahl der benutzen Kopien Array *Character.Typeface_Character(0) ; Zeichen Array *KerningPair.Typeface_KerningPair(#TypefaceInclude_KerningSlots) ; Unterscheidungspaare Elements.Typeface_CharacterSet_Elements ; Zeichensatzelemente MaxCharacterHeight.f Map Info.s() EndStructure Structure Typeface Number.i ; Nummer *CharacterSet.Typeface_CharacterSet ; Zeichensatz Style.Typeface_Style ; Gestaltung List StyleStack.Typeface_Style() EndStructure ; Typeface Chunks Structure Typeface_Chunk_Characters_Character Index.u ; Zeichenindex OutlayX.w ; Ausgabe: X-Versatz (in Pixel) OutlayY.w ; Ausgabe: Y-Versatz (in Pixel) OutlayWidth.w ; Ausgabe: Breite (in Pixel) OutlayHeight.w ; Ausgabe: Höhe (in Pixel) SourceX.w ; Quelle: X-Position (in Pixel) SourceY.w ; Quelle: Y-Position (in Pixel) SourceWidth.w ; Quelle: Breite (in Pixel) SourceHeight.w ; Quelle: Höhe (in Pixel) EndStructure Structure Typeface_Chunk_Characters Type.l ; Chunktyp Count.l ; Anzahl der Zeichen Character.Typeface_Chunk_Characters_Character[0] ; Zeichendefinition EndStructure Structure Typeface_Chunk_KerningPairs_KerningPair LeftCharacter.u ; linkes Zeichen RightCharacter.u ; rechtes Zeichen Amount.w ; Verschiebung EndStructure Structure Typeface_Chunk_KerningPairs Type.l ; Chunktyp Count.l ; Anzahl der Unterscheidungspaare KerningPair.Typeface_Chunk_KerningPairs_KerningPair[0] ; Unterscheidungspaar EndStructure Structure Typeface_Chunk_Info Type.l ; Chunktyp Count.l ; Anzahl der Infos *Info[0] EndStructure Structure Typeface_Chunk Length.l ; Länge Checksum.l ; Prüfsumme StructureUnion Type.l ; Typ ChunkData.l ; Inhalt des Chunks EndStructureUnion StructureUnion ImageData.l ; Daten des Bilds InfoData.l EndStructureUnion EndStructure ; TypefaceInclude Structure TypefaceInclude List TypefaceCharacterSet.Typeface_CharacterSet() ; Liste für Zeichensätze List Typeface.Typeface() ; Liste für Typefaces Array *TypefaceID.Typeface(0) ; Array für Typeface-IDs DefaultStyle.Typeface_Style ; Standardstil EndStructure ;-> Initialization ;ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ EnableExplicit Global TypefaceInclude.TypefaceInclude With TypefaceInclude\DefaultStyle \AlignH = 0.0 \AlignV = 0.0 \Color = #Typeface_Default \Opacity = 1.0 \Rotation\A11 = 1.0 \Rotation\A22 = 1.0 \Rotation\A33 = 1.0 \Size = 1.0 \Translation\Z = -200 \EnabledRegion = #False \Kerning = #True EndWith ;-> Private Procedures ;ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ CompilerIf Defined(CRC32Fingerprint, #PB_Procedure) = #False UseCRC32Fingerprint() Procedure.l CRC32Fingerprint(*Buffer, Size.i) ProcedureReturn Val("$"+Fingerprint(*Buffer, Size, #PB_Cipher_CRC32)) EndProcedure CompilerEndIf ; Limits a value into the range. Procedure.f Typeface_Limit(*Value.Float, Min.f, Max.f) If *Value\f > Max *Value\f = Max ElseIf *Value\f < Min *Value\f = Min EndIf EndProcedure ; Creates a typeface template. Procedure.i Typeface_Create(Typeface.i, *CharacterSet.Typeface_CharacterSet=#Null) Protected *Typeface.Typeface If Typeface = #PB_Any *Typeface.Typeface = AddElement(TypefaceInclude\Typeface()) Typeface = *Typeface ElseIf Not Typeface & #TypefaceInclude_AnyNumber *Typeface.Typeface = AddElement(TypefaceInclude\Typeface()) If ArraySize(TypefaceInclude\TypefaceID()) < Typeface ReDim TypefaceInclude\TypefaceID(Typeface) ElseIf TypefaceInclude\TypefaceID(Typeface) FreeTypeface(TypefaceInclude\TypefaceID(Typeface)) EndIf TypefaceInclude\TypefaceID(Typeface) = *Typeface Else ProcedureReturn #False EndIf With *Typeface \Number = Typeface If *CharacterSet = #Null \CharacterSet = AddElement(TypefaceInclude\TypefaceCharacterSet()) CompilerIf #PB_Compiler_Unicode = #True Dim \CharacterSet\Character($FFFF) CompilerElse Dim *Typeface\CharacterSet\Character($FF) CompilerEndIf Else \CharacterSet = *CharacterSet : \CharacterSet\Copys + 1 EndIf EndWith *Typeface\Style = TypefaceInclude\DefaultStyle ProcedureReturn *Typeface EndProcedure ; Mirrors the sprite for rotations Procedure.i Typeface_Mirror(*Typeface.Typeface) Protected *Buffer, Pitch.i, *Line, Y.i, LastY.i If IsSprite(*Typeface\CharacterSet\MirroredSprite) FreeSprite(*Typeface\CharacterSet\MirroredSprite) EndIf *Typeface\CharacterSet\MirroredSprite = CopySprite(*Typeface\CharacterSet\Sprite, #PB_Any, #PB_Sprite_AlphaBlending) *Typeface\CharacterSet\MirroredSpriteHeight = SpriteHeight(*Typeface\CharacterSet\MirroredSprite) If StartDrawing(SpriteOutput(*Typeface\CharacterSet\MirroredSprite)) *Buffer = DrawingBuffer() Pitch = DrawingBufferPitch() *Line = AllocateMemory(Pitch) LastY = OutputHeight()-1 For Y = (LastY-1)/2 To 0 Step -1 CopyMemory(*Buffer+Y*Pitch, *Line, Pitch) CopyMemory(*Buffer+(LastY-Y)*Pitch, *Buffer+Y*Pitch, Pitch) CopyMemory(*Line, *Buffer+(LastY-Y)*Pitch, Pitch) Next StopDrawing() EndIf EndProcedure ; Add a kerming pair to the typeface. Procedure.i Typeface_AddKerningPair(*Typeface.Typeface, LeftCharacter.c, RightCharacter.c, Amount.i) Protected Hash.q, *CurrentKerningPair.Typeface_KerningPair CompilerIf #PB_Compiler_Unicode = #False If LeftCharacter > 255 Or RightCharacter > 255 ProcedureReturn #False EndIf CompilerEndIf AddElement(*Typeface\CharacterSet\Elements\KerningPair()) With *Typeface\CharacterSet\Elements\KerningPair() \CharacterPair = LeftCharacter<<16 | RightCharacter \Amount = Amount Hash = \CharacterPair % #TypefaceInclude_KerningSlots *CurrentKerningPair = *Typeface\CharacterSet\KerningPair(Hash) If *CurrentKerningPair While *CurrentKerningPair\NextPair *CurrentKerningPair = *CurrentKerningPair\NextPair Wend *CurrentKerningPair\NextPair = @*Typeface\CharacterSet\Elements\KerningPair() Else *Typeface\CharacterSet\KerningPair(Hash) = @*Typeface\CharacterSet\Elements\KerningPair() EndIf EndWith ProcedureReturn *Typeface\CharacterSet\Elements\KerningPair() EndProcedure ; Loads the typeface from a TF memory buffer. Procedure.i Typeface_Catch_TF(*Typeface.Typeface, *Memory.Typeface_Chunk) Protected Index.i Protected *Characters.Typeface_Chunk_Characters Protected *KerningPairs.Typeface_Chunk_KerningPairs Protected *Info.Typeface_Chunk_Info, *InfoCursor Protected Scale.f = 1.0 Protected Key.s, Value.s UsePNGImageDecoder() Repeat If CRC32Fingerprint(@*Memory\ChunkData, *Memory\Length) <> *Memory\Checksum Break EndIf Select *Memory\Type Case #TypefaceChunk_End Break Case #TypefaceChunk_Image With *Typeface\CharacterSet \Image = CatchImage(#PB_Any, @*Memory\ImageData) CompilerIf #TypefaceCompilation & #TypefaceCompilation_UBEngine CompilerIf Defined(UBE_SHADER_2D_NONE, #PB_Constant) \Material = UBE_CreateMaterial(#UBE_ANY, UBE_CatchTexture(#UBE_ANY, @*Memory\ImageData, #UBE_TEXTURE_FILTER_LINEAR), #UBE_SHADER_2D_NONE) CompilerElse \Material = UBE_CreateMaterial(#UBE_ANY, UBE_CatchTexture(#UBE_ANY, @*Memory\ImageData, #UBE_TEXTURE_FILTER_LINEAR), #UBE_SHADER_2D_DEFAULT) CompilerEndIf CompilerElse \Sprite = CatchSprite(#PB_Any, @*Memory\ImageData, #PB_Sprite_AlphaBlending) Typeface_Mirror(*Typeface) CompilerEndIf EndWith Case #TypefaceChunk_Characters *Characters = *Memory + 8 For Index = 0 To *Characters\Count-1 CompilerIf #PB_Compiler_Unicode = #False If *Characters\Character[Index]\Index > 255 Continue EndIf CompilerEndIf *Typeface\CharacterSet\Character(*Characters\Character[Index]\Index) = AddElement(*Typeface\CharacterSet\Elements\Character()) With *Typeface\CharacterSet\Elements\Character() \Index = *Characters\Character[Index]\Index \Outlay\X = *Characters\Character[Index]\OutlayX * Scale \Outlay\Y = *Characters\Character[Index]\OutlayY * Scale \Outlay\Width = *Characters\Character[Index]\OutlayWidth * Scale \Outlay\Height = *Characters\Character[Index]\OutlayHeight * Scale \Source\X = *Characters\Character[Index]\SourceX * Scale \Source\Y = *Characters\Character[Index]\SourceY * Scale \Source\Width = *Characters\Character[Index]\SourceWidth * Scale \Source\Height = *Characters\Character[Index]\SourceHeight * Scale If *Typeface\CharacterSet\MaxCharacterHeight < \Outlay\Height *Typeface\CharacterSet\MaxCharacterHeight = \Outlay\Height EndIf EndWith Next Case #TypefaceChunk_KerningPairs *KerningPairs = *Memory + 8 For Index = 0 To *KerningPairs\Count-1 With *KerningPairs\KerningPair[Index] Typeface_AddKerningPair(*Typeface, \LeftCharacter, \RightCharacter, \Amount*Scale) EndWith Next Case #TypefaceChunk_Info *Info = *Memory + 8 *InfoCursor = *Info + SizeOf(Typeface_Chunk_Info) For Index = 0 To *Info\Count-1 Key = PeekS(*InfoCursor, #PB_Default, #PB_UTF8) : *InfoCursor + MemoryStringLength(*InfoCursor, #PB_UTF8) + 1 Value = PeekS(*InfoCursor, #PB_Default, #PB_UTF8) : *InfoCursor + MemoryStringLength(*InfoCursor, #PB_UTF8) + 1 *Typeface\CharacterSet\Info(Key) = Value Next EndSelect *Memory + 8 + *Memory\Length ForEver ProcedureReturn *Typeface EndProcedure ; Loads the typeface from a XML file. Procedure.i Typeface_Load_XML(*Typeface.Typeface, XML, Path.s) Protected *MainNode, *Node, Index.i, *SourceNode, *OutlayNode Protected X.i, Y.i, LastX.i, Pixel.i Protected Scale.f = 1.0 *MainNode = MainXMLNode(XML) With *Typeface\CharacterSet If GetXMLAttribute(*MainNode, "Image") \Image = LoadImage(#PB_Any, Path+GetXMLAttribute(*MainNode, "Image")) CompilerIf #TypefaceCompilation & #TypefaceCompilation_UBEngine CompilerIf Defined(UBE_SHADER_2D_NONE, #PB_Constant) \Material = UBE_CreateMaterial(#UBE_ANY, UBE_LoadTextureFile(#UBE_ANY, Path+GetXMLAttribute(*MainNode, "Image")), #UBE_SHADER_2D_NONE) CompilerElse \Material = UBE_CreateMaterial(#UBE_ANY, UBE_LoadTextureFile(#UBE_ANY, Path+GetXMLAttribute(*MainNode, "Image")), #UBE_SHADER_2D_DEFAULT) CompilerEndIf CompilerElse \Sprite = LoadSprite(#PB_Any, Path+GetXMLAttribute(*MainNode, "Image"), #PB_Sprite_AlphaBlending) Typeface_Mirror(*Typeface) CompilerEndIf EndIf EndWith *Node = ChildXMLNode(*MainNode) While *Node If XMLNodeType(*Node) = #PB_XML_Normal Select GetXMLNodeName(*Node) Case "Attribute" *Typeface\CharacterSet\Info(GetXMLAttribute(*Node, "Name")) = GetXMLNodeText(*Node) Case "KerningPair" Typeface_AddKerningPair(*Typeface, Val(GetXMLAttribute(*Node, "Left")), Val(GetXMLAttribute(*Node, "Right")), Val(GetXMLAttribute(*Node, "Amount"))*Scale) Case "Character" Index = Val(GetXMLAttribute(*Node, "Index")) If Index <= 255 Or #PB_Compiler_Unicode *SourceNode = XMLNodeFromPath(*Node, "Source") *OutlayNode = XMLNodeFromPath(*Node, "Outlay") *Typeface\CharacterSet\Character(Index) = AddElement(*Typeface\CharacterSet\Elements\Character()) With *Typeface\CharacterSet\Elements\Character() \Index = Index \Source\X = Val(GetXMLAttribute(*SourceNode, "X")) * Scale \Source\Y = Val(GetXMLAttribute(*SourceNode, "Y")) * Scale \Source\Width = Val(GetXMLAttribute(*SourceNode, "Width")) * Scale \Source\Height = Val(GetXMLAttribute(*SourceNode, "Height")) * Scale \Outlay\X = Val(GetXMLAttribute(*OutlayNode, "X")) * Scale \Outlay\Y = Val(GetXMLAttribute(*OutlayNode, "Y")) * Scale \Outlay\Width = Val(GetXMLAttribute(*OutlayNode, "Width")) * Scale \Outlay\Height = Val(GetXMLAttribute(*OutlayNode, "Height")) * Scale If *Typeface\CharacterSet\MaxCharacterHeight < \Outlay\Height *Typeface\CharacterSet\MaxCharacterHeight = \Outlay\Height EndIf EndWith EndIf EndSelect EndIf *Node = NextXMLNode(*Node) Wend ProcedureReturn *Typeface EndProcedure ; Transforms the vertices (rotation) Procedure Typeface_TransformVertices(*Typeface.Typeface, *Vertices.Typeface_Vertices) Protected I.i, Vertex.Typeface_Vertex, *Vertex.Typeface_Vertex Protected *Rotation.Typeface_Matrix = *Typeface\Style\Rotation Protected *Translation.Typeface_Vertex = *Typeface\Style\Translation For I = 0 To 3 *Vertex = *Vertices\I[I] ; Vertex\X = *Vertex\X : Vertex\Y = *Vertex\Y : Vertex\Z = *Vertex\Z ; *Vertex\Z = Vertex\X**Rotation\A31 + Vertex\Y**Rotation\A32 + Vertex\Z**Rotation\A33 + Distance ; *Vertex\Y = ( Vertex\X**Rotation\A21 + Vertex\Y**Rotation\A22 + Vertex\Z**Rotation\A23 ) * Distance / *Vertex\Z ; *Vertex\X = ( Vertex\X**Rotation\A11 + Vertex\Y**Rotation\A12 + Vertex\Z**Rotation\A13 ) * Distance / *Vertex\Z ; Vertex\X = *Vertex\X : Vertex\Y = *Vertex\Y ; *Vertex\W = 1.0 ; *Vertex\Z = Vertex\X**Rotation\A31 + Vertex\Y**Rotation\A32 - *Translation\Z ; *Vertex\Y = ( Vertex\X**Rotation\A21 + Vertex\Y**Rotation\A22 + *Translation\Y ) * *Translation\Z / *Vertex\Z - *Translation\Y ; *Vertex\X = ( Vertex\X**Rotation\A11 + Vertex\Y**Rotation\A12 + *Translation\X ) * *Translation\Z / *Vertex\Z - *Translation\X Vertex\X = *Vertex\X : Vertex\Y = *Vertex\Y *Vertex\Z = (Vertex\X**Rotation\A31 + Vertex\Y**Rotation\A32 - *Translation\Z) *Vertex\Y = -( Vertex\X**Rotation\A21 + Vertex\Y**Rotation\A22 + *Translation\Y ) * *Translation\Z / *Vertex\Z; + *Translation\Y *Vertex\X = -( Vertex\X**Rotation\A11 + Vertex\Y**Rotation\A12 + *Translation\X ) * *Translation\Z / *Vertex\Z; + *Translation\X *Vertex\W = 1.0 Next EndProcedure ; Transforms the vertices (bending) Procedure Typeface_BendVertices(*Typeface.Typeface, *Vertices.Typeface_Vertices, X.f, Y.f) Protected I.i, Vertex.Typeface_Vertex, *Vertex.Typeface_Vertex Protected BendAngle.f Protected Sin.f, Cos.f For I = 0 To 3 *Vertex = *Vertices\I[I] BendAngle = X / (*Typeface\Style\BendRadius-Y) Vertex\X = *Vertex\X - X : Vertex\Y = *Vertex\Y - Y Cos = Cos(BendAngle) Sin = Sin(BendAngle) *Vertex\X = Vertex\X*Cos - Vertex\Y*Sin + *Typeface\Style\BendRadius*Sin *Vertex\Y = Vertex\X*Sin + Vertex\Y*Cos - *Typeface\Style\BendRadius*(Cos-1) Next EndProcedure ; Returns the amount of kerning. Procedure.i Typeface_KerningAmount(*Typeface.Typeface, CharacterPair.q) Protected Hash.i = CharacterPair % #TypefaceInclude_KerningSlots Protected *KerningPair.Typeface_KerningPair = *Typeface\CharacterSet\KerningPair(Hash) While *KerningPair If *KerningPair\CharacterPair = CharacterPair ProcedureReturn *KerningPair\Amount EndIf *KerningPair = *KerningPair\NextPair Wend ProcedureReturn 0 EndProcedure ; Calculates the width and height of a string part using the specified typeface and returns the number of lines. Procedure.i Typeface_Frame(*Typeface.Typeface, *Character.Typeface_CharacterArray, Size.f, *Width.Float=#Null, *Height.Float=#Null) Protected CurrentWidth.f, CharacterWidth.f, Width.f Protected I.i = 0, Length.i, *TypefaceCharacter.Typeface_Character Protected LetterSpace.i = #False, WordSpace.i = #False, LastCaracter.u If *Character = #Null Or *Character\C[0] = #NUL If *Width : *Width\f = 0 : EndIf If *Height : *Height\f = 0 : EndIf ProcedureReturn 0 EndIf Repeat *TypefaceCharacter = *Typeface\CharacterSet\Character(*Character\C[I]) If *TypefaceCharacter CharacterWidth = *TypefaceCharacter\Outlay\Width * Size If LetterSpace CharacterWidth + *Typeface\Style\LetterSpace * Size EndIf If WordSpace CharacterWidth + *Typeface\Style\WordSpace * Size WordSpace = #False EndIf LetterSpace = #True If *Typeface\Style\Kerning CharacterWidth + Typeface_KerningAmount(*Typeface, LastCaracter<<16|*Character\c[I]) * Size EndIf LastCaracter = *Character\c[I] Else CharacterWidth = 0.0 EndIf If *Typeface\Style\WordWrap > 0 And CurrentWidth + CharacterWidth > *Typeface\Style\WordWrap If Length = 0 Length = I + Bool(I=0) Width = CurrentWidth EndIf Break EndIf Select *Character\C[I] Case #NUL ; end of string Length = I Width = CurrentWidth Break Case #LF ; end of line Length = I + 1 Width = CurrentWidth Break Case ' ' ; end of word Length = I + 1 Width = CurrentWidth CurrentWidth + CharacterWidth WordSpace = #True Case '-', ',', '.', '?', '!' ; possible line break Length = I + 1 CurrentWidth + CharacterWidth Width = CurrentWidth Default CurrentWidth + CharacterWidth EndSelect I + 1 ForEver If *Width : *Width\f = Width : EndIf If *Height : *Height\f = *Typeface\CharacterSet\MaxCharacterHeight * Size : EndIf ProcedureReturn Length EndProcedure ; Saves the typface as a TF file. Procedure.i Typeface_Save_TF(*Typeface.Typeface, FileName.s) Protected File.i = CreateFile(#PB_Any, FileName) Protected *Buffer.Typeface_Chunk_Characters, Checksum.l, *ImageBuffer, Index.i, Type.l Protected *KerningPairs.Typeface_Chunk_KerningPairs Protected *Info.Typeface_Chunk_Info, InfoLength.i If Not File ProcedureReturn #False EndIf ; File Header WriteQuad(File, #TypefaceInclude_MagicNumber) ; Image If *Typeface\CharacterSet\Image *ImageBuffer = EncodeImage(*Typeface\CharacterSet\Image, #PB_ImagePlugin_PNG) *Buffer = AllocateMemory(4+MemorySize(*ImageBuffer)) PokeL(*Buffer, #TypefaceChunk_Image) CopyMemory(*ImageBuffer, *Buffer+4, MemorySize(*ImageBuffer)) WriteLong(File, MemorySize(*Buffer)) WriteLong(File, CRC32Fingerprint(*Buffer, MemorySize(*Buffer))) WriteData(File, *Buffer, MemorySize(*Buffer)) FreeMemory(*ImageBuffer) FreeMemory(*Buffer) EndIf ; Characters *Buffer = AllocateMemory(SizeOf(Typeface_Chunk_Characters)+ListSize(*Typeface\CharacterSet\Elements\Character())*SizeOf(Typeface_Chunk_Characters_Character)) *Buffer\Type = #TypefaceChunk_Characters *Buffer\Count = ListSize(*Typeface\CharacterSet\Elements\Character()) Index = 0 ForEach *Typeface\CharacterSet\Elements\Character() With *Typeface\CharacterSet\Elements\Character() *Buffer\Character[Index]\Index = \Index *Buffer\Character[Index]\SourceX = \Source\X *Buffer\Character[Index]\SourceY = \Source\Y *Buffer\Character[Index]\SourceWidth = \Source\Width *Buffer\Character[Index]\SourceHeight = \Source\Height *Buffer\Character[Index]\OutlayX = \Outlay\X *Buffer\Character[Index]\OutlayY = \Outlay\Y *Buffer\Character[Index]\OutlayWidth = \Outlay\Width *Buffer\Character[Index]\OutlayHeight = \Outlay\Height Index + 1 EndWith Next WriteLong(File, MemorySize(*Buffer)) WriteLong(File, CRC32Fingerprint(*Buffer, MemorySize(*Buffer))) WriteData(File, *Buffer, MemorySize(*Buffer)) FreeMemory(*Buffer) ; KerningPairs *KerningPairs = AllocateMemory(SizeOf(Typeface_Chunk_KerningPairs)+ListSize(*Typeface\CharacterSet\Elements\KerningPair())*SizeOf(Typeface_Chunk_KerningPairs_KerningPair)) *KerningPairs\Type = #TypefaceChunk_KerningPairs *KerningPairs\Count = ListSize(*Typeface\CharacterSet\Elements\KerningPair()) Index = 0 ForEach *Typeface\CharacterSet\Elements\KerningPair() With *Typeface\CharacterSet\Elements\KerningPair() *KerningPairs\KerningPair[Index]\LeftCharacter = \Character[1] *KerningPairs\KerningPair[Index]\RightCharacter = \Character[0] *KerningPairs\KerningPair[Index]\Amount = \Amount Index + 1 EndWith Next WriteLong(File, MemorySize(*KerningPairs)) WriteLong(File, CRC32Fingerprint(*KerningPairs, MemorySize(*KerningPairs))) WriteData(File, *KerningPairs, MemorySize(*KerningPairs)) FreeMemory(*KerningPairs) ; Info InfoLength = 0 *Info = AllocateMemory(SizeOf(Typeface_Chunk_Info)) *Info\Type = #TypefaceChunk_Info *Info\Count = MapSize(*Typeface\CharacterSet\Info()) ForEach *Typeface\CharacterSet\Info() InfoLength = StringByteLength(MapKey(*Typeface\CharacterSet\Info()), #PB_UTF8) + 1 + StringByteLength(*Typeface\CharacterSet\Info(), #PB_UTF8) + 1 *Info = ReAllocateMemory(*Info, MemorySize(*Info)+InfoLength) PokeS(*Info+MemorySize(*Info)-InfoLength, MapKey(*Typeface\CharacterSet\Info()), #PB_Default, #PB_UTF8) InfoLength - ( StringByteLength(MapKey(*Typeface\CharacterSet\Info()), #PB_UTF8) + 1 ) PokeS(*Info+MemorySize(*Info)-InfoLength, *Typeface\CharacterSet\Info(), #PB_Default, #PB_UTF8) Next WriteLong(File, MemorySize(*Info)) WriteLong(File, CRC32Fingerprint(*Info, MemorySize(*Info))) WriteData(File, *Info, MemorySize(*Info)) FreeMemory(*Info) ; End Type = #TypefaceChunk_End WriteLong(File, 4) WriteLong(File, CRC32Fingerprint(@Type, 4)) WriteLong(File, Type) CloseFile(File) ProcedureReturn #True EndProcedure ; Saves the typface as a XML file and PNG image file. Procedure.i Typeface_Save_XML(*Typeface.Typeface, FileName.s) Protected *MainNode, *Node, *SubNode Protected ImageFileName.s = FileName+".png" Protected Result.i, XML = CreateXML(#PB_Any) If Not XML ProcedureReturn #False EndIf *MainNode = CreateXMLNode(RootXMLNode(XML), "Typeface") SetXMLAttribute(*MainNode, "Version", "1.4") If *Typeface\CharacterSet\Image SetXMLAttribute(*MainNode, "Image", GetFilePart(ImageFileName)) Else SetXMLAttribute(*MainNode, "Image", "") EndIf ; Attribute ForEach *Typeface\CharacterSet\Info() *Node = CreateXMLNode(*MainNode, "Attribute") SetXMLAttribute(*Node, "Name", MapKey(*Typeface\CharacterSet\Info())) SetXMLNodeText(*Node, *Typeface\CharacterSet\Info()) Next ; Zeichen ForEach *Typeface\CharacterSet\Elements\Character() With *Typeface\CharacterSet\Elements\Character() *Node = CreateXMLNode(*MainNode, "Character") SetXMLAttribute(*Node, "Index", Str(\Index)) *SubNode = CreateXMLNode(*Node, "Source") SetXMLAttribute(*SubNode, "X", Str(\Source\X)) SetXMLAttribute(*SubNode, "Y", Str(\Source\Y)) SetXMLAttribute(*SubNode, "Width", Str(\Source\Width)) SetXMLAttribute(*SubNode, "Height", Str(\Source\Height)) *SubNode = CreateXMLNode(*Node, "Outlay") SetXMLAttribute(*SubNode, "X", Str(\Outlay\X)) SetXMLAttribute(*SubNode, "Y", Str(\Outlay\Y)) SetXMLAttribute(*SubNode, "Width", Str(\Outlay\Width)) SetXMLAttribute(*SubNode, "Height", Str(\Outlay\Height)) EndWith Next ; Unterschneidung ForEach *Typeface\CharacterSet\Elements\KerningPair() With *Typeface\CharacterSet\Elements\KerningPair() *Node = CreateXMLNode(*MainNode, "KerningPair") SetXMLAttribute(*Node, "Left", Str(\Character[1])) SetXMLAttribute(*Node, "Right", Str(\Character[0])) SetXMLAttribute(*Node, "Amount", Str(\Amount)) EndWith Next FormatXML(XML, #PB_XML_ReFormat) Result = SaveXML(XML, FileName) FreeXML(XML) If Result If *Typeface\CharacterSet\Image If SaveImage(*Typeface\CharacterSet\Image, ImageFileName, #PB_ImagePlugin_PNG) ProcedureReturn #True EndIf Else ProcedureReturn #True EndIf EndIf EndProcedure ;-> Public Procedures: Management ;ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ ; Creates a copy of the source typeface as a new typeface. ; SourceTypeface : A valid identifier of the source typeface ; Typeface : A number as an identifier of the new typeface or #PB_Any to assign the address itself as the identifier ; ProcedureReturn : Address of the new typeface Procedure.i CopyTypeface(SourceTypeface.i, Typeface.i) Protected *SourceTypeface.Typeface = TypefaceID(SourceTypeface) Protected *Typeface.Typeface = Typeface_Create(Typeface, *SourceTypeface\CharacterSet) *SourceTypeface\Style = *Typeface\Style ProcedureReturn *Typeface EndProcedure ; Releases the typeface and its resources. ; Typeface : A valid identifier of the typeface or #PB_All to release all available typefaces. ; ProcedureReturn : - Procedure FreeTypeface(Typeface.i) Protected *Typeface.Typeface With *Typeface If Typeface = #PB_All ForEach TypefaceInclude\Typeface() FreeTypeface(TypefaceInclude\Typeface()) Next Else *Typeface.Typeface = TypefaceID(Typeface) If Not \Number & #TypefaceInclude_AnyNumber TypefaceInclude\TypefaceID(\Number) = #Null EndIf If \CharacterSet\Copys \CharacterSet\Copys - 1 Else CompilerIf #TypefaceCompilation & #TypefaceCompilation_UBEngine If UBE_IsMaterial(\CharacterSet\Material) UBE_FreeMaterial(\CharacterSet\Material) EndIf CompilerElse If IsSprite(\CharacterSet\Sprite) FreeSprite(\CharacterSet\Sprite) EndIf If IsSprite(\CharacterSet\MirroredSprite) FreeSprite(\CharacterSet\MirroredSprite) EndIf CompilerEndIf If IsImage(\CharacterSet\Image) FreeImage(\CharacterSet\Image) EndIf ChangeCurrentElement(TypefaceInclude\TypefaceCharacterSet(), \CharacterSet) DeleteElement(TypefaceInclude\TypefaceCharacterSet()) EndIf ChangeCurrentElement(TypefaceInclude\Typeface(), *Typeface) DeleteElement(TypefaceInclude\Typeface()) EndIf EndWith EndProcedure ; Checks whether the typeface exists. ; Typeface : Any Identifier ; ProcedureReturn : #False, if the identifier is invalid, otherwise the address of the found typeface Procedure.i IsTypeface(Typeface.i) ForEach TypefaceInclude\Typeface() If TypefaceInclude\Typeface()\Number = Typeface Or @TypefaceInclude\Typeface() = Typeface ProcedureReturn @TypefaceInclude\Typeface() EndIf Next EndProcedure ; Loads a typeface from a file. ; Typeface : A number as an identifier of the typeface or #PB_Any to assign the address itself as the identifier ; FileName : The file name of the typeface file ; ProcedureReturn : #False, if the loading fails, otherwise the address of the loaded typeface Procedure.i LoadTypeface(Typeface.i, FileName.s) Protected XML.i, File.i, *FileBuffer, *Typeface File = ReadFile(#PB_Any, FileName) If File If ReadQuad(File) = #TypefaceInclude_MagicNumber *FileBuffer = AllocateMemory(Lof(File)-8) ReadData(File, *FileBuffer, Lof(File)-8) *Typeface = Typeface_Catch_TF(Typeface_Create(Typeface), *FileBuffer) FreeMemory(*FileBuffer) CloseFile(File) ProcedureReturn *Typeface EndIf CloseFile(File) EndIf XML = LoadXML(#PB_Any, FileName) If XML If XMLStatus(XML) = #PB_XML_Success *Typeface = Typeface_Load_XML(Typeface_Create(Typeface), XML, GetPathPart(FileName)) EndIf FreeXML(XML) EndIf ProcedureReturn *Typeface EndProcedure ; Returns the address of the typeface. ; Typeface : A valid identifier of the typeface ; ProcedureReturn : Address of the typeface Procedure.i TypefaceID(Typeface.i) If Typeface & #TypefaceInclude_AnyNumber ProcedureReturn Typeface Else ProcedureReturn TypefaceInclude\TypefaceID(Typeface) EndIf EndProcedure ; Loads a typeface from the memory address. (only TF format is supported) ; Typeface : A number as an identifier of the typeface or #PB_Any to assign the address itself as the identifier ; *Memory : The address of the memory buffer ; ProcedureReturn : #False, if the loading fails, otherwise the address of the loaded typeface Procedure.i CatchTypeface(Typeface.i, *Memory) If PeekQ(*Memory) = #TypefaceInclude_MagicNumber ProcedureReturn Typeface_Catch_TF(Typeface_Create(Typeface), *Memory+8) EndIf EndProcedure ; Saves the typeface into a file. ; Typeface : A valid identifier of the typeface ; FileName : Name of the file ; Format : Format of the file data. #Typeface_Format_TF for own binary format or #Typeface_Format_XML for a XML file and a PNG image file ; ProcedureReturn : #False, if the saving fails, otherwise #True Procedure.i SaveTypeface(Typeface.i, FileName.s, Format.i=#Typeface_Format_TF) Protected *Typeface.Typeface = TypefaceID(Typeface) Select Format Case #Typeface_Format_TF ProcedureReturn Typeface_Save_TF(*Typeface, FileName) Case #Typeface_Format_XML ProcedureReturn Typeface_Save_XML(*Typeface, FileName) EndSelect EndProcedure ;-> Public Procedures: Styling ;ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ ; Pops all style settings of the typeface from the stack. ; Typeface : A valid identifier of the typeface ; ProcedureReturn : - Procedure PopTypefaceStyles(Typeface.i) Protected *Typeface.Typeface = TypefaceID(Typeface) LastElement(*Typeface\StyleStack()) *Typeface\Style = *Typeface\StyleStack() DeleteElement(*Typeface\StyleStack()) EndProcedure ; Pushes all style settings of the typeface on the stack. ; Typeface : A valid identifier of the typeface ; ProcedureReturn : - Procedure PushTypefaceStyles(Typeface.i) Protected *Typeface.Typeface = TypefaceID(Typeface) LastElement(*Typeface\StyleStack()) AddElement(*Typeface\StyleStack()) *Typeface\StyleStack() = *Typeface\Style EndProcedure ; Resets all style setting of the typeface to default. ; Typeface : A valid identifier of the typeface ; ProcedureReturn : - Procedure ResetTypefaceStyles(Typeface.i) Protected *Typeface.Typeface = TypefaceID(Typeface) *Typeface\Style = TypefaceInclude\DefaultStyle EndProcedure ; Changes the alignment of the typeface. ; Typeface : A valid identifier of the typeface ; AlignmentH : Horizontal alignment between 0.0 (left justified) over 0.5 (centered) and 1.0 (right justified) or #Typeface_Ignore to ignore this parameter ; AlignmentV : Vertical alignment between 0.0 (top aligned) over 0.5 (centered) and 1.0 (bottom aligned) or #Typeface_Ignore to ignore this parameter ; ProcedureReturn : - Procedure TypefaceAlignment(Typeface.i, AlignmentH.f=#Typeface_Ignore, AlignmentV.f=#Typeface_Ignore) Protected *Typeface.Typeface = TypefaceID(Typeface) If AlignmentH <> #Typeface_Ignore *Typeface\Style\AlignH = AlignmentH EndIf If AlignmentV <> #Typeface_Ignore *Typeface\Style\AlignV = AlignmentV EndIf EndProcedure ; Changes the bend radius of the typeface. ; Typeface : A valid identifier of the typeface ; BendRadius : Bend radius (in pixel) or 0.0 for no bending. The Bending is clockwise for positive radii and anti-clockwise for negative radii. ; ProcedureReturn : - Procedure TypefaceBendRadius(Typeface.i, BendRadius.f=0.0) Protected *Typeface.Typeface = TypefaceID(Typeface) *Typeface\Style\BendRadius = BendRadius EndProcedure ; Changes the displayed clipping region of the typeface. ; Typeface : A valid identifier of the typeface ; State : State of the clipping: #True (enable) or #False (disable) ; X, Y : Left-top position of the clipped region ; Width, Height : Size of the clipped region. ; ProcedureReturn : - Procedure TypefaceClipping(Typeface.i, State.i, X.f=0.0, Y.f=0.0, Width.f=0.0, Height.f=0.0) Protected *Typeface.Typeface = TypefaceID(Typeface) If State = #False *Typeface\Style\EnabledRegion = #False Else *Typeface\Style\EnabledRegion = #True *Typeface\Style\Region\X = X *Typeface\Style\Region\Y = Y *Typeface\Style\Region\Width = Width *Typeface\Style\Region\Height = Height EndIf EndProcedure ; Changes the color of the typeface. ; Typeface : A valid identifier of the typeface ; Color : 24 bit RGB or 32 bit RGBA color or #Typeface_Default to prevent the colorizing ; ProcedureReturn : - Procedure TypefaceColor(Typeface.i, Color.q=#Typeface_Default) Protected *Typeface.Typeface = TypefaceID(Typeface) *Typeface\Style\Color = Color EndProcedure ; Change the angle of italic strength of the typeface. ; Typeface : A valid identifier of the typeface ; Angle : Inclination angle (in degree) of the characters ; ProcedureReturn : - Procedure TypefaceItalic(Typeface.i, InclinationAngle.f=0.0) Protected *Typeface.Typeface = TypefaceID(Typeface) *Typeface\Style\Italic = InclinationAngle EndProcedure ; Changes the kerning of the typeface. ; State : State of the kerning: #True (enable) or #False (disable) ; ProcedureReturn : - Procedure TypefaceKerning(Typeface.i, State.i=#True) Protected *Typeface.Typeface = TypefaceID(Typeface) If State And ListSize(*Typeface\CharacterSet\Elements\KerningPair()) *Typeface\Style\Kerning = #True Else *Typeface\Style\Kerning = #False EndIf EndProcedure ; Changes the opacity of the typeface. ; Typeface : A valid identifier of the typeface ; Opacity : Opacity of the displayed text between 0.0 (transparent) and 1.0 (opaque) ; ProcedureReturn : - Procedure TypefaceOpacity(Typeface.i, Opacity.f=1.0) Protected *Typeface.Typeface = TypefaceID(Typeface) *Typeface\Style\Opacity = Opacity EndProcedure ; Changes the origin of display and rotation of the typeface. ; Typeface : A valid identifier of the typeface ; X.f, Y.f, Z.f : Position (in pixel) of the origin of display and rotation ; ProcedureReturn : - Procedure TypefaceOrigin(Typeface.i, X.f=0, Y.f=0, Z.f=#Typeface_Ignore) Protected *Typeface.Typeface = TypefaceID(Typeface) *Typeface\Style\Translation\X = X *Typeface\Style\Translation\Y = Y If Z <> #Typeface_Ignore If Z = #Typeface_Default *Typeface\Style\Translation\Z = TypefaceInclude\DefaultStyle\Translation\Z Else *Typeface\Style\Translation\Z = Z EndIf EndIf EndProcedure ; Changes the rotation of the typeface. ; Typeface : A valid identifier of the typeface ; AxisZ : Angle (in degree) of the rotation around the Z-axis ; AxisY : Angle (in degree) of the rotation around the Y-axis ; AxisX : Angle (in degree) of the rotation around the X-axis ; ProcedureReturn : - Procedure TypefaceRotation(Typeface.i, AxisZ.f, AxisY.f=0.0, AxisX.f=0.0) Protected *Typeface.Typeface = TypefaceID(Typeface) Protected CosZ.f = Cos(Radian(AxisZ)), CosY.f = Cos(Radian(AxisY)), CosX.f = Cos(Radian(AxisX)) Protected SinZ.f = Sin(Radian(AxisZ)), SinY.f = Sin(Radian(AxisY)), SinX.f = Sin(Radian(AxisX)) With *Typeface\Style\Rotation \A11 = CosY*CosZ : \A12 = -CosY*SinZ : \A13 = SinY \A21 = SinX*SinY*CosZ+CosX*SinZ : \A22 = -SinX*SinY*SinZ+CosX*CosZ : \A23 = -SinX*CosY \A31 = -CosX*SinY*CosZ+SinX*SinZ : \A32 = CosX*SinY*SinZ+SinX*CosZ : \A33 = CosX*CosY EndWith EndProcedure ; Changes the size of the typeface. ; Typeface : A valid identifier of the typeface ; Size : Size in pixel or relative to the original size, depending on the Mode parameter ; Mode : Mode of the Size parameter: #PB_Absolute (size in pixel) or #PB_Relative (relative size) ; ProcedureReturn : - Procedure TypefaceSize(Typeface.i, Size.f=1.0, Mode.i=#PB_Relative) Protected *Typeface.Typeface = TypefaceID(Typeface) Select Mode Case #PB_Absolute *Typeface\Style\Size = Size / *Typeface\CharacterSet\MaxCharacterHeight Case #PB_Relative *Typeface\Style\Size = Size EndSelect EndProcedure ; Change the (additional) letter and word spacing of the typeface. ; Typeface : A valid identifier of the typeface ; LetterSpacing : Additional spacing (in pixel) between each character or #Typeface_Ignore to ignore this parameter ; WordSpacing : Additional spacing (in pixel) after each space-character or #Typeface_Ignore to ignore this parameter ; ProcedureReturn : - Procedure TypefaceSpacing(Typeface.i, LetterSpacing.f=#Typeface_Ignore, WordSpacing.f=#Typeface_Ignore) Protected *Typeface.Typeface = TypefaceID(Typeface) If LetterSpacing <> #Typeface_Ignore *Typeface\Style\LetterSpace = LetterSpacing EndIf If WordSpacing <> #Typeface_Ignore *Typeface\Style\WordSpace = WordSpacing EndIf EndProcedure ; Changes the maximum width of the typeface to force a line break. ; Typeface : A valid identifier of the typeface ; Width : Maximum width, or 0.0 to disabled this effect ; ProcedureReturn : - Procedure TypefaceWordWrap(Typeface.i, Width.f=0.0) Protected *Typeface.Typeface = TypefaceID(Typeface) *Typeface\Style\WordWrap = Width EndProcedure ; Changes the accent color of the typeface. (no official support!) ; Typeface : A valid identifier of the typeface ; Color : 24 bit RGB or 32 bit RGBA color or #Typeface_Default to prevent the colorizing ; Character : Start and end character to determine the accent section ; ProcedureReturn : - Procedure TypefaceAccent(Typeface.i, Color.i, Character.u=#ESC) Protected *Typeface.Typeface = TypefaceID(Typeface) *Typeface\Style\AccentColor = Color *Typeface\Style\AccentCharacter = Character EndProcedure ;-> Public Procedures: Display ;ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ ; Calculates the width and height of the text using the specified typeface. This function does not consider bending or rotation! ; Typeface : A valid identifier of the typeface ; *StringCharacters : Address of the null terminated string. ; *Width : Destination address of the calculated width of the text ; *Height : Destination address of the calculated height of the text ; Size : Relative size of the original typeface ; ProcedureReturn : Number of lines of the text Procedure.i TypefaceDimension(Typeface.i, *StringCharacters.Typeface_CharacterArray, *Width.Float=#Null, *Height.Float=#Null, Size.f=#Typeface_Ignore) Protected *Typeface.Typeface = TypefaceID(Typeface) Protected Width.f, MaxWidth.f, Height.f, MaxHeight.f Protected I.i, Length.i, Lines.i If Size = #Typeface_Ignore : Size = *Typeface\Style\Size : EndIf If *StringCharacters = #Null If *Width <> #Null : *Width\f = 0 : EndIf If *Height <> #Null : *Height\f = 0 : EndIf ProcedureReturn #False EndIf Repeat Length = Typeface_Frame(*Typeface, @*StringCharacters\C[I], Size, @Width, @Height) If Length = 0 Break EndIf If Width > MaxWidth : MaxWidth = Width : EndIf MaxHeight + Height I + Length Lines + 1 ForEver If *Width <> #Null : *Width\f = MaxWidth : EndIf If *Height <> #Null : *Height\f = MaxHeight : EndIf ProcedureReturn Lines EndProcedure ; Returns the width of the text using the specified typeface. This function does not consider bending or rotation! ; Typeface : A valid identifier of the typeface ; Text : Any string ; Size : Relative size of the original typeface ; ProcedureReturn : Width (in pixel) of the text Procedure.f TypefaceWidth(Typeface.i, Text.s, Size.f=#Typeface_Ignore) Protected Width.f TypefaceDimension(Typeface, @Text, @Width, #Null, Size) ProcedureReturn Width EndProcedure ; Returns the height of the text using the specified typeface. This function does not consider bending or rotation! ; Typeface : A valid identifier of the typeface ; Text : Any string ; Size : Relative size of the original typeface ; ProcedureReturn : Height (in pixel) of the text Procedure.f TypefaceHeight(Typeface.i, Text.s, Size.f=#Typeface_Ignore) Protected Height.f TypefaceDimension(Typeface, @Text, #Null, @Height, Size) ProcedureReturn Height EndProcedure ; Displays text using the specified typeface on the screen. ; Typeface : A valid identifier of the typeface ; X, Y : Position (in pixel) of the display ; Text : Any string ; Opacity : Optional opacity of the displayed text between 0.0 (transparent) and 1.0 (opaque) or #Typeface_Ignore to ignore this parameter ; Color : 24 bit RGB or 32 bit RGBA color, #Typeface_Default to prevent the colorizing or #Typeface_Ignore to ignore this parameter ; Size : Size relative to the original size or #Typeface_Ignore to ignore this parameter ; Italic : Inclination angle (in degree) of the characters or #Typeface_Ignore to ignore this parameter Procedure DisplayTypeface(Typeface.i, X.f, Y.f, Text.s, Opacity.f=#Typeface_Ignore, Color.q=#Typeface_Ignore, Size.f=#Typeface_Ignore, Italic.f=#Typeface_Ignore) Protected *Typeface.Typeface = TypefaceID(Typeface) Protected *Character.Typeface_CharacterArray = @Text Protected CurrentCharacter.i CompilerIf #TypefaceCompilation & #TypefaceCompilation_UBEngine Protected m4fMatrix.UBE_MATRIX4f If Not *Character Or *Typeface\CharacterSet\Material = #Null : ProcedureReturn #False : EndIf CompilerElse Protected Sprite = *Typeface\CharacterSet\Sprite Protected MirroredSprite = *Typeface\CharacterSet\MirroredSprite Protected MirroredSpriteHeight = *Typeface\CharacterSet\MirroredSpriteHeight If *Character = #Null Or Sprite = #Null : ProcedureReturn #False : EndIf CompilerEndIf Protected *TypefaceCharacter.Typeface_Character Protected Index.i, LastIndex.i = Len(Text)-1, Length.i, Height.f, Width.f, LineWidth.f, SetWidth.f, SetHeight.f Protected Vertices.Typeface_Vertices Protected Corner.Typeface_Vertex Protected CurrentCorner.Typeface_Vertex Protected Clipping.Typeface_Region Protected Value.f, AccentColor.q ; Styles With *Typeface\Style If Opacity = #Typeface_Ignore : Opacity = \Opacity : EndIf If Color = #Typeface_Ignore : Color = \Color : EndIf If Size = #Typeface_Ignore : Size = \Size : EndIf If Italic = #Typeface_Ignore : Italic = \Italic : EndIf If Color & $FF000000 Opacity = Opacity * Alpha(Color) Else Opacity = Opacity * 255 EndIf AccentColor = \AccentColor Italic = Tan(Radian(Italic)) If \AlignH <> 0.0 Or \AlignV <> 0.0 TypefaceDimension(Typeface, *Character, @Width, @Height, Size) Corner\X = Round(-\AlignH*Width, #PB_Round_Nearest) Corner\Y = Round(-\AlignV*Height, #PB_Round_Nearest) Corner\X = -\AlignH*Width Corner\Y = -\AlignV*Height EndIf EndWith CompilerIf #TypefaceCompilation & #TypefaceCompilation_UBEngine SetWidth = 1.0 / *Typeface\CharacterSet\Material\pTexture[0]\lWidth SetHeight = 1.0 / *Typeface\CharacterSet\Material\pTexture[0]\lHeight *Typeface\CharacterSet\Material\v4fColor\R = Red(Color)/255.0 *Typeface\CharacterSet\Material\v4fColor\G = Green(Color)/255.0 *Typeface\CharacterSet\Material\v4fColor\B = Blue(Color)/255.0 *Typeface\CharacterSet\Material\v4fColor\A = Opacity/255.0 CompilerIf Defined(UBE_m4fFromPosition, #PB_Procedure) UBE_m4fFromPosition(m4fMatrix, X, Y, 0) CompilerElse UBE_m4fSet(m4fMatrix, X, Y, 0, 0, 0, 0, 1, 1, 1) CompilerEndIf UBE_Bind2dShader(*Typeface\CharacterSet\Material, m4fMatrix) glBindVertexArray(UBE\FontManager\glVAO) glBindBuffer(#GL_ARRAY_BUFFER, UBE\FontManager\glVBO) CompilerEndIf CurrentCorner\Y = Corner\Y Repeat Length = Typeface_Frame(*Typeface, @*Character\C[Index], Size, @LineWidth, @Height) CurrentCorner\X = Corner\X + Round(*Typeface\Style\AlignH*(Width-LineWidth), #PB_Round_Nearest) If Length = 0 Index + 1 Else While Length>0 If *Character\c[Index] = *Typeface\Style\AccentCharacter : Swap Color, AccentColor : EndIf *TypefaceCharacter = *Typeface\CharacterSet\Character(*Character\c[Index]) If *TypefaceCharacter With *TypefaceCharacter ; Vertices CompilerIf #TypefaceCompilation & #TypefaceCompilation_UBEngine UBE\FontManager\aVertex(CurrentCharacter*4+0)\v4fPosition\X = CurrentCorner\X + (\Outlay\X+(\Outlay\Height-\Outlay\Y)*Italic*0.5)*Size UBE\FontManager\aVertex(CurrentCharacter*4+0)\v4fPosition\Y = CurrentCorner\Y + \Outlay\Y*Size UBE\FontManager\aVertex(CurrentCharacter*4+1)\v4fPosition\X = UBE\FontManager\aVertex(CurrentCharacter*4+0)\v4fPosition\X + \Source\Width*Size UBE\FontManager\aVertex(CurrentCharacter*4+1)\v4fPosition\Y = UBE\FontManager\aVertex(CurrentCharacter*4+0)\v4fPosition\Y UBE\FontManager\aVertex(CurrentCharacter*4+2)\v4fPosition\X = UBE\FontManager\aVertex(CurrentCharacter*4+1)\v4fPosition\X - \Source\Height*Italic*Size UBE\FontManager\aVertex(CurrentCharacter*4+2)\v4fPosition\Y = UBE\FontManager\aVertex(CurrentCharacter*4+1)\v4fPosition\Y + \Source\Height*Size UBE\FontManager\aVertex(CurrentCharacter*4+3)\v4fPosition\X = UBE\FontManager\aVertex(CurrentCharacter*4+0)\v4fPosition\X - \Source\Height*Italic*Size UBE\FontManager\aVertex(CurrentCharacter*4+3)\v4fPosition\Y = UBE\FontManager\aVertex(CurrentCharacter*4+2)\v4fPosition\Y If *Typeface\Style\BendRadius Typeface_BendVertices(*Typeface, @UBE\FontManager\aVertex(CurrentCharacter*4), CurrentCorner\X+\Outlay\Width*0.5*Size, CurrentCorner\Y+(\Outlay\Height**Typeface\Style\AlignV)*Size) EndIf Typeface_TransformVertices(*Typeface, @UBE\FontManager\aVertex(CurrentCharacter*4)) CompilerElse Vertices\I[0]\X = CurrentCorner\X + (\Outlay\X+(\Outlay\Height-\Outlay\Y)*Italic*0.5)*Size Vertices\I[0]\Y = CurrentCorner\Y + \Outlay\Y*Size Vertices\I[1]\X = Vertices\I[0]\X + \Source\Width*Size Vertices\I[1]\Y = Vertices\I[0]\Y Vertices\I[2]\X = Vertices\I[1]\X - \Source\Height*Italic*Size Vertices\I[2]\Y = Vertices\I[1]\Y + \Source\Height*Size Vertices\I[3]\X = Vertices\I[0]\X - \Source\Height*Italic*Size Vertices\I[3]\Y = Vertices\I[2]\Y If *Typeface\Style\BendRadius Typeface_BendVertices(*Typeface, Vertices, CurrentCorner\X+\Outlay\Width*0.5*Size, CurrentCorner\Y+(\Outlay\Height**Typeface\Style\AlignV)*Size) EndIf Typeface_TransformVertices(*Typeface, Vertices) CompilerEndIf If *Typeface\Style\Rotation\A33 < 0 ;(Vertices\I[1]\X-Vertices\I[0]\X)*(Vertices\I[3]\Y-Vertices\I[0]\Y) - (Vertices\I[1]\Y-Vertices\I[0]\Y)*(Vertices\I[3]\X-Vertices\I[0]\X) < 0 CompilerIf #TypefaceCompilation & #TypefaceCompilation_UBEngine UBE\FontManager\aVertex(CurrentCharacter*4+1)\v2fTexCoord\U = \Source\X*SetWidth UBE\FontManager\aVertex(CurrentCharacter*4+1)\v2fTexCoord\V = \Source\Y*SetHeight UBE\FontManager\aVertex(CurrentCharacter*4+0)\v2fTexCoord\U = (\Source\X+\Source\Width)*SetWidth UBE\FontManager\aVertex(CurrentCharacter*4+0)\v2fTexCoord\V = \Source\Y*SetHeight UBE\FontManager\aVertex(CurrentCharacter*4+3)\v2fTexCoord\U = (\Source\X+\Source\Width)*SetWidth UBE\FontManager\aVertex(CurrentCharacter*4+3)\v2fTexCoord\V = (\Source\Y+\Source\Height)*SetHeight UBE\FontManager\aVertex(CurrentCharacter*4+2)\v2fTexCoord\U = \Source\X*SetWidth UBE\FontManager\aVertex(CurrentCharacter*4+2)\v2fTexCoord\V = (\Source\Y+\Source\Height)*SetHeight CompilerElse ClipSprite(MirroredSprite, \Source\X, MirroredSpriteHeight-\Source\Y-\Source\Height, \Source\Width, \Source\Height) TransformSprite(MirroredSprite, X+Vertices\I[3]\X, Y+Vertices\I[3]\Y, Vertices\I[3]\Z, X+Vertices\I[2]\X, Y+Vertices\I[2]\Y, Vertices\I[2]\Z, X+Vertices\I[1]\X, Y+Vertices\I[1]\Y, Vertices\I[1]\Z, X+Vertices\I[0]\X, Y+Vertices\I[0]\Y, Vertices\I[0]\Z) If Color = #Typeface_Default DisplayTransparentSprite(MirroredSprite, 0, 0, Opacity) Else DisplayTransparentSprite(MirroredSprite, 0, 0, Opacity, Color & $FFFFFF) EndIf CompilerEndIf Else CompilerIf #TypefaceCompilation & #TypefaceCompilation_UBEngine UBE\FontManager\aVertex(CurrentCharacter*4+0)\v2fTexCoord\U = \Source\X*SetWidth UBE\FontManager\aVertex(CurrentCharacter*4+0)\v2fTexCoord\V = \Source\Y*SetHeight UBE\FontManager\aVertex(CurrentCharacter*4+1)\v2fTexCoord\U = (\Source\X+\Source\Width)*SetWidth UBE\FontManager\aVertex(CurrentCharacter*4+1)\v2fTexCoord\V = \Source\Y*SetHeight UBE\FontManager\aVertex(CurrentCharacter*4+2)\v2fTexCoord\U = (\Source\X+\Source\Width)*SetWidth UBE\FontManager\aVertex(CurrentCharacter*4+2)\v2fTexCoord\V = (\Source\Y+\Source\Height)*SetHeight UBE\FontManager\aVertex(CurrentCharacter*4+3)\v2fTexCoord\U = \Source\X*SetWidth UBE\FontManager\aVertex(CurrentCharacter*4+3)\v2fTexCoord\V = (\Source\Y+\Source\Height)*SetHeight If *Typeface\Style\EnabledRegion ; -X If X+UBE\FontManager\aVertex(CurrentCharacter*4+0)\v4fPosition\X < *Typeface\Style\Region\X Value = (*Typeface\Style\Region\X-UBE\FontManager\aVertex(CurrentCharacter*4+0)\v4fPosition\X-X)/Size*SetWidth UBE\FontManager\aVertex(CurrentCharacter*4+0)\v2fTexCoord\U + Value UBE\FontManager\aVertex(CurrentCharacter*4+3)\v2fTexCoord\U + Value UBE\FontManager\aVertex(CurrentCharacter*4+0)\v4fPosition\X = *Typeface\Style\Region\X - X UBE\FontManager\aVertex(CurrentCharacter*4+3)\v4fPosition\X = *Typeface\Style\Region\X - X EndIf ; +X If X+UBE\FontManager\aVertex(CurrentCharacter*4+1)\v4fPosition\X > *Typeface\Style\Region\X+*Typeface\Style\Region\Width Value = (UBE\FontManager\aVertex(CurrentCharacter*4+1)\v4fPosition\X+X-*Typeface\Style\Region\X-*Typeface\Style\Region\Width)/Size*SetWidth UBE\FontManager\aVertex(CurrentCharacter*4+1)\v2fTexCoord\U - Value UBE\FontManager\aVertex(CurrentCharacter*4+2)\v2fTexCoord\U - Value UBE\FontManager\aVertex(CurrentCharacter*4+1)\v4fPosition\X = *Typeface\Style\Region\X+*Typeface\Style\Region\Width - X UBE\FontManager\aVertex(CurrentCharacter*4+2)\v4fPosition\X = *Typeface\Style\Region\X+*Typeface\Style\Region\Width - X EndIf Typeface_Limit(@UBE\FontManager\aVertex(CurrentCharacter*4+1)\v4fPosition\X, UBE\FontManager\aVertex(CurrentCharacter*4+0)\v4fPosition\X, 1e100) Typeface_Limit(@UBE\FontManager\aVertex(CurrentCharacter*4+2)\v4fPosition\X, UBE\FontManager\aVertex(CurrentCharacter*4+0)\v4fPosition\X, 1e100) ; -Y If Y+UBE\FontManager\aVertex(CurrentCharacter*4+0)\v4fPosition\Y < *Typeface\Style\Region\Y Value = (*Typeface\Style\Region\Y-UBE\FontManager\aVertex(CurrentCharacter*4+0)\v4fPosition\Y-Y)/Size*SetHeight UBE\FontManager\aVertex(CurrentCharacter*4+0)\v2fTexCoord\V + Value UBE\FontManager\aVertex(CurrentCharacter*4+1)\v2fTexCoord\V + Value UBE\FontManager\aVertex(CurrentCharacter*4+0)\v4fPosition\Y = *Typeface\Style\Region\Y - Y UBE\FontManager\aVertex(CurrentCharacter*4+1)\v4fPosition\Y = *Typeface\Style\Region\Y - Y EndIf ; +Y If Y+UBE\FontManager\aVertex(CurrentCharacter*4+2)\v4fPosition\Y > *Typeface\Style\Region\Y+*Typeface\Style\Region\Height Value = (UBE\FontManager\aVertex(CurrentCharacter*4+2)\v4fPosition\Y+Y-*Typeface\Style\Region\Y-*Typeface\Style\Region\Height)/Size*SetHeight UBE\FontManager\aVertex(CurrentCharacter*4+2)\v2fTexCoord\V - Value UBE\FontManager\aVertex(CurrentCharacter*4+3)\v2fTexCoord\V - Value UBE\FontManager\aVertex(CurrentCharacter*4+2)\v4fPosition\Y = *Typeface\Style\Region\Y+*Typeface\Style\Region\Height - Y UBE\FontManager\aVertex(CurrentCharacter*4+3)\v4fPosition\Y = *Typeface\Style\Region\Y+*Typeface\Style\Region\Height - Y EndIf EndIf CompilerElse Clipping\X = \Source\X Clipping\Y = \Source\Y Clipping\Width = \Source\Width Clipping\Height = \Source\Height If *Typeface\Style\EnabledRegion ; -X If X+Vertices\I[0]\X < *Typeface\Style\Region\X Value = (*Typeface\Style\Region\X-Vertices\I[0]\X-X)/Size Clipping\X + Value Clipping\Width - Value Vertices\I[0]\X = *Typeface\Style\Region\X - X Vertices\I[3]\X = *Typeface\Style\Region\X - X EndIf ; +X If X+Vertices\I[1]\X > *Typeface\Style\Region\X+*Typeface\Style\Region\Width Value = (Vertices\I[1]\X+X-*Typeface\Style\Region\X-*Typeface\Style\Region\Width)/Size Clipping\Width - Value Vertices\I[1]\X = *Typeface\Style\Region\X+*Typeface\Style\Region\Width - X Vertices\I[2]\X = *Typeface\Style\Region\X+*Typeface\Style\Region\Width - X EndIf ; -Y If Y+Vertices\I[0]\Y < *Typeface\Style\Region\Y Value = (*Typeface\Style\Region\Y-Vertices\I[0]\Y-Y)/Size Clipping\Y + Value Clipping\Height - Value Vertices\I[0]\Y = *Typeface\Style\Region\Y - Y Vertices\I[1]\Y = *Typeface\Style\Region\Y - Y EndIf ; +Y If Y+Vertices\I[2]\Y > *Typeface\Style\Region\Y+*Typeface\Style\Region\Height Value = (Vertices\I[2]\Y+Y-*Typeface\Style\Region\Y-*Typeface\Style\Region\Height)/Size Clipping\Height - Value Vertices\I[2]\Y = *Typeface\Style\Region\Y+*Typeface\Style\Region\Height - Y Vertices\I[3]\Y = *Typeface\Style\Region\Y+*Typeface\Style\Region\Height - Y EndIf EndIf ClipSprite(Sprite, Clipping\X, Clipping\Y, Clipping\Width, Clipping\Height) TransformSprite(Sprite, X+Vertices\I[0]\X, Y+Vertices\I[0]\Y, Vertices\I[0]\Z, X+Vertices\I[1]\X, Y+Vertices\I[1]\Y, Vertices\I[1]\Z, X+Vertices\I[2]\X, Y+Vertices\I[2]\Y, Vertices\I[2]\Z, X+Vertices\I[3]\X, Y+Vertices\I[3]\Y, Vertices\I[3]\Z) If Color = #Typeface_Default DisplayTransparentSprite(Sprite, 0, 0, Opacity) Else DisplayTransparentSprite(Sprite, 0, 0, Opacity, Color & $FFFFFF) EndIf CompilerEndIf EndIf CurrentCorner\X + (\Outlay\Width+*Typeface\Style\LetterSpace)*Size If *Character\c[Index] = ' ' CurrentCorner\X + *Typeface\Style\WordSpace*Size EndIf If *Typeface\Style\Kerning CurrentCorner\X + Typeface_KerningAmount(*Typeface, *Character\c[Index]<<16|*Character\c[Index+1])*Size EndIf EndWith CurrentCharacter + 1 EndIf Length - 1 Index + 1 CompilerIf #TypefaceCompilation & #TypefaceCompilation_UBEngine If CurrentCharacter = 256 Or Index > LastIndex glBufferSubData(#GL_ARRAY_BUFFER, 0, CurrentCharacter*4*SizeOf(UBE_FONTVERTEX), @UBE\FontManager\aVertex()) glDrawElements(#GL_TRIANGLES, CurrentCharacter*6, #GL_UNSIGNED_INT, #Null) CurrentCharacter = 0 EndIf CompilerEndIf Wend EndIf CurrentCorner\Y + Height Until Index > LastIndex EndProcedure EndModule ; IDE Options = PureBasic 5.60 (Windows - x64) ; CursorPosition = 568 ; FirstLine = 451 ; Folding = ----p+-X24ZBAAQ9- ; EnableXP ; Executable = ..\Includes\Typeface.dll.exe ; EnableCompileCount = 88 ; EnableBuildCount = 1