123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267 |
- Namespace mojo.graphics
- #Import "<freetype>"
- Private
- Using freetype
- Global FreeType:FT_Library
- Function FontError()
- RuntimeError( "Font error" )
- End
- Public
- #rem monkeydoc @hidden
- #end
- Class FreeTypeFont Extends Font
-
- Method GetGlyph:Glyph( char:Int ) Override
-
- Local page:=char Shr 8
- If page<0 Or page>=_pages.Length Return _nullGlyph
- Local gpage:=_pages[page]
- If Not gpage Return _nullGlyph
- If Not gpage.image LoadGlyphPage( page,gpage )
-
- Local index:=char & 255
- If index>=gpage.glyphs.Length Return _nullGlyph
-
- Return gpage.glyphs[index]
- End
-
- Method GetGlyphPage:Image( char:Int ) Override
-
- Local page:=char Shr 8
- If page<0 Or page>=_pages.Length Return Null
-
- Local gpage:=_pages[page]
- If Not gpage Return Null
-
- If Not gpage.image LoadGlyphPage( page,gpage )
-
- Local index:=char & 255
- If index>=gpage.glyphs.Length Return Null
-
- Return gpage.image
- End
-
- Method GetKerning:Float( firstChar:Int,secondChar:Int ) Override
-
- If Not _hasKerning Return 0
- Local firstGlyph:=FT_Get_Char_Index( _face,firstChar )
- Local secondGlyph:=FT_Get_Char_Index( _face,secondChar )
-
- Local delta:FT_Vector
-
- FT_Get_Kerning( _face,firstGlyph,secondGlyph,0,Varptr delta )
-
- Return delta.x Shr 6
- End
-
- Function Load:FreeTypeFont( path:String,height:Float,shader:Shader=Null,textureFlags:TextureFlags=TextureFlags.FilterMipmap )
-
- If Not FreeType And FT_Init_FreeType( Varptr FreeType ) Return Null
-
- Local data:=DataBuffer.Load( path )
- If Not data
- If Not ExtractRootDir( path ) data=DataBuffer.Load( "font::"+path )
- If Not data Return Null
- Endif
-
- Local face:FT_Face
- If FT_New_Memory_Face( FreeType,data.Data,data.Length,0,Varptr face )
- data.Discard()
- Return Null
- Endif
-
- If Not shader shader=Shader.Open( "font" )
-
- Local font:=New FreeTypeFont( data,face,height,shader,textureFlags )
-
- Return font
- End
-
- Protected
-
- Method OnDiscard() Override
-
- FT_Done_Face( _face )
-
- _data.Discard()
-
- _data=Null
- _face=Null
- End
-
- Private
-
- Class GlyphPage
- Field image:Image
- Field glyphs:Glyph[]
- End
-
- Field _data:DataBuffer
- Field _face:FT_Face
- Field _shader:Shader
- Field _textureFlags:TextureFlags
- Field _hasKerning:Bool
-
- Field _height:Int
- Field _ascent:Int
-
- Field _pages:GlyphPage[]
-
- Field _nullGlyph:Glyph
-
- Method LoadGlyphPage( page:Int,gpage:GlyphPage )
-
- Const MaxTexWidth:=1024
-
- Local firstChar:=page * 256
- Local numChars:=256
-
- Local slot:=_face->glyph
-
- 'Measure atlas first
- '
- 'Would really rather not render glyphs here, but can't see how...
- '
- Local tx:=0,ty:=0,texw:=0,texh:=0,maxh:=0
-
- For Local i:=-1 Until numChars
-
- If i<0
- If FT_Load_Char( _face,0,FT_LOAD_RENDER|FT_LOAD_FORCE_AUTOHINT ) FontError()
- Else
- If Not FT_Get_Char_Index( _face,firstChar+i ) Or FT_Load_Char( _face,firstChar+i,FT_LOAD_RENDER|FT_LOAD_FORCE_AUTOHINT ) Continue
- Endif
-
- Local gw:=Int( slot->bitmap.width )
- Local gh:=Int( slot->bitmap.rows )
-
- If tx+gw+1>MaxTexWidth
- texw=Max( texw,tx )
- texh+=maxh
- maxh=0
- tx=0
- Endif
-
- maxh=Max( maxh,gh+1 )
- tx+=gw+1
- Next
-
- texw=Max( texw,tx )
- If tx texh+=maxh
-
- 'round up texw, texh to ^2 in case we're mipmapping on mobile/webgl.
- texw=1 Shl Int( Ceil( Log2( texw ) ) )
- texh=1 Shl Int( Ceil( Log2( texh ) ) )
-
- Local pixmap:=New Pixmap( texw,texh,PixelFormat.I8 )
- pixmap.Clear( Color.None )
-
- Local glyphs:=New Glyph[numChars],glyph:Glyph,nullGlyph:Glyph
-
- tx=0;ty=0;maxh=0
-
- For Local i:=-1 Until numChars
-
- If i<0
- If FT_Load_Char( _face,0,FT_LOAD_RENDER|FT_LOAD_FORCE_AUTOHINT ) FontError()
- Else
- If Not FT_Get_Char_Index( _face,firstChar+i ) Or FT_Load_Char( _face,firstChar+i,FT_LOAD_RENDER|FT_LOAD_FORCE_AUTOHINT )
- glyphs[i]=nullGlyph
- Continue
- Endif
- Endif
-
- Local gw:=Int( slot->bitmap.width )
- Local gh:=Int( slot->bitmap.rows )
-
- Local tmp:=New Pixmap( gw,gh,PixelFormat.I8,slot->bitmap.buffer,slot->bitmap.pitch )
-
- If tx+gw+1>pixmap.Width
- ty+=maxh
- maxh=0
- tx=0
- Endif
-
- pixmap.Paste( tmp,tx,ty )
-
- tmp.Discard()
-
- glyph.rect=New Recti( tx,ty,tx+gw,ty+gh )
- glyph.offset=New Vec2f( slot->bitmap_left,_ascent-slot->bitmap_top )
- glyph.advance=slot->advance.x Shr 6
-
- If i>=0 glyphs[i]=glyph Else nullGlyph=glyph
-
- maxh=Max( maxh,gh+1 )
- tx+=gw+1
- Next
-
- gpage.image=New Image( pixmap,_textureFlags,_shader )
- gpage.glyphs=glyphs
-
- ' Print "Loading glyph page "+page+", image size="+gpage.image.Rect.Size
- End
-
- Method New( data:DataBuffer,face:FT_Face,fheight:Float,shader:Shader,textureFlags:TextureFlags )
-
- _data=data
- _face=face
- _shader=shader
- _textureFlags=textureFlags
- _hasKerning=FT_HAS_KERNING( _face )
-
- Local size_req:FT_Size_RequestRec
-
- size_req.type=FT_SIZE_REQUEST_TYPE_REAL_DIM
- size_req.width=0
- size_req.height=fheight * 64
- size_req.horiResolution=0
- size_req.vertResolution=0
-
- If FT_Request_Size( face,Varptr size_req ) FontError()
-
- _height=(face->size->metrics.height+32) Shr 6
- _ascent=(face->size->metrics.ascender+32) Shr 6
- Local gindex:FT_UInt
- Local char:=FT_Get_First_Char( face,Varptr gindex )
- Local minChar:=char,maxChar:=char,maxPage:=0
-
- _pages=New GlyphPage[256]
-
- While gindex
-
- Local page:Int=char Shr 8
-
- If page>=0 And page<_pages.Length And Not _pages[page]
-
- maxPage=Max( page,maxPage )
- _pages[page]=New GlyphPage
-
- Endif
-
- char=FT_Get_Next_Char( face,char,Varptr gindex )
-
- minChar=Min( char,minChar )
- maxChar=Max( char,maxChar )
- Wend
-
- _pages=_pages.Slice( 0,maxPage+1 )
-
- Super.Init( _height,minChar,maxChar-minChar+1 )
-
- _nullGlyph=GetGlyph( 0 )
- End
-
- End
|