freetypefont.monkey2 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. Namespace mojo.graphics
  2. #Import "<freetype>"
  3. Private
  4. Using freetype
  5. Global FreeType:FT_Library
  6. Function FontError()
  7. RuntimeError( "Font error" )
  8. End
  9. Public
  10. #rem monkeydoc @hidden
  11. #end
  12. Class FreeTypeFont Extends Font
  13. Function Load:FreeTypeFont( path:String,fheight:Float,shader:Shader )
  14. Local ext:=ExtractExt( path )
  15. If Not ext
  16. Local font:=Load( path+".otf",fheight,shader )
  17. If Not font font=Load( path+".ttf",fheight,shader )
  18. If Not font font=Load( path+".fon",fheight,shader )
  19. Return font
  20. Endif
  21. If Not FreeType And FT_Init_FreeType( Varptr FreeType ) Return Null
  22. Local data:=DataBuffer.Load( path )
  23. If Not data Return Null
  24. Local face:FT_Face
  25. If FT_New_Memory_Face( FreeType,data.Data,data.Length,0,Varptr face )
  26. data.Discard()
  27. Return Null
  28. Endif
  29. Local font:=New FreeTypeFont( data,face,fheight,shader )
  30. Return font
  31. End
  32. Protected
  33. Method OnDiscard() Override
  34. FT_Done_Face( _face )
  35. _data.Discard()
  36. Super.OnDiscard()
  37. End
  38. Method OnLoadGlyphPage( page:Int,gpage:GlyphPage ) Override
  39. Const MaxTexWidth:=1024
  40. Local firstChar:=page * 256
  41. Local numChars:=256
  42. Local slot:=_face->glyph
  43. 'Measure atlas first
  44. '
  45. 'Would really rather not render glyphs here, but can't see how...
  46. '
  47. Local tx:=0,ty:=0,texw:=0,texh:=0,maxh:=0
  48. For Local i:=-1 Until numChars
  49. If i<0
  50. If FT_Load_Char( _face,0,FT_LOAD_RENDER|FT_LOAD_FORCE_AUTOHINT ) FontError()
  51. Else
  52. If Not FT_Get_Char_Index( _face,firstChar+i ) Or FT_Load_Char( _face,firstChar+i,FT_LOAD_RENDER|FT_LOAD_FORCE_AUTOHINT ) Continue
  53. Endif
  54. Local gw:=Int( slot->bitmap.width )
  55. Local gh:=Int( slot->bitmap.rows )
  56. If tx+gw+1>MaxTexWidth
  57. texw=Max( texw,tx )
  58. texh+=maxh
  59. maxh=0
  60. tx=0
  61. Endif
  62. maxh=Max( maxh,gh+1 )
  63. tx+=gw+1
  64. Next
  65. texw=Max( texw,tx )
  66. If tx texh+=maxh
  67. 'round up texw, texh to ^2 in case we're mipmapping on mobile/webgl.
  68. texw=1 Shl Int( Ceil( Log2( texw ) ) )
  69. texh=1 Shl Int( Ceil( Log2( texh ) ) )
  70. Local pixmap:=New Pixmap( texw,texh,PixelFormat.A8 )
  71. pixmap.Clear( Color.None )
  72. Local glyphs:=New Glyph[numChars],nullGlyph:Glyph
  73. tx=0;ty=0;maxh=0
  74. For Local i:=-1 Until numChars
  75. If i<0
  76. If FT_Load_Char( _face,0,FT_LOAD_RENDER|FT_LOAD_FORCE_AUTOHINT ) FontError()
  77. Else
  78. If Not FT_Get_Char_Index( _face,firstChar+i ) Or FT_Load_Char( _face,firstChar+i,FT_LOAD_RENDER|FT_LOAD_FORCE_AUTOHINT )
  79. glyphs[i]=nullGlyph
  80. Continue
  81. Endif
  82. Endif
  83. Local gw:=Int( slot->bitmap.width )
  84. Local gh:=Int( slot->bitmap.rows )
  85. Local tmp:=New Pixmap( gw,gh,PixelFormat.A8,slot->bitmap.buffer,slot->bitmap.pitch )
  86. If tx+gw+1>pixmap.Width
  87. ty+=maxh
  88. maxh=0
  89. tx=0
  90. Endif
  91. pixmap.Paste( tmp,tx,ty )
  92. tmp.Discard()
  93. Local glyph:=New Glyph( New Recti( tx,ty,tx+gw,ty+gh ),New Vec2f( slot->bitmap_left,_ascent-slot->bitmap_top ),slot->advance.x Shr 6 )
  94. If i>=0 glyphs[i]=glyph Else nullGlyph=glyph
  95. maxh=Max( maxh,gh+1 )
  96. tx+=gw+1
  97. Next
  98. gpage.image=New Image( pixmap,Null,_shader )
  99. gpage.glyphs=glyphs
  100. pixmap.Discard()
  101. ' Print "Loading glyph page "+page+", image size="+gpage.image.Rect.Size
  102. End
  103. Private
  104. Field _data:DataBuffer
  105. Field _face:FT_Face
  106. Field _shader:Shader
  107. Field _height:Int
  108. Field _ascent:Int
  109. Method New( data:DataBuffer,face:FT_Face,fheight:Float,shader:Shader )
  110. _data=data
  111. _face=face
  112. _shader=shader
  113. Local size_req:FT_Size_RequestRec
  114. size_req.type=FT_SIZE_REQUEST_TYPE_REAL_DIM
  115. size_req.width=0
  116. size_req.height=fheight * 64
  117. size_req.horiResolution=0
  118. size_req.vertResolution=0
  119. If FT_Request_Size( face,Varptr size_req ) FontError()
  120. _height=(face->size->metrics.height+32) Shr 6
  121. _ascent=(face->size->metrics.ascender+32) Shr 6
  122. Local gindex:FT_UInt,nchars:=0
  123. Local charcode:=FT_Get_First_Char( face,Varptr gindex )
  124. Local pages:=New GlyphPage[256]
  125. Local maxpage:=0
  126. While gindex
  127. Local page:Int=charcode Shr 8
  128. If page>=0 And page<pages.Length
  129. maxpage=Max( maxpage,page )
  130. If Not pages[page] pages[page]=New GlyphPage
  131. Endif
  132. charcode=FT_Get_Next_Char( face,charcode,Varptr gindex )
  133. Wend
  134. InitFont( _height,pages.Slice( 0,maxpage+1 ) )
  135. End
  136. End