Browse Source

Changed Font/Text rendering from Texture Maps to Signed Distance Field Maps to dramatically improve scaling.

seanpaultaylor 12 years ago
parent
commit
7e639e4da5
54 changed files with 189 additions and 89 deletions
  1. 6 3
      gameplay/res/shaders/font.frag
  2. 0 1
      gameplay/res/shaders/font.vert
  3. 1 1
      gameplay/src/Bundle.cpp
  4. 1 0
      gameplay/src/Form.cpp
  5. BIN
      samples/browser/res/common/arial.gpb
  6. BIN
      samples/browser/res/common/arial14.gpb
  7. BIN
      samples/browser/res/common/arial18.gpb
  8. BIN
      samples/browser/res/common/badaboom.gpb
  9. BIN
      samples/browser/res/common/baroque.gpb
  10. BIN
      samples/browser/res/common/custom.gpb
  11. 8 8
      samples/browser/res/common/default.theme
  12. BIN
      samples/browser/res/common/dynamic.gpb
  13. BIN
      samples/browser/res/common/fishfingers.gpb
  14. BIN
      samples/browser/res/common/neuropol.gpb
  15. BIN
      samples/browser/res/common/pirulen.gpb
  16. BIN
      samples/browser/res/common/squarehead.gpb
  17. 1 1
      samples/browser/res/common/text.form
  18. 1 1
      samples/browser/src/Audio3DSample.cpp
  19. 1 1
      samples/browser/src/BillboardSample.cpp
  20. 1 1
      samples/browser/src/CreateSceneSample.cpp
  21. 1 1
      samples/browser/src/GamepadSample.cpp
  22. 1 1
      samples/browser/src/GestureSample.cpp
  23. 1 1
      samples/browser/src/InputSample.cpp
  24. 1 1
      samples/browser/src/LightSample.cpp
  25. 1 1
      samples/browser/src/LoadSceneSample.cpp
  26. 1 1
      samples/browser/src/MeshBatchSample.cpp
  27. 1 1
      samples/browser/src/MeshPrimitiveSample.cpp
  28. 1 1
      samples/browser/src/PhysicsCollisionObjectSample.cpp
  29. 1 1
      samples/browser/src/PostProcessSample.cpp
  30. 1 1
      samples/browser/src/SamplesGame.cpp
  31. 1 1
      samples/browser/src/SpriteBatchSample.cpp
  32. 1 1
      samples/browser/src/TerrainSample.cpp
  33. 9 9
      samples/browser/src/TextSample.cpp
  34. 1 1
      samples/browser/src/TextureSample.cpp
  35. 1 1
      samples/browser/src/TriangleSample.cpp
  36. BIN
      samples/character/res/common/arial.gpb
  37. BIN
      samples/character/res/common/arial40.gpb
  38. BIN
      samples/lua/res/arial.gpb
  39. BIN
      samples/lua/res/arial40.gpb
  40. BIN
      samples/mesh/res/arial.gpb
  41. BIN
      samples/mesh/res/arial40.gpb
  42. BIN
      samples/particles/res/arial.gpb
  43. BIN
      samples/racer/res/common/arial.gpb
  44. BIN
      samples/racer/res/common/arial40.gpb
  45. 6 6
      samples/racer/res/common/menu.theme
  46. BIN
      samples/spaceship/res/airstrip.gpb
  47. BIN
      samples/spaceship/res/airstrip28.gpb
  48. 4 4
      samples/spaceship/res/menu.theme
  49. 2 0
      tools/encoder/gameplay-encoder.vcxproj
  50. 6 0
      tools/encoder/gameplay-encoder.vcxproj.filters
  51. 2 2
      tools/encoder/gameplay-encoder.vcxproj.user
  52. 12 0
      tools/encoder/src/Base.h
  53. 1 0
      tools/encoder/src/Material.cpp
  54. 113 37
      tools/encoder/src/TTFFontEncoder.cpp

+ 6 - 3
gameplay/res/shaders/font.frag

@@ -1,5 +1,6 @@
 #ifdef OPENGL_ES
 precision highp float;
+#extension GL_OES_standard_derivatives : enable
 #endif
 
 // Uniforms
@@ -9,9 +10,11 @@ uniform sampler2D u_texture;
 varying vec2 v_texCoord;
 varying vec4 v_color;
 
-
 void main()
-{
+{ 
     gl_FragColor = v_color;
-    gl_FragColor.a = texture2D(u_texture, v_texCoord).a * v_color.a;
+    float distance = texture2D(u_texture, v_texCoord).a;
+    float smoothing = fwidth(distance);
+    float alpha = smoothstep(0.5 - smoothing, 0.5 + smoothing, distance);
+    gl_FragColor.a = alpha * v_color.a;
 }

+ 0 - 1
gameplay/res/shaders/font.vert

@@ -10,7 +10,6 @@ uniform mat4 u_projectionMatrix;
 varying vec2 v_texCoord;
 varying vec4 v_color;
 
-
 void main()
 {
     gl_Position = u_projectionMatrix * vec4(a_position, 1);

+ 1 - 1
gameplay/src/Bundle.cpp

@@ -1705,7 +1705,7 @@ Font* Bundle::loadFont(const char* id)
     }
 
     // Create the texture for the font.
-    Texture* texture = Texture::create(Texture::ALPHA, width, height, textureData, true);
+    Texture* texture = Texture::create(Texture::ALPHA, width, height, textureData, false);
 
     // Free the texture data (no longer needed).
     SAFE_DELETE_ARRAY(textureData);

+ 1 - 0
gameplay/src/Form.cpp

@@ -576,6 +576,7 @@ void Form::draw()
             _spriteBatch = SpriteBatch::create(_frameBuffer->getRenderTarget()->getTexture());
             GP_ASSERT(_spriteBatch);
         }
+
         _spriteBatch->start();
         _spriteBatch->draw(_bounds.x, _bounds.y, 0, _bounds.width, _bounds.height, 0, _v1, _u2, 0, Vector4::one());
         _spriteBatch->finish();

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


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


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


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


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


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


+ 8 - 8
samples/browser/res/common/default.theme

@@ -213,8 +213,8 @@ theme mainMenu
         {
             skin = underliner
             textColor = #ffffffff
-            font = res/common/arial18.gpb
-            fontSize = 25
+            font = res/common/arial.gpb
+            fontSize = 24
             textAlignment = ALIGN_BOTTOM_HCENTER
         }
     }
@@ -234,7 +234,7 @@ theme mainMenu
             skin = mainNormal
             imageList = normalImages
 
-            font = res/common/arial18.gpb
+            font = res/common/arial.gpb
             textColor = #ffffffff
             fontSize = 18
             textAlignment = ALIGN_VCENTER_HCENTER
@@ -289,7 +289,7 @@ theme mainMenu
 
         stateNormal
         {
-            font = res/common/arial18.gpb
+            font = res/common/arial.gpb
             fontSize = 20
         }
 
@@ -312,7 +312,7 @@ theme mainMenu
         stateNormal
         {
             imageList = normalImages
-            font = res/common/arial18.gpb
+            font = res/common/arial.gpb
             textColor = #ffffffff
             fontSize = 14
             textAlignment = ALIGN_VCENTER_HCENTER
@@ -334,14 +334,14 @@ theme mainMenu
     {
         stateNormal
         {
-            font = res/common/arial18.gpb
+            font = res/common/arial.gpb
             fontSize = 20
             textAlignment = ALIGN_VCENTER_LEFT
         }
 
         stateActive
         {
-            font = res/common/arial18.gpb
+            font = res/common/arial.gpb
             fontSize = 20
             textAlignment = ALIGN_VCENTER_LEFT
         }
@@ -365,7 +365,7 @@ theme mainMenu
         stateNormal
         {
             textColor = #ffffffff
-            font = res/common/arial18.gpb
+            font = res/common/arial.gpb
             fontSize = 26
             textAlignment = ALIGN_BOTTOM_HCENTER
         }

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


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


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


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


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


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

@@ -26,7 +26,7 @@ form textTest
         autoWidth = true
         height = 50
         consumeInputEvents = false
-        text = Font (arial18)
+        text = Font (arial)
     }
 
     button wrapButton : fontButton

+ 1 - 1
samples/browser/src/Audio3DSample.cpp

@@ -24,7 +24,7 @@ Audio3DSample::Audio3DSample()
 void Audio3DSample::initialize()
 {
     setMultiTouch(true);
-    _font = Font::create("res/common/arial18.gpb");
+    _font = Font::create("res/common/arial.gpb");
     // Load game scene from file
     _scene = Scene::load("res/common/box.gpb");
 

+ 1 - 1
samples/browser/src/BillboardSample.cpp

@@ -34,7 +34,7 @@ void BillboardSample::initialize()
     setMultiTouch(true);
 
 	// Create the font and scene
-    _font = Font::create("res/common/arial18.gpb");
+    _font = Font::create("res/common/arial.gpb");
 	_scene = Scene::create();
 
 	// Initialize the camera

+ 1 - 1
samples/browser/src/CreateSceneSample.cpp

@@ -67,7 +67,7 @@ CreateSceneSample::CreateSceneSample()
 void CreateSceneSample::initialize()
 {
     // Create the font for drawing the framerate.
-    _font = Font::create("res/common/arial18.gpb");
+    _font = Font::create("res/common/arial.gpb");
 
     // Create a new empty scene.
     _scene = Scene::create();

+ 1 - 1
samples/browser/src/GamepadSample.cpp

@@ -23,7 +23,7 @@ void GamepadSample::initialize()
     if (_gamepad && _gamepad->isVirtual())
         _gamepad->getForm()->setEnabled(true);
 
-    _font = Font::create("res/common/arial18.gpb");
+    _font = Font::create("res/common/arial.gpb");
     _status = "Looking for gamepads...";
 }
 

+ 1 - 1
samples/browser/src/GestureSample.cpp

@@ -20,7 +20,7 @@ void GestureSample::initialize()
     setMultiTouch(true);
 
     // Load font
-    _font = Font::create("res/common/arial18.gpb");
+    _font = Font::create("res/common/arial.gpb");
     assert(_font);
 
     bool anySupported = false;

+ 1 - 1
samples/browser/src/InputSample.cpp

@@ -21,7 +21,7 @@ void InputSample::initialize()
     setMultiTouch(true);
 
     // Load font
-    _font = Font::create("res/common/arial18.gpb");
+    _font = Font::create("res/common/arial.gpb");
     assert(_font);
 
     // Reuse part of the gamepad texture as the crosshair in this sample.

+ 1 - 1
samples/browser/src/LightSample.cpp

@@ -43,7 +43,7 @@ LightSample::LightSample()
 void LightSample::initialize()
 {
     // Create the font for drawing the framerate.
-    _font = Font::create("res/common/arial18.gpb");
+    _font = Font::create("res/common/arial.gpb");
 
 	// Load the scene
 	_scene = Scene::load("res/common/lightBrickWall.gpb");

+ 1 - 1
samples/browser/src/LoadSceneSample.cpp

@@ -14,7 +14,7 @@ LoadSceneSample::LoadSceneSample()
 void LoadSceneSample::initialize()
 {
     // Create the font for drawing the framerate.
-    _font = Font::create("res/common/arial18.gpb");
+    _font = Font::create("res/common/arial.gpb");
 
     _scene = Scene::load("res/common/sample.scene");
 

+ 1 - 1
samples/browser/src/MeshBatchSample.cpp

@@ -43,7 +43,7 @@ void MeshBatchSample::initialize()
 {
     setMultiTouch(true);
     // Create the font for drawing the framerate.
-    _font = Font::create("res/common/arial18.gpb");
+    _font = Font::create("res/common/arial.gpb");
 
     Matrix::createOrthographic(getWidth(), getHeight(), -1.0f, 1.0f, &_worldViewProjectionMatrix);
     _meshBatch = createMeshBatch(Mesh::TRIANGLES);

+ 1 - 1
samples/browser/src/MeshPrimitiveSample.cpp

@@ -190,7 +190,7 @@ MeshPrimitiveSample::MeshPrimitiveSample()
 void MeshPrimitiveSample::initialize()
 {
     // Create the font for drawing the framerate.
-    _font = Font::create("res/common/arial18.gpb");
+    _font = Font::create("res/common/arial.gpb");
 
     // Create an orthographic projection matrix.
     float width = getWidth() / (float)getHeight();

+ 1 - 1
samples/browser/src/PhysicsCollisionObjectSample.cpp

@@ -21,7 +21,7 @@ PhysicsCollisionObjectSample::PhysicsCollisionObjectSample()
 void PhysicsCollisionObjectSample::initialize()
 {
     // Create the font for drawing the framerate.
-    _font = Font::create("res/common/arial18.gpb");
+    _font = Font::create("res/common/arial.gpb");
 
     _scene = Scene::load("res/common/physics.scene");
     // Use the aspect ratio of the display instead of the aspect ratio defined in the scene file.

+ 1 - 1
samples/browser/src/PostProcessSample.cpp

@@ -79,7 +79,7 @@ PostProcessSample::PostProcessSample()
 
 void PostProcessSample::initialize()
 {
-    _font = Font::create("res/common/arial18.gpb");
+    _font = Font::create("res/common/arial.gpb");
 
     // Load game scene from file
     _scene = Scene::load("res/common/duck.gpb");

+ 1 - 1
samples/browser/src/SamplesGame.cpp

@@ -16,7 +16,7 @@ SamplesGame::SamplesGame()
 
 void SamplesGame::initialize()
 {
-    _font = Font::create("res/common/arial18.gpb");
+    _font = Font::create("res/common/arial.gpb");
 
     for (size_t i = 0; i < _categories->size(); ++i)
     {

+ 1 - 1
samples/browser/src/SpriteBatchSample.cpp

@@ -49,7 +49,7 @@ SpriteBatchSample::SpriteBatchSample()
 void SpriteBatchSample::initialize()
 {
     // Create the font for drawing the framerate.
-    _font = Font::create("res/common/arial18.gpb");
+    _font = Font::create("res/common/arial.gpb");
 
     // Create an orthographic projection matrix.
     float width = getWidth() / (float)getHeight();

+ 1 - 1
samples/browser/src/TerrainSample.cpp

@@ -55,7 +55,7 @@ void TerrainSample::initialize()
     SAFE_RELEASE(bundle);
 
     // Load font
-	_font = Font::create("res/common/arial18.gpb");
+	_font = Font::create("res/common/arial.gpb");
 
     // Setup form
     _form = Form::create("res/common/terrain/terrain.form");

+ 9 - 9
samples/browser/src/TextSample.cpp

@@ -9,11 +9,11 @@
 
 std::string _fontNames[] =
 {
-    "arial18",
-    "dynamic",
-    "pirulen",
-    "squarehead",
+    "arial",
     "baroque",
+    "badaboom",
+    "fishfingers",
+    "neuropol",
     "custom",
 };
 
@@ -95,14 +95,14 @@ void TextSample::render(float elapsedTime)
     char fps[5];
     sprintf(fps, "%u", getFrameRate());
 
-    _fonts[1]->start();
+    _fonts[0]->start();
 
-    _fonts[1]->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), _fonts[0]->getSize());
     
     _form->draw();
 
     unsigned int size = (float)_font->getSize() * _scale;
-    if (_font != _fonts[1])
+    if (_font != _fonts[0])
         _font->start();
 
     if (_simple)
@@ -135,11 +135,11 @@ void TextSample::render(float elapsedTime)
         _font->drawText(".", area.x + area.width, area.y + area.height, Vector4::fromColor(0x0000ffff), size);
     }
 
-    if (_font != _fonts[1])
+    if (_font != _fonts[0])
     {
         _font->finish();
     }
-    _fonts[1]->finish();
+    _fonts[0]->finish();
 }
 
 void TextSample::touchEvent(Touch::TouchEvent event, int x, int y, unsigned int contactIndex)

+ 1 - 1
samples/browser/src/TextureSample.cpp

@@ -49,7 +49,7 @@ TextureSample::TextureSample()
 void TextureSample::initialize()
 {
     // Create the font for drawing the framerate.
-    _font = Font::create("res/common/arial18.gpb");
+    _font = Font::create("res/common/arial.gpb");
 
     // Create an empty scene.
     _scene = Scene::create();

+ 1 - 1
samples/browser/src/TriangleSample.cpp

@@ -49,7 +49,7 @@ TriangleSample::TriangleSample()
 void TriangleSample::initialize()
 {
     // Create the font for drawing the framerate.
-    _font = Font::create("res/common/arial18.gpb");
+    _font = Font::create("res/common/arial.gpb");
 
     // Create an orthographic projection matrix.
     float width = getWidth() / (float)getHeight();

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


BIN
samples/character/res/common/arial40.gpb


BIN
samples/lua/res/arial.gpb


BIN
samples/lua/res/arial40.gpb


BIN
samples/mesh/res/arial.gpb


BIN
samples/mesh/res/arial40.gpb


BIN
samples/particles/res/arial.gpb


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


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


+ 6 - 6
samples/racer/res/common/menu.theme

@@ -119,7 +119,7 @@ theme menuTheme
             skin = mainNormal
             imageList = normalImages
 
-            font = res/common/arial40.gpb
+            font = res/common/arial.gpb
             textColor = #ffffffff
             fontSize = 18
             textAlignment = ALIGN_VCENTER_HCENTER
@@ -141,7 +141,7 @@ theme menuTheme
 
         stateNormal
         {
-            font = res/common/arial40.gpb
+            font = res/common/arial.gpb
             fontSize = 20
         }
 
@@ -161,7 +161,7 @@ theme menuTheme
         stateNormal
         {
             imageList = normalImages
-            font = res/common/arial40.gpb
+            font = res/common/arial.gpb
             textColor = #ffffffff
             fontSize = 14
             textAlignment = ALIGN_VCENTER_HCENTER
@@ -183,14 +183,14 @@ theme menuTheme
     {
         stateNormal
         {
-            font = res/common/arial40.gpb
+            font = res/common/arial.gpb
             fontSize = 20
             textAlignment = ALIGN_VCENTER_LEFT
         }
 
         stateActive
         {
-            font = res/common/arial40.gpb
+            font = res/common/arial.gpb
             fontSize = 20
             textAlignment = ALIGN_VCENTER_LEFT
         }
@@ -201,7 +201,7 @@ theme menuTheme
         stateNormal
         {
             textColor = #ffffffff
-            font = res/common/arial40.gpb
+            font = res/common/arial.gpb
             fontSize = 26
             textAlignment = ALIGN_TOP_HCENTER
         }

BIN
samples/spaceship/res/airstrip.gpb


BIN
samples/spaceship/res/airstrip28.gpb


+ 4 - 4
samples/spaceship/res/menu.theme

@@ -147,7 +147,7 @@ theme menuTheme
             skin = mainNormal
             imageList = normalImages
 
-            font = res/airstrip28.gpb
+            font = res/airstrip.gpb
             textColor = #ffffffff
             fontSize = 15
             textAlignment = ALIGN_VCENTER_HCENTER
@@ -169,7 +169,7 @@ theme menuTheme
 
         stateNormal
         {
-            font = res/airstrip28.gpb
+            font = res/airstrip.gpb
             fontSize = 30
         }
 
@@ -184,7 +184,7 @@ theme menuTheme
         stateNormal
         {
             imageList = normalImages
-            font = res/airstrip28.gpb
+            font = res/airstrip.gpb
             textColor = #ffffffff
             fontSize = 15
             textAlignment = ALIGN_VCENTER_HCENTER
@@ -224,7 +224,7 @@ theme menuTheme
         {
             skin = empty
             textColor = #ffffffff
-            font = res/airstrip28.gpb
+            font = res/airstrip.gpb
             fontSize = 25
             textAlignment = ALIGN_TOP_HCENTER
         }

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

@@ -18,6 +18,7 @@
     <ClCompile Include="src\Camera.cpp" />
     <ClCompile Include="src\Constants.cpp" />
     <ClCompile Include="src\Curve.cpp" />
+    <ClCompile Include="src\edtaa3func.c" />
     <ClCompile Include="src\EncoderArguments.cpp" />
     <ClCompile Include="src\Effect.cpp" />
     <ClCompile Include="src\FBXSceneEncoder.cpp" />
@@ -65,6 +66,7 @@
     <ClInclude Include="src\Camera.h" />
     <ClInclude Include="src\Constants.h" />
     <ClInclude Include="src\Curve.h" />
+    <ClInclude Include="src\edtaa3func.h" />
     <ClInclude Include="src\EncoderArguments.h" />
     <ClInclude Include="src\Effect.h" />
     <ClInclude Include="src\FBXSceneEncoder.h" />

+ 6 - 0
tools/encoder/gameplay-encoder.vcxproj.filters

@@ -136,6 +136,9 @@
     <ClCompile Include="src\Sampler.cpp">
       <Filter>src</Filter>
     </ClCompile>
+    <ClCompile Include="src\edtaa3func.c">
+      <Filter>src</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\VertexElement.h">
@@ -273,6 +276,9 @@
     <ClInclude Include="src\Sampler.h">
       <Filter>src</Filter>
     </ClInclude>
+    <ClInclude Include="src\edtaa3func.h">
+      <Filter>src</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="src\Vector2.inl">

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

@@ -1,11 +1,11 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-    <LocalDebuggerCommandArguments>
-    </LocalDebuggerCommandArguments>
+    <LocalDebuggerCommandArguments>-s 72 -p arial.ttf</LocalDebuggerCommandArguments>
     <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
     <LocalDebuggerEnvironment>
     </LocalDebuggerEnvironment>
+    <LocalDebuggerWorkingDirectory>.\Debug</LocalDebuggerWorkingDirectory>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     <LocalDebuggerEnvironment>

+ 12 - 0
tools/encoder/src/Base.h

@@ -25,8 +25,20 @@ using std::size_t;
 using std::min;
 using std::max;
 
+#if defined(WIN32)
+    #pragma warning( disable : 4005 )
+    #pragma warning( disable : 4172 )
+    #pragma warning( disable : 4244 )
+    #pragma warning( disable : 4267 )
+    #pragma warning( disable : 4311 )
+    #pragma warning( disable : 4390 )
+    #pragma warning( disable : 4800 )
+    #pragma warning( disable : 4996 )
+#endif
+
 // PNG
 #include <png.h>
+#include "edtaa3func.h"
 
 // Defines
 #ifndef M_1_PI        

+ 1 - 0
tools/encoder/src/Material.cpp

@@ -1,6 +1,7 @@
 #include "Material.h"
 #include "FileIO.h"
 #include "StringUtil.h"
+#include "edtaa3func.h"
 
 namespace gameplay
 {

+ 113 - 37
tools/encoder/src/TTFFontEncoder.cpp

@@ -34,6 +34,79 @@ static void writeString(FILE* fp, const char* str)
     }
 }
 
+unsigned char* createDistanceFieldMap(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));
+    double* gx = (double*)calloc(width * height, sizeof(double));
+    double* gy = (double*)calloc(width * height, sizeof(double));
+    double* data = (double*)calloc(width * height, sizeof(double));
+    double* outside = (double*)calloc(width * height, sizeof(double));
+    double* inside = (double*)calloc(width * height, sizeof(double));
+    unsigned int i;
+
+    // Convert img into double (data)
+    double imgMin = 255;
+    double imgMax = -255;
+    for (i = 0; i < width * height; ++i)
+    {
+        double v = img[i];
+        data[i] = v;
+        if (v > imgMax) 
+            imgMax = v;
+        if (v < imgMin) 
+            imgMin = v;
+    }
+    // Rescale image levels between 0 and 1
+    for (i = 0; i < width * height; ++i)
+    {
+        data[i] = (img[i] - imgMin) / imgMax;
+    }
+    // Compute outside = edtaa3(bitmap); % Transform background (0's)
+    computegradient(data, width, height, gx, gy);
+    edtaa3(data, gx, gy, height, width, xDistance, yDistance, outside);
+    for (i = 0; i < width * height; ++i)
+    {
+        if (outside[i] < 0 )
+            outside[i] = 0.0;
+    }
+    // Compute inside = edtaa3(1-bitmap); % Transform foreground (1's)
+    memset(gx, 0, sizeof(double) * width * height);
+    memset(gy, 0, sizeof(double) * width * height);
+    for (i = 0; i < width * height; ++i)
+    {
+        data[i] = 1 - data[i];
+    }
+    computegradient(data, width, height, gx, gy);
+    edtaa3(data, gx, gy, height, width, xDistance, yDistance, inside);
+    for (i = 0; i < width * height; ++i)
+    {
+        if( inside[i] < 0 )
+            inside[i] = 0.0;
+    }
+    // distmap = outside - inside; % Bipolar distance field
+    unsigned char* out = (unsigned char*)malloc(sizeof(unsigned char) * width * height);
+    for (i = 0; i < width * height; ++i)
+    {
+        outside[i] -= inside[i];
+        outside[i] = 128 + outside[i] * 16;
+        if (outside[i] < 0) 
+            outside[i] = 0;
+        if (outside[i] > 255) 
+            outside[i] = 255;
+        out[i] = 255 - (unsigned char) outside[i];
+    }
+    free(xDistance);
+    free(yDistance);
+    free(gx);
+    free(gy);
+    free(data);
+    free(outside);
+    free(inside);
+
+    return out;
+}
+
 int writeFont(const char* inFilePath, const char* outFilePath, unsigned int fontSize, const char* id, bool fontpreview = false)
 {
     Glyph glyphArray[END_INDEX - START_INDEX];
@@ -56,13 +129,8 @@ int writeFont(const char* inFilePath, const char* outFilePath, unsigned int font
         return -1;
     }
     
-    // Set the pixel size.
-    error = FT_Set_Char_Size(
-            face,           // handle to face object.
-            0,              // char_width in 1/64th of points.
-            fontSize * 64,   // char_height in 1/64th of points.
-            0,              // horizontal device resolution (defaults to 72 dpi if resolution (0, 0)).
-            0 );            // vertical device resolution.
+    // Set the pixel size.  char_width in 1/64th of points.
+    error = FT_Set_Char_Size(  face,  0, fontSize * 64, 0, 0 ); 
     
     if (error)
     {
@@ -72,9 +140,9 @@ int writeFont(const char* inFilePath, const char* outFilePath, unsigned int font
 
     // Save glyph information (slot contains the actual glyph bitmap).
     FT_GlyphSlot slot = face->glyph;
-    
     int actualfontHeight = 0;
-    int rowSize = 0; // Stores the total number of rows required to all glyphs.
+    // Stores the total number of rows required to all glyphs.
+    int rowSize = 0;
     
     // Find the width of the image.
     for (unsigned char ascii = START_INDEX; ascii < END_INDEX; ++ascii)
@@ -103,7 +171,7 @@ int writeFont(const char* inFilePath, const char* outFilePath, unsigned int font
     int penX = 0;
     int penY = 0;
     int row = 0;
-    
+
     double powerOf2 = 2;
     unsigned int imageWidth = 0;
     unsigned int imageHeight = 0;
@@ -135,7 +203,7 @@ int writeFont(const char* inFilePath, const char* outFilePath, unsigned int font
             int glyphWidth = slot->bitmap.pitch;
             int glyphHeight = slot->bitmap.rows;
 
-            advance = glyphWidth + GLYPH_PADDING; //((int)slot->advance.x >> 6) + GLYPH_PADDING;
+            advance = glyphWidth + GLYPH_PADDING; 
 
             // If we reach the end of the image wrap aroud to the next row.
             if ((penX + advance) > (int)imageWidth)
@@ -158,11 +226,10 @@ int writeFont(const char* inFilePath, const char* outFilePath, unsigned int font
             // Move Y back to the top of the row.
             penY = row * rowSize;
 
-            if (ascii == (END_INDEX-1))
+            if (ascii == (END_INDEX - 1))
             {
                 textureSizeFound = true;
             }
-
             i++;
         }
     }
@@ -183,7 +250,7 @@ int writeFont(const char* inFilePath, const char* outFilePath, unsigned int font
     }
     
     // Allocate temporary image buffer to draw the glyphs into.
-    unsigned char* imageBuffer = (unsigned char *)malloc(imageWidth * imageHeight);
+    unsigned char* imageBuffer = (unsigned char*)malloc(imageWidth * imageHeight);
     memset(imageBuffer, 0, imageWidth * imageHeight);
     penX = 0;
     penY = 0;
@@ -203,7 +270,7 @@ int writeFont(const char* inFilePath, const char* outFilePath, unsigned int font
         int glyphWidth = slot->bitmap.pitch;
         int glyphHeight = slot->bitmap.rows;
 
-        advance = glyphWidth + GLYPH_PADDING;//((int)slot->advance.x >> 6) + GLYPH_PADDING;
+        advance = glyphWidth + GLYPH_PADDING;
 
         // If we reach the end of the image wrap aroud to the next row.
         if ((penX + advance) > (int)imageWidth)
@@ -238,14 +305,12 @@ int writeFont(const char* inFilePath, const char* outFilePath, unsigned int font
         glyphArray[i].uvCoords[3] = (float)(penY + rowSize) / (float)imageHeight;
 
         // Set the pen position for the next glyph
-        penX += advance; // Move X to next glyph position
+        penX += advance;
         i++;
     }
-
-
-    FILE *gpbFp = fopen(outFilePath, "wb");
     
     // File header and version.
+    FILE *gpbFp = fopen(outFilePath, "wb");
     char fileHeader[9]     = {'«', 'G', 'P', 'B', '»', '\r', '\n', '\x1A', '\n'};
     fwrite(fileHeader, sizeof(char), 9, gpbFp);
     fwrite(gameplay::GPB_VERSION, sizeof(char), 2, gpbFp);
@@ -255,23 +320,18 @@ int writeFont(const char* inFilePath, const char* outFilePath, unsigned int font
     writeString(gpbFp, id);             // Ref id
     writeUint(gpbFp, 128);              // Ref type
     writeUint(gpbFp, ftell(gpbFp) + 4); // Ref offset (current pos + 4 bytes)
-    
-    // Write Font object.
-    
+
     // Family name.
     writeString(gpbFp, face->family_name);
 
     // Style.
-    // TODO: Switch based on TTF style name and write appropriate font style unsigned int
-    // For now just hardcoding to 0.
-    //char* style = face->style_name;
-    writeUint(gpbFp, 0); // 0 == PLAIN
+    // TODO: Switch based on TTF style name and write appropriate font style unsigned int for now just hardcoding to 0 = PLAIN.
+    writeUint(gpbFp, 0);
 
     // Font size.
     writeUint(gpbFp, rowSize);
 
-    // Character set.
-    // TODO: Empty for now
+    // Character set. TODO: Empty for now
     writeString(gpbFp, "");
     
     // Glyphs.
@@ -279,32 +339,48 @@ int writeFont(const char* inFilePath, const char* outFilePath, unsigned int font
     writeUint(gpbFp, glyphSetSize);
     fwrite(&glyphArray, sizeof(Glyph), glyphSetSize, gpbFp);
     
-    // Texture.
-    unsigned int textureSize = imageWidth * imageHeight;
+    // Image dimensions
+    unsigned int imageSize = imageWidth * imageHeight;
     writeUint(gpbFp, imageWidth);
     writeUint(gpbFp, imageHeight);
-    writeUint(gpbFp, textureSize);
-    fwrite(imageBuffer, sizeof(unsigned char), textureSize, gpbFp);
+    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);
+
     // Close file.
     fclose(gpbFp);
 
     LOG(1, "%s.gpb created successfully. \n", getBaseName(outFilePath).c_str());
 
+    // Save out a pgm monochome image file for preview
     if (fontpreview)
     {
         // Write out font map to an image.
         std::string pgmFilePath = getFilenameNoExt(outFilePath);
         pgmFilePath.append(".pgm");
-        FILE *imageFp = fopen(pgmFilePath.c_str(), "wb");
-        fprintf(imageFp, "P5 %u %u 255\n", imageWidth, imageHeight);
-        fwrite((const char *)imageBuffer, sizeof(unsigned char), imageWidth * imageHeight, imageFp);
-        fclose(imageFp);
+        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);
+        
+        fclose(previewFp);
+
+        LOG(1, "%s.pgm preview image created successfully. \n", getBaseName(pgmFilePath).c_str());
     }
 
     // Cleanup resources.
     free(imageBuffer);
-    
+    free(distanceFieldBuffer);
+
     FT_Done_Face(face);
     FT_Done_FreeType(library);
     return 0;