Parcourir la source

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

seanpaultaylor il y a 12 ans
Parent
commit
7e639e4da5
54 fichiers modifiés avec 189 ajouts et 89 suppressions
  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;