Browse Source

Version 1.2 - Reverse order option, edge coloring seed, glyph loading fix

Viktor Chlumský 9 years ago
parent
commit
4e443d8a72
7 changed files with 94 additions and 20 deletions
  1. 5 0
      README.md
  2. 28 6
      core/edge-coloring.cpp
  3. 1 1
      core/edge-coloring.h
  4. 10 5
      ext/import-font.cpp
  5. 48 6
      main.cpp
  6. BIN
      msdfgen.exe
  7. 2 2
      msdfgen.h

+ 5 - 0
README.md

@@ -14,6 +14,11 @@ The following comparison demonstrates the improvement in image quality.
 ![demo-sdf16](https://cloud.githubusercontent.com/assets/18639794/14770360/20c51156-0a70-11e6-8f03-ed7632d07997.png)
 ![demo-sdf32](https://cloud.githubusercontent.com/assets/18639794/14770361/251a4406-0a70-11e6-95a7-e30e235ac729.png)
 
+## New in version 1.2
+ - Option to specify that shape is defined in reverse order (-reverseorder)
+ - Option to set a seed for the edge coloring heuristic (-seed \<n\>), which can be used to adjust the output
+ - Fixed parsing of glyph contours starting that start with a curve control point.
+
 ## Getting started
 
 The project can be used either as a library or as a console program. is divided into two parts, **[core](core)**

+ 28 - 6
core/edge-coloring.cpp

@@ -7,7 +7,24 @@ static bool isCorner(const Vector2 &aDir, const Vector2 &bDir, double crossThres
     return dotProduct(aDir, bDir) <= 0 || fabs(crossProduct(aDir, bDir)) > crossThreshold;
 }
 
-void edgeColoringSimple(Shape &shape, double angleThreshold) {
+static void switchColor(EdgeColor &color, unsigned long long &seed, EdgeColor banned = BLACK) {
+    EdgeColor combined = EdgeColor(color&banned);
+    if (combined == RED || combined == GREEN || combined == BLUE) {
+        color = EdgeColor(combined^WHITE);
+        return;
+    }
+    if (color == BLACK || color == WHITE) {
+        static const EdgeColor start[3] = { CYAN, MAGENTA, YELLOW };
+        color = start[seed%3];
+        seed /= 3;
+        return;
+    }
+    int shifted = color<<(1+(seed&1));
+    color = EdgeColor((shifted|shifted>>3)&WHITE);
+    seed >>= 1;
+}
+
+void edgeColoringSimple(Shape &shape, double angleThreshold, unsigned long long seed) {
     double crossThreshold = sin(angleThreshold);
     std::vector<int> corners;
     for (std::vector<Contour>::iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) {
@@ -29,7 +46,9 @@ void edgeColoringSimple(Shape &shape, double angleThreshold) {
                 (*edge)->color = WHITE;
         // "Teardrop" case
         else if (corners.size() == 1) {
-            const EdgeColor colors[] = { MAGENTA, WHITE, YELLOW };
+            EdgeColor colors[3] = { WHITE, WHITE };
+            switchColor(colors[0], seed);
+            switchColor(colors[2] = colors[0], seed);
             int corner = corners[0];
             if (contour->edges.size() >= 3) {
                 int m = contour->edges.size();
@@ -57,16 +76,19 @@ void edgeColoringSimple(Shape &shape, double angleThreshold) {
         // Multiple corners
         else {
             int cornerCount = corners.size();
-            // CMYCMYCMYCMY / YMYCMYC if corner count % 3 == 1
-            EdgeColor colors[] = { cornerCount%3 == 1 ? YELLOW : CYAN, CYAN, MAGENTA, YELLOW };
             int spline = 0;
             int start = corners[0];
             int m = contour->edges.size();
+            EdgeColor color = WHITE;
+            switchColor(color, seed);
+            EdgeColor initialColor = color;
             for (int i = 0; i < m; ++i) {
                 int index = (start+i)%m;
-                if (cornerCount > spline+1 && corners[spline+1] == index)
+                if (spline+1 < cornerCount && corners[spline+1] == index) {
                     ++spline;
-                contour->edges[index]->color = (colors+1)[spline%3-!spline];
+                    switchColor(color, seed, EdgeColor((spline == cornerCount-1)*initialColor));
+                }
+                contour->edges[index]->color = color;
             }
         }
     }

+ 1 - 1
core/edge-coloring.h

@@ -10,6 +10,6 @@ namespace msdfgen {
  *  angleThreshold specifies the maximum angle (in radians) to be considered a corner, for example 3 (~172 degrees).
  *  Values below 1/2 PI will be treated as the external angle.
  */
-void edgeColoringSimple(Shape &shape, double angleThreshold);
+void edgeColoringSimple(Shape &shape, double angleThreshold, unsigned long long seed = 0);
 
 }

+ 10 - 5
ext/import-font.cpp

@@ -109,6 +109,7 @@ bool loadGlyph(Shape &output, FontHandle *font, int unicode, double *advance) {
 
         Contour &contour = output.addContour();
         int first = last+1;
+        int firstPathPoint = -1;
         last = font->face->glyph->outline.contours[i];
 
         PointType state = NONE;
@@ -117,20 +118,24 @@ bool loadGlyph(Shape &output, FontHandle *font, int unicode, double *advance) {
 
         // For each point on the contour
         for (int round = 0, index = first; round == 0; ++index) {
-            // Close contour
             if (index > last) {
+                REQUIRE(firstPathPoint >= 0);
                 index = first;
-                round++;
             }
+            // Close contour
+            if (index == firstPathPoint)
+                ++round;
 
             Point2 point(font->face->glyph->outline.points[index].x/64., font->face->glyph->outline.points[index].y/64.);
             PointType pointType = font->face->glyph->outline.tags[index]&1 ? PATH_POINT : font->face->glyph->outline.tags[index]&2 ? CUBIC_POINT : QUADRATIC_POINT;
 
             switch (state) {
                 case NONE:
-                    REQUIRE(pointType == PATH_POINT);
-                    startPoint = point;
-                    state = PATH_POINT;
+                    if (pointType == PATH_POINT) {
+                        firstPathPoint = index;
+                        startPoint = point;
+                        state = PATH_POINT;
+                    }
                     break;
                 case PATH_POINT:
                     if (pointType == PATH_POINT) {

+ 48 - 6
main.cpp

@@ -1,6 +1,6 @@
 
 /*
- * MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR v1.1 (2016-05-08) - standalone console program
+ * MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR v1.2 (2016-07-20) - standalone console program
  * --------------------------------------------------------------------------------------------
  * A utility by Viktor Chlumsky, (c) 2014 - 2016
  *
@@ -44,6 +44,11 @@ static bool parseUnsigned(unsigned &value, const char *arg) {
     return sscanf(arg, "%u%c", &value, &c) == 1;
 }
 
+static bool parseUnsignedLL(unsigned long long &value, const char *arg) {
+    static char c;
+    return sscanf(arg, "%llu%c", &value, &c) == 1;
+}
+
 static bool parseUnsignedHex(unsigned &value, const char *arg) {
     static char c;
     return sscanf(arg, "%x%c", &value, &c) == 1;
@@ -126,6 +131,21 @@ static void parseColoring(Shape &shape, const char *edgeAssignment) {
     }
 }
 
+static void invertColor(Bitmap<FloatRGB> &bitmap) {
+    for (int y = 0; y < bitmap.height(); ++y)
+        for (int x = 0; x < bitmap.width(); ++x) {
+            bitmap(x, y).r = .5f-bitmap(x, y).r;
+            bitmap(x, y).g = .5f-bitmap(x, y).g;
+            bitmap(x, y).b = .5f-bitmap(x, y).b;
+        }
+}
+
+static void invertColor(Bitmap<float> &bitmap) {
+    for (int y = 0; y < bitmap.height(); ++y)
+        for (int x = 0; x < bitmap.width(); ++x)
+            bitmap(x, y) = .5f-bitmap(x, y);
+}
+
 static bool writeTextBitmap(FILE *file, const float *values, int cols, int rows) {
     for (int row = 0; row < rows; ++row) {
         for (int col = 0; col < cols; ++col) {
@@ -222,7 +242,7 @@ static const char * writeOutput(const Bitmap<T> &bitmap, const char *filename, F
                 return NULL;
             }
             default:
-              break;
+                break;
         }
     } else {
         if (format == AUTO || format == TEXT)
@@ -302,6 +322,10 @@ static const char *helpText =
         "\tSets the translation of the shape in shape units.\n"
     "  -yflip\n"
         "\tInverts the Y axis in the output distance field. The default order is bottom to top.\n"
+    "  -reverseorder\n"
+        "\tReverses the order of the points in each contour.\n"
+    "  -seed <n>\n"
+        "\tSets the random seed for edge coloring heuristic.\n"
     "\n";
 
 int main(int argc, const char * const *argv) {
@@ -351,6 +375,8 @@ int main(int argc, const char * const *argv) {
     bool yFlip = false;
     bool printMetrics = false;
     bool skipColoring = false;
+    bool reverseOrder = false;
+    unsigned long long coloringSeed = 0;
 
     int argPos = 1;
     bool suggestHelp = false;
@@ -540,6 +566,17 @@ int main(int argc, const char * const *argv) {
             argPos += 1;
             continue;
         }
+        ARG_CASE("-reverseorder", 0) {
+            reverseOrder = true;
+            argPos += 1;
+            continue;
+        }
+        ARG_CASE("-seed", 1) {
+            if (!parseUnsignedLL(coloringSeed, argv[argPos+1]))
+                ABORT("Invalid seed. Use -seed <N> with N being a non-negative integer.");
+            argPos += 2;
+            continue;
+        }
         ARG_CASE("-help", 0)
             ABORT(helpText);
         printf("Unknown setting or insufficient parameters: %s\n", arg);
@@ -600,7 +637,7 @@ int main(int argc, const char * const *argv) {
             break;
         }
         default:
-          break;
+            break;
     }
 
     // Validate and normalize shape
@@ -692,7 +729,7 @@ int main(int argc, const char * const *argv) {
         }
         case MULTI: {
             if (!skipColoring)
-                edgeColoringSimple(shape, angleThreshold);
+                edgeColoringSimple(shape, angleThreshold, coloringSeed);
             if (edgeAssignment)
                 parseColoring(shape, edgeAssignment);
             msdf = Bitmap<FloatRGB>(width, height);
@@ -700,7 +737,12 @@ int main(int argc, const char * const *argv) {
             break;
         }
         default:
-          break;
+            break;
+    }
+
+    if (reverseOrder) {
+        invertColor(sdf);
+        invertColor(msdf);
     }
 
     // Save output
@@ -753,7 +795,7 @@ int main(int argc, const char * const *argv) {
                     ABORT("Failed to write test render file.");
             }
             break;
-          default:
+        default:
             break;
     }
 

BIN
msdfgen.exe


+ 2 - 2
msdfgen.h

@@ -2,7 +2,7 @@
 #pragma once
 
 /*
- * MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR v1.1 (2016-05-08)
+ * MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR v1.2 (2016-07-20)
  * ---------------------------------------------------------------
  * A utility by Viktor Chlumsky, (c) 2014 - 2016
  *
@@ -24,7 +24,7 @@
 #include "core/save-bmp.h"
 #include "core/shape-description.h"
 
-#define MSDFGEN_VERSION "1.1"
+#define MSDFGEN_VERSION "1.2"
 
 namespace msdfgen {