Advertisement
Pillager86

it finally works

May 18th, 2020
669
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. module textrenderer;
  2.  
  3. import bindbc.freetype;
  4.  
  5. import misanthropyd.renderer.textures;
  6.  
  7. /// renders text
  8. class TextRenderer
  9. {
  10.     /// initialize the text renderer
  11.     static bool initialize()
  12.     {
  13.         immutable ret = loadFreeType();
  14.         if(ret != ftSupport)
  15.             return false;
  16.  
  17.         if(FT_Init_FreeType(cast(FT_Library*)&library_))
  18.             return false;
  19.  
  20.         return true;
  21.     }
  22.  
  23.     /// clean up all fonts and libraries
  24.     static void shutdown()
  25.     {
  26.         foreach(font ; fonts_)
  27.         {
  28.             destroy(font);
  29.         }
  30.         fonts_ = null;
  31.         FT_Done_Library(cast(FT_Library)library_);
  32.         library_ = null;
  33.     }
  34.  
  35.     /// load and store a font under name
  36.     static void loadFont(const string name, const string path, const uint size)
  37.     {
  38.         // todo: check for overwriting and warn
  39.         Font font = new Font(path, size);
  40.         fonts_[name] = cast(shared(Font))font;
  41.     }
  42.  
  43.     /// render colored text on a transparent background
  44.     static Texture2D renderText(const string fontName, const wstring text, ubyte r=0xff, ubyte g=0xff, ubyte b=0xff)
  45.     {
  46.         if(fontName !in fonts_)
  47.             throw new TextRenderException("No such font loaded: `" ~ fontName ~ "`");
  48.         Font font = cast(Font)fonts_[fontName];
  49.         uint width, height; // @suppress(dscanner.suspicious.unmodified)
  50.         sizeTextInternal(font, text, width, height);
  51.         uint[] pixels = new uint[width * height];
  52.         pixels[] = r | g<<8 | b<<16;
  53.         int x = 0;
  54.         foreach(ch ; text)
  55.         {
  56.             if(FT_Load_Char(font.face_, ch, FT_LOAD_RENDER))
  57.                 continue; // ignore unrenderable chars
  58.             for(int row=0; row < font.face_.glyph.bitmap.rows; ++row)
  59.             {
  60.                 immutable YPOS = height - (font.baseline_ - font.face_.glyph.bitmap_top + row) - 1;
  61.                 for(int col=0; col < font.face_.glyph.bitmap.width; ++col)
  62.                 {
  63.                     immutable XPOS = x + col;
  64.                     pixels[XPOS + YPOS * width] |=
  65.                         font.face_.glyph.bitmap.buffer[col + row * font.face_.glyph.bitmap.width] << 24;
  66.                 }
  67.             }
  68.             x += font.face_.glyph.advance.x / 64;
  69.         }
  70.         Texture2D texture = Texture2D.create(width, height);
  71.         texture.setData(cast(ubyte[])pixels);
  72.         return texture;
  73.     }
  74.  
  75.     private static void sizeTextInternal(Font font, const wstring text, ref uint width, ref uint height)
  76.     {
  77.         height = font.height_;
  78.         width = 0;
  79.         foreach(ch ; text)
  80.         {
  81.             if(FT_Load_Char(font.face_, ch, FT_LOAD_RENDER))
  82.                 continue; // ignore invalid chars
  83.             width += font.face_.glyph.advance.x / 64;
  84.         }
  85.     }
  86.  
  87.     package static shared(FT_Library) library_;
  88.     private static shared(Font[string]) fonts_;
  89. }
  90.  
  91. /// thrown when text rendering fails
  92. class TextRenderException : Exception
  93. {
  94.     /// constructor
  95.     this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable nextInChain = null)
  96.             pure nothrow @nogc @safe
  97.     {
  98.         super(msg, file, line, nextInChain);
  99.     }
  100. }
  101.  
  102. /// thrown when font loading fails
  103. class FontLoadException : Exception
  104. {
  105.     /// constructor
  106.     this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable nextInChain = null)
  107.             pure nothrow @nogc @safe
  108.     {
  109.         super(msg, file, line, nextInChain);
  110.     }
  111. }
  112.  
  113. private class Font
  114. {
  115.     this(const string path, const uint size)
  116.     {
  117.         import std.conv: to;
  118.         import std.string: toStringz;
  119.         if(FT_New_Face(cast(FT_Library)TextRenderer.library_, path.toStringz, 0, &face_))
  120.             throw new FontLoadException("Unable to load font `" ~ path ~ "`");
  121.         if(FT_Set_Char_Size(face_, 0, size * 64, 0, 0))
  122.             throw new FontLoadException("Unable to set font size " ~ size.to!string);
  123.         // set metrics
  124.         ascent_ = cast(int)(face_.size.metrics.ascender / 64);
  125.         descent_ = cast(int)(face_.size.metrics.descender / 64);
  126.         height_ = cast(int)(face_.size.metrics.height / 64);
  127.         baseline_ = height_ + descent_;
  128.     }
  129.  
  130.     ~this()
  131.     {
  132.         FT_Done_Face(face_);
  133.     }
  134.  
  135.     package
  136.     {
  137.         FT_Face face_;
  138.         int ascent_, descent_, height_, baseline_;
  139.     }
  140. }
Advertisement
RAW Paste Data Copied
Advertisement