Browse Source

Added back bitmap font support for backward compatibility.
Added auto-hinting on freetype bitmap output.

seanpaultaylor 12 years ago
parent
commit
fa895b61e2

+ 11 - 1
gameplay/res/shaders/font.frag

@@ -5,16 +5,26 @@ precision highp float;
 
 // Uniforms
 uniform sampler2D u_texture;
+#ifdef DISTANCE_FIELD
+uniform vec2 u_cutoff;
+#endif
 
 // Varyings
 varying vec2 v_texCoord;
 varying vec4 v_color;
 
+
 void main()
 { 
+#ifdef DISTANCE_FIELD
     gl_FragColor = v_color;
     float distance = texture2D(u_texture, v_texCoord).a;
     float smoothing = fwidth(distance);
-    float alpha = smoothstep(0.5 - smoothing, 0.5 + smoothing, distance);
+    float alpha = smoothstep(0.5 - smoothing * u_cutoff.x, 0.5 + smoothing * u_cutoff.y, distance);
     gl_FragColor.a = alpha * v_color.a;
+
+#else
+    gl_FragColor = v_color;
+    gl_FragColor.a = texture2D(u_texture, v_texCoord).a * v_color.a;
+#endif
 }

+ 39 - 8
gameplay/src/Bundle.cpp

@@ -5,8 +5,9 @@
 #include "Scene.h"
 #include "Joint.h"
 
-#define BUNDLE_VERSION_MAJOR            1
-#define BUNDLE_VERSION_MINOR            2
+// Minimum version numbers supported
+#define BUNDLE_VERSION_MAJOR_REQUIRED   1 
+#define BUNDLE_VERSION_MINOR_REQUIRED   2
 
 #define BUNDLE_TYPE_SCENE               1
 #define BUNDLE_TYPE_NODE                2
@@ -26,6 +27,9 @@
 // For sanity checking string reads
 #define BUNDLE_MAX_STRING_LENGTH        5000
 
+#define BUNDLE_VERSION_MAJOR_FONT_FORMAT  1
+#define BUNDLE_VERSION_MINOR_FONT_FORMAT  3
+
 namespace gameplay
 {
 
@@ -55,6 +59,16 @@ Bundle::~Bundle()
     }
 }
 
+unsigned int Bundle::getVersionMajor() const
+{
+    return (unsigned int)_version[0];
+}
+
+unsigned int Bundle::getVersionMinor() const
+{
+    return (unsigned int)_version[1];
+}
+
 template <class T>
 bool Bundle::readArray(unsigned int* length, T** ptr)
 {
@@ -189,17 +203,18 @@ Bundle* Bundle::create(const char* path)
     }
 
     // Read version.
-    unsigned char ver[2];
-    if (stream->read(ver, 1, 2) != 2)
+    unsigned char version[2];
+    if (stream->read(version, 1, 2) != 2)
     {
         SAFE_DELETE(stream);
         GP_ERROR("Failed to read GPB version for bundle '%s'.", path);
         return NULL;
     }
-    if (ver[0] != BUNDLE_VERSION_MAJOR || ver[1] != BUNDLE_VERSION_MINOR)
+    // Check for the minimal 
+    if (version[0] != BUNDLE_VERSION_MAJOR_REQUIRED || version[1] < BUNDLE_VERSION_MINOR_REQUIRED)
     {
         SAFE_DELETE(stream);
-        GP_ERROR("Unsupported version (%d.%d) for bundle '%s' (expected %d.%d).", (int)ver[0], (int)ver[1], path, BUNDLE_VERSION_MAJOR, BUNDLE_VERSION_MINOR);
+        GP_ERROR("Unsupported version (%d.%d) for bundle '%s' (expected %d.%d).", (int)version[0], (int)version[1], path, BUNDLE_VERSION_MAJOR_REQUIRED, BUNDLE_VERSION_MINOR_REQUIRED);
         return NULL;
     }
 
@@ -229,6 +244,8 @@ Bundle* Bundle::create(const char* path)
 
     // Keep file open for faster reading later.
     Bundle* bundle = new Bundle(path);
+    bundle->_version[0] = version[0];
+    bundle->_version[1] = version[1];
     bundle->_referenceCount = refCount;
     bundle->_references = refs;
     bundle->_stream = stream;
@@ -1704,8 +1721,22 @@ Font* Bundle::loadFont(const char* id)
         return NULL;
     }
 
+    unsigned int format = Font::BITMAP;
+    // After bundle version we add enum FontFormat to bundle format
+    if (getVersionMajor() >= BUNDLE_VERSION_MAJOR_FONT_FORMAT &&
+        getVersionMinor() >= BUNDLE_VERSION_MINOR_FONT_FORMAT)
+    {
+        if (_stream->read(&format, 4, 1) != 1)
+        {
+            GP_ERROR("Failed to font format'%u'.", format);
+            SAFE_DELETE_ARRAY(glyphs);
+            SAFE_DELETE_ARRAY(textureData);
+            return NULL;
+        }
+    }
+
     // Create the texture for the font.
-    Texture* texture = Texture::create(Texture::ALPHA, width, height, textureData, false);
+    Texture* texture = Texture::create(Texture::ALPHA, width, height, textureData, true);
 
     // Free the texture data (no longer needed).
     SAFE_DELETE_ARRAY(textureData);
@@ -1718,7 +1749,7 @@ Font* Bundle::loadFont(const char* id)
     }
 
     // Create the font.
-    Font* font = Font::create(family.c_str(), Font::PLAIN, size, glyphs, glyphCount, texture);
+    Font* font = Font::create(family.c_str(), Font::PLAIN, size, glyphs, glyphCount, texture, (Font::Format)format);
 
     // Free the glyph array.
     SAFE_DELETE_ARRAY(glyphs);

+ 16 - 1
gameplay/src/Bundle.h

@@ -89,7 +89,7 @@ public:
     unsigned int getObjectCount() const;
 
     /**
-     * Returns the unique identifier of the top-level object at the specified index in this bundle.
+     * Gets the unique identifier of the top-level object at the specified index in this bundle.
      *
      * @param index The index of the object.
      * 
@@ -97,6 +97,20 @@ public:
      */
     const char* getObjectId(unsigned int index) const;
 
+    /**
+     * Gets the major version of the loaded bundle.
+     *
+     * @return The major version of the loaded bundle.
+     */
+    unsigned int getVersionMajor() const;
+
+    /**
+     * Gets the minor version of the loaded bundle.
+     *
+     * @return The minor version of the loaded bundle.
+     */
+    unsigned int getVersionMinor() const;
+
 private:
 
     class Reference
@@ -433,6 +447,7 @@ private:
      */
     bool skipNode();
 
+    unsigned char _version[2];
     std::string _path;
     std::string _materialPath;
     unsigned int _referenceCount;

+ 22 - 4
gameplay/src/Font.cpp

@@ -16,7 +16,7 @@ static std::vector<Font*> __fontCache;
 static Effect* __fontEffect = NULL;
 
 Font::Font() :
-    _style(PLAIN), _size(0), _spacing(0.125f), _glyphs(NULL), _glyphCount(0), _texture(NULL), _batch(NULL)
+    _format(BITMAP), _style(PLAIN), _size(0), _spacing(0.125f), _glyphs(NULL), _glyphCount(0), _texture(NULL), _batch(NULL), _cutoffParam(NULL)
 {
 }
 
@@ -90,7 +90,7 @@ Font* Font::create(const char* path, const char* id)
     return font;
 }
 
-Font* Font::create(const char* family, Style style, unsigned int size, Glyph* glyphs, int glyphCount, Texture* texture)
+Font* Font::create(const char* family, Style style, unsigned int size, Glyph* glyphs, int glyphCount, Texture* texture, Font::Format format)
 {
     GP_ASSERT(family);
     GP_ASSERT(glyphs);
@@ -99,7 +99,10 @@ Font* Font::create(const char* family, Style style, unsigned int size, Glyph* gl
     // Create the effect for the font's sprite batch.
     if (__fontEffect == NULL)
     {
-        __fontEffect = Effect::createFromFile(FONT_VSH, FONT_FSH);
+        char * defines = NULL;
+        if (format == DISTANCE_FIELD)
+            defines = "DISTANCE_FIELD";
+        __fontEffect = Effect::createFromFile(FONT_VSH, FONT_FSH, defines);
         if (__fontEffect == NULL)
         {
             GP_ERROR("Failed to create effect for font.");
@@ -126,12 +129,14 @@ Font* Font::create(const char* family, Style style, unsigned int size, Glyph* gl
 
     // Add linear filtering for better font quality.
     Texture::Sampler* sampler = batch->getSampler();
-    sampler->setFilterMode(Texture::LINEAR, Texture::LINEAR);
+    sampler->setFilterMode(Texture::LINEAR_MIPMAP_LINEAR, Texture::LINEAR);
+    sampler->setWrapMode(Texture::CLAMP, Texture::CLAMP);
 
     // Increase the ref count of the texture to retain it.
     texture->addRef();
 
     Font* font = new Font();
+    font->_format = format;
     font->_family = family;
     font->_style = style;
     font->_size = size;
@@ -151,6 +156,11 @@ unsigned int Font::getSize()
     return _size;
 }
 
+Font::Format Font::getFormat()
+{
+    return _format;
+}
+
 void Font::start()
 {
     GP_ASSERT(_batch);
@@ -509,6 +519,14 @@ void Font::drawText(const char* text, int x, int y, const Vector4& color, unsign
                 if (index >= 0 && index < (int)_glyphCount)
                 {
                     Glyph& g = _glyphs[index];
+
+                    if (getFormat() == DISTANCE_FIELD )
+                    {
+                        if (_cutoffParam == NULL)
+                            _cutoffParam = getSpriteBatch()->getMaterial()->getParameter("u_cutoff");    
+                        // TODO: Fix me so that smaller font are much smoother
+                        _cutoffParam->setVector2(Vector2(1.0, 1.0));
+                    }
                     _batch->draw(xPos, yPos, g.width * scale, size, g.uvs[0], g.uvs[1], g.uvs[2], g.uvs[3], color);
                     xPos += floor(g.width * scale + spacing);
                     break;

+ 19 - 2
gameplay/src/Font.h

@@ -49,6 +49,15 @@ public:
         ALIGN_BOTTOM_RIGHT = ALIGN_BOTTOM | ALIGN_RIGHT
     };
 
+    /**
+     * Defines the format of the font.
+     */
+    enum Format
+    {
+        BITMAP = 0,
+        DISTANCE_FIELD = 1
+    };
+
     /**
      * Vertex coordinates, UVs and indices can be computed and stored in a Text object.
      * For static text labels that do not change frequently, this means these computations
@@ -111,10 +120,15 @@ public:
     static Font* create(const char* path, const char* id = NULL);
 
     /**
-     * Returns the font size (max height of glyphs) in pixels.
+     * Gets the font size (max height of glyphs) in pixels.
      */
     unsigned int getSize();
 
+    /**
+     * Gets the font format. BITMAP or DISTANCEMAP.
+     */
+    Format getFormat();
+
     /**
      * Starts text drawing for this font.
      */
@@ -327,10 +341,11 @@ private:
      * @param glyphs An array of font glyphs, defining each character in the font within the texture map.
      * @param glyphCount The number of items in the glyph array.
      * @param texture A texture map containing rendered glyphs.
+     * @param format The format of the font (bitmap or distance fields)
      * 
      * @return The new Font.
      */
-    static Font* create(const char* family, Style style, unsigned int size, Glyph* glyphs, int glyphCount, Texture* texture);
+    static Font* create(const char* family, Style style, unsigned int size, Glyph* glyphs, int glyphCount, Texture* texture, Font::Format format);
 
     void getMeasurementInfo(const char* text, const Rectangle& area, unsigned int size, Justify justify, bool wrap, bool rightToLeft,
                             std::vector<int>* xPositions, int* yPosition, std::vector<unsigned int>* lineLengths);
@@ -349,6 +364,7 @@ private:
     void addLineInfo(const Rectangle& area, int lineWidth, int lineLength, Justify hAlign,
                      std::vector<int>* xPositions, std::vector<unsigned int>* lineLengths, bool rightToLeft);
 
+    Format _format;
     std::string _path;
     std::string _id;
     std::string _family;
@@ -360,6 +376,7 @@ private:
     Texture* _texture;
     SpriteBatch* _batch;
     Rectangle _viewport;
+    MaterialParameter* _cutoffParam;
 };
 
 }

+ 3 - 2
gameplay/src/Form.cpp

@@ -552,8 +552,7 @@ void Form::draw()
         // that have changed is disabled.  Currently, repositioning controls can result in areas of the screen being cleared
         // after another control has been drawn there.  This should probably be done in two passes -- one to clear areas where
         // dirty controls were last frame, and another to draw them where they are now.
-        Container::draw(_theme->getSpriteBatch(), Rectangle(0, 0, _bounds.width, _bounds.height),
-                        /*_skin != NULL*/ true, false, _bounds.height);
+        Container::draw(_theme->getSpriteBatch(), Rectangle(0, 0, _bounds.width, _bounds.height), true, false, _bounds.height);
         _theme->setProjectionMatrix(_defaultProjectionMatrix);
 
         // Restore the previous game viewport.
@@ -577,6 +576,8 @@ void Form::draw()
             GP_ASSERT(_spriteBatch);
         }
 
+        _spriteBatch->getSampler()->setFilterMode(Texture::LINEAR, Texture::LINEAR);
+        _spriteBatch->getSampler()->setWrapMode(Texture::CLAMP, Texture::CLAMP);
         _spriteBatch->start();
         _spriteBatch->draw(_bounds.x, _bounds.y, 0, _bounds.width, _bounds.height, 0, _v1, _u2, 0, Vector4::one());
         _spriteBatch->finish();

+ 2 - 1
gameplay/src/Theme.cpp

@@ -93,7 +93,8 @@ Theme* Theme::create(const char* url)
     GP_ASSERT(theme->_texture);
     theme->_spriteBatch = SpriteBatch::create(theme->_texture);
     GP_ASSERT(theme->_spriteBatch);
-    theme->_spriteBatch->getSampler()->setFilterMode(Texture::NEAREST, Texture::NEAREST);
+    theme->_spriteBatch->getSampler()->setFilterMode(Texture::LINEAR, Texture::LINEAR);
+    theme->_spriteBatch->getSampler()->setWrapMode(Texture::CLAMP, Texture::CLAMP);
 
     float tw = 1.0f / theme->_texture->getWidth();
     float th = 1.0f / theme->_texture->getHeight();

+ 1 - 0
samples/browser/game.config

@@ -4,6 +4,7 @@ window
     width = 1280
     height = 720
     fullscreen = false
+    //samples = 4
 }
 
 aliases

BIN
samples/browser/res/common/arial-distance.gpb


BIN
samples/browser/res/common/arial.gpb


BIN
samples/browser/res/common/badaboom.gpb


BIN
samples/browser/res/common/baroque.gpb


BIN
samples/browser/res/common/custom.gpb


BIN
samples/browser/res/common/fishfingers.gpb


BIN
samples/browser/res/common/neuropol.gpb


+ 3 - 3
samples/browser/res/common/text.form

@@ -54,12 +54,12 @@ form textTest
         text = Font API (Advanced)
     }
 
-    label scaleLabel : topLabel
+    label sizeLabel : topLabel
     {
-        text = Scale (1.0)
+        text = Size (18)
     }
 
-    container scaling
+    container size
     {
         style = noBorder
         autoWidth = true

+ 29 - 30
samples/browser/src/TextSample.cpp

@@ -10,7 +10,7 @@
 std::string _fontNames[] =
 {
     "arial",
-    "baroque",
+    "arial-distance",
     "badaboom",
     "fishfingers",
     "neuropol",
@@ -18,7 +18,7 @@ std::string _fontNames[] =
 };
 
 TextSample::TextSample()
-    : _form(NULL), _stateBlock(NULL), _scale(1.0f), _wrap(true), _ignoreClip(false), _useViewport(true), _rightToLeft(false), _simple(false), _alignment(Font::ALIGN_LEFT),
+    : _form(NULL), _stateBlock(NULL), _size(18), _wrap(true), _ignoreClip(false), _useViewport(true), _rightToLeft(false), _simple(false), _alignment(Font::ALIGN_LEFT),
       _fontsCount(FONT_COUNT), _fontIndex(0), _font(NULL), _viewport(250, 100, 512, 200)
 {
 }
@@ -55,7 +55,7 @@ void TextSample::initialize()
     }
     _font = _fonts[0];
     
-    _sampleString = std::string( "Lorem ipsum dolor sit amet, \n" \
+    _sampleString = std::string("Lorem ipsum dolor sit amet, \n" \
                                 "consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n" \
                                 "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n" \
                                 "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\n" \
@@ -97,11 +97,10 @@ void TextSample::render(float elapsedTime)
 
     _fonts[0]->start();
 
-    _fonts[0]->drawText(fps, 245, 5, Vector4(0, 0.5f, 1, 1), _fonts[0]->getSize());
+    _fonts[0]->drawText(fps, 245, 5, Vector4(0, 0.5f, 1, 1), _size);
     
     _form->draw();
 
-    unsigned int size = (float)_font->getSize() * _scale;
     if (_font != _fonts[0])
         _font->start();
 
@@ -109,30 +108,30 @@ void TextSample::render(float elapsedTime)
     {
         // Sample simple versions of measureText, drawText.
         unsigned int w, h;
-        _font->measureText(_sampleString.c_str(), size, &w, &h);
-        _font->drawText(_sampleString.c_str(), _viewport.x, _viewport.y, Vector4::fromColor(0xff0000ff), size, _rightToLeft);
+        _font->measureText(_sampleString.c_str(), _size, &w, &h);
+        _font->drawText(_sampleString.c_str(), _viewport.x, _viewport.y, Vector4::fromColor(0xff0000ff), _size, _rightToLeft);
 
-        _font->drawText("'", _viewport.x, _viewport.y, Vector4::fromColor(0x00ff00ff), size);
-        _font->drawText(".", _viewport.x, _viewport.y + h, Vector4::fromColor(0x00ff00ff), size);
-        _font->drawText("'", _viewport.x + w, _viewport.y, Vector4::fromColor(0x00ff00ff), size);
-        _font->drawText(".", _viewport.x + w, _viewport.y + h, Vector4::fromColor(0x00ff00ff), size);
+        _font->drawText("'", _viewport.x, _viewport.y, Vector4::fromColor(0x00ff00ff), _size);
+        _font->drawText(".", _viewport.x, _viewport.y + h, Vector4::fromColor(0x00ff00ff), _size);
+        _font->drawText("'", _viewport.x + w, _viewport.y, Vector4::fromColor(0x00ff00ff), _size);
+        _font->drawText(".", _viewport.x + w, _viewport.y + h, Vector4::fromColor(0x00ff00ff), _size);
     }
     else
     {
         // Sample viewport versions.
         gameplay::Rectangle area;
-        _font->measureText(_sampleString.c_str(), _viewport, size, &area, _alignment, _wrap, _ignoreClip);
-        _font->drawText(_sampleString.c_str(), _useViewport? _viewport : area, Vector4::fromColor(0xffffffff), size, _alignment, _wrap, _rightToLeft);
+        _font->measureText(_sampleString.c_str(), _viewport, _size, &area, _alignment, _wrap, _ignoreClip);
+        _font->drawText(_sampleString.c_str(), _useViewport? _viewport : area, Vector4::fromColor(0xffffffff), _size, _alignment, _wrap, _rightToLeft);
     
-        _font->drawText("'", _viewport.x, _viewport.y, Vector4::fromColor(0x00ff00ff), size);
-        _font->drawText(".", _viewport.x, _viewport.y + _viewport.height, Vector4::fromColor(0x00ff00ff), size);
-        _font->drawText("'", _viewport.x + _viewport.width, _viewport.y, Vector4::fromColor(0x00ff00ff), size);
-        _font->drawText(".", _viewport.x + _viewport.width, _viewport.y + _viewport.height, Vector4::fromColor(0x00ff00ff), size);
+        _font->drawText("'", _viewport.x, _viewport.y, Vector4::fromColor(0x00ff00ff), _size);
+        _font->drawText(".", _viewport.x, _viewport.y + _viewport.height, Vector4::fromColor(0x00ff00ff), _size);
+        _font->drawText("'", _viewport.x + _viewport.width, _viewport.y, Vector4::fromColor(0x00ff00ff), _size);
+        _font->drawText(".", _viewport.x + _viewport.width, _viewport.y + _viewport.height, Vector4::fromColor(0x00ff00ff), _size);
 
-        _font->drawText("'", area.x, area.y, Vector4::fromColor(0x0000ffff), size);
-        _font->drawText(".", area.x, area.y + area.height, Vector4::fromColor(0x0000ffff), size);
-        _font->drawText("'", area.x + area.width, area.y, Vector4::fromColor(0x0000ffff), size);
-        _font->drawText(".", area.x + area.width, area.y + area.height, Vector4::fromColor(0x0000ffff), size);
+        _font->drawText("'", area.x, area.y, Vector4::fromColor(0x0000ffff), _size);
+        _font->drawText(".", area.x, area.y + area.height, Vector4::fromColor(0x0000ffff), _size);
+        _font->drawText("'", area.x + area.width, area.y, Vector4::fromColor(0x0000ffff), _size);
+        _font->drawText(".", area.x + area.width, area.y + area.height, Vector4::fromColor(0x0000ffff), _size);
     }
 
     if (_font != _fonts[0])
@@ -210,22 +209,22 @@ void TextSample::controlEvent(Control* control, EventType evt)
     }
     else if (strcmp(id, "smallerButton") == 0)
     {
-        if (_scale > 0.11f)
+        if (_size > 12)
         {
-            _scale -= 0.1f;
-            Label* scaleLabel = static_cast<Label*>(_form->getControl("scaleLabel"));
+            _size -= 2;
+            Label* sizeLabel = static_cast<Label*>(_form->getControl("sizeLabel"));
             char s[20];
-            sprintf(s, "Font Scale (%.1f)", _scale);
-            scaleLabel->setText(s);
+            sprintf(s, "Size (%u)", _size);
+            sizeLabel->setText(s);
         }
     }
     else if (strcmp(id, "biggerButton") == 0)
     {
-        _scale += 0.1f;
-        Label* scaleLabel = static_cast<Label*>(_form->getControl("scaleLabel"));
+        _size += 2;
+        Label* sizeLabel = static_cast<Label*>(_form->getControl("sizeLabel"));
         char s[20];
-        sprintf(s, "Scale (%.1f)", _scale);
-        scaleLabel->setText(s);
+        sprintf(s, "Size (%u)", _size);
+        sizeLabel->setText(s);
     }
     else if (strcmp(id, "topLeftButton") == 0)
     {

+ 1 - 1
samples/browser/src/TextSample.h

@@ -29,7 +29,7 @@ private:
 
     Form* _form;
     RenderState::StateBlock* _stateBlock;
-    float _scale;
+    unsigned int _size;
     bool _wrap;
     bool _ignoreClip;
     bool _useViewport;

BIN
samples/mesh/res/arial.gpb


BIN
samples/mesh/res/arial.ttf


BIN
samples/particles/res/arial.gpb


BIN
samples/particles/res/arial.ttf


BIN
samples/racer/res/common/arial.gpb


BIN
samples/spaceship/res/airstrip.gpb


+ 7 - 0
tools/encoder/gameplay-bundle.txt

@@ -97,6 +97,12 @@ enum FontStyle
     BOLD_ITALIC = 4
 }
 
+enum FontFormat
+{
+    BITMAP = 0,
+    DISTANCE_FIELD = 1
+}
+
 enum PrimitiveType
 {
     TRIANGLES = GL_TRIANGLES (4),
@@ -224,3 +230,4 @@ Reference
                 texMapWidth             uint
                 texMapHeight            uint
                 texMap                  byte[]
+                format                  enum FontFormat      @since version [1,3]

+ 2 - 0
tools/encoder/gameplay-encoder.vcxproj.user

@@ -11,5 +11,7 @@
     <LocalDebuggerEnvironment>
     </LocalDebuggerEnvironment>
     <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
+    <LocalDebuggerCommandArguments>-s 12 arial.ttf</LocalDebuggerCommandArguments>
+    <LocalDebuggerWorkingDirectory>.\Release</LocalDebuggerWorkingDirectory>
   </PropertyGroup>
 </Project>

+ 22 - 7
tools/encoder/src/EncoderArguments.cpp

@@ -8,7 +8,7 @@
     #define realpath(A,B)    _fullpath(B,A,PATH_MAX)
 #endif
 
-#define MAX_HEIGHTMAP_SIZE 2049
+#define HEIGHTMAP_SIZE_MAX 2049
 
 namespace gameplay
 {
@@ -18,10 +18,11 @@ static EncoderArguments* __instance;
 extern int __logVerbosity = 1;
 
 EncoderArguments::EncoderArguments(size_t argc, const char** argv) :
-    _fontSize(0),
     _normalMap(false),
     _parseError(false),
+    _fontSize(0),
     _fontPreview(false),
+    _fontFormat(Font::BITMAP),
     _textOutput(false),
     _optimizeAnimations(false),
     _animationGrouping(ANIMATIONGROUP_PROMPT),
@@ -284,8 +285,9 @@ void EncoderArguments::printUsage() const
         "  terrain generation tools.\n" \
     "\n" \
     "TTF file options:\n" \
-    "  -s <size>\tSize of the font.\n" \
+    "  -s <size>\tSize of the bitmap font. (in pixels).\n" \
     "  -p\t\tOutput font preview.\n" \
+    "  -f Format of font. -f:b (BITMAP), -f:d (DISTANCE_FIELD).\n" \
     "\n");
     exit(8);
 }
@@ -295,6 +297,11 @@ bool EncoderArguments::fontPreviewEnabled() const
     return _fontPreview;
 }
 
+Font::FontFormat EncoderArguments::getFontFormat() const
+{
+    return _fontFormat;
+}
+
 bool EncoderArguments::textOutputEnabled() const
 {
     return _textOutput;
@@ -378,6 +385,16 @@ void EncoderArguments::readOption(const std::vector<std::string>& options, size_
     }
     switch (str[1])
     {
+    case 'f':
+        if (str.compare("-f:b") == 0)
+        {
+            _fontFormat = Font::BITMAP;
+        }
+       else  if (str.compare("-f:d") == 0)
+        {
+            _fontFormat = Font::DISTANCE_FIELD;
+        }
+        break;
     case 'g':
         if (str.compare("-groupAnimations:auto") == 0 || str.compare("-g:auto") == 0)
         {
@@ -450,9 +467,9 @@ void EncoderArguments::readOption(const std::vector<std::string>& options, size_
                     heightmap.height = atoi(parts[1].c_str());
 
                     // Put some artificial bounds on heightmap dimensions
-                    if (heightmap.width <= 0 || heightmap.height <= 0 || heightmap.width > MAX_HEIGHTMAP_SIZE || heightmap.height > MAX_HEIGHTMAP_SIZE)
+                    if (heightmap.width <= 0 || heightmap.height <= 0 || heightmap.width > HEIGHTMAP_SIZE_MAX || heightmap.height > HEIGHTMAP_SIZE_MAX)
                     {
-                        LOG(1, "Error: size argument for -h|-heightmap must be between (1,1) and (%d,%d).\n", (int)MAX_HEIGHTMAP_SIZE, (int)MAX_HEIGHTMAP_SIZE);
+                        LOG(1, "Error: size argument for -h|-heightmap must be between (1,1) and (%d,%d).\n", (int)HEIGHTMAP_SIZE_MAX, (int)HEIGHTMAP_SIZE_MAX);
                         _parseError = true;
                         return;
                     }
@@ -557,7 +574,6 @@ void EncoderArguments::readOption(const std::vector<std::string>& options, size_
         else
         {
             // Font Size
-
             // old format was -s##
             if (str.length() > 2)
             {
@@ -685,7 +701,6 @@ std::string concat(const std::string& a, const char* b)
     return str;
 }
 
-
 void unittestsEncoderArguments()
 {
     std::string dir = EncoderArguments::getRealPath(".");

+ 11 - 3
tools/encoder/src/EncoderArguments.h

@@ -3,6 +3,7 @@
 
 #include <set>
 #include "Vector3.h"
+#include "Font.h"
 
 namespace gameplay
 {
@@ -151,13 +152,20 @@ public:
      */
     void printUsage() const;
 
+    unsigned int getFontSize() const;
+
     bool fontPreviewEnabled() const;
+
+    Font::FontFormat getFontFormat() const;
+
     bool textOutputEnabled() const;
+
     bool optimizeAnimationsEnabled() const;
+
     bool outputMaterialEnabled() const;
 
     const char* getNodeId() const;
-    unsigned int getFontSize() const;
+
 
 
     static std::string getRealPath(const std::string& filepath);
@@ -192,14 +200,14 @@ private:
     std::string _fileOutputPath;
     std::string _nodeId;
 
-    unsigned int _fontSize;
-
     bool _normalMap;
     Vector3 _heightmapWorldSize;
     int _heightmapResolution[2];
 
     bool _parseError;
+    unsigned int _fontSize;
     bool _fontPreview;
+    Font::FontFormat _fontFormat;
     bool _textOutput;
     bool _optimizeAnimations;
     AnimationGroupOption _animationGrouping;

+ 7 - 0
tools/encoder/src/Font.h

@@ -42,6 +42,13 @@ public:
         ITALIC = 2,
         BOLD_ITALIC = 4
     };
+
+
+    enum FontFormat
+    {
+        BITMAP = 0,
+        DISTANCE_FIELD = 1
+    };
 };
 
 }

+ 1 - 1
tools/encoder/src/GPBFile.h

@@ -21,7 +21,7 @@ namespace gameplay
  * Increment the version number when making a change that break binary compatibility.
  * [0] is major, [1] is minor.
  */
-const unsigned char GPB_VERSION[2] = {1, 2};
+const unsigned char GPB_VERSION[2] = {1, 3};
 
 /**
  * The GamePlay Binary file class handles writing the GamePlay Binary file.

+ 30 - 19
tools/encoder/src/TTFFontEncoder.cpp

@@ -34,7 +34,7 @@ static void writeString(FILE* fp, const char* str)
     }
 }
 
-unsigned char* createDistanceFieldMap(unsigned char* img, unsigned int width, unsigned int height)
+unsigned char* createDistanceFields(unsigned char* img, unsigned int width, unsigned int height)
 {
     short* xDistance = (short*)malloc(width * height * sizeof(short));
     short* yDistance = (short*)malloc(width * height * sizeof(short));
@@ -107,9 +107,9 @@ unsigned char* createDistanceFieldMap(unsigned char* img, unsigned int width, un
     return out;
 }
 
-int writeFont(const char* inFilePath, const char* outFilePath, unsigned int fontSize, const char* id, bool fontpreview = false)
+int writeFont(const char* inFilePath, const char* outFilePath, unsigned int fontSize, const char* id, bool fontpreview = false, Font::FontFormat fontFormat = Font::BITMAP)
 {
-    Glyph glyphArray[END_INDEX - START_INDEX];
+    TTFGlyph glyphArray[END_INDEX - START_INDEX];
     
     // Initialize freetype library.
     FT_Library library;
@@ -148,7 +148,8 @@ int writeFont(const char* inFilePath, const char* outFilePath, unsigned int font
     for (unsigned char ascii = START_INDEX; ascii < END_INDEX; ++ascii)
     {
         // Load glyph image into the slot (erase previous one)
-        error = FT_Load_Char(face, ascii, FT_LOAD_RENDER);
+        FT_Int32 loadFlags = FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT;
+        error = FT_Load_Char(face, ascii, loadFlags);
         if (error)
         {
             LOG(1, "FT_Load_Char error : %d \n", error);
@@ -198,7 +199,6 @@ int writeFont(const char* inFilePath, const char* outFilePath, unsigned int font
             {
                 LOG(1, "FT_Load_Char error : %d \n", error);
             }
-
             // Glyph image.
             int glyphWidth = slot->bitmap.pitch;
             int glyphHeight = slot->bitmap.rows;
@@ -337,7 +337,7 @@ int writeFont(const char* inFilePath, const char* outFilePath, unsigned int font
     // Glyphs.
     unsigned int glyphSetSize = END_INDEX - START_INDEX;
     writeUint(gpbFp, glyphSetSize);
-    fwrite(&glyphArray, sizeof(Glyph), glyphSetSize, gpbFp);
+    fwrite(&glyphArray, sizeof(TTFGlyph), glyphSetSize, gpbFp);
     
     // Image dimensions
     unsigned int imageSize = imageWidth * imageHeight;
@@ -345,13 +345,19 @@ int writeFont(const char* inFilePath, const char* outFilePath, unsigned int font
     writeUint(gpbFp, imageHeight);
     writeUint(gpbFp, imageSize);
     
-    // Flip height and width since the distance field map generator is column-wise.
-    unsigned char* distanceFieldBuffer = createDistanceFieldMap(imageBuffer, imageHeight, imageWidth);
-    
-    // Write out the buffer
-    fwrite(distanceFieldBuffer, sizeof(unsigned char), imageSize, gpbFp);
-
-    //fwrite(imageBuffer, sizeof(unsigned char), imageSize, gpbFp);
+    unsigned char* distanceFieldBuffer = NULL;
+    if (fontFormat == Font::DISTANCE_FIELD)
+    {
+        // Flip height and width since the distance field map generator is column-wise.
+        distanceFieldBuffer = createDistanceFields(imageBuffer, imageHeight, imageWidth);
+        fwrite(distanceFieldBuffer, sizeof(unsigned char), imageSize, gpbFp);
+        writeUint(gpbFp, Font::DISTANCE_FIELD);
+    }
+    else
+    {
+        fwrite(imageBuffer, sizeof(unsigned char), imageSize, gpbFp);
+        writeUint(gpbFp, Font::BITMAP);
+    }
 
     // Close file.
     fclose(gpbFp);
@@ -367,11 +373,15 @@ int writeFont(const char* inFilePath, const char* outFilePath, unsigned int font
         FILE* previewFp = fopen(pgmFilePath.c_str(), "wb");
         fprintf(previewFp, "P5 %u %u 255\n", imageWidth, imageHeight);
         
-        // Write out the preview buffer
-        fwrite((const char*)distanceFieldBuffer, sizeof(unsigned char), imageSize, previewFp);
-
-        //fwrite((const char*)imageBuffer, sizeof(unsigned char), imageWidth * imageHeight, previewFp);
-        
+        if (fontFormat == Font::DISTANCE_FIELD)
+        {
+            // Write out the preview buffer
+            fwrite((const char*)distanceFieldBuffer, sizeof(unsigned char), imageSize, previewFp);
+        }
+        else
+        {
+            fwrite((const char*)imageBuffer, sizeof(unsigned char), imageWidth * imageHeight, previewFp);
+        }
         fclose(previewFp);
 
         LOG(1, "%s.pgm preview image created successfully. \n", getBaseName(pgmFilePath).c_str());
@@ -379,7 +389,8 @@ int writeFont(const char* inFilePath, const char* outFilePath, unsigned int font
 
     // Cleanup resources.
     free(imageBuffer);
-    free(distanceFieldBuffer);
+    if (fontFormat == Font::DISTANCE_FIELD)
+        free(distanceFieldBuffer);
 
     FT_Done_Face(face);
     FT_Done_FreeType(library);

+ 4 - 3
tools/encoder/src/TTFFontEncoder.h

@@ -1,5 +1,6 @@
 #include <ft2build.h>
 #include FT_FREETYPE_H
+#include "Font.h"
 
 #define START_INDEX     32
 #define END_INDEX       127
@@ -8,8 +9,8 @@
 namespace gameplay
 {
 
-// Structure of Glyph.
-class Glyph
+// Structure of TTF Glyph.
+class TTFGlyph
 {
 public:
     unsigned int index;
@@ -28,6 +29,6 @@ public:
  * 
  * @return 0 if successful, -1 if error.
  */
-int writeFont(const char* inFilePath, const char* outFilePath, unsigned int fontSize, const char* id, bool fontpreview);
+int writeFont(const char* inFilePath, const char* outFilePath, unsigned int fontSize, const char* id, bool fontpreview, Font::FontFormat fontFormat);
 
 }

+ 23 - 6
tools/encoder/src/main.cpp

@@ -4,9 +4,12 @@
 #include "GPBDecoder.h"
 #include "EncoderArguments.h"
 #include "NormalMapGenerator.h"
+#include "Font.h"
 
 using namespace gameplay;
 
+#define FONT_SIZE_DISTANCEFIELD 48
+
 /**
  * Prompts the user for a font size until a valid font size is entered.
  * 
@@ -14,13 +17,13 @@ using namespace gameplay;
  */
 static unsigned int promptUserFontSize()
 {
-    static const int lowerBound = 8;
-    static const int upperBound = 500;
+    static const int lowerBound = 12;
+    static const int upperBound = 72;
     unsigned int fontSize = 0;
     char buffer[80];
     do
     {
-        printf("Enter font size (between %d and %d):\n", lowerBound, upperBound);
+        printf("Enter font size (pixels) (between %d and %d):\n", lowerBound, upperBound);
         std::cin.getline(buffer, 80);
         int i = atoi(buffer);
         if (i >= lowerBound && i <= upperBound)
@@ -31,6 +34,7 @@ static unsigned int promptUserFontSize()
     return fontSize;
 }
 
+
 /**
  * Main application entry point.
  *
@@ -80,12 +84,25 @@ int main(int argc, const char** argv)
     case EncoderArguments::FILEFORMAT_TTF:
         {
             unsigned int fontSize = arguments.getFontSize();
-            if (fontSize == 0)
+            
+            Font::FontFormat fontFormat = arguments.getFontFormat();
+            if (fontFormat == Font::BITMAP)
+            {
+                if (fontSize == 0)
+                {
+                    fontSize = promptUserFontSize();
+                }
+            }
+            else
             {
-                fontSize = promptUserFontSize();
+                // Distance fields use size
+                if (fontSize == 0)
+                {
+                    fontSize = FONT_SIZE_DISTANCEFIELD;
+                }
             }
             std::string id = getBaseName(arguments.getFilePath());
-            writeFont(arguments.getFilePath().c_str(), arguments.getOutputFilePath().c_str(), fontSize, id.c_str(), arguments.fontPreviewEnabled());
+            writeFont(arguments.getFilePath().c_str(), arguments.getOutputFilePath().c_str(), fontSize, id.c_str(), arguments.fontPreviewEnabled(), fontFormat);
             break;
         }
     case EncoderArguments::FILEFORMAT_GPB: