mirror of
				https://github.com/godotengine/godot.git
				synced 2025-10-31 13:41:03 +00:00 
			
		
		
		
	 4c3f7d1290
			
		
	
	
		4c3f7d1290
		
	
	
	
	
		
			
			Adds multi-channel SDF font texture generation and rendering support. Adds per-font oversampling support. Adds FontData import plugins (for dynamic fonts, BMFonts and monospaced image fonts), font texture cache pre-generation and loading. Adds BMFont binary format and outline support.
		
			
				
	
	
		
			284 lines
		
	
	
	
		
			9.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			284 lines
		
	
	
	
		
			9.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
 | |
| #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;
 | |
| }
 | |
| 
 | |
| }
 |