public static RenderData DrawMesh(Elements.Geometry.Mesh mesh, ref Outline outline, DisplayStyle displayStyle)
        {
            var min = new XYZ(double.MaxValue, double.MaxValue, double.MaxValue);
            var max = new XYZ(double.MinValue, double.MinValue, double.MinValue);

            var numVertices   = mesh.Triangles.Count * 3;
            var numPrimitives = mesh.Triangles.Count;
            var pType         = PrimitiveType.TriangleList;
            var numIndices    = GetPrimitiveSize(pType) * numPrimitives;
            VertexFormatBits vertexFormatBits;

            switch (displayStyle)
            {
            case DisplayStyle.HLR:
            case DisplayStyle.FlatColors:
                vertexFormatBits = VertexFormatBits.PositionColored;
                break;

            default:
                vertexFormatBits = VertexFormatBits.PositionNormalColored;
                break;
            }
            var vertexFormat = new VertexFormat(vertexFormatBits);

            var vBuffer = new VertexBuffer(GetVertexSize(vertexFormatBits) * numVertices);
            var iBuffer = new IndexBuffer(numIndices);

            vBuffer.Map(GetVertexSize(vertexFormatBits) * numVertices);
            iBuffer.Map(numIndices);

            var verticesFlat = new List <VertexPositionColored>();
            var vertices     = new List <VertexPositionNormalColored>();
            var triangles    = new List <IndexTriangle>();

            // We duplicate the vertices on each triangle so that
            // we can get the correct number of face normals.
            foreach (var t in mesh.Triangles)
            {
                foreach (var v in t.Vertices)
                {
                    var pos = v.Position.ToXYZFeet();

                    outline.AddPoint(pos);

                    switch (vertexFormatBits)
                    {
                    case VertexFormatBits.PositionColored:
                        var color = displayStyle == DisplayStyle.HLR ? new ColorWithTransparency(255, 255, 255, 0) : v.Color.ToColorWithTransparency();
                        verticesFlat.Add(new VertexPositionColored(pos, color));
                        break;

                    default:
                        vertices.Add(new VertexPositionNormalColored(pos, t.Normal.ToXYZ(), v.Color.ToColorWithTransparency()));
                        break;
                    }

                    if (pos.X < min.X && pos.Y < min.Y && pos.Z < min.Z)
                    {
                        min = pos;
                    }
                    if (pos.X > min.X && pos.Y > min.Y && pos.Z > min.Z)
                    {
                        max = pos;
                    }
                }

                triangles.Add(new IndexTriangle(t.Vertices[0].Index, t.Vertices[1].Index, t.Vertices[2].Index));
            }

            switch (displayStyle)
            {
            case DisplayStyle.HLR:
            case DisplayStyle.FlatColors:
                var pc = vBuffer.GetVertexStreamPositionColored();
                pc.AddVertices(verticesFlat);
                break;

            default:
                var pnc = vBuffer.GetVertexStreamPositionNormalColored();
                pnc.AddVertices(vertices);
                break;
            }

            var iPos = iBuffer.GetIndexStreamTriangle();

            iPos.AddTriangles(triangles);

            vBuffer.Unmap();
            iBuffer.Unmap();

            var effect = new EffectInstance(vertexFormatBits);
            // There is no reason why this should work.
            // In other situations, 255 is the 'full' component.
            // In the case of hidden line rendering, 0, 0, 0 makes white.
            // if (displayStyle == DisplayStyle.HLR)
            // {
            //     var color = new ColorWithTransparency(0, 0, 0, 0);
            //     effect.SetColor(color.GetColor());
            //     effect.SetAmbientColor(color.GetColor());
            //     effect.SetDiffuseColor(color.GetColor());
            // }

            // Create a render data for reuse
            // on non-update calls.
            var renderData = new RenderData()
            {
                VertexBuffer   = vBuffer,
                VertexCount    = numVertices,
                IndexBuffer    = iBuffer,
                IndexCount     = numIndices,
                VertexFormat   = vertexFormat,
                Effect         = effect,
                PrimitiveType  = pType,
                PrimitiveCount = numPrimitives
            };

            if (displayStyle != DisplayStyle.Wireframe && numPrimitives > 0)
            {
                DrawContext.FlushBuffer(vBuffer, numVertices, iBuffer, numIndices, vertexFormat, effect, pType, 0, numPrimitives);
            }

            return(renderData);
        }
        private static RenderData ProcessPrimitive(ILogger logger, glTFLoader.Schema.MeshPrimitive primitive, Gltf gltf, byte[][] buffers, DisplayStyle displayStyle, Outline outline, Transform transform)
        {
            if (primitive.Mode != MeshPrimitive.ModeEnum.TRIANGLES)
            {
                logger.Debug("The selected primitive mode is not supported.");
                return(null);
            }

            var indexAccessor    = gltf.Accessors[(int)primitive.Indices];
            var positionAccessor = gltf.Accessors[primitive.Attributes["POSITION"]];
            var normalAccessor   = gltf.Accessors[primitive.Attributes["NORMAL"]];
            var hasColor         = primitive.Attributes.ContainsKey("COLOR_0");

            var indexBufferView    = gltf.BufferViews[(int)indexAccessor.BufferView];
            var positionBufferView = gltf.BufferViews[(int)positionAccessor.BufferView];
            var normalBufferView   = gltf.BufferViews[(int)normalAccessor.BufferView];

            var indices = new List <int>();

            for (var i = indexBufferView.ByteOffset; i < indexBufferView.ByteOffset + indexBufferView.ByteLength; i += indexBufferView.ByteStride ?? sizeof(ushort))
            {
                var index = BitConverter.ToUInt16(buffers[indexBufferView.Buffer], i);
                indices.Add(index);
            }

            var floatSize = sizeof(float);
            var positions = new List <XYZ>();

            for (var i = positionBufferView.ByteOffset; i < positionBufferView.ByteOffset + positionBufferView.ByteLength; i += positionBufferView.ByteStride ?? (floatSize * 3))
            {
                // Read x, y, z values
                var x  = BitConverter.ToSingle(buffers[positionBufferView.Buffer], i);
                var y  = BitConverter.ToSingle(buffers[positionBufferView.Buffer], i + floatSize);
                var z  = BitConverter.ToSingle(buffers[positionBufferView.Buffer], i + floatSize * 2);
                var pt = new XYZ(Elements.Units.MetersToFeet(x), Elements.Units.MetersToFeet(y), Elements.Units.MetersToFeet(z));
                if (transform != null)
                {
                    pt = transform.OfPoint(pt);
                }
                outline.AddPoint(pt);
                positions.Add(pt);
            }

            var normals = new List <XYZ>();

            for (var i = normalBufferView.ByteOffset; i < normalBufferView.ByteOffset + normalBufferView.ByteLength; i += normalBufferView.ByteStride ?? (floatSize * 3))
            {
                // Read x, y, z values
                var x = BitConverter.ToSingle(buffers[normalBufferView.Buffer], i);
                var y = BitConverter.ToSingle(buffers[normalBufferView.Buffer], i + floatSize);
                var z = BitConverter.ToSingle(buffers[normalBufferView.Buffer], i + floatSize * 2);
                var n = new XYZ(x, y, z);
                if (transform != null)
                {
                    n = transform.OfVector(n);
                }
                normals.Add(n);
            }

            var colors = new List <ColorWithTransparency>();

            if (hasColor)
            {
                var colorAccessor   = gltf.Accessors[primitive.Attributes["COLOR_0"]];
                var colorBufferView = gltf.BufferViews[(int)colorAccessor.BufferView];
                for (var i = colorBufferView.ByteOffset; i < colorBufferView.ByteOffset + colorBufferView.ByteLength; i += colorBufferView.ByteStride ?? (floatSize * 3))
                {
                    // Read x, y, z values
                    var r = BitConverter.ToSingle(buffers[colorBufferView.Buffer], i);
                    var g = BitConverter.ToSingle(buffers[colorBufferView.Buffer], i + floatSize);
                    var b = BitConverter.ToSingle(buffers[colorBufferView.Buffer], i + floatSize * 2);
                    colors.Add(displayStyle == DisplayStyle.HLR ? new ColorWithTransparency(255, 255, 255, 0) : new ColorWithTransparency((uint)(r * 255), (uint)(g * 255), (uint)(b * 255), 0));
                }
            }

            // The number of vertices will be the same as the length of the indices
            // because we'll duplicate vertices at every position.
            var numVertices   = indices.Count;
            var pType         = PrimitiveType.TriangleList;
            var numPrimitives = indices.Count / 3;
            var numIndices    = GetPrimitiveSize(pType) * numPrimitives;

            VertexFormatBits vertexFormatBits;

            switch (displayStyle)
            {
            case DisplayStyle.HLR:
            case DisplayStyle.FlatColors:
                vertexFormatBits = VertexFormatBits.PositionColored;
                break;

            default:
                vertexFormatBits = VertexFormatBits.PositionNormalColored;
                break;
            }
            var vertexFormat = new VertexFormat(vertexFormatBits);

            var vBuffer = new VertexBuffer(GetVertexSize(vertexFormatBits) * numVertices);
            var iBuffer = new IndexBuffer(numIndices);

            vBuffer.Map(GetVertexSize(vertexFormatBits) * numVertices);
            iBuffer.Map(numIndices);

            var verticesFlat = new List <VertexPositionColored>();
            var vertices     = new List <VertexPositionNormalColored>();
            var triangles    = new List <IndexTriangle>();

            ColorWithTransparency color = null;

            if (displayStyle == DisplayStyle.HLR)
            {
                color = new ColorWithTransparency(255, 255, 255, 0);
            }
            else if (primitive.Material != null)
            {
                var material = gltf.Materials[(int)primitive.Material];
                var r        = (uint)(material.PbrMetallicRoughness.BaseColorFactor[0] * 255);
                var g        = (uint)(material.PbrMetallicRoughness.BaseColorFactor[1] * 255);
                var b        = (uint)(material.PbrMetallicRoughness.BaseColorFactor[2] * 255);
                var a        = (uint)(material.PbrMetallicRoughness.BaseColorFactor[3] * 255);
                color = new ColorWithTransparency(r, g, b, a);
            }

            for (var i = 0; i < indices.Count; i += 3)
            {
                var ia = indices[i];
                var ib = indices[i + 1];
                var ic = indices[i + 2];

                var a = positions[ia];
                var b = positions[ib];
                var c = positions[ic];

                var na = normals[ia];
                var nb = normals[ib];
                var nc = normals[ic];

                switch (vertexFormatBits)
                {
                case VertexFormatBits.PositionColored:
                    if (hasColor)
                    {
                        color = colors[ia];
                    }
                    verticesFlat.Add(new VertexPositionColored(a, hasColor ? colors[ia] : color));
                    verticesFlat.Add(new VertexPositionColored(b, hasColor ? colors[ib] : color));
                    verticesFlat.Add(new VertexPositionColored(c, hasColor ? colors[ic] : color));
                    break;

                default:
                    if (hasColor)
                    {
                        color = colors[ia];
                    }
                    vertices.Add(new VertexPositionNormalColored(a, na, hasColor ? colors[ia] : color));
                    vertices.Add(new VertexPositionNormalColored(b, nb, hasColor ? colors[ib] : color));
                    vertices.Add(new VertexPositionNormalColored(c, nc, hasColor ? colors[ic] : color));
                    break;
                }

                triangles.Add(new IndexTriangle(i, i + 1, i + 2));
            }

            switch (displayStyle)
            {
            case DisplayStyle.HLR:
            case DisplayStyle.FlatColors:
                var pc = vBuffer.GetVertexStreamPositionColored();
                pc.AddVertices(verticesFlat);
                break;

            default:
                var pnc = vBuffer.GetVertexStreamPositionNormalColored();
                pnc.AddVertices(vertices);
                break;
            }

            var iPos = iBuffer.GetIndexStreamTriangle();

            iPos.AddTriangles(triangles);

            vBuffer.Unmap();
            iBuffer.Unmap();

            var effect = new EffectInstance(vertexFormatBits);

            var renderData = new RenderData()
            {
                VertexBuffer   = vBuffer,
                VertexCount    = numVertices,
                IndexBuffer    = iBuffer,
                IndexCount     = numIndices,
                VertexFormat   = vertexFormat,
                Effect         = effect,
                PrimitiveType  = pType,
                PrimitiveCount = numPrimitives
            };

            if (displayStyle != DisplayStyle.Wireframe && numPrimitives > 0)
            {
                DrawContext.FlushBuffer(vBuffer, numVertices, iBuffer, numIndices, vertexFormat, effect, pType, 0, numPrimitives);
            }

            return(renderData);
        }