diff mde/resource/font.d @ 44:07bd1a09e161

Started implementing text rendering. Can now position glyphs accurately and render them, in a very basic way. A basic TextWidget. committer: Diggory Hardy <diggory.hardy@gmail.com>
author Diggory Hardy <diggory.hardy@gmail.com>
date Fri, 16 May 2008 12:22:10 +0100
parents
children 0fd51d2c6c8a
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mde/resource/font.d	Fri May 16 12:22:10 2008 +0100
@@ -0,0 +1,128 @@
+/* LICENSE BLOCK
+Part of mde: a Modular D game-oriented Engine
+Copyright © 2007-2008 Diggory Hardy
+
+This program is free software: you can redistribute it and/or modify it under the terms
+of the GNU General Public License as published by the Free Software Foundation, either
+version 2 of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+/// Sets up freetype (in a basic way).
+module mde.resource.font;
+
+import mde.resource.exception;
+
+import derelict.freetype.ft;
+import derelict.opengl.gl;
+
+import tango.stdc.stringz;
+import tango.util.log.Log : Log, Logger;
+
+private Logger logger;
+static this () {
+    logger = Log.getLogger ("mde.resource.font");
+}
+
+/** Font class.
+ *
+ * Particular to a font and size. (Maybe not size?) */
+class Font
+{
+    //BEGIN Static: manager
+    static {
+        /** Load the freetype library. */
+        void initialize () {
+            if (FT_Init_FreeType (&library))
+                throw new fontException ("error initialising the FreeType library");
+        }
+        
+        //FIXME: don't use GC for Font resources
+        /** Cleanup: delete all fonts. */
+        void cleanup () {
+            if (font)
+                delete font;
+            
+            FT_Done_FreeType (library);
+        }
+        
+        /** Get a font.
+         *
+         * Later specify font/size.
+         *
+         * Throws:
+         *  fontLoadException when unable to load the font. */
+        Font get(char[] path) {
+            if (font is null) font = new Font(path);
+            return font;
+        }
+        
+    private:
+        FT_Library	library;
+        Font font;
+    }
+    //END Static
+    
+    
+    /** Load & cache a new font. */
+    this (char[] path)
+    in {
+        assert (library !is null, "font: library is null");
+    } body {
+        if (FT_New_Face (library, toStringz(path), 0, &face))
+            throw new fontLoadException ("Unable to read font: "~path);
+        
+        if (FT_Set_Pixel_Sizes (face, 12,12))
+            throw new fontLoadException ("Unable to set pixel size");
+    }
+    
+    void drawStr (int x, int y, char[] str) {
+        FT_Vector pen = { x*64, y*64 };
+        auto g = face.glyph;
+        
+        FT_Matrix m;
+        m.xx = 0x10000;
+        m.xy = m.yx = 0;
+        m.yy = -0x10000;
+        
+        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+        
+        FT_Pos y_adj = 0;	// y adjustment (for height)
+        
+        foreach (chr; str) {
+            FT_Set_Transform(face, &m, &pen);
+            if (FT_Load_Char(face, chr, FT_LOAD_RENDER))
+                return;	// give up
+            
+            if (y_adj < g.metrics.height) y_adj = g.metrics.height;
+            
+            auto b = g.bitmap;
+            if (b.pixel_mode != FT_Pixel_Mode.FT_PIXEL_MODE_GRAY || b.num_grays != 256) {
+                char[128] tmp;
+                logger.warn (logger.format (tmp,"Unsupported freetype bitmap format: {}, {}", b.pixel_mode, b.num_grays));
+                return;
+            }
+            if (b.pitch != b.width)
+                logger.info ("b.pitch != b.width");
+            
+            //NOTE: y direction!
+            glRasterPos2i (g.bitmap_left,g.bitmap_top + y_adj/64);
+            glDrawPixels (b.width, b.rows, GL_LUMINANCE, GL_UNSIGNED_BYTE, cast(void*) b.buffer);
+            
+            pen.x += g.advance.x;
+            pen.y += g.advance.y;
+        }
+    }
+    
+    ~this () {
+        FT_Done_Face (face);
+    }
+    
+private:
+    FT_Face	face;
+}