changeset 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 1530d9c04d4d
children 0fd51d2c6c8a
files codeDoc/jobs.txt data/conf/gui.mtt doc/Readme.txt mde/ft/init.d mde/gl/basic.d mde/gui/widget/Widget.d mde/gui/widget/createWidget.d mde/resource/exception.d mde/resource/font.d mde/resource/paths.d mde/scheduler/init2.d
diffstat 11 files changed, 219 insertions(+), 61 deletions(-) [+]
line wrap: on
line diff
--- a/codeDoc/jobs.txt	Thu May 15 10:39:57 2008 +0100
+++ b/codeDoc/jobs.txt	Fri May 16 12:22:10 2008 +0100
@@ -3,6 +3,7 @@
 
 
 In progress:
+Implementing font rendering
 
 
 
--- a/data/conf/gui.mtt	Thu May 15 10:39:57 2008 +0100
+++ b/data/conf/gui.mtt	Fri May 16 12:22:10 2008 +0100
@@ -7,4 +7,4 @@
 {W2}
 <int|x=150>
 <int|y=200>
-<int[][int]|widgetData=[0:[0xB004,5,5,2,1,2,1,2,1,1,1,1,1,2,1,2,1,2,1,1,1,1,1,2,1,2,1,2],1:[0x3001],2:[0x4010,75,75]]>
+<int[][int]|widgetData=[0:[0xB004,5,5,2,1,2,1,2,1,1,1,1,1,2,1,2,1,2,1,1,1,1,1,2,1,2,1,2],1:[0x3001],2:[0x2]]>
--- a/doc/Readme.txt	Thu May 15 10:39:57 2008 +0100
+++ b/doc/Readme.txt	Fri May 16 12:22:10 2008 +0100
@@ -21,6 +21,10 @@
 Also thanks to:
 Walter Bright and Digital Mars for D and DMD.
 The tango team for Tango.
+[derelict]
+[sdl]
+[opengl]
+[freetype]
 
 
 
--- a/mde/ft/init.d	Thu May 15 10:39:57 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/* 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.ft.init;
-
-import derelict.freetype.ft;
-
-import tango.stdc.stringz;
-import tango.util.log.Log : Log, Logger;
-
-private Logger logger;
-static this () {
-    logger = Log.getLogger ("mde.ft.init");
-}
-
-FT_Library  library;
-FT_Face     face;
-
-// FIXME: use a different exception
-const PATH = "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf";
-void initFreeType () {
-    if (FT_Init_FreeType (&library))
-        throw new Exception ("error initialising the FreeType library");
-        
-    if (FT_New_Face (library, toStringz(PATH), 0, &face))
-        throw new Exception ("Unable to read font: "~PATH);
-        
-    if (FT_Set_Pixel_Sizes (face, 32,32))
-        throw new Exception ("Unable to set pixel size");
-}
-
-void cleanupFreeType () {
-    FT_Done_Face (face);
-    FT_Done_FreeType (library);
-}
--- a/mde/gl/basic.d	Thu May 15 10:39:57 2008 +0100
+++ b/mde/gl/basic.d	Fri May 16 12:22:10 2008 +0100
@@ -25,6 +25,10 @@
 //BEGIN GL & window setup
 void glSetup () {
     glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
+    glDisable(GL_DEPTH_TEST);
+    
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
 }
 
 void setProjection (int w, int h) {
@@ -38,7 +42,6 @@
     //glOrtho (0.0,1.0,0.0,1.0,-1.0,1.0);
     
     glMatrixMode(GL_MODELVIEW);
-    glLoadIdentity();
 }
 //END GL & window setup
 
--- a/mde/gui/widget/Widget.d	Thu May 15 10:39:57 2008 +0100
+++ b/mde/gui/widget/Widget.d	Fri May 16 12:22:10 2008 +0100
@@ -20,6 +20,8 @@
 import mde.gui.exception;
 import mde.gui.renderer.IRenderer;
 
+import mde.resource.font;
+
 import tango.io.Stdout;
 
 /** An abstract base widget class.
@@ -42,6 +44,9 @@
         return data;
     }
     
+    bool isWSizable () {    return false;   }
+    bool isHSizable () {    return false;   }
+    
     // Widget type should always be the first value.
     int[] getCreationData () {
         return [widgetType];
@@ -84,18 +89,15 @@
 /** A base for fixed-size widgets. */
 class FixedWidget : Widget {
     this (IWindow wind, int[] data) {
+        w = wF;
+        h = hF;
         super (wind, data);
-        w = wF = data[1];
-        h = hF = data[2];
     }
     
     int[] getCreationData () {
         return [widgetType, wF, hF];
     }
     
-    bool isWSizable () {    return false;   }
-    bool isHSizable () {    return false;   }
-    
     /* Not resizable, so return current size. */
     void getMinimalSize (out int mw, out int mh) {
         mw = wF;
@@ -142,6 +144,8 @@
 {
     this (IWindow wind, int[] data) {
         if (data.length != 3) throw new WidgetDataException;
+        wF = data[1];
+        hF = data[2];
         super (wind, data);
     }
     void draw () {
@@ -169,6 +173,8 @@
     
     this (IWindow wind, int[] data) {
         if (data.length != 3) throw new WidgetDataException;
+        wF = data[1];
+        hF = data[2];
         super (wind, data);
     }
     
@@ -206,4 +212,24 @@
             window.requestRedraw;
     }
 }
+
+/// Basic text widget
+class TextWidget : FixedWidget
+{
+    this (IWindow wind, int[] data) {
+        if (data.length != 1) throw new WidgetDataException;
+        wF = 100;	//FIXME: set properly
+        hF = 25;
+        super (wind,data);
+    }
+    
+    void draw () {
+        super.draw();
+        if (font is null) font = Font.get("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf");
+        font.drawStr (x,y, "Text Widget");
+    }
+    
+protected:
+    static Font font;
+}
 //END Widgets
--- a/mde/gui/widget/createWidget.d	Thu May 15 10:39:57 2008 +0100
+++ b/mde/gui/widget/createWidget.d	Fri May 16 12:22:10 2008 +0100
@@ -60,6 +60,9 @@
     FixedBlank              = 0x1,
     SizableBlank            = WSIZABLE | HSIZABLE | 0x1,
     
+    // text: 0x2
+    Text		    = 0x2,
+    
     // buttons: 0x10
     Button                  = INTERACTIBLE | 0x10,
     
@@ -71,20 +74,21 @@
 // Only used for binarySearch algorithm generation; must be ordered by numerical values.
 const char[][] WIDGETS = [
         "FixedBlank",
+        "Text",
         "SizableBlank",
         "Button",
         "GridLayout"   ];
 
 // Purely to add indentation. Could just return "" without affecting functionality.
-/+static char[] indent (uint i) {
+static char[] indent (uint i) {
     char[] ret;
     for (; i > 0; --i) ret ~= "  ";
         // This is not executable at compile time:
         //ret.length = i * 4;		// number of characters for each indentation
         //ret[] = ' ';		// character to indent with
     return ret;
-}+/
-char[] indent (uint) {  return "";  }
+}
+//char[] indent (uint) {  return "";  }
 
 /* Generates a binary search algorithm. */
 char[] binarySearch (char[] var, char[][] consts, int indents = 0) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mde/resource/exception.d	Fri May 16 12:22:10 2008 +0100
@@ -0,0 +1,40 @@
+/* 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/>. */
+
+/// Contains resource exceptions
+module mde.resource.exception;
+import mde.exception;
+
+/// Thrown when initialising freetype fails.
+class fontException : mdeException {
+    char[] getSymbol () {
+        return super.getSymbol ~ ".resource.font";
+    }
+    
+    this (char[] msg) {
+        super(msg);
+    }
+}
+
+/// Thrown when loading a freetype font fails.
+class fontLoadException : fontException {
+    char[] getSymbol () {
+        return super.getSymbol ~ ".resource.font";
+    }
+    
+    this (char[] msg) {
+        super(msg);
+    }
+}
--- /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;
+}
--- a/mde/resource/paths.d	Thu May 15 10:39:57 2008 +0100
+++ b/mde/resource/paths.d	Fri May 16 12:22:10 2008 +0100
@@ -150,7 +150,7 @@
 /** Find at least one path for each required directory.
 *
 * Note: the logger cannot be used yet, so only output is exception messages. */
-
+// FIXME: use tango/sys/Environment.d
 version (linux) {
     void resolvePaths () {
         // Home directory:
--- a/mde/scheduler/init2.d	Thu May 15 10:39:57 2008 +0100
+++ b/mde/scheduler/init2.d	Fri May 16 12:22:10 2008 +0100
@@ -35,7 +35,7 @@
 import imde = mde.imde;
 import mde.gui.Gui;
 import mde.input.Input;
-import ft = mde.ft.init;
+import font = mde.resource.font;
 
 // NOTE: error reporting needs a revision
 
@@ -86,7 +86,7 @@
 
 void initFreeType () {  // init func
     try {
-        ft.initFreeType;
+        font.Font.initialize;
     } catch (Exception e) {
         logger.fatal ("initFreeType failed: " ~ e.msg);
         setInitFailure;