angelfont.monkey2 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. Namespace mojo.graphics
  2. Private
  3. Function GetArg:String( name:String,args:String )
  4. Local i0:=args.Find( name+"=" )
  5. If i0=-1 Return 0
  6. i0+=name.Length+1
  7. Local i1:=args.Find( " ",i0 )
  8. If i1=-1 Return 0
  9. Return args.Slice( i0,i1 )
  10. End
  11. Function GetIntArg:Int( name:String,args:String )
  12. Return Int( GetArg( name,args ) )
  13. End
  14. Public
  15. Class AngelFont Extends Font
  16. Method GetGlyph:Glyph( char:Int ) Override
  17. If char>=0 And char<_glyphs.Length Return _glyphs[char]
  18. Return _glyphs[0]
  19. End
  20. Method GetGlyphPage:Image( char:Int ) Override
  21. If char>=0 And char<_glyphs.Length Return _pages[ _glyphs[char].page ]
  22. Return _pages[0]
  23. End
  24. Method GetKerning:Float( firstChar:Int,secondChar:Int ) Override
  25. If Not _kernings.Length Return 0
  26. Local min:=0,max:=_kernings.Length
  27. While max>min
  28. Local mid:=(min+max)/2
  29. If firstChar>_kernings[mid].first
  30. min=mid+1
  31. Else If firstChar<_kernings[mid].first
  32. max=mid
  33. Else If secondChar>_kernings[mid].second
  34. min=mid+1
  35. Else If secondChar<_kernings[mid].second
  36. max=mid
  37. Else
  38. Return _kernings[mid].amount
  39. Endif
  40. Wend
  41. Return 0
  42. End
  43. Function Load:AngelFont( path:String,shader:Shader=Null,textureFlags:TextureFlags=TextureFlags.FilterMipmap )
  44. Local fnt:=LoadString( path,True )
  45. If Not fnt
  46. If Not ExtractRootDir( path ) fnt=LoadString( "font::"+path,True )
  47. If Not fnt Return Null
  48. Endif
  49. Local dir:=ExtractDir( path )
  50. Local lines:=fnt.Split( "~n" )
  51. Local pages:=New Stack<Image>
  52. Local glyphs:=New Stack<Glyph>
  53. Local kernings:=New Stack<Kerning>
  54. Local height:=0.0,minChar:=$ffff,maxChar:=0
  55. for Local i:=0 Until lines.Length
  56. Local line:=lines[i].Trim()
  57. If Not line Continue
  58. Local i:=line.Find( " " )
  59. If i=-1 Continue
  60. Local tag:=line.Slice( 0,i ).Trim()
  61. Local args:=line.Slice( i+1 ).Trim()+" "
  62. Select tag
  63. Case "common"
  64. height=GetIntArg( "lineHeight",args )
  65. Case "page"
  66. Local id:=GetIntArg( "id",args )
  67. Local file:=GetArg( "file",args )
  68. Local fpath:=dir+file.Slice( 1,-1 )
  69. Local pixmap:=Pixmap.Load( fpath,Null,True )
  70. Local pshader:=shader ?Else (pixmap.Format=PixelFormat.I8 ? Shader.Open( "font" ) Else Shader.Open( "sprite" ))
  71. Local image:=New Image( pixmap,textureFlags,pshader )
  72. If id>=pages.Length pages.Resize( id+1 )
  73. pages[id]=image
  74. Case "char"
  75. Local id:=GetIntArg( "id",args )
  76. Local x:=GetIntArg( "x",args )
  77. Local y:=GetIntArg( "y",args )
  78. Local w:=GetIntArg( "width",args )
  79. Local h:=GetIntArg( "height",args )
  80. Local tx:=GetIntArg( "xoffset",args )
  81. Local ty:=GetIntArg( "yoffset",args )
  82. Local advance:=GetIntArg( "xadvance",args )
  83. Local page:=GetIntArg( "page",args )
  84. Local chnl:=GetIntArg( "chnl",args )
  85. Local glyph:Glyph
  86. glyph.rect=New Recti( x,y,x+w,y+h )
  87. glyph.offset=New Vec2f( tx,ty )
  88. glyph.advance=advance
  89. glyph.page=page
  90. If id>=glyphs.Length glyphs.Resize( id+1 )
  91. glyphs[id]=glyph
  92. minChar=Min( id,minChar )
  93. maxChar=Max( id,maxChar )
  94. Case "kerning"
  95. Local kerning:Kerning
  96. kerning.first=GetIntArg( "first",args )
  97. kerning.second=GetIntArg( "second",args )
  98. kerning.amount=GetIntArg( "amount",args )
  99. kernings.Add( kerning )
  100. End
  101. Next
  102. kernings.Sort( Lambda:Int( x:Kerning,y:Kerning )
  103. If x.first<y.first Return -1
  104. If x.first>y.first Return 1
  105. If x.second<y.second Return -1
  106. If x.second>y.second Return 1
  107. Return 0
  108. End )
  109. ' Print "Kernings:"
  110. ' For Local k:=Eachin kernings
  111. ' Print "first="+k.first+" second="+k.second+" amount="+k.amount
  112. ' Next
  113. Local font:=New AngelFont( height,minChar,maxChar-minChar+1,glyphs.ToArray(),pages.ToArray(),kernings.ToArray() )
  114. Return font
  115. End
  116. Private
  117. Field _glyphs:Glyph[]
  118. Field _pages:Image[]
  119. Field _kernings:Kerning[]
  120. Struct Kerning
  121. Field first:Int
  122. Field second:Int
  123. Field amount:Int
  124. End
  125. Method New( height:Float,firstChar:Int,numChars:Int,glyphs:Glyph[],pages:Image[],kernings:Kerning[] )
  126. Init( height,firstChar,numChars )
  127. _glyphs=glyphs
  128. _pages=pages
  129. _kernings=kernings
  130. End
  131. End