public void Set(GlyphPoint point) { Active = true; OnCurve = point.OnCurve; X = point.X; Y = point.Y; }
private static void LoadGlyph(Glyph glyph,int contourCount,FontParser parser,float range){ // The contour count (tiny set): ushort[] endPointIndices=new ushort[contourCount]; // Load each endpoint: for(int i=0;i<contourCount;i++){ endPointIndices[i]=parser.ReadUInt16(); } // How big is the instruction block? int instructionLength=parser.ReadUInt16(); // And skip it! parser.Position+=instructionLength; // How many coordinates? int numberOfCoordinates=endPointIndices[endPointIndices.Length-1]+1; // Create the flag set: byte[] flags=new byte[numberOfCoordinates]; // For each one.. for (int i = 0; i < numberOfCoordinates;i++) { byte flag=parser.ReadByte(); flags[i]=flag; // If bit 3 is set, we repeat this flag n times, where n is the next byte. if((flag&8)>0){ int repeatCount = parser.ReadByte(); for (int j = 0; j < repeatCount; j += 1) { i++; flags[i]=flag; } } } if (endPointIndices.Length > 0) { // X/Y coordinates are relative to the previous point, except for the first point which is relative to 0,0. if (numberOfCoordinates > 0){ // Current coord: int coord=0; // Coord index: int coordIndex=0; // The coord set: float[] coords=new float[numberOfCoordinates*2]; // Load X coords: for (int i = 0; i < numberOfCoordinates; i++) { byte flag = flags[i]; coord = LoadGlyphCoordinate(parser,flag,coord,2,16); coords[coordIndex]=(float)coord/range; coordIndex+=2; } // Reset shared vars: coord=0; coordIndex=1; // Load Y coords: for (int i = 0; i < numberOfCoordinates; i++) { byte flag = flags[i]; coord = LoadGlyphCoordinate(parser,flag,coord,4,32); coords[coordIndex]=(float)coord/range; coordIndex+=2; } int[] orderedEnds=new int[endPointIndices.Length]; int currentEnd=0; for (int i = 0; i < numberOfCoordinates; i++) { // Grab the flag: byte flag=flags[i]; // On curve flag - Control point otherwise: flag=(byte)(flag&1); // Last point of the current contour? // For each end point index (tiny set - better than hash): for(int e=endPointIndices.Length-1;e>=0;e--){ if(endPointIndices[e]==i){ orderedEnds[currentEnd]=i; currentEnd++; break; } } // Update the flag - it's now just a 1 or 0: flags[i]=flag; } // Reset shared index again: coordIndex=0; // Create our temp holders of point info: GlyphPoint firstPointRaw=new GlyphPoint(flags,coords); GlyphPoint lastPointRaw=new GlyphPoint(flags,coords); GlyphPoint prevPointRaw=new GlyphPoint(flags,coords); GlyphPoint currentPointRaw=new GlyphPoint(flags,coords); GlyphPoint controlPoint=new GlyphPoint(flags,coords); // For each contour.. for(int i=0;i<contourCount;i++){ int pointOffset=0; // Get the indices of the first/last points on this contour. int firstIndex=0; int lastIndex=orderedEnds[i]; if(i!=0){ firstIndex=orderedEnds[i-1]+1; } GlyphPoint firstPoint=firstPointRaw; firstPoint.Set(firstIndex); GlyphPoint lastPoint=lastPointRaw; lastPoint.Set(lastIndex); if(firstPoint.OnCurve){ // No control point: controlPoint.Active=false; // The first point will be consumed by the moveTo command so skip it: pointOffset=1; }else{ if(lastPoint.OnCurve){ // If the first point is off-curve and the last point is on-curve, // start at the last point. firstPoint=lastPoint; }else{ // If both first and last points are off-curve, start at their middle. firstPoint.X=(firstPoint.X+lastPoint.X)/2f; firstPoint.Y=(firstPoint.Y+lastPoint.Y)/2f; } controlPoint.Set(firstPoint); } glyph.MoveTo(firstPoint.X,firstPoint.Y); int contourStart=firstIndex+pointOffset; for(int j=contourStart;j<=lastIndex;j++){ // Setup the previous point: GlyphPoint prevPoint; if(j==firstIndex){ prevPoint=firstPoint; }else{ prevPoint=prevPointRaw; prevPoint.Set(j-1); } // Setup the current point: GlyphPoint pt=currentPointRaw; pt.Set(j); if(prevPoint.OnCurve && pt.OnCurve) { // Just a line here: glyph.LineTo(pt.X,pt.Y); }else if (prevPoint.OnCurve && !pt.OnCurve){ controlPoint.Set(pt); }else if(!prevPoint.OnCurve && !pt.OnCurve){ float midPointX=(prevPoint.X+pt.X)/2f; float midPointY=(prevPoint.Y+pt.Y)/2f; glyph.QuadraticCurveTo(prevPoint.X,prevPoint.Y,midPointX,midPointY); controlPoint.Set(pt); }else if(!prevPoint.OnCurve && pt.OnCurve){ // Previous point off-curve, this point on-curve. glyph.QuadraticCurveTo(controlPoint.X,controlPoint.Y,pt.X,pt.Y); controlPoint.Active=false; } } if(firstPoint!=lastPoint){ // Close the path. if(controlPoint.Active){ // Still got a spare control point: glyph.QuadraticCurveTo(controlPoint.X,controlPoint.Y,firstPoint.X,firstPoint.Y); } // Just a normal close: glyph.ClosePath(); } } } } if(glyph.Font.WindingUnknown){ // Find the winding now: glyph.Font.FindWinding(glyph); } }
//--------------------------------------
private static void LoadGlyph(Glyph glyph, int contourCount, FontParser parser, float range) { // The contour count (tiny set): ushort[] endPointIndices = new ushort[contourCount]; // Load each endpoint: for (int i = 0; i < contourCount; i++) { endPointIndices[i] = parser.ReadUInt16(); } // How big is the instruction block? int instructionLength = parser.ReadUInt16(); // And skip it! parser.Position += instructionLength; // How many coordinates? int numberOfCoordinates = endPointIndices[endPointIndices.Length - 1] + 1; // Create the flag set: byte[] flags = new byte[numberOfCoordinates]; // For each one.. for (int i = 0; i < numberOfCoordinates; i++) { byte flag = parser.ReadByte(); flags[i] = flag; // If bit 3 is set, we repeat this flag n times, where n is the next byte. if ((flag & 8) > 0) { int repeatCount = parser.ReadByte(); for (int j = 0; j < repeatCount; j += 1) { i++; flags[i] = flag; } } } if (endPointIndices.Length > 0) { // X/Y coordinates are relative to the previous point, except for the first point which is relative to 0,0. if (numberOfCoordinates > 0) { // Current coord: int coord = 0; // Coord index: int coordIndex = 0; // The coord set: float[] coords = new float[numberOfCoordinates * 2]; // Load X coords: for (int i = 0; i < numberOfCoordinates; i++) { byte flag = flags[i]; coord = LoadGlyphCoordinate(parser, flag, coord, 2, 16); coords[coordIndex] = (float)coord / range; coordIndex += 2; } // Reset shared vars: coord = 0; coordIndex = 1; // Load Y coords: for (int i = 0; i < numberOfCoordinates; i++) { byte flag = flags[i]; coord = LoadGlyphCoordinate(parser, flag, coord, 4, 32); coords[coordIndex] = (float)coord / range; coordIndex += 2; } int[] orderedEnds = new int[endPointIndices.Length]; int currentEnd = 0; for (int i = 0; i < numberOfCoordinates; i++) { // Grab the flag: byte flag = flags[i]; // On curve flag - Control point otherwise: flag = (byte)(flag & 1); // Last point of the current contour? // For each end point index (tiny set - better than hash): for (int e = endPointIndices.Length - 1; e >= 0; e--) { if (endPointIndices[e] == i) { orderedEnds[currentEnd] = i; currentEnd++; break; } } // Update the flag - it's now just a 1 or 0: flags[i] = flag; } // Reset shared index again: coordIndex = 0; // Create our temp holders of point info: GlyphPoint firstPointRaw = new GlyphPoint(flags, coords); GlyphPoint lastPointRaw = new GlyphPoint(flags, coords); GlyphPoint prevPointRaw = new GlyphPoint(flags, coords); GlyphPoint currentPointRaw = new GlyphPoint(flags, coords); GlyphPoint controlPoint = new GlyphPoint(flags, coords); // For each contour.. for (int i = 0; i < contourCount; i++) { int pointOffset = 0; // Get the indices of the first/last points on this contour. int firstIndex = 0; int lastIndex = orderedEnds[i]; if (i != 0) { firstIndex = orderedEnds[i - 1] + 1; } GlyphPoint firstPoint = firstPointRaw; firstPoint.Set(firstIndex); GlyphPoint lastPoint = lastPointRaw; lastPoint.Set(lastIndex); if (firstPoint.OnCurve) { // No control point: controlPoint.Active = false; // The first point will be consumed by the moveTo command so skip it: pointOffset = 1; } else { if (lastPoint.OnCurve) { // If the first point is off-curve and the last point is on-curve, // start at the last point. firstPoint = lastPoint; } else { // If both first and last points are off-curve, start at their middle. firstPoint.X = (firstPoint.X + lastPoint.X) / 2f; firstPoint.Y = (firstPoint.Y + lastPoint.Y) / 2f; } controlPoint.Set(firstPoint); } glyph.MoveTo(firstPoint.X, firstPoint.Y); int contourStart = firstIndex + pointOffset; for (int j = contourStart; j <= lastIndex; j++) { // Setup the previous point: GlyphPoint prevPoint; if (j == firstIndex) { prevPoint = firstPoint; } else { prevPoint = prevPointRaw; prevPoint.Set(j - 1); } // Setup the current point: GlyphPoint pt = currentPointRaw; pt.Set(j); if (prevPoint.OnCurve && pt.OnCurve) { // Just a line here: glyph.LineTo(pt.X, pt.Y); } else if (prevPoint.OnCurve && !pt.OnCurve) { controlPoint.Set(pt); } else if (!prevPoint.OnCurve && !pt.OnCurve) { float midPointX = (prevPoint.X + pt.X) / 2f; float midPointY = (prevPoint.Y + pt.Y) / 2f; glyph.QuadraticCurveTo(prevPoint.X, prevPoint.Y, midPointX, midPointY); controlPoint.Set(pt); } else if (!prevPoint.OnCurve && pt.OnCurve) { // Previous point off-curve, this point on-curve. glyph.QuadraticCurveTo(controlPoint.X, controlPoint.Y, pt.X, pt.Y); controlPoint.Active = false; } } if (firstPoint != lastPoint) { // Close the path. if (controlPoint.Active) { // Still got a spare control point: glyph.QuadraticCurveTo(controlPoint.X, controlPoint.Y, firstPoint.X, firstPoint.Y); } // Just a normal close: glyph.ClosePath(); } } } } if (glyph.Font.WindingUnknown) { // Find the winding now: glyph.Font.FindWinding(glyph); } }