Beispiel #1
0
                    /// <summary>
                    /// Sets the formatting for the given range of characters in the line
                    /// </summary>
                    public void SetFormatting(int start, int end, GlyphFormat format, bool onlyChangeColor)
                    {
                        Vector4 bbColor = QuadBoard.GetQuadBoardColor(format.Data.Item4);

                        for (int n = start; n <= end; n++)
                        {
                            if (onlyChangeColor)
                            {
                                var quadBoard = glyphBoards[n];
                                quadBoard.bbColor = bbColor;

                                glyphBoards[n]     = quadBoard;
                                formattedGlyphs[n] = new FormattedGlyph(formattedGlyphs[n].glyph, format);
                            }
                            else if (!formattedGlyphs[n].format.Equals(format))
                            {
                                IFontStyle fontStyle = FontManager.GetFontStyle(format.Data.Item3);
                                float      scale     = format.Data.Item2 * fontStyle.FontScale;
                                Glyph      glyph     = fontStyle[chars[n]];
                                Vector2    glyphSize = new Vector2(glyph.advanceWidth, fontStyle.Height) * scale;

                                formattedGlyphs[n] = new FormattedGlyph(glyph, format);
                                locData[n]         = new GlyphLocData(glyph.MatFrame.Material.size * scale, glyphSize);
                                glyphBoards[n]     = glyph.GetQuadBoard(format, bbColor);
                            }
                        }
                    }
                /// <summary>
                /// Updates the position of the right character.
                /// </summary>
                private float UpdateCharOffset(Line line, int right, int left, Vector2 pos, float xAlign)
                {
                    char           ch             = line.Chars[right];
                    FormattedGlyph formattedGlyph = line.FormattedGlyphs[right];
                    IFontStyle     fontStyle      = FontManager.GetFontStyle(formattedGlyph.format.StyleIndex);

                    float textSize    = formattedGlyph.format.TextSize,
                          formatScale = textSize * fontStyle.FontScale,
                    // Quick fix for CJK characters in Space Engineers font data
                          cjkOffset = (formattedGlyph.format.StyleIndex.X == 0 && ch >= 0x4E00) ? (-4f * textSize) : 0f;

                    // Kerning adjustment
                    if (left >= 0)
                    {
                        GlyphFormat leftFmt = line.FormattedGlyphs[left].format, rightFmt = formattedGlyph.format;

                        if (leftFmt.StyleIndex == rightFmt.StyleIndex && leftFmt.TextSize == rightFmt.TextSize)
                        {
                            pos.X += fontStyle.GetKerningAdjustment(line.Chars[left], ch) * formatScale;
                        }
                    }

                    GlyphLocData locData = line.LocData[right];

                    line.SetOffsetAt(right, new Vector2()
                    {
                        X = pos.X + locData.bbSize.X * .5f + (formattedGlyph.glyph.leftSideBearing * formatScale) + xAlign,
                        Y = pos.Y - (locData.bbSize.Y * .5f) + (fontStyle.BaseLine * formatScale) + cjkOffset
                    });

                    return(pos.X + locData.chSize.X);
                }
Beispiel #3
0
                    /// <summary>
                    /// Recalculates the width and height of the line.
                    /// </summary>
                    public void UpdateSize()
                    {
                        _size = Vector2.Zero;

                        if (chars.Count > 0)
                        {
                            for (int n = 0; n < locData.Count; n++)
                            {
                                GlyphLocData sizeData = locData[n];

                                if (sizeData.chSize.Y > _size.Y)
                                {
                                    _size.Y = sizeData.chSize.Y;
                                }

                                float chWidth = sizeData.chSize.X;

                                if (chars[n] == '\t')
                                {
                                    FormattedGlyph formattedGlyph = formattedGlyphs[n];
                                    IFontStyle     fontStyle      = FontManager.GetFontStyle(formattedGlyph.format.StyleIndex);
                                    float          scale          = formattedGlyph.format.TextSize * fontStyle.FontScale;

                                    chWidth = formattedGlyphs[n].glyph.advanceWidth * scale;
                                    float rem = _size.X % chWidth;

                                    if (rem < chWidth * .8f)
                                    {
                                        chWidth -= rem;
                                    }
                                    else // if it's really close, just skip to the next stop
                                    {
                                        chWidth += (chWidth - rem);
                                    }

                                    sizeData.chSize.X = chWidth;
                                    sizeData.bbSize.X = chWidth;

                                    locData[n] = sizeData;
                                }

                                _size.X += chWidth;
                            }
                        }
                    }
                /// <summary>
                /// Calculates the horizontal offset needed to ensure that the character specified is within
                /// the visible range.
                /// </summary>
                private float GetCharRangeOffset(Vector2I index)
                {
                    Line  line   = lines[index.X];
                    float offset = _textOffset.X;

                    if (line.Count > 0)
                    {
                        if (index.Y != 0)
                        {
                            GlyphLocData locData = line.LocData[index.Y];

                            float minOffset = -locData.bbOffset.X + locData.chSize.X * .5f - _fixedSize.X * .5f,
                                  maxOffset = minOffset - locData.chSize.X + _fixedSize.X;

                            offset = MathHelper.Clamp(offset, minOffset, maxOffset);
                        }
                        else
                        {
                            offset = 0f;
                        }
                    }

                    return(offset);
                }
                /// <summary>
                /// Generates underlines for underlined text
                /// </summary>
                private void UpdateUnderlines()
                {
                    int visRange = endLine - startLine;

                    underlines.Clear();
                    underlines.EnsureCapacity(visRange);

                    for (int ln = startLine; ln <= endLine; ln++)
                    {
                        Line line = lines[ln];

                        if (line.Count > 0)
                        {
                            GlyphFormatMembers?formatData = line.FormattedGlyphs[0].format.Data;
                            int startCh = 0;

                            for (int ch = 0; ch < lines[ln].Count; ch++)
                            {
                                GlyphFormatMembers?nextFormat = null;

                                if (ch != line.Count - 1)
                                {
                                    nextFormat = line.FormattedGlyphs[ch + 1].format.Data;
                                }

                                bool formatEqual = nextFormat != null &&
                                                   formatData.Value.Item1 == nextFormat.Value.Item1 &&
                                                   formatData.Value.Item2 == nextFormat.Value.Item2 &&
                                                   formatData.Value.Item3 == nextFormat.Value.Item3 &&
                                                   formatData.Value.Item4 == nextFormat.Value.Item4;

                                if (!formatEqual)
                                {
                                    if (((FontStyles)formatData.Value.Item3.Y & FontStyles.Underline) > 0)
                                    {
                                        GlyphLocData start = line.LocData[startCh], end = line.LocData[ch];
                                        Vector2      pos = new Vector2
                                                           (
                                            (start.bbOffset.X + end.bbOffset.X) * .5f,
                                            end.bbOffset.Y - (end.chSize.Y * .5f - (1f * formatData.Value.Item2))
                                                           );

                                        Vector2 size = new Vector2
                                                       (
                                            (end.bbOffset.X - start.bbOffset.X) + (end.chSize.X + start.chSize.X) * .5f,
                                            Math.Max((int)formatData.Value.Item2, 1)
                                                       );

                                        Vector4 color = QuadBoard.GetQuadBoardColor(formatData.Value.Item4) * .9f;
                                        underlines.Add(new UnderlineBoard(size, pos, color));
                                    }

                                    startCh    = ch;
                                    formatData = nextFormat;
                                }
                            }
                        }
                    }

                    if (visRange > 9 && underlines.Capacity > 3 * underlines.Count && underlines.Capacity > visRange)
                    {
                        underlines.TrimExcess();
                    }
                }
                /// <summary>
                /// Draws the text board in world space on the XY plane of the matrix, facing in the +Z
                /// direction.
                /// </summary>
                public void Draw(BoundingBox2 box, BoundingBox2 mask, MatrixD[] matrix)
                {
                    ContainmentType containment;

                    mask.Contains(ref box, out containment);

                    if (containment != ContainmentType.Disjoint)
                    {
                        if (offsetsAreStale)
                        {
                            UpdateOffsets();
                        }
                        else if (lineRangeIsStale || (endLine == -1 && lines.Count > 0))
                        {
                            UpdateLineRange();
                        }

                        if (AutoResize)
                        {
                            _textOffset = Vector2.Zero;
                        }

                        if (updateEvent && (eventTimer.ElapsedTicks / TimeSpan.TicksPerMillisecond) > 500)
                        {
                            TextChanged?.Invoke();
                            eventTimer.Restart();
                            updateEvent = false;
                        }

                        BoundingBox2 textMask = box.Intersect(mask);
                        Vector2      offset   = box.Center + _textOffset * Scale;

                        IReadOnlyList <Line> lineList = lines.PooledLines;
                        CroppedBox           bb       = default(CroppedBox);
                        bb.mask = textMask;

                        // Draw glyphs
                        for (int ln = startLine; ln <= endLine && ln < lines.Count; ln++)
                        {
                            Line line = lineList[ln];

                            for (int ch = 0; ch < line.Count; ch++)
                            {
                                GlyphLocData locData  = line.LocData[ch];
                                Vector2      halfSize = locData.bbSize * Scale * .5f,
                                             pos      = offset + locData.bbOffset * Scale;

                                bb.bounds = new BoundingBox2(pos - halfSize, pos + halfSize);
                                bb.mask.Value.Contains(ref bb.bounds, out containment);

                                if (containment == ContainmentType.Contains)
                                {
                                    line.GlyphBoards[ch].Draw(ref bb, ref matrix[0]);
                                }
                                else if (containment != ContainmentType.Disjoint)
                                {
                                    line.GlyphBoards[ch].DrawCroppedTex(ref bb, ref matrix[0]);
                                }
                            }
                        }

                        QuadBoard underlineBoard = QuadBoard.Default;

                        // Draw underlines
                        for (int n = 0; n < underlines.Count; n++)
                        {
                            Vector2 halfSize = underlines[n].size * Scale * .5f,
                                    pos      = offset + underlines[n].offset * Scale;

                            bb.bounds = new BoundingBox2(pos - halfSize, pos + halfSize);
                            bb.mask.Value.Contains(ref bb.bounds, out containment);
                            underlineBoard.bbColor = underlines[n].color;

                            if (containment == ContainmentType.Contains)
                            {
                                underlineBoard.Draw(ref bb, ref matrix[0]);
                            }
                            else if (containment != ContainmentType.Disjoint)
                            {
                                underlineBoard.DrawCropped(ref bb, ref matrix[0]);
                            }
                        }
                    }
                }