diff -urN ogre-14.1.2/Components/Bites/src/OgreTrays.cpp ogre-14.1.2-fixed/Components/Bites/src/OgreTrays.cpp
--- ogre-14.1.2/Components/Bites/src/OgreTrays.cpp	2023-10-31 09:33:29.000000000 -0500
+++ ogre-14.1.2-fixed/Components/Bites/src/OgreTrays.cpp	2023-12-13 04:38:24.278017175 -0600
@@ -81,11 +81,11 @@
         if (caption[i] == ' ')
         {
             if (area->getSpaceWidth() != 0) lineWidth += area->getSpaceWidth();
-            else lineWidth += font->getGlyphInfo(' ').advance * area->getCharHeight();
+            else lineWidth += font->getGlyphAspectRatio(' ') * area->getCharHeight();
         }
         else if (caption[i] == '\n') break;
         // use glyph information to calculate line width
-        else lineWidth += font->getGlyphInfo(caption[i]).advance * area->getCharHeight();
+        else lineWidth += font->getGlyphAspectRatio(caption[i]) * area->getCharHeight();
     }
 
     return (unsigned int)lineWidth;
@@ -105,7 +105,7 @@
     for (unsigned int i = 0; i < s.length(); i++)
     {
         if (s[i] == ' ' && area->getSpaceWidth() != 0) width += area->getSpaceWidth();
-        else width += f->getGlyphInfo(s[i]).advance * area->getCharHeight();
+        else width += f->getGlyphAspectRatio(s[i]) * area->getCharHeight();
         if (width > maxWidth)
         {
             s = s.substr(0, i);
@@ -247,7 +247,7 @@
         if (current[i] == ' ')
         {
             if (mTextArea->getSpaceWidth() != 0) lineWidth += mTextArea->getSpaceWidth();
-            else lineWidth += font->getGlyphInfo(' ').advance * mTextArea->getCharHeight();
+            else lineWidth += font->getGlyphAspectRatio(' ') * mTextArea->getCharHeight();
             firstWord = false;
             lastSpace = i;
         }
@@ -261,7 +261,7 @@
         else
         {
             // use glyph information to calculate line width
-            lineWidth += font->getGlyphInfo(current[i]).advance * mTextArea->getCharHeight();
+            lineWidth += font->getGlyphAspectRatio(current[i]) * mTextArea->getCharHeight();
             if (lineWidth > rightBoundary)
             {
                 if (firstWord)
diff -urN ogre-14.1.2/Components/Overlay/include/OgreFont.h ogre-14.1.2-fixed/Components/Overlay/include/OgreFont.h
--- ogre-14.1.2/Components/Overlay/include/OgreFont.h	2023-10-31 09:33:29.000000000 -0500
+++ ogre-14.1.2-fixed/Components/Overlay/include/OgreFont.h	2023-12-13 04:38:24.346018049 -0600
@@ -32,7 +32,6 @@
 #include "OgreCommon.h"
 #include "OgreSharedPtr.h"
 #include "OgreColourValue.h"
-#include "OgreException.h"
 
 namespace Ogre
 {
@@ -58,19 +57,6 @@
     };
 
 
-    /// Information about the position and size of a glyph in a texture
-    struct GlyphInfo
-    {
-        typedef uint32 CodePoint;
-        typedef FloatRect UVRect;
-
-        CodePoint codePoint;
-        UVRect uvRect;
-        float aspectRatio; // width/ height
-        float bearing; // bearingX/ height
-        float advance; // advanceX/ height
-    };
-
     /** Class representing a font in the system.
 
     This class is simply a way of getting a font texture into the OGRE system and
@@ -102,8 +88,21 @@
 
 
     public:
-        typedef GlyphInfo::CodePoint CodePoint;
-        typedef GlyphInfo::UVRect UVRect;
+        typedef Ogre::uint32 CodePoint;
+        typedef Ogre::FloatRect UVRect;
+        /// Information about the position and size of a glyph in a texture
+        struct GlyphInfo 
+        {
+            CodePoint codePoint;
+            UVRect uvRect;
+            Real aspectRatio;
+
+            GlyphInfo(CodePoint id, const UVRect& rect, Real aspect)
+                : codePoint(id), uvRect(rect), aspectRatio(aspect)
+            {
+
+            }
+        };
         /// A range of code points, inclusive on both ends
         typedef std::pair<CodePoint, CodePoint> CodePointRange;
         typedef std::vector<CodePointRange> CodePointRangeList;
@@ -208,7 +207,19 @@
             @return A rectangle with the UV coordinates, or null UVs if the
                 code point was not present
         */
-        const UVRect& getGlyphTexCoords(CodePoint id) const { return getGlyphInfo(id).uvRect; }
+        inline const UVRect& getGlyphTexCoords(CodePoint id) const
+        {
+            CodePointMap::const_iterator i = mCodePointMap.find(id);
+            if (i != mCodePointMap.end())
+            {
+                return i->second.uvRect;
+            }
+            else
+            {
+                static UVRect nullRect(0.0, 0.0, 0.0, 0.0);
+                return nullRect;
+            }
+        }
 
         /** Sets the texture coordinates of a glyph.
 
@@ -217,22 +228,42 @@
             Also sets the aspect ratio (width / height) of this character. textureAspect
             is the width/height of the texture (may be non-square)
         */
-        void setGlyphInfoFromTexCoords(CodePoint id, const UVRect& rect, float textureAspect = 1.0)
+        inline void setGlyphTexCoords(CodePoint id, Real u1, Real v1, Real u2, Real v2, Real textureAspect)
         {
-            auto glyphAspect = textureAspect * rect.width()  / rect.height();
-            setGlyphInfo({id, rect, glyphAspect, 0, glyphAspect});
-        }
-
-        void setGlyphInfo(const GlyphInfo& info) { mCodePointMap[info.codePoint] = info; }
+            CodePointMap::iterator i = mCodePointMap.find(id);
+            if (i != mCodePointMap.end())
+            {
+                i->second.uvRect.left = u1;
+                i->second.uvRect.top = v1;
+                i->second.uvRect.right = u2;
+                i->second.uvRect.bottom = v2;
+                i->second.aspectRatio = textureAspect * (u2 - u1)  / (v2 - v1);
+            }
+            else
+            {
+                mCodePointMap.emplace(id, GlyphInfo(id, UVRect(u1, v1, u2, v2), textureAspect * (u2 - u1) / (v2 - v1)));
+            }
 
+        }
         /** Gets the aspect ratio (width / height) of this character. */
-        float getGlyphAspectRatio(CodePoint id) const { return getGlyphInfo(id).aspectRatio; }
+        inline Real getGlyphAspectRatio(CodePoint id) const
+        {
+            CodePointMap::const_iterator i = mCodePointMap.find(id);
+            if (i != mCodePointMap.end())
+            {
+                return i->second.aspectRatio;
+            }
+            else
+            {
+                return 1.0;
+            }
+        }
         /** Sets the aspect ratio (width / height) of this character.
 
             You only need to call this if you're setting up a font loaded from a 
             texture manually.
         */
-        void setGlyphAspectRatio(CodePoint id, Real ratio)
+        inline void setGlyphAspectRatio(CodePoint id, Real ratio)
         {
             CodePointMap::iterator i = mCodePointMap.find(id);
             if (i != mCodePointMap.end())
@@ -244,22 +275,7 @@
         /** Gets the information available for a glyph corresponding to a
             given code point, or throws an exception if it doesn't exist;
         */
-        const GlyphInfo& getGlyphInfo(CodePoint id) const
-        {
-            CodePointMap::const_iterator i = mCodePointMap.find(id);
-            if (i == mCodePointMap.end())
-            {
-                // Try a fallback first.
-                i = mCodePointMap.find(static_cast<CodePoint>('?'));
-
-                if (i == mCodePointMap.end())
-                {
-                    OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, StringUtil::format(
-                        "Code point %d and fallback 63 not found in font %s", id, mName.c_str()));
-                }
-            }
-            return i->second;
-        }
+        const GlyphInfo& getGlyphInfo(CodePoint id) const;
 
         /** Adds a range of code points to the list of code point ranges to generate
             glyphs for, if this is a truetype based font.
diff -urN ogre-14.1.2/Components/Overlay/src/OgreFont.cpp ogre-14.1.2-fixed/Components/Overlay/src/OgreFont.cpp
--- ogre-14.1.2/Components/Overlay/src/OgreFont.cpp	2023-10-31 09:33:29.000000000 -0500
+++ ogre-14.1.2-fixed/Components/Overlay/src/OgreFont.cpp	2023-12-13 04:38:24.382018513 -0600
@@ -30,6 +30,7 @@
 #include "OgreTexture.h"
 #include "OgreLogManager.h"
 #include "OgreStringConverter.h"
+#include "OgreException.h"
 #include "OgreTextureUnitState.h"
 #include "OgreTechnique.h"
 #include "OgreBitwise.h"
@@ -205,6 +206,18 @@
         return mTtfMaxBearingY;
     }
     //---------------------------------------------------------------------
+    const Font::GlyphInfo& Font::getGlyphInfo(CodePoint id) const
+    {
+        CodePointMap::const_iterator i = mCodePointMap.find(id);
+        if (i == mCodePointMap.end())
+        {
+            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 
+                "Code point " + StringConverter::toString(id) + " not found in font "
+                + mName, "Font::getGlyphInfo");
+        }
+        return i->second;
+    }
+    //---------------------------------------------------------------------
     void Font::_setMaterial(const MaterialPtr &mat)
     {
         mMaterial = mat;
@@ -220,6 +233,8 @@
         bbs->setBillboardOrigin(BBO_CENTER_LEFT);
         bbs->setDefaultDimensions(0, 0);
 
+        float spaceWidth = mCodePointMap.find('0')->second.aspectRatio * height;
+
         text.resize(text.size() + 3); // add padding for decoder
         auto it = text.c_str();
         auto end = text.c_str() + text.size() - 3;
@@ -236,6 +251,12 @@
             if(err)
                 continue;
 
+            if (cpId == ' ')
+            {
+                left += spaceWidth;
+                continue;
+            }
+
             if(cpId == '\n')
             {
                 top -= height;
@@ -243,18 +264,16 @@
                 continue;
             }
 
-            const auto& cp = getGlyphInfo(cpId);
-
-            left += cp.bearing * height;
+            auto cp = mCodePointMap.find(cpId);
+            if (cp == mCodePointMap.end())
+                continue;
 
-            if(!cp.uvRect.isNull())
-            {
-                auto bb = bbs->createBillboard(Vector3(left, top, 0), colour);
-                bb->setDimensions(cp.aspectRatio * height, height);
-                bb->setTexcoordRect(cp.uvRect);
-            }
+            float width = cp->second.aspectRatio * height;
+            auto bb = bbs->createBillboard(Vector3(left, top, 0), colour);
+            bb->setDimensions(width, height);
+            bb->setTexcoordRect(cp->second.uvRect);
 
-            left += (cp.advance - cp.bearing) * height;
+            left += width;
         }
     }
 
@@ -350,7 +369,7 @@
         // If codepoints not supplied, assume ASCII
         if (mCodePointRangeList.empty())
         {
-            mCodePointRangeList.push_back(CodePointRange(32, 126));
+            mCodePointRangeList.push_back(CodePointRange(33, 126));
         }
         float vpScale = OverlayManager::getSingleton().getPixelRatio();
 #ifdef HAVE_FREETYPE
@@ -386,9 +405,9 @@
             {
                 FT_Load_Char( face, cp, FT_LOAD_RENDER );
 
-                max_height = std::max<FT_Pos>(2 * face->glyph->bitmap.rows - (face->glyph->metrics.horiBearingY >> 6), max_height);
-                mTtfMaxBearingY = std::max(int(face->glyph->metrics.horiBearingY >> 6), mTtfMaxBearingY);
-                max_width = std::max<FT_Pos>(face->glyph->bitmap.width, max_width);
+                max_height = std::max<FT_Pos>(2 * (face->glyph->bitmap.rows << 6) - face->glyph->metrics.horiBearingY, max_height);
+                mTtfMaxBearingY = std::max(int(face->glyph->metrics.horiBearingY), mTtfMaxBearingY);
+                max_width = std::max<FT_Pos>((face->glyph->advance.x >> 6) + (face->glyph->metrics.horiBearingX >> 6), max_width);
             }
 
         }
@@ -458,21 +477,22 @@
                 if (ftResult)
                 {
                     // problem loading this glyph, continue
-                    LogManager::getSingleton().logError(
-                        StringUtil::format("Charcode %u is not in font %s", cp, mSource.c_str()));
+                    LogManager::getSingleton().logError(StringUtil::format(
+                        "Freetype could not load charcode %u in font %s", cp, mSource.c_str()));
                     continue;
                 }
 
                 buffer = face->glyph->bitmap.buffer;
-                OgreAssertDbg(buffer || (!face->glyph->bitmap.width && !face->glyph->bitmap.rows), "attempting to load NULL buffer");
+                if (!buffer)
+                {
+                    // Yuck, FT didn't detect this but generated a null pointer!
+                    LogManager::getSingleton().logWarning(StringUtil::format(
+                        "Freetype did not find charcode %u in font %s", cp, mSource.c_str()));
+                    continue;
+                }
 
                 uint advance = face->glyph->advance.x >> 6;
-                uint width = face->glyph->bitmap.width;
-                buffer_pitch = face->glyph->bitmap.pitch;
-                buffer_h = face->glyph->bitmap.rows;
 
-                FT_Pos y_bearing = mTtfMaxBearingY - (face->glyph->metrics.horiBearingY >> 6);
-                FT_Pos x_bearing = face->glyph->metrics.horiBearingX >> 6;
 #else
                 int idx = stbtt_FindGlyphIndex(&font, cp);
                 if (!idx)
@@ -496,18 +516,27 @@
                 // stbtt_GetGlyphHMetrics(&font, cp, &advance, &x_bearing);
 #endif
                 // If at end of row
-                if( finalWidth - 1 < l + width )
+                if( finalWidth - 1 < l + ( advance ) )
                 {
                     m += max_height + char_spacer;
                     l = 0;
                 }
 
-                for(int j = 0; j < buffer_h; j++ )
+                FT_Pos y_bearing = ( mTtfMaxBearingY >> 6 ) - ( face->glyph->metrics.horiBearingY >> 6 );
+                FT_Pos x_bearing = face->glyph->metrics.horiBearingX >> 6;
+
+                // x_bearing might be negative
+                uint x_offset = std::max(0, int(x_bearing));
+                // width might be larger than advance
+                uint start = x_offset - x_bearing; // case x_bearing is negative
+                uint width = std::min(face->glyph->bitmap.width - start, advance - x_offset);
+
+                for(unsigned int j = 0; j < face->glyph->bitmap.rows; j++ )
                 {
-                    uchar* pSrc = buffer + j * buffer_pitch;
-                    uint32 row = j + m + y_bearing;
-                    uchar* pDest = img.getData(l, row);
-                    for(unsigned int k = 0; k < width; k++ )
+                    uchar* pSrc = face->glyph->bitmap.buffer + j * face->glyph->bitmap.pitch + start;
+                    size_t row = j + m + y_bearing;
+                    uchar* pDest = img.getData(l + x_offset, row);
+                    for(unsigned int k = 0; k < (width); k++ )
                     {
                         if (mAntialiasColour)
                         {
@@ -525,16 +554,16 @@
                     }
                 }
 
-                UVRect uvs((Real)l / (Real)finalWidth,                   // u1
-                           (Real)m / (Real)finalHeight,                  // v1
-                           (Real)(l + width) / (Real)finalWidth,         // u2
-                           (m + max_height) / (Real)finalHeight); // v2
-                this->setGlyphInfo({cp, uvs, float(textureAspect * uvs.width() / uvs.height()),
-                                    float(x_bearing) / max_height, float(advance) / max_height});
+                this->setGlyphTexCoords(cp,
+                    (Real)l / (Real)finalWidth,  // u1
+                    (Real)m / (Real)finalHeight,  // v1
+                    (Real)( l + advance ) / (Real)finalWidth, // u2
+                    ( m + ( max_height >> 6 ) ) / (Real)finalHeight, // v2
+                    textureAspect
+                    );
 
                 // Advance a column
-                if(width)
-                    l += (width + char_spacer);
+                l += (advance + char_spacer);
             }
         }
 #ifdef HAVE_FREETYPE
diff -urN ogre-14.1.2/Components/Overlay/src/OgreOverlayTranslator.cpp ogre-14.1.2-fixed/Components/Overlay/src/OgreOverlayTranslator.cpp
--- ogre-14.1.2/Components/Overlay/src/OgreOverlayTranslator.cpp	2023-10-31 09:33:29.000000000 -0500
+++ ogre-14.1.2-fixed/Components/Overlay/src/OgreOverlayTranslator.cpp	2023-12-13 04:38:24.382018513 -0600
@@ -92,8 +92,8 @@
             // Direct character
             cp = val[0];
         }
-        pFont->setGlyphInfoFromTexCoords(
-            cp, FloatRect(coords[0], coords[1], coords[2], coords[3])); // assume image is square
+        pFont->setGlyphTexCoords(cp, coords[0], coords[1], coords[2], coords[3],
+                                 1.0); // assume image is square
     }
     else if (attrib == "antialias_colour")
     {
@@ -216,9 +216,6 @@
                 succ = getString(prop->values.front(), &val);
             }
 
-            if(prop->name == "space_width")
-                compiler->addError(ScriptCompiler::CE_DEPRECATEDSYMBOL, prop->file, prop->line, prop->name);
-
             if(!succ || !newElement->setParameter(prop->name, val))
                 compiler->addError(ScriptCompiler::CE_INVALIDPARAMETERS, prop->file, prop->line);
         }
diff -urN ogre-14.1.2/Components/Overlay/src/OgreTextAreaOverlayElement.cpp ogre-14.1.2-fixed/Components/Overlay/src/OgreTextAreaOverlayElement.cpp
--- ogre-14.1.2/Components/Overlay/src/OgreTextAreaOverlayElement.cpp	2023-10-31 09:33:29.000000000 -0500
+++ ogre-14.1.2-fixed/Components/Overlay/src/OgreTextAreaOverlayElement.cpp	2023-12-13 04:38:24.386018564 -0600
@@ -105,6 +105,7 @@
     #define UNICODE_CR 0x000D
     #define UNICODE_LF 0x000A
     #define UNICODE_SPACE 0x0020
+    #define UNICODE_ZERO 0x0030
     //---------------------------------------------------------------------
     TextAreaOverlayElement::TextAreaOverlayElement(const String& name)
         : OverlayElement(name), mColourBottom(ColourValue::White), mColourTop(ColourValue::White)
@@ -245,6 +246,12 @@
         float left = _getDerivedLeft() * 2.0f - 1.0f;
         float top = -( (_getDerivedTop() * 2.0f ) - 1.0f );
 
+        // Derive space with from a number 0
+        if(mSpaceWidth == 0)
+        {
+            mSpaceWidth = mFont->getGlyphAspectRatio(UNICODE_ZERO) * mCharHeight;
+        }
+
         // Use iterator
         auto iend = decoded.end();
         bool newLine = true;
@@ -262,13 +269,13 @@
                     {
                         break;
                     }
-                    else if (character == UNICODE_SPACE && mSpaceWidth) // space
+                    else if (character == UNICODE_SPACE) // space
                     {
                         len += mSpaceWidth * 2.0f * mViewportAspectCoef;
                     }
                     else 
                     {
-                        len += mFont->getGlyphInfo(character).advance * mCharHeight * 2.0f * mViewportAspectCoef;
+                        len += mFont->getGlyphAspectRatio(character) * mCharHeight * 2.0f * mViewportAspectCoef;
                     }
                 }
 
@@ -305,7 +312,7 @@
                 }
                 continue;
             }
-            else if (character == UNICODE_SPACE && mSpaceWidth) // space
+            else if (character == UNICODE_SPACE) // space
             {
                 // Just leave a gap, no tris
                 left += mSpaceWidth * 2.0f * mViewportAspectCoef;
@@ -318,17 +325,6 @@
             Real horiz_height = glyphInfo.aspectRatio * mViewportAspectCoef ;
             const Font::UVRect& uvRect = glyphInfo.uvRect;
 
-            if(uvRect.isNull())
-            {
-                // Just leave a gap, no tris
-                left += glyphInfo.advance * mCharHeight * 2.0f * mViewportAspectCoef;
-                // Also reduce tri count
-                mRenderOp.vertexData->vertexCount -= 6;
-                continue;
-            }
-
-            left += glyphInfo.bearing * mCharHeight * 2 * mViewportAspectCoef;
-
             // each vert is (x, y, z, u, v)
             //-------------------------------------------------------------------------------------
             // First tri
@@ -393,10 +389,6 @@
             // Go back up with top
             top += mCharHeight * 2.0f;
 
-            // advance
-            left -= horiz_height  * mCharHeight * 2.0f;
-            left += (glyphInfo.advance  - glyphInfo.bearing) * mCharHeight * 2.0f * mViewportAspectCoef;
-
             float currentWidth = (left + 1)/2 - _getDerivedLeft();
             if (currentWidth > largestWidth)
             {
diff -urN ogre-14.1.2/Docs/src/scripts.md ogre-14.1.2-fixed/Docs/src/scripts.md
--- ogre-14.1.2/Docs/src/scripts.md	2023-10-31 09:33:29.000000000 -0500
+++ ogre-14.1.2-fixed/Docs/src/scripts.md	2023-12-13 04:38:06.313785998 -0600
@@ -1293,6 +1293,6 @@
 
 @param antialias\_colour <b>&lt;true|false&gt;</b> This is an optional flag, which defaults to `false`. The generator will antialias the font by default using the alpha component of the texture, which will look fine if you use alpha blending to render your text (this is the default assumed by TextAreaOverlayElement for example). If, however you wish to use a colour based blend like add or modulate in your own code, you should set this to `true` so the colour values are anti-aliased too. If you set this to true and use alpha blending, you’ll find the edges of your font are antialiased too quickly resulting in a *thin* look to your fonts, because not only is the alpha blending the edges, the colour is fading too. Leave this option at the default if in doubt.
 
-@param code\_points <b>nn-nn \[nn-nn\] ..</b> This directive allows you to specify which unicode code points should be generated as glyphs into the font texture. If you don’t specify this, code points 32-126 will be generated by default which covers the ASCII glyphs. If you use this flag, you should specify a space-separated list of inclusive code point ranges of the form ’start-end’. Numbers must be decimal.
+@param code\_points <b>nn-nn \[nn-nn\] ..</b> This directive allows you to specify which unicode code points should be generated as glyphs into the font texture. If you don’t specify this, code points 33-126 will be generated by default which covers the ASCII glyphs. If you use this flag, you should specify a space-separated list of inclusive code point ranges of the form ’start-end’. Numbers must be decimal.
 
 You can also create new fonts at runtime by using the FontManager if you wish.
diff -urN ogre-14.1.2/Tests/Media/BillboardText.fontdef ogre-14.1.2-fixed/Tests/Media/BillboardText.fontdef
--- ogre-14.1.2/Tests/Media/BillboardText.fontdef	2023-10-31 09:33:29.000000000 -0500
+++ ogre-14.1.2-fixed/Tests/Media/BillboardText.fontdef	2023-12-13 04:38:06.313785998 -0600
@@ -4,5 +4,5 @@
 	source 		DejaVuSerifCondensed-Italic.ttf
 	size 		15
 	resolution 	180
-	code_points 32-126 192-255
+	code_points 33-126 192-255
 }
\ No newline at end of file
