Пример #1
0
 // NB: vertexColor needs to be as srgb when in gamma space, and in linear otherwise
 public static unsafe void LayoutString(char *text, int textLength, float fontSize, HorizontalAlignment hAlign,
                                        VerticalAlignment vAlign, float4 vertexColor,
                                        ref FontData font, DynamicBuffer <DynamicSimpleVertex> dynMesh, DynamicBuffer <DynamicIndex> dynTriangles,
                                        out AABB aabb)
 {
     LayoutString(text, textLength, fontSize, hAlign, vAlign, vertexColor, ref font,
                  dynMesh.Reinterpret <SimpleVertex>(),
                  dynTriangles.Reinterpret <ushort>(),
                  out aabb);
 }
Пример #2
0
        // NB: vertexColor needs to be as srgb when in gamma space, and in linear otherwise
        public static unsafe void LayoutString <T1, T2>(char *text, int textLength, float fontSize,
                                                        HorizontalAlignment hAlign, VerticalAlignment vAlign, float4 vertexColor,
                                                        ref FontData font, T1 mesh, T2 triangles,
                                                        out AABB aabb)
            where T1 : INativeList <SimpleVertex>
            where T2 : INativeList <ushort>
        {
            // TODO -- unicode code points may map to 0..N glyphs.  We just assume 1:1 right now because we're not shaping
            int *glyphIndices = stackalloc int[textLength];

            // figure out the glyph indices
            int gi = 0;

            for (int ci = 0; ci < textLength; ci++)
            {
                var charUnicode = text[ci];
                int glyphIndex  = font.FindGlyphIndexForCodePoint(charUnicode);

                // TODO handle tofu
                if (glyphIndex == -1)
                {
                    continue;
                }
                glyphIndices[gi++] = glyphIndex;
            }

            int numGlyphs = gi;

            // font  base calcs
            bool  isOrtho             = false; // ???
            float baseScale           = fontSize / font.Face.PointSize * font.Face.Scale * (isOrtho ? 1 : 0.1f);
            float currentElementScale = baseScale;

            // allocate space in the mesh
            mesh.Length = numGlyphs * 4;

            int numLines = CountLines(text, textLength);

            float fontBaseLineOffset = font.Face.Baseline * currentElementScale;

            if (vAlign == VerticalAlignment.Top)
            {
                fontBaseLineOffset -= font.Face.Ascent * currentElementScale;
            }
            else if (vAlign == VerticalAlignment.Bottom)
            {
                fontBaseLineOffset += (-(font.Face.Descent) * currentElementScale);
                fontBaseLineOffset += (font.Face.Ascent + font.Face.Descent) * (numLines - 1);
            }
            else if (vAlign == VerticalAlignment.Center)
            {
                fontBaseLineOffset = (font.Face.Baseline - (font.Face.Ascent + font.Face.Descent) * 0.5f) *
                                     currentElementScale;
                fontBaseLineOffset += (font.Face.Ascent + font.Face.Descent) * (numLines - 1) * 0.5f;
            }

            // experimental multi line: wrap mesh generation into a while loop so we can change offset for each line
            bool keepGoing  = true;
            int  startIndex = 0;
            int  meshIndex  = 0;

            while (keepGoing)
            {
                int blockLength = StrTok('\n', text, textLength, out char *nextBlock, out int remainingTextLength);

                float xAdvance     = 0.0f;
                float totalAdvance = 0.0f;
                if (hAlign != HorizontalAlignment.Left)
                {
                    for (int i = startIndex; i < startIndex + blockLength; ++i)
                    {
                        int glyphIndex = glyphIndices[i];
                        var glyph      = font.Glyphs[glyphIndex];

                        totalAdvance += glyph.HorizontalAdvance * currentElementScale;
                    }

                    if (hAlign == HorizontalAlignment.Center)
                    {
                        xAdvance = -(totalAdvance / 2.0f);
                    }
                    else if (hAlign == HorizontalAlignment.Right)
                    {
                        xAdvance = -totalAdvance;
                    }
                }

                for (gi = startIndex; gi < startIndex + blockLength; ++gi)
                {
                    int glyphIndex = glyphIndices[gi];

                    var glyph     = font.Glyphs[glyphIndex];
                    var glyphRect = font.GlyphRects[glyphIndex];

                    SimpleVertex topLeft     = new SimpleVertex();
                    SimpleVertex bottomLeft  = new SimpleVertex();
                    SimpleVertex topRight    = new SimpleVertex();
                    SimpleVertex bottomRight = new SimpleVertex();

                    // TODO store this in the asset data per glyph
                    float2 tl = new float2(glyph.HorizontalBearing.x, glyph.HorizontalBearing.y);
                    float2 br = new float2(glyph.HorizontalBearing.x + glyph.Size.x,
                                           glyph.HorizontalBearing.y - glyph.Size.y);

                    float2 advance = new float2(xAdvance, fontBaseLineOffset);

                    topLeft.Position    = new float3(advance + tl * currentElementScale, 0.0f);
                    bottomLeft.Position = new float3(advance + new float2(tl.x, br.y) * currentElementScale, 0.0f);
                    topRight.Position   = new float3(advance + new float2(br.x, tl.y) * currentElementScale, 0.0f);

                    bottomRight.Position.x = topRight.Position.x;
                    bottomRight.Position.y = bottomLeft.Position.y;
                    bottomRight.Position.z = 0.0f;

                    topLeft.TexCoord0     = glyphRect.TopLeftUV;
                    bottomLeft.TexCoord0  = new float2(glyphRect.TopLeftUV.x, glyphRect.BottomRightUV.y);
                    bottomRight.TexCoord0 = glyphRect.BottomRightUV;
                    topRight.TexCoord0    = new float2(glyphRect.BottomRightUV.x, glyphRect.TopLeftUV.y);

                    topLeft.Color     = vertexColor;
                    bottomLeft.Color  = vertexColor;
                    topRight.Color    = vertexColor;
                    bottomRight.Color = vertexColor;

                    mesh[meshIndex + 0] = bottomLeft;
                    mesh[meshIndex + 1] = topLeft;
                    mesh[meshIndex + 2] = topRight;
                    mesh[meshIndex + 3] = bottomRight;
                    meshIndex          += 4;

                    xAdvance += glyph.HorizontalAdvance * currentElementScale;
                }

                keepGoing           = remainingTextLength > 0;
                fontBaseLineOffset -= (font.Face.Ascent + font.Face.Descent);

                textLength  = remainingTextLength;
                text        = nextBlock;
                startIndex += blockLength;
            }

            // mesh bounds
            MinMaxAABB bounds = MinMaxAABB.Empty;

            for (int i = 0; i < numGlyphs * 4; ++i)
            {
                bounds.Encapsulate(mesh[i].Position);
            }

            aabb = bounds;

            // Then make the index buffer
            triangles.Length = numGlyphs * 6;

            int index4 = 0;
            int index6 = 0;

            for (int i = 0; i < numGlyphs; i++)
            {
                triangles[index6 + 0] = (ushort)(index4 + 0);
                triangles[index6 + 1] = (ushort)(index4 + 1);
                triangles[index6 + 2] = (ushort)(index4 + 2);
                triangles[index6 + 3] = (ushort)(index4 + 2);
                triangles[index6 + 4] = (ushort)(index4 + 3);
                triangles[index6 + 5] = (ushort)(index4 + 0);

                index4 += 4;
                index6 += 6;
            }
        }