Loading font from memory

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
desertkun
Posts: 1
Joined: Thu May 24, 2012 7:40 am

Loading font from memory

Post by desertkun »

Hello eweryone!
As you can know, irrlicht don't allows to load fonts from memory by default, and IGUIEnvironment contains only

Code: Select all

IGUIFont* getFont(const c8* filename)
method that allows to load font from file.

I've didn't find any solution here, so i decided to make my own one by patching irrlicht.
Irrlicht can emulate files from memory by

Code: Select all

IReadFile* createMemoryReadFile(void* memory, s32 len, const c8* fileName, bool deleteMemoryWhenDropped=false)
method. So, I've added mew method to the IGUIEnvironment class:

Code: Select all

IGUIFont* getFont(irr::io::IReadFile* xmlFile, irr::core::map<irr::core::stringc, irr::io::IReadFile*>& file)
First argument — the main font file (xml), of course, it's can be emulated from memory.
Second one — the map of other files needed for font (textures). The keys of map is file names only (e.g. texture0.png) without any path ("/"). The values of map — texture files, could be emulated from memory.

You can find patch for Irrlicht 1.5 at the bottom of the message, but you shold locate it into root directory (with include, source, doc ...) and apply it via SVN.

Example of usage:

Code: Select all

IGUIEnvironment *env = /* blah blah blah */;
IFileSystem *sys = /* blah blah blah */;
IReadFile* fontXML = sys->createMemoryReadFile(/* pointer to xml file in memory */, /* size of it */, "lucida.xml");
irr::core::map<irr::core::stringc, irr::io::IReadFile*> otherFiles;
otherFiles["lucida0.png"] = sys->createMemoryReadFile(/* pointer to texture file in memory */, /* size of it */, "lucida0.png");
IGUIFont *fnt = env->getFont(fontXML, otherFiles);
Of course, you should rebuild irrlicht if you use dll to use this feature :)

PATCH FOR IRRLICTH 1.5:

Code: Select all

Index: include/IGUIEnvironment.h
===================================================================
--- include/IGUIEnvironment.h   (revision 4513)
+++ include/IGUIEnvironment.h   (working copy)
@@ -11,6 +11,7 @@
 #include "EMessageBoxFlags.h"
 #include "IEventReceiver.h"
 #include "IXMLReader.h"
+#include "irrMap.h"
 
 namespace irr
 {
@@ -150,7 +151,16 @@
    \return Pointer to the font. Returns 0 if the font could not be loaded.
    This pointer should not be dropped. See IReferenceCounted::drop() for
    more information. */
-   virtual IGUIFont* getFont(const c8* filename) = 0;
+   virtual IGUIFont* getFont(const c8* filename) = 0;  
+   
+   //! Returns pointer to the font with the specified filereader.
+   /** Loads the font if it was not loaded before.
+   \param xmlFile File contains xml config for font
+   \param files Map of files that should be loaded to font (textures). The key is filenames.
+   \return Pointer to the font. Returns 0 if the font could not be loaded.
+   This pointer should not be dropped. See IReferenceCounted::drop() for
+   more information. */
+   virtual IGUIFont* getFont(irr::io::IReadFile* xmlFile, irr::core::map<irr::core::stringc, irr::io::IReadFile*>& file) = 0;
 
    //! Returns the default built-in font.
    /** \return Pointer to the default built-in font.
Index: source/CGUIEnvironment.cpp
===================================================================
--- source/CGUIEnvironment.cpp  (revision 4513)
+++ source/CGUIEnvironment.cpp  (working copy)
@@ -1287,7 +1287,76 @@
    return t;
 }
 
+//! returns the font
+IGUIFont* CGUIEnvironment::getFont(irr::io::IReadFile* xmlFile, irr::core::map<irr::core::stringc, irr::io::IReadFile*>& file)
+{
+   SFont f;
+   IGUIFont* ifont=0;
 
+   // if file does not have files
+   if (file.isEmpty())
+   {
+       return 0;
+   }
+
+   io::IXMLReader *xml = FileSystem->createXMLReader(xmlFile);
+   if (xml)
+   {
+       // this is an XML font, but we need to know what type
+       EGUI_FONT_TYPE t = EGFT_CUSTOM;
+
+       bool found=false;
+       while(xml->read() && !found)
+       {
+           if (xml->getNodeType() == io::EXN_ELEMENT)
+           {
+               if (core::stringw(L"font") == xml->getNodeName())
+               {
+                   if (core::stringw(L"vector") == xml->getAttributeValue(L"type"))
+                   {
+                       t = EGFT_VECTOR;
+                       found=true;
+                   }
+                   else if (core::stringw(L"bitmap") == xml->getAttributeValue(L"type"))
+                   {
+                       t = EGFT_BITMAP;
+                       found=true;
+                   }
+                   else found=true;
+               }
+           }
+       }
+
+       if (t==EGFT_BITMAP)
+       {
+           CGUIFont* font = new CGUIFont(this, "");
+           ifont = (IGUIFont*)font;
+
+           // load the font
+           if (!font->load(xml, file))
+           {
+               font->drop();
+               font  = 0;
+               ifont = 0;
+           }
+       }
+       else if (t==EGFT_VECTOR)
+       {
+           // todo: vector fonts
+           os::Printer::log("Unable to load font, XML vector fonts are not supported yet", f.Filename.c_str(), ELL_ERROR);
+       
+       }
+       xml->drop();
+   }
+
+   // add to fonts.
+
+   f.Font = ifont;
+   Fonts.push_back(f);
+
+   return ifont;
+}
+
 //! returns the font
 IGUIFont* CGUIEnvironment::getFont(const c8* filename)
 {
Index: source/CGUIEnvironment.h
===================================================================
--- source/CGUIEnvironment.h    (revision 4513)
+++ source/CGUIEnvironment.h    (working copy)
@@ -73,6 +73,9 @@
    //! returns the font
    virtual IGUIFont* getFont(const c8* filename);
 
+   //! returns the font
+   virtual IGUIFont* getFont(irr::io::IReadFile* xmlFile, irr::core::map<irr::core::stringc, irr::io::IReadFile*>& file);
+
    //! returns the sprite bank
    virtual IGUISpriteBank* getSpriteBank(const c8* filename);
 
Index: source/CGUIFont.cpp
===================================================================
--- source/CGUIFont.cpp (revision 4513)
+++ source/CGUIFont.cpp (working copy)
@@ -186,7 +186,146 @@
    return true;
 }
 
+//! loads a font file from xml
+bool CGUIFont::load(io::IXMLReader* xml, irr::core::map<irr::core::stringc, irr::io::IReadFile*>& files)
+{
+   if (!SpriteBank)
+       return false;
 
+   while (xml->read())
+   {
+       if (io::EXN_ELEMENT == xml->getNodeType())
+       {
+           if (core::stringw(L"Texture") == xml->getNodeName())
+           {
+               // add a texture
+               core::stringc fn = xml->getAttributeValue(L"filename");
+               u32 i = (u32)xml->getAttributeValueAsInt(L"index");
+               core::stringw alpha = xml->getAttributeValue(L"hasAlpha");
+
+               irr::core::map<irr::core::stringc, irr::io::IReadFile*>::Node* it = 
+                   files.find(fn);
+
+               if (it)
+               {
+
+                   while (i+1 > SpriteBank->getTextureCount())
+                       SpriteBank->addTexture(0);
+
+                   // disable mipmaps+filtering
+                   bool mipmap = Driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS);
+                   Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
+
+                   // load texture
+                   SpriteBank->setTexture(i, Driver->getTexture(it->getValue()));
+
+                   // set previous mip-map+filter state
+                   Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, mipmap);
+
+                   // couldn't load texture, abort.
+                   if (!SpriteBank->getTexture(i))
+                   {
+                       os::Printer::log("Unable to load all textures in the font, aborting", ELL_ERROR);
+                       _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
+                       return false;
+                   }
+                   else
+                   {
+                       // colorkey texture rather than alpha channel?
+                       if (alpha == core::stringw("false"))
+                           Driver->makeColorKeyTexture(SpriteBank->getTexture(i), core::position2di(0,0));
+                   }
+               }
+           }
+           else if (core::stringw(L"c") == xml->getNodeName())
+           {
+               // adding a character to this font
+               SFontArea a;
+               SGUISpriteFrame f;
+               SGUISprite s;
+               core::rect<s32> rectangle;
+
+               a.underhang     = xml->getAttributeValueAsInt(L"u");
+               a.overhang      = xml->getAttributeValueAsInt(L"o");
+               a.spriteno      = SpriteBank->getSprites().size();
+               s32 texno       = xml->getAttributeValueAsInt(L"i");
+
+               // parse rectangle
+               core::stringc rectstr   = xml->getAttributeValue(L"r");
+               wchar_t ch      = xml->getAttributeValue(L"c")[0];
+
+               const c8 *c = rectstr.c_str();
+               s32 val;
+               val = 0;
+               while (*c >= '0' && *c <= '9')
+               {
+                   val *= 10;
+                   val += *c - '0';
+                   c++;
+               }
+               rectangle.UpperLeftCorner.X = val;
+               while (*c == L' ' || *c == L',') c++;
+
+               val = 0;
+               while (*c >= '0' && *c <= '9')
+               {
+                   val *= 10;
+                   val += *c - '0';
+                   c++;
+               }
+               rectangle.UpperLeftCorner.Y = val;
+               while (*c == L' ' || *c == L',') c++;
+
+               val = 0;
+               while (*c >= '0' && *c <= '9')
+               {
+                   val *= 10;
+                   val += *c - '0';
+                   c++;
+               }
+               rectangle.LowerRightCorner.X = val;
+               while (*c == L' ' || *c == L',') c++;
+
+               val = 0;
+               while (*c >= '0' && *c <= '9')
+               {
+                   val *= 10;
+                   val += *c - '0';
+                   c++;
+               }
+               rectangle.LowerRightCorner.Y = val;
+
+               CharacterMap.insert(ch,Areas.size());
+
+               // make frame
+               f.rectNumber = SpriteBank->getPositions().size();
+               f.textureNumber = texno;
+
+               // add frame to sprite
+               s.Frames.push_back(f);
+               s.frameTime = 0;
+
+               // add rectangle to sprite bank
+               SpriteBank->getPositions().push_back(rectangle);
+               a.width = rectangle.getWidth();
+
+               // add sprite to sprite bank
+               SpriteBank->getSprites().push_back(s);
+
+               // add character to font
+               Areas.push_back(a);
+           }
+       }
+   }
+
+   // set bad character
+   WrongCharacter = getAreaFromCharacter(L' ');
+
+   setMaxHeight();
+
+   return true;
+}
+
 void CGUIFont::setMaxHeight()
 {
    MaxHeight = 0;
Index: source/CGUIFont.h
===================================================================
--- source/CGUIFont.h   (revision 4513)
+++ source/CGUIFont.h   (working copy)
@@ -48,6 +48,9 @@
    //! loads a font from an XML file
    bool load(io::IXMLReader* xml);
 
+   //! loads a font from an XML file and list of texture files 
+   bool load(io::IXMLReader* xml, irr::core::map<irr::core::stringc, irr::io::IReadFile*>& files);
+
    //! draws an text and clips it to the specified rectangle if wanted
    virtual void draw(const wchar_t* text, const core::rect<s32>& position,
            video::SColor color, bool hcenter=false,
Post Reply