changeset 57:9e1f05fbbcef

Coloured and alpha-blended text is now supported. TextWidgets get text colour from argument.
author Diggory Hardy <diggory.hardy@gmail.com>
date Sat, 14 Jun 2008 13:09:03 +0100
parents f9f5e04f20b2
children d43523ed4b62
files codeDoc/jobs.txt codeDoc/mergetag/file-format-binary.txt data/conf/fonts.mtt data/conf/gui.mtt mde/gl/basic.d mde/gui/widget/miscWidgets.d mde/resource/FontTexture.d mde/resource/font.d mde/types/basic.d
diffstat 9 files changed, 145 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/codeDoc/jobs.txt	Sat Jun 14 12:04:25 2008 +0100
+++ b/codeDoc/jobs.txt	Sat Jun 14 13:09:03 2008 +0100
@@ -51,6 +51,6 @@
 1   Mergetag binary support
 
 
-Done (for git log message):
-Implemented gl.texture module to load textures from file (untested).
-Fixed log level/option setting in Init.
\ No newline at end of file
+Done (for mercurial log message):
+Coloured and alpha-blended text is now supported.
+TextWidgets get text colour from argument.
\ No newline at end of file
--- a/codeDoc/mergetag/file-format-binary.txt	Sat Jun 14 12:04:25 2008 +0100
+++ b/codeDoc/mergetag/file-format-binary.txt	Sat Jun 14 13:09:03 2008 +0100
@@ -2,6 +2,9 @@
 License: GNU General Public License version 2 or later (see COPYING)
 
 
+No file format is set yet; this basically includes possibilities. The file format may or may not be compatible across platforms; if not it may just be used as a cache (i.e. open .mtt/.mtb, whichever is newest, and if it's .mtt then save a .mtb version).
+
+
 This is the file format for mergetag binary files. The unit size is a byte. Most numbers to do with the layout (i.e. not stored data) should be stored as a 32-bit uint.
 
 
--- a/data/conf/fonts.mtt	Sat Jun 14 12:04:25 2008 +0100
+++ b/data/conf/fonts.mtt	Sat Jun 14 13:09:03 2008 +0100
@@ -1,5 +1,6 @@
 {MT01}
 <char[]|fallback="default">
+!{Lists available fonts. This data may be moved to options for more generic handling.}
 {default}
 <char[]|path="/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf">
 <int|size=16>
--- a/data/conf/gui.mtt	Sat Jun 14 12:04:25 2008 +0100
+++ b/data/conf/gui.mtt	Sat Jun 14 13:09:03 2008 +0100
@@ -7,7 +7,7 @@
 {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:[0x2]]>
+<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,0xFFFF00]]>
 {WEmbedded}
 <int|x=20>
 <int|y=100>
--- a/mde/gl/basic.d	Sat Jun 14 12:04:25 2008 +0100
+++ b/mde/gl/basic.d	Sat Jun 14 13:09:03 2008 +0100
@@ -24,14 +24,14 @@
 
 //BEGIN GL & window setup
 void glSetup () {
+    glDisable(GL_LIGHTING);
     glDisable(GL_DEPTH_TEST);
     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
     glEnable(GL_TEXTURE_2D);
-    glShadeModel(GL_FLAT);
+    glShadeModel(GL_SMOOTH);
     
     glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
     
--- a/mde/gui/widget/miscWidgets.d	Sat Jun 14 12:04:25 2008 +0100
+++ b/mde/gui/widget/miscWidgets.d	Sat Jun 14 13:09:03 2008 +0100
@@ -106,21 +106,25 @@
 class TextWidget : Widget
 {
     this (IWindow wind, int[] data) {
-        if (data.length != 1) throw new WidgetDataException;
+        if (data.length != 2) throw new WidgetDataException;
         if (font is null) font = FontStyle.get("default");
         font.updateBlock (str, textCache);
         mw = textCache.w;
         mh = textCache.h;
+        colour = Colour (cast(ubyte) (data[1] >> 16u),
+                         cast(ubyte) (data[1] >> 8u),
+                         cast(ubyte) data[1] );
         super (wind,data);
     }
     
     void draw () {
         super.draw();
-        font.textBlock (x,y, str, textCache);	// test new-lines and unicode characters
+        font.textBlock (x,y, str, textCache, colour);	// test new-lines and unicode characters
     }
     
 protected:
     const str = "Text Widget\nαβγ − ΑΒΓ";
     TextBlock textCache;
+    Colour colour;
     static FontStyle font;
 }
--- a/mde/resource/FontTexture.d	Sat Jun 14 12:04:25 2008 +0100
+++ b/mde/resource/FontTexture.d	Sat Jun 14 13:09:03 2008 +0100
@@ -24,6 +24,7 @@
  * matter. However, for the model/world coords, y increases downwards. */
 module mde.resource.FontTexture;
 
+import mde.types.basic;	// Colour
 import mde.Options;
 import mde.resource.exception;
 
@@ -160,15 +161,59 @@
         }
     }
     
-    /** Render a block of text using a cache. Updates the cache if necessary. */
-    void drawTextCache (FT_Face face, char[] str, ref TextBlock cache, int x, int y) {
+    /** Render a block of text using a cache. Updates the cache if necessary.
+     *
+     * Params:
+     *  face =	Current typeface pointer; must be passed from font.d (only needed if the cache is
+     *  	invalid)
+     *  str =	Text to render (only needed if the cache is invalid)
+     *  cache =	Cache used to speed up CPU-side rendering code
+     *  x =	Smaller x-coordinate of position
+     *  y =	Smaller y-coordinate of position
+     *  col =	Text colour (note: currently limited to black or white) */
+    void drawCache (FT_Face face, char[] str, ref TextBlock cache, int x, int y, Colour col ) {
         updateCache (face, str, cache);	// update if necessary
         debug scope (failure)
                 logger.error ("drawTextCache failed");
         
+        // opaque (GL_DECAL would be equivalent)
+        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+        
+        drawCacheImpl (cache, x, y, col);
+    }
+    /** A variation of drawCache, for transparent text.
+     *
+     * Instead of passing the alpha value(s) as arguments, set the openGL colour prior to calling:
+     * ---
+     * glColor3f (.5f, .5f, .5f);	// set alpha to half
+     * drawCacheA (face, ...);
+     * 
+     * glColor3ub (0, 255, 127);	// alpha 0 for red, 1 for green, half for blue
+     * drawCacheA (face, ...);
+     * ---
+     *
+     * The overhead of the transparency is minimal. */
+    void drawCacheA (FT_Face face, char[] str, ref TextBlock cache, int x, int y, Colour col/+ = Colour.WHITE+/) {
+        updateCache (face, str, cache);	// update if necessary
+        debug scope (failure)
+                logger.error ("drawTextCache failed");
+        
+        // transparency alpha
+        // alpha is current colour, per component
+        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+        
+        drawCacheImpl (cache, x, y, col);
+    }
+   
+    private void drawCacheImpl (ref TextBlock cache, int x, int y, Colour col) {
+        if (DerelictGL.availableVersion() >= GLVersion.Version14) {
+            glBlendFunc (GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR);
+            glBlendColor(col.r, col.g, col.b, 1f);	// text colour
+        } else
+            glBlendFunc (col.nearestGLConst, GL_ONE_MINUS_SRC_COLOR);
+        
         glEnable (GL_TEXTURE_2D);
         glEnable(GL_BLEND);
-        glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_COLOR);
         
         foreach (chr; cache.chars) {
             GlyphAttribs* ga = chr.ga;
@@ -281,10 +326,13 @@
     
     void drawTexture () {	// temp func
         if (tex.length == 0) return;
+        glEnable (GL_TEXTURE_2D);
         glBindTexture(GL_TEXTURE_2D, tex[0].texID);
-        glEnable (GL_TEXTURE_2D);
         glEnable(GL_BLEND);
         glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_COLOR);
+        float[4] Cc = [ 1.0f, 1f, 1f, 1f ];
+        glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, Cc.ptr);
+        glColor3f (1f, 0f, 0f);
         
         glBegin (GL_QUADS);
         glTexCoord2f (0f, 0f);	glVertex2i (0, 0);
@@ -312,14 +360,12 @@
     // create a new texture
     static LinePacker create () {
         LinePacker p;
-        //FIXME: check for error?
+        //FIXME: why do I get a blank texture when binding to non-0?
         //glGenTextures (1, &(p.texID));
         p.texID = 0;
-        //FIXME: why do I get a blank texture when using bind?
-        glBindTexture(GL_TEXTURE_2D, p.texID);
         
         // add a pretty background to the texture
-        static if (false) {
+        static if (true) {
             glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
             glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
             ubyte[3][dimH][dimW] testTex;
@@ -335,7 +381,8 @@
             const void* ptr = null;
         
         // Create a texture without initialising values.
-        glTexImage2D(GL_TEXTURE_2D, 0, 3,
+        glBindTexture(GL_TEXTURE_2D, p.texID);
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
                      dimW, dimH, 0,
                      GL_RGB, GL_UNSIGNED_BYTE, ptr);
         return p;
--- a/mde/resource/font.d	Sat Jun 14 12:04:25 2008 +0100
+++ b/mde/resource/font.d	Sat Jun 14 13:09:03 2008 +0100
@@ -16,6 +16,7 @@
 /// Sets up freetype (in a basic way).
 module mde.resource.font;
 
+public import mde.types.basic;	// Colour
 import mde.Options;
 import mde.resource.FontTexture;
 import mde.resource.exception;
@@ -228,7 +229,10 @@
      *
      * The text block is drawn with top-left corner at x,y. To put the text's baseline at a given
      * y coordinate would require some changes. Line height is currently variable, depending on the
-     * highest glyph in the line.
+     * highest glyph in the line (should probably be fixed: FIXME).
+     *
+     * Specify the text's colour with col; currently this is only Colour.WHITE or Colour.BLACK
+     * (FIXME). FIXME: add alpha support.
      *
      * As a CPU-side code optimisation, store a TextBlock (unique to str) and pass a reference as
      * the cache argument. This is the recommended method, although for one-time calls when you
@@ -246,26 +250,37 @@
      * than this cache only serves as a small optimisation. However, the only way to get the size
      * of a text block is to use a TextBlock cache and update it, either with this function or with
      * the updateBlock function. */
-    void textBlock (int x, int y, char[] str, ref TextBlock cache) {
+    void textBlock (int x, int y, char[] str, ref TextBlock cache, Colour col) {
         try {
-            fontTex.drawTextCache (face, str, cache, x, y);
+            fontTex.drawCache (face, str, cache, x, y, col);
         } catch (Exception e) {
             logger.warn ("Exception while drawing text: "~e.msg);
         }
     }
     /** ditto */
-    void textBlock (int x, int y, char[] str) {
+    void textBlock (int x, int y, char[] str, Colour col) {
         try {
             // Using the cache method for one-time use is slightly less than optimal, but doing so
             // isn't really recommended anyway (and maintaining two versions of fontTex.drawText
             // would be horrible).
             TextBlock cache;
-            fontTex.drawTextCache (face, str, cache, x, y);
+            fontTex.drawCache (face, str, cache, x, y, col);
         } catch (Exception e) {
             logger.warn ("Exception while drawing text: "~e.msg);
         }
     }
     
+    /** A variation of textBlock for transparency.
+     *
+     * Set the alpha by calling glColor*() first. See FontTexture.drawCacheA()'s documentation for
+     * details. */
+    void textBlockA (int x, int y, char[] str, ref TextBlock cache, Colour col) {
+        try {
+            fontTex.drawCacheA (face, str, cache, x, y, col);
+        } catch (Exception e) {
+            logger.warn ("Exception while drawing text: "~e.msg);
+        }
+    }
     
     /** The font-specified vertical distance between the baseline of consecutive lines. */
     int getLineSeparation () {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mde/types/basic.d	Sat Jun 14 13:09:03 2008 +0100
@@ -0,0 +1,53 @@
+/* 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 basic types used by mde. Some may be moved to other modules. */
+module mde.types.basic;
+
+//FIXME: remove import and change types or not?
+import derelict.opengl.gltypes;
+
+/// Represent a colour using clamped floats
+struct Colour {
+    /// Returns GL_ONE if total value is nearer white than black, else GL_ZERO.
+    GLenum nearestGLConst () {
+        return r+g+b >= 1.5f ? GL_ONE : GL_ZERO;
+    }
+    
+    GLclampf r,g,b;	/// values
+    
+    static {
+        /// Predefined colours
+        const Colour WHITE = { r:1f, g:1f, b:1f };
+        const Colour BLACK = { r:0f, g:0f, b:0f };	/// ditto
+        
+        /// Construct from floats (doesn't clamp, but GL does when values are passed)
+        Colour opCall (float r, float g, float b) {
+            Colour c;
+            c.r = r;
+            c.g = g;
+            c.b = b;
+            return c;
+        }
+        /// Construct from ubytes
+        Colour opCall (ubyte r, ubyte g, ubyte b) {
+            Colour c;
+            c.r = cast(float) r / 255f;
+            c.g = cast(float) g / 255f;
+            c.b = cast(float) b / 255f;
+            return c;
+        }
+    }
+}