summaryrefslogtreecommitdiff
path: root/thirdparty/msdfgen/core/shape-description.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/msdfgen/core/shape-description.cpp')
-rw-r--r--thirdparty/msdfgen/core/shape-description.cpp284
1 files changed, 284 insertions, 0 deletions
diff --git a/thirdparty/msdfgen/core/shape-description.cpp b/thirdparty/msdfgen/core/shape-description.cpp
new file mode 100644
index 0000000000..a096fa2541
--- /dev/null
+++ b/thirdparty/msdfgen/core/shape-description.cpp
@@ -0,0 +1,284 @@
+
+#define _CRT_SECURE_NO_WARNINGS
+#include "shape-description.h"
+
+namespace msdfgen {
+
+int readCharF(FILE *input) {
+ int c = '\0';
+ do {
+ c = fgetc(input);
+ } while (c == ' ' || c == '\t' || c == '\r' || c == '\n');
+ return c;
+}
+
+int readCharS(const char **input) {
+ int c = '\0';
+ do {
+ c = *(*input)++;
+ } while (c == ' ' || c == '\t' || c == '\r' || c == '\n');
+ if (!c) {
+ --c;
+ return EOF;
+ }
+ return c;
+}
+
+int readCoordF(FILE *input, Point2 &coord) {
+ return fscanf(input, "%lf,%lf", &coord.x, &coord.y);
+}
+
+int readCoordS(const char **input, Point2 &coord) {
+ int read = 0;
+ int result = sscanf(*input, "%lf,%lf%n", &coord.x, &coord.y, &read);
+ *input += read;
+ return result;
+}
+
+static bool writeCoord(FILE *output, Point2 coord) {
+ fprintf(output, "%.12g, %.12g", coord.x, coord.y);
+ return true;
+}
+
+template <typename T, int (*readChar)(T *), int (*readCoord)(T *, Point2 &)>
+static int readControlPoints(T *input, Point2 *output) {
+ int result = readCoord(input, output[0]);
+ if (result == 2) {
+ switch (readChar(input)) {
+ case ')':
+ return 1;
+ case ';':
+ break;
+ default:
+ return -1;
+ }
+ result = readCoord(input, output[1]);
+ if (result == 2 && readChar(input) == ')')
+ return 2;
+ } else if (result != 1 && readChar(input) == ')')
+ return 0;
+ return -1;
+}
+
+template <typename T, int (*readChar)(T *), int (*readCoord)(T *, Point2 &)>
+static bool readContour(T *input, Contour &output, const Point2 *first, int terminator, bool &colorsSpecified) {
+ Point2 p[4], start;
+ if (first)
+ p[0] = *first;
+ else {
+ int result = readCoord(input, p[0]);
+ if (result != 2)
+ return result != 1 && readChar(input) == terminator;
+ }
+ start = p[0];
+ int c = '\0';
+ while ((c = readChar(input)) != terminator) {
+ if (c != ';')
+ return false;
+ EdgeColor color = WHITE;
+ int result = readCoord(input, p[1]);
+ if (result == 2) {
+ output.addEdge(EdgeHolder(p[0], p[1], color));
+ p[0] = p[1];
+ continue;
+ } else if (result == 1)
+ return false;
+ else {
+ int controlPoints = 0;
+ switch ((c = readChar(input))) {
+ case '#':
+ output.addEdge(EdgeHolder(p[0], start, color));
+ p[0] = start;
+ continue;
+ case ';':
+ goto FINISH_EDGE;
+ case '(':
+ goto READ_CONTROL_POINTS;
+ case 'C': case 'c':
+ color = CYAN;
+ colorsSpecified = true;
+ break;
+ case 'M': case 'm':
+ color = MAGENTA;
+ colorsSpecified = true;
+ break;
+ case 'Y': case 'y':
+ color = YELLOW;
+ colorsSpecified = true;
+ break;
+ case 'W': case 'w':
+ color = WHITE;
+ colorsSpecified = true;
+ break;
+ default:
+ return c == terminator;
+ }
+ switch (readChar(input)) {
+ case ';':
+ goto FINISH_EDGE;
+ case '(':
+ READ_CONTROL_POINTS:
+ if ((controlPoints = readControlPoints<T, readChar, readCoord>(input, p+1)) < 0)
+ return false;
+ break;
+ default:
+ return false;
+ }
+ if (readChar(input) != ';')
+ return false;
+ FINISH_EDGE:
+ result = readCoord(input, p[1+controlPoints]);
+ if (result != 2) {
+ if (result == 1)
+ return false;
+ else {
+ if (readChar(input) == '#')
+ p[1+controlPoints] = start;
+ else
+ return false;
+ }
+ }
+ switch (controlPoints) {
+ case 0:
+ output.addEdge(EdgeHolder(p[0], p[1], color));
+ p[0] = p[1];
+ continue;
+ case 1:
+ output.addEdge(EdgeHolder(p[0], p[1], p[2], color));
+ p[0] = p[2];
+ continue;
+ case 2:
+ output.addEdge(EdgeHolder(p[0], p[1], p[2], p[3], color));
+ p[0] = p[3];
+ continue;
+ }
+ }
+ }
+ return true;
+}
+
+bool readShapeDescription(FILE *input, Shape &output, bool *colorsSpecified) {
+ bool locColorsSpec = false;
+ output.contours.clear();
+ output.inverseYAxis = false;
+ Point2 p;
+ int result = readCoordF(input, p);
+ if (result == 2) {
+ return readContour<FILE, readCharF, readCoordF>(input, output.addContour(), &p, EOF, locColorsSpec);
+ } else if (result == 1)
+ return false;
+ else {
+ int c = readCharF(input);
+ if (c == '@') {
+ char after = '\0';
+ if (fscanf(input, "invert-y%c", &after) != 1)
+ return feof(input) != 0;
+ output.inverseYAxis = true;
+ c = after;
+ if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
+ c = readCharF(input);
+ }
+ for (; c == '{'; c = readCharF(input))
+ if (!readContour<FILE, readCharF, readCoordF>(input, output.addContour(), NULL, '}', locColorsSpec))
+ return false;
+ if (colorsSpecified)
+ *colorsSpecified = locColorsSpec;
+ return c == EOF && feof(input);
+ }
+}
+
+bool readShapeDescription(const char *input, Shape &output, bool *colorsSpecified) {
+ bool locColorsSpec = false;
+ output.contours.clear();
+ output.inverseYAxis = false;
+ Point2 p;
+ int result = readCoordS(&input, p);
+ if (result == 2) {
+ return readContour<const char *, readCharS, readCoordS>(&input, output.addContour(), &p, EOF, locColorsSpec);
+ } else if (result == 1)
+ return false;
+ else {
+ int c = readCharS(&input);
+ if (c == '@') {
+ for (int i = 0; i < (int) sizeof("invert-y")-1; ++i)
+ if (input[i] != "invert-y"[i])
+ return false;
+ output.inverseYAxis = true;
+ input += sizeof("invert-y")-1;
+ c = readCharS(&input);
+ }
+ for (; c == '{'; c = readCharS(&input))
+ if (!readContour<const char *, readCharS, readCoordS>(&input, output.addContour(), NULL, '}', locColorsSpec))
+ return false;
+ if (colorsSpecified)
+ *colorsSpecified = locColorsSpec;
+ return c == EOF;
+ }
+}
+
+static bool isColored(const Shape &shape) {
+ for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour)
+ for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge)
+ if ((*edge)->color != WHITE)
+ return true;
+ return false;
+}
+
+bool writeShapeDescription(FILE *output, const Shape &shape) {
+ if (!shape.validate())
+ return false;
+ bool writeColors = isColored(shape);
+ if (shape.inverseYAxis)
+ fprintf(output, "@invert-y\n");
+ for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) {
+ fprintf(output, "{\n");
+ if (!contour->edges.empty()) {
+ for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
+ char colorCode = '\0';
+ if (writeColors) {
+ switch ((*edge)->color) {
+ case YELLOW: colorCode = 'y'; break;
+ case MAGENTA: colorCode = 'm'; break;
+ case CYAN: colorCode = 'c'; break;
+ case WHITE: colorCode = 'w'; break;
+ default:;
+ }
+ }
+ if (const LinearSegment *e = dynamic_cast<const LinearSegment *>(&**edge)) {
+ fprintf(output, "\t");
+ writeCoord(output, e->p[0]);
+ fprintf(output, ";\n");
+ if (colorCode)
+ fprintf(output, "\t\t%c;\n", colorCode);
+ }
+ if (const QuadraticSegment *e = dynamic_cast<const QuadraticSegment *>(&**edge)) {
+ fprintf(output, "\t");
+ writeCoord(output, e->p[0]);
+ fprintf(output, ";\n\t\t");
+ if (colorCode)
+ fprintf(output, "%c", colorCode);
+ fprintf(output, "(");
+ writeCoord(output, e->p[1]);
+ fprintf(output, ");\n");
+ }
+ if (const CubicSegment *e = dynamic_cast<const CubicSegment *>(&**edge)) {
+ fprintf(output, "\t");
+ writeCoord(output, e->p[0]);
+ fprintf(output, ";\n\t\t");
+ if (colorCode)
+ fprintf(output, "%c", colorCode);
+ fprintf(output, "(");
+ writeCoord(output, e->p[1]);
+ fprintf(output, "; ");
+ writeCoord(output, e->p[2]);
+ fprintf(output, ");\n");
+ }
+ }
+ fprintf(output, "\t#\n");
+ }
+ fprintf(output, "}\n");
+ }
+ return true;
+}
+
+}