changeset 51:387a80724c35

Enabled LCD font rendering mode (only tested with freetype's sub-pixel rendering disabled). committer: Diggory Hardy <diggory.hardy@gmail.com>
author Diggory Hardy <diggory.hardy@gmail.com>
date Mon, 02 Jun 2008 14:34:24 +0100
parents f68ae1d667f9
children 94a4ddb549e5 f000d6cd0f74
files data/L10n/OptionsFont.mtt data/conf/options.mtt mde/resource/FontTexture.d mde/resource/font.d mde/sdl.d
diffstat 5 files changed, 58 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/data/L10n/OptionsFont.mtt	Sun Jun 01 18:22:54 2008 +0100
+++ b/data/L10n/OptionsFont.mtt	Mon Jun 02 14:34:24 2008 +0100
@@ -1,4 +1,4 @@
 {MT01}
 {en-GB}
-<entry|lcdFilter=["LCD filtering","Enable or disable LCD filtering. Note that the FreeType library may be compiled with this support disabled due to patents."]>
-<entry|renderMode=["Font rendering mode","Controls how fonts are rendered: in gray-scale, or for LCDs (with a horizontal (normal) or vertical layout, with an RGB (normal) or BGR sub-pixel mode."]>
+<entry|lcdFilter=["LCD filtering","Enable or disable sub-pixel rendering. Note that the FreeType library may be compiled without support due to patent issues."]>
+<entry|renderMode=["Font rendering mode","Controls how fonts are rendered: in gray-scale, or for LCDs (with a horizontal (usual) or vertical layout, with an RGB (usual) or BGR sub-pixel mode."]>
--- a/data/conf/options.mtt	Sun Jun 01 18:22:54 2008 +0100
+++ b/data/conf/options.mtt	Mon Jun 02 14:34:24 2008 +0100
@@ -8,7 +8,7 @@
 
 {font}
 <int|lcdFilter=0>
-<int|hinting=0>
+<int|renderMode=0>
 
 {video}
 <bool|noFrame=false>
--- a/mde/resource/FontTexture.d	Sun Jun 01 18:22:54 2008 +0100
+++ b/mde/resource/FontTexture.d	Mon Jun 02 14:34:24 2008 +0100
@@ -32,6 +32,7 @@
 
 import Utf = tango.text.convert.Utf;
 import tango.util.log.Log : Log, Logger;
+import tango.io.Stdout;
 
 private Logger logger;
 static this () {
@@ -213,7 +214,7 @@
             //throw new fontGlyphException ("Unsupported freetype bitmap: b.pitch != b.width");
         }
         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-        glPixelStorei (GL_UNPACK_ROW_LENGTH, b.pitch);
+        //glPixelStorei (GL_UNPACK_ROW_LENGTH, b.pitch);
         
         GlyphAttribs ga;
         ga.w		= b.width;
@@ -222,6 +223,10 @@
         ga.top		= g.bitmap_top;
         ga.advanceX	= g.advance.x >> 6;
         ga.index	= gi;
+        if (b.pixel_mode == FT_Pixel_Mode.FT_PIXEL_MODE_LCD)
+            ga.w /= 3;
+        if (b.pixel_mode == FT_Pixel_Mode.FT_PIXEL_MODE_LCD_V)
+            ga.h /= 3;
         
         foreach (ref t; tex) {
             if (t.addGlyph (ga))
@@ -236,14 +241,37 @@
         gotTexSpace:
         glBindTexture(GL_TEXTURE_2D, ga.texID);
         GLenum format;
-        if (b.pixel_mode == FT_Pixel_Mode.FT_PIXEL_MODE_GRAY && b.num_grays == 256)
+        ubyte[] buffer;	// use our own pointer, since for LCD modes we need to perform a conversion
+        if (b.pixel_mode == FT_Pixel_Mode.FT_PIXEL_MODE_GRAY && b.num_grays == 256) {
+            buffer = b.buffer[0..b.pitch*b.rows];
             format = GL_LUMINANCE;
-        else if (b.pixel_mode == FT_Pixel_Mode.FT_PIXEL_MODE_LCD ||
-                 b.pixel_mode == FT_Pixel_Mode.FT_PIXEL_MODE_LCD_V) {
-            if (fontOpts.renderMode & RENDER_LCD_BGR)
-                format = GL_BGR;
-            else
-                format = GL_RGB;
+        } else if (b.pixel_mode == FT_Pixel_Mode.FT_PIXEL_MODE_LCD) {
+            // NOTE: Can't seem to get OpenGL to read freetype's RGB buffers properly, so convent.
+            /* NOTE: Sub-pixel rendering probably also needs filtering. I haven't tried, since it's
+             * disabled in my build of the library. For a tutorial on the filtering, see:
+             * http://dmedia.dprogramming.com/?n=Tutorials.TextRendering1 */
+            buffer = new ubyte[b.width*b.rows];
+            for (uint i = 0; i < b.rows; ++i)
+                for (uint j = 0; j < b.width; j+= 3)
+            {
+                buffer[i*b.width + j + 0] = b.buffer[i*b.pitch + j + 0];
+                buffer[i*b.width + j + 1] = b.buffer[i*b.pitch + j + 1];
+                buffer[i*b.width + j + 2] = b.buffer[i*b.pitch + j + 2];
+            }
+            
+            format = (fontOpts.renderMode & RENDER_LCD_BGR) ? GL_BGR : GL_RGB;
+        } else if (b.pixel_mode == FT_Pixel_Mode.FT_PIXEL_MODE_LCD_V) {
+            // NOTE: Notes above apply. Only in this case converting the buffers seems essential.
+            buffer = new ubyte[b.width*b.rows];
+            for (uint i = 0; i < b.rows; ++i)
+                for (uint j = 0; j < b.width; ++j)
+            {
+                // i/3 is the "real" row, b.width*3 is our width (with subpixels), j is column,
+                // i%3 is sub-pixel (R/G/B). i/3*3 necessary to round to multiple of 3
+                buffer[i/3*b.width*3 + 3*j + i%3] = b.buffer[i*b.pitch + j];
+            }
+            
+            format = (fontOpts.renderMode & RENDER_LCD_BGR) ? GL_BGR : GL_RGB;
         } else
             throw new fontGlyphException ("Unsupported freetype bitmap format");
         
@@ -251,7 +279,7 @@
                         ga.x, ga.y,
                         ga.w, ga.h,
                         format, GL_UNSIGNED_BYTE,
-                        cast(void*) b.buffer);
+                        cast(void*) buffer.ptr);
         
         cachedGlyphs[chr] = ga;
     }
@@ -352,6 +380,7 @@
         Line line;
         line.yPos = nextYPos;
         line.height = attr.h * EXTRA_H;
+        Stdout.format ("Creating new line of height {}", line.height).newline;
         line.length = attr.w;
         size_t i = 0;
         while (i < lines.length && lines[i].height < line.height) ++i;
@@ -388,7 +417,7 @@
      * FT_LOAD_TARGET_MONO is unsupported.
      *
      * lcdFilter should come from enum FT_LcdFilter:
-     * FT_LCD_FILTER_NONE, FT_LCD_FILTER_DEFAULT, FT_LCD_FILTER_LIGHT */
+     * FT_LCD_FILTER_NONE = 0, FT_LCD_FILTER_DEFAULT = 1, FT_LCD_FILTER_LIGHT = 2 */
     mixin (impl!("int renderMode, lcdFilter;"));
     
     static this() {
--- a/mde/resource/font.d	Sun Jun 01 18:22:54 2008 +0100
+++ b/mde/resource/font.d	Mon Jun 02 14:34:24 2008 +0100
@@ -71,13 +71,20 @@
                 logger.warn (logger.format (tmp, "Using an untested FreeType version: {}.{}.{}", maj, min, patch));
             }
             
-            // Set LCD filtering method
-            if (FT_Library_SetLcdFilter(library, cast(FT_LcdFilter)fontOpts.lcdFilter)) {
+            // Set LCD filtering method (note: FT_Library_SetLcdFilter can still complain with
+            // FT_LcdFilter.FT_LCD_FILTER_NONE).
+            if (fontOpts.lcdFilter && FT_Library_SetLcdFilter(library, cast(FT_LcdFilter)fontOpts.lcdFilter)) {
                 // If setting failed, leave at default (disabled status). Note: it is disabled by
                 // default because the code isn't compiled in by default, to avoid patents.
-                logger.warn ("Bad/unsupported LCD filter option; disabling.");
+                logger.warn ("Bad/unsupported LCD filter option; disabling LCD filtering.");
+                logger.warn ("Your FreeType 2 library may compiled without support for LCD/sub-pixel rendering.");
                 Options.setInt ("font", "lcdFilter", FT_LcdFilter.FT_LCD_FILTER_NONE);
             }
+            const RMF = FT_LOAD_TARGET_MONO | FT_LOAD_TARGET_LCD | FT_LOAD_TARGET_LCD_V;
+            if (fontOpts.renderMode & RMF && fontOpts.lcdFilter == 0) {
+                logger.warn ("Using LCD rendering when LCD filtering is disabled has no effect; disabling.");
+                Options.setInt ("font", "renderMode", FT_LOAD_TARGET_NORMAL);
+            }
             
             /* Load font settings
              *
@@ -208,7 +215,11 @@
      * This function will only actually update the cache if it is invalid, caused either by the
      * font being changed or if cache.cacheVer < 0. */
     void updateBlock (char[] str, ref TextBlock cache) {
-        fontTex.updateCache (face, str, cache);
+        try {
+            fontTex.updateCache (face, str, cache);
+        } catch (Exception e) {
+            logger.warn ("Exception while drawing text: "~e.msg);
+        }
     }
     
     /** Draw a block of text (may inlcude new-lines).
--- a/mde/sdl.d	Sun Jun 01 18:22:54 2008 +0100
+++ b/mde/sdl.d	Mon Jun 02 14:34:24 2008 +0100
@@ -128,7 +128,7 @@
      * the highest supported version but this way we know what we're getting.
      */
     try {
-        DerelictGL.loadVersions(GLVersion.Version13);
+        DerelictGL.loadVersions(GLVersion.Version21);
     } catch (SharedLibProcLoadException e) {
         logger.warn ("Loading OpenGL version 1.3 failed:");
         logger.warn (e.msg);