From 18bece731a894f004357d38e5d692fb997b6c268 Mon Sep 17 00:00:00 2001
From: timoore <timoore>
Date: Fri, 6 Jun 2008 19:02:17 +0000
Subject: [PATCH] Fix GUI and HUD text rendering problems.

After the changes that moved the GUI and HUD to a slave camera, the
texture-based fonts wouldn't display. The main fixes here are making
sure that the TXF textures are all loaded into the font cache early,
and explicitly setting the active texture unit in the GUI / HUD
drawImplementation.
---
 src/Cockpit/hud.cxx   |   1 +
 src/GUI/gui.cxx       |   1 +
 src/GUI/new_gui.cxx   | 124 +++++++++++++++++++++++++++++++++---------
 src/GUI/new_gui.hxx   |  43 ++++++++++++++-
 src/Main/renderer.cxx |   7 ++-
 5 files changed, 145 insertions(+), 31 deletions(-)

diff --git a/src/Cockpit/hud.cxx b/src/Cockpit/hud.cxx
index 606a29efb..564b536dc 100644
--- a/src/Cockpit/hud.cxx
+++ b/src/Cockpit/hud.cxx
@@ -542,6 +542,7 @@ void fgTextList::draw()
     vector<fgText>::iterator lastString = List.end();
 
     glPushAttrib(GL_COLOR_BUFFER_BIT);
+    glEnable(GL_TEXTURE_2D);
     glEnable(GL_BLEND);
     if (HUDprop->isTransparent())
         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
diff --git a/src/GUI/gui.cxx b/src/GUI/gui.cxx
index b730270f5..69b172d1b 100644
--- a/src/GUI/gui.cxx
+++ b/src/GUI/gui.cxx
@@ -80,6 +80,7 @@ public:
         puSetDefaultColourScheme  (0.8, 0.8, 0.9, 1);
 
         FGFontCache *fc = globals->get_fontcache();
+        fc->initializeFonts();
         puFont *GuiFont
             = fc->get(globals->get_locale()->getStringValue("font",
                                                             "typewriter.txf"),
diff --git a/src/GUI/new_gui.cxx b/src/GUI/new_gui.cxx
index 9f67a41d3..c6057b771 100644
--- a/src/GUI/new_gui.cxx
+++ b/src/GUI/new_gui.cxx
@@ -1,5 +1,9 @@
 // new_gui.cxx: implementation of XML-configurable GUI support.
+#include <algorithm>
 #include <iostream>
+#include <cstring>
+#include <sys/types.h>
+#include <dirent.h>
 
 #include "new_gui.hxx"
 
@@ -13,7 +17,6 @@
 
 #include "menubar.hxx"
 #include "dialog.hxx"
-#include "SafeTexFont.hxx"
 
 extern puFont FONT_HELVETICA_14;
 extern puFont FONT_SANS_12B;
@@ -400,10 +403,25 @@ FGColor::merge(const FGColor *color)
 // FGFontCache class.
 ////////////////////////////////////////////////////////////////////////
 
-static const struct {
+namespace
+{
+struct GuiFont
+{
     const char *name;
     puFont *font;
-} guifonts[] = {
+    struct Predicate
+        : public std::unary_function<const GuiFont, bool>
+    {
+        Predicate(const char* name_) : name(name_) {}
+        bool operator() (const GuiFont& f1) const
+        {
+            return std::strcmp(f1.name, name) == 0;
+        }
+        const char* name;
+    };
+};
+
+const GuiFont guifonts[] = {
     { "default",      &FONT_HELVETICA_14 },
     { "FIXED_8x13",   &PUFONT_8_BY_13 },
     { "FIXED_9x15",   &PUFONT_9_BY_15 },
@@ -413,10 +431,11 @@ static const struct {
     { "HELVETICA_12", &PUFONT_HELVETICA_12 },
     { "HELVETICA_14", &FONT_HELVETICA_14 },
     { "HELVETICA_18", &PUFONT_HELVETICA_18 },
-    { "SANS_12B",     &FONT_SANS_12B },
-    { 0, 0 }
+    { "SANS_12B",     &FONT_SANS_12B }
 };
 
+const GuiFont* guifontsEnd = &guifonts[sizeof(guifonts)/ sizeof(guifonts[0])];
+}
 
 FGFontCache::FGFontCache() :
     _initialized(false)
@@ -425,31 +444,59 @@ FGFontCache::FGFontCache() :
 
 FGFontCache::~FGFontCache()
 {
-   map<const string, fnt *>::iterator it, end = _fonts.end();
-   for (it = _fonts.begin(); it != end; ++it)
+   PuFontMap::iterator it, end = _puFonts.end();
+   for (it = _puFonts.begin(); it != end; ++it)
        delete it->second;
 }
 
+inline bool FGFontCache::FntParamsLess::operator()(const FntParams& f1,
+                                                   const FntParams& f2) const
+{
+    int comp = f1.name.compare(f2.name);
+    if (comp < 0)
+        return true;
+    else if (comp > 0)
+        return false;
+    if (f1.size < f2.size)
+        return true;
+    else if (f1.size > f2.size)
+        return false;
+    return f1.slant < f2.slant;
+}
+
 struct FGFontCache::fnt *
 FGFontCache::getfnt(const char *name, float size, float slant)
 {
-    _itt_t it;
-    if ((it = _fonts.find(name)) != _fonts.end())
-        return it->second;
-
-    SGPath path = getfntpath(name);
-
-    fnt *f = new fnt();
-    f->texfont = new flightgear::SafeTexFont;
-
-    if (f->texfont->load((char *)path.c_str())) {
+    string fontName(name);
+    FntParams fntParams(fontName, size, slant);
+    PuFontMap::iterator i = _puFonts.find(fntParams);
+    if (i != _puFonts.end())
+        return i->second;
+    // fntTexFont s are all preloaded into the _texFonts map
+    TexFontMap::iterator texi = _texFonts.find(fontName);
+    fntTexFont* texfont = 0;
+    puFont* pufont = 0;
+    if (texi != _texFonts.end()) {
+        texfont = texi->second;
+    } else {
+        const GuiFont* guifont = std::find_if(&guifonts[0], guifontsEnd,
+                                              GuiFont::Predicate(name));
+        if (guifont != guifontsEnd) {
+            pufont = guifont->font;
+        }
+    }
+    fnt* f = new fnt;
+    if (pufont) {
+        f->pufont = pufont;
+    } else if (texfont) {
+        f->texfont = texfont;
         f->pufont = new puFont;
         f->pufont->initialize(static_cast<fntFont *>(f->texfont), size, slant);
-        return _fonts[name] = f;
+    } else {
+        f->pufont = guifonts[0].font;
     }
-
-    delete f;
-    return _fonts["default"];
+    _puFonts[fntParams] = f;
+    return f;
 }
 
 puFont *
@@ -477,8 +524,7 @@ FGFontCache::get(SGPropertyNode *node)
     return get(name, size, slant);
 }
 
-SGPath
-FGFontCache::getfntpath(const char *name)
+void FGFontCache::init()
 {
     if (!_initialized) {
         char *envp = ::getenv("FG_FONTS");
@@ -488,13 +534,14 @@ FGFontCache::getfntpath(const char *name)
             _path.set(globals->get_fg_root());
             _path.append("Fonts");
         }
-
-        for (int i = 0; guifonts[i].name; i++)
-            _fonts[guifonts[i].name] = new fnt(guifonts[i].font);
-
         _initialized = true;
     }
+}
 
+SGPath
+FGFontCache::getfntpath(const char *name)
+{
+    init();
     SGPath path(_path);
     if (name && std::string(name) != "") {
         path.append(name);
@@ -508,4 +555,27 @@ FGFontCache::getfntpath(const char *name)
     return path;
 }
 
+bool FGFontCache::initializeFonts()
+{
+    static string fontext("txf");
+    init();
+    DIR* fontdir = opendir(_path.c_str());
+    if (!fontdir)
+        return false;
+    const dirent *dirEntry;
+    while ((dirEntry = readdir(fontdir)) != 0) {
+        SGPath path(_path);
+        path.append(dirEntry->d_name);
+        if (path.extension() == fontext) {
+            fntTexFont* f = new fntTexFont;
+            if (f->load((char *)path.c_str()))
+                _texFonts[string(dirEntry->d_name)] = f;
+            else
+                delete f;
+        }
+    }
+    closedir(fontdir);
+    return true;
+}
+
 // end of new_gui.cxx
diff --git a/src/GUI/new_gui.hxx b/src/GUI/new_gui.hxx
index 674bd73e2..3fb1703d2 100644
--- a/src/GUI/new_gui.hxx
+++ b/src/GUI/new_gui.hxx
@@ -18,6 +18,7 @@
 #include <simgear/structure/subsystem_mgr.hxx>
 #include <simgear/misc/sg_path.hxx>
 
+#include <functional>
 #include <vector>
 #include <map>
 
@@ -286,23 +287,51 @@ private:
 
 
 /**
- * A small class to keep all fonts available for future use.
+ * A class to keep all fonts available for future use.
  * This also assures a font isn't resident more than once.
  */
 class FGFontCache {
 private:
+    // The parameters of a request to the cache.
+    struct FntParams
+    {
+        const std::string name;
+        const float size;
+        const float slant;
+        FntParams() : size(0.0f), slant(0.0f) {}
+        FntParams(const FntParams& rhs)
+            : name(rhs.name), size(rhs.size), slant(rhs.slant)
+        {
+        }
+        FntParams(const std::string& name_, float size_, float slant_)
+            : name(name_), size(size_), slant(slant_)
+        {
+        }
+    };
+    struct FntParamsLess
+        : public std::binary_function<const FntParams, const FntParams, bool>
+    {
+        bool operator() (const FntParams& f1, const FntParams& f2) const;
+    };
     struct fnt {
         fnt(puFont *pu = 0) : pufont(pu), texfont(0) {}
         ~fnt() { if (texfont) { delete pufont; delete texfont; } }
+        // Font used by plib GUI code
         puFont *pufont;
+        // TXF font
         fntTexFont *texfont;
     };
+    // Path to the font directory
     SGPath _path;
 
-    map<const string,fnt *> _fonts;
-    typedef map<const string,fnt *>::const_iterator _itt_t;
+    typedef map<const string, fntTexFont*> TexFontMap;
+    typedef map<const FntParams, fnt*, FntParamsLess> PuFontMap;
+    TexFontMap _texFonts;
+    PuFontMap _puFonts;
+
     bool _initialized;
     struct fnt *getfnt(const char *name, float size, float slant);
+    void init();
 
 public:
     FGFontCache();
@@ -314,6 +343,14 @@ public:
     fntTexFont *getTexFont(const char *name, float size=15.0, float slant=0.0);
 
     SGPath getfntpath(const char *name);
+    /**
+     * Preload all the fonts in the FlightGear font directory. It is
+     * important to load the font textures early, with the proper
+     * graphics context current, so that no plib (or our own) code
+     * tries to load a font from disk when there's no current graphics
+     * context.
+     */
+    bool initializeFonts();
 };
 
 
diff --git a/src/Main/renderer.cxx b/src/Main/renderer.cxx
index 8840ca5bb..56b68cc08 100644
--- a/src/Main/renderer.cxx
+++ b/src/Main/renderer.cxx
@@ -159,6 +159,9 @@ public:
   {
     if (!fgOSIsMainContext(state.getGraphicsContext()))
       return;
+    state.setActiveTextureUnit(0);
+    state.setClientActiveTextureUnit(0);
+
     state.disableAllVertexArrays();
 
     glPushAttrib(GL_ALL_ATTRIB_BITS);
@@ -201,7 +204,8 @@ public:
   {
     if (!fgOSIsMainContext(state.getGraphicsContext()))
       return;
-
+    state.setActiveTextureUnit(0);
+    state.setClientActiveTextureUnit(0);
     state.disableAllVertexArrays();
 
     glPushAttrib(GL_ALL_ATTRIB_BITS);
@@ -222,6 +226,7 @@ public:
 
     glPopClientAttrib();
     glPopAttrib();
+
   }
 
   virtual osg::Object* cloneType() const { return new SGHUDAndPanelDrawable; }