/// <summary> /// Constructor. /// </summary> /// <param name="glyph">The glyph being constructed.</param> /// <param name="local">Local subroutines.</param> /// <param name="global">Global subroutines.</param> public ExecContext( Font.Glyph glyph, Dictionary <int, Type2Charstring> local, Dictionary <int, Type2Charstring> global) { this.atStart = true; this.glyph = glyph; this.contour = null; this.pos = Vector2.zero; this.local = local; this.global = global; this.ended = false; this.processedFirstMT = false; this.width = 0.0f; this.hstems = new List <float>(); this.vstems = new List <float>(); this.hintMasks = null; this.cntrMasks = null; this.stack = new List <Operand>(); }
public Text(string text, string font, float textSize, Color color) { Vertices = new Vec2[4 * text.Length]; Colors = new Color[4 * text.Length]; TextureOffsets = new Vec2[text.Length, 4]; Font currentFont = TextureManager.Instance.GetFont(font); Texture = currentFont.Texture; // Get start center float xStartCenter = -((text.Length * textSize) / 2); for (int i = 0; i < text.Length; i++) { Font.Glyph curGlyph = currentFont.GetGlyph(text[i]); // Get glyph position in texture float xpos, ypos, xff, yff; if (curGlyph.xpos == 0) { xpos = 0; } else { xpos = curGlyph.xpos / (float)Tao.LayerWidth; } if (curGlyph.ypos == 0) { ypos = 1.0f; } else { ypos = 1.0f - (curGlyph.ypos / (float)Tao.LayerHeight); } xff = (float)curGlyph.xsize / (float)Tao.LayerWidth; yff = (float)curGlyph.ysize / ((float)Tao.LayerHeight + currentFont.FreeYSpace); Colors[i * 4 + 0] = color; Colors[i * 4 + 1] = color; Colors[i * 4 + 2] = color; Colors[i * 4 + 3] = color; Vertices[i * 4 + 0] = new Vec2(-textSize + (textSize * i) + xStartCenter, -textSize); Vertices[i * 4 + 1] = new Vec2(textSize + (textSize * i) + xStartCenter, -textSize); Vertices[i * 4 + 2] = new Vec2(textSize + (textSize * i) + xStartCenter, textSize); Vertices[i * 4 + 3] = new Vec2(-textSize + (textSize * i) + xStartCenter, textSize); TextureOffsets[i, 0] = new Vec2(xpos, ypos - yff); TextureOffsets[i, 1] = new Vec2(xpos + xff, ypos - yff); TextureOffsets[i, 2] = new Vec2(xpos + xff, ypos); TextureOffsets[i, 3] = new Vec2(xpos, ypos); } }
public unsafe bool DrawNext(uint *bmpAddress, int bmpWidth, int bmpHeight, int count) { int i = 0; while (i < count && _index < _str.Length) { int curX = _startX + _nextXOffset; int curY = _startY + _nextYOffset; Font.Glyph glyph = _font.GetGlyph(_str, ref _index, ref _nextXOffset, ref _nextYOffset); if (glyph != null) { _font.DrawGlyph(bmpAddress, bmpWidth, bmpHeight, curX, curY, glyph, _fontColors); i++; } } return(_index >= _str.Length); }
public void DrawText(string text, Vector2 position, float size) { float xpos = position.X; float scaleFactor = size / font.Size; scale = Matrix4.CreateScale(scaleFactor); //this is for all text we draw and counts the last DrawText call foreach (var c in text) { if (!font.Characters.ContainsKey(c)) { continue; } Font.Glyph glyph = font.Characters[c]; // Find the texture coordinates for this glyph float u1 = (float)(glyph.X + glyph.OriginX) / font.Width; float u2 = (float)(glyph.X + glyph.OriginX + glyph.Width) / font.Width; float v1 = (float)glyph.Y / font.Height; float v2 = (float)(glyph.Y + glyph.Height) / font.Height; // calculate y position for glyphs that are below baseline float ypos = position.Y - (glyph.Height - glyph.OriginY); // add 4 vertices for each corner to draw the glyph as a texture // Use of indices below to tell the triangles // NOTE Try to add the last 2 for each glyph and use the last 2 of the previous as the start for the next vertices.Add(new VertexTexture(xpos, ypos, -1.0f, u1, v2)); vertices.Add(new VertexTexture(xpos, ypos + glyph.Height, -1.0f, u1, v1)); vertices.Add(new VertexTexture(xpos + glyph.Width, ypos, -1.0f, u2, v2)); vertices.Add(new VertexTexture(xpos + glyph.Width, ypos + glyph.Height, -1.0f, u2, v1)); //Advance to the next position a glyph can be drawn, add padding(defaults to 1.0f) xpos += glyph.Advance; // Indices for the above vertices to create the 2 triangles for the quad int last = vertices.Count - 1; indices.AddRange(new ushort[] { (ushort)(last - 3), (ushort)(last - 1), (ushort)(last - 2) }); indices.AddRange(new ushort[] { (ushort)(last - 2), (ushort)(last - 1), (ushort)(last) }); } }
public Button(Vec2 size, Color quadColor, string font, string text, Color textColor) { int totalVertices = 4 + (text.Length * 4); size = size / 2; Vertices = new Vec2[totalVertices]; Colors = new Color[totalVertices]; TextureOffsets = new Vec2[text.Length + 4, 4]; Font currentFont = TextureManager.Instance.GetFont(font); Texture = currentFont.Texture; // Make Quad Vertices[0] = new Vec2(-size.X, -size.Y); Vertices[1] = new Vec2(size.X, -size.Y); Vertices[2] = new Vec2(size.X, size.Y); Vertices[3] = new Vec2(-size.X, size.Y); Colors[0] = quadColor; Colors[1] = quadColor; Colors[2] = quadColor; Colors[3] = quadColor; TextureOffsets[0, 0] = new Vec2(-1, -1); TextureOffsets[0, 1] = new Vec2(-1, -1); TextureOffsets[0, 2] = new Vec2(-1, -1); TextureOffsets[0, 3] = new Vec2(-1, -1); // Generate text // Get start center float xStartCenter = -size.X; float textSize = (size.X * 2) / (text.Length + 1); for (int i = 1; i < text.Length + 1; i++) { Font.Glyph curGlyph = currentFont.GetGlyph(text[i - 1]); // Get glyph position in texture float xpos, ypos, xff, yff; if (curGlyph.xpos == 0) { xpos = 0; } else { xpos = curGlyph.xpos / (float)Tao.LayerWidth; } if (curGlyph.ypos == 0) { ypos = 1.0f; } else { ypos = 1.0f - (curGlyph.ypos / (float)Tao.LayerHeight); } xff = (float)curGlyph.xsize / (float)Tao.LayerWidth; yff = (float)curGlyph.ysize / ((float)Tao.LayerHeight + currentFont.FreeYSpace); Colors[i * 4 + 0] = textColor; Colors[i * 4 + 1] = textColor; Colors[i * 4 + 2] = textColor; Colors[i * 4 + 3] = textColor; Vertices[i * 4 + 0] = new Vec2(-textSize + (textSize * i) + xStartCenter, -textSize); Vertices[i * 4 + 1] = new Vec2(textSize + (textSize * i) + xStartCenter, -textSize); Vertices[i * 4 + 2] = new Vec2(textSize + (textSize * i) + xStartCenter, textSize); Vertices[i * 4 + 3] = new Vec2(-textSize + (textSize * i) + xStartCenter, textSize); TextureOffsets[i, 0] = new Vec2(xpos, ypos - yff); TextureOffsets[i, 1] = new Vec2(xpos + xff, ypos - yff); TextureOffsets[i, 2] = new Vec2(xpos + xff, ypos); TextureOffsets[i, 3] = new Vec2(xpos, ypos); } }
/// <summary> /// Given a font glyph, generate a formal path for it. /// </summary> /// <param name="glyph">The glyph to turn into a path.</param> /// <param name="l">The layer to create the shape in.</param> /// <param name="offset">The offset to translate the glyph.</param> /// <param name="scale">The scale of the glyph, with 1.0 being the /// default size.</param> /// <returns>The created path. If the glyph has multiple /// contours, they will be created as individual loops.</returns> public static BShape GenerateGlyph( Font.Glyph glyph, Layer l, Vector2 offset, float scale) { BShape shapeLetter = new BShape(Vector2.zero, 0.0f); shapeLetter.layer = l; if (l != null) { l.shapes.Add(shapeLetter); } // Generate each contour in the glyph. When we're iterating through the glyph points, // we need to remember we're dealing with two possible conventions at once - TTF/OTF and // CFF. // // Remember TTF/OTF uses quadratic Beziers and the control flags. // // While CCF uses cubic Beziers and the point tangents and tangent flags. for (int j = 0; j < glyph.contours.Count; ++j) { BLoop loopCont = new BLoop(shapeLetter); //https://stackoverflow.com/questions/20733790/truetype-fonts-glyph-are-made-of-quadratic-bezier-why-do-more-than-one-consecu Font.Contour cont = glyph.contours[j]; for (int k = 0; k < cont.points.Count; ++k) { int nextId = (k + 1) % cont.points.Count; // If two control points are next to each other, there's an implied // point in between them at their average. The easiest way to handle // that is to make a representation where we manually inserted them // to define them explicitly. // // NOTE: We should probably just directly "sanitize" this information // when it's first loaded. if (cont.points[k].isControl == true && cont.points[nextId].isControl == true) { Font.Point pt = new Font.Point(); pt.isControl = false; pt.position = (cont.points[k].position + cont.points[nextId].position) * 0.5f; // Things that process this data may want to know it's implied, especially // diagnostic tools. pt.implied = true; cont.points.Insert(nextId, pt); ++k; } } BNode firstNode = null; // Used to know what to link the last node to when we're done looping. BNode prevNode = null; // Used to have a record of the last node when we're done looping. Vector2?lastTan = null; // The last used tangent when dealing with control points. // Point are now either points, or curve controls surrounded by points - // or it's a CFF and we don't actually care about control points since we have // explicitly defined tangents. // // The code is written to handle both without explicitly knowing which system is being used. for (int k = 0; k < cont.points.Count; ++k) { Vector2 ptpos = cont.points[k].position * scale + offset; if (cont.points[k].isControl == false) { BNode node = new BNode(loopCont, ptpos); loopCont.nodes.Add(node); if (lastTan.HasValue == true) { node.UseTanIn = true; node.TanIn = (lastTan.Value - ptpos) * (2.0f / 3.0f) * scale; } lastTan = null; if (prevNode != null) { node.prev = prevNode; prevNode.next = node; } if (firstNode == null) { firstNode = node; } int kPrev = (k - 1 + cont.points.Count) % cont.points.Count; if (k != 0 && cont.points[kPrev].isControl == false && cont.points[kPrev].useTangentOut == false) { prevNode.UseTanOut = false; node.UseTanIn = false; } if (cont.points[k].useTangentIn == true) { node.UseTanIn = true; node.TanIn = cont.points[k].tangentIn; } if (cont.points[k].useTangentOut == true) { node.UseTanOut = true; node.TanOut = cont.points[k].tangentOut; } node.FlagDirty(); prevNode = node; } else // if (cont.points[k].control == true) { lastTan = ptpos; if (prevNode != null) { prevNode.UseTanOut = true; prevNode.TanOut = (ptpos - prevNode.Pos) * (2.0f / 3.0f) * scale; } } } if (firstNode != null) { prevNode.next = firstNode; firstNode.prev = prevNode; if ( cont.points[0].isControl == false && cont.points[0].useTangentIn == false && cont.points[cont.points.Count - 1].isControl == false && cont.points[cont.points.Count - 1].useTangentOut == false) { firstNode.UseTanIn = false; prevNode.UseTanOut = false; } if (lastTan.HasValue == true) { firstNode.UseTanIn = true; firstNode.TanIn = (lastTan.Value - firstNode.Pos) * (2.0f / 3.0f) * scale; } } } return(shapeLetter); }