/// <summary>
        /// Clones this object.
        /// </summary>
        public VertexStructureSurface Clone(
            VertexStructure newOwner,
            bool copyGeometryData = true, int capacityMultiplier = 1,
            int baseIndex         = 0)
        {
            newOwner.EnsureNotNull(nameof(newOwner));

            // Create new VertexStructure object
            int indexCount = m_indices.Count;
            VertexStructureSurface result = new VertexStructureSurface(newOwner, (indexCount / 3) * capacityMultiplier);

            // Copy geometry
            if (copyGeometryData)
            {
                for (int loop = 0; loop < indexCount; loop++)
                {
                    result.m_indices.Add(m_indices[loop] + baseIndex);
                }
            }

            // Copy metadata
            result.m_materialProperties = m_materialProperties.Clone();

            return(result);
        }
        /// <summary>
        /// Creates the surface on this VertexStructure.
        /// </summary>
        /// <param name="triangleCapacity">The triangle capacity.</param>
        /// <param name="name">The internal name of the material.</param>
        public VertexStructureSurface CreateSurface(int triangleCapacity = 512, string name = "")
        {
            VertexStructureSurface newSurface = new VertexStructureSurface(this, triangleCapacity);

            newSurface.MaterialProperties.Name = name;

            m_surfaces.Add(newSurface);
            return(newSurface);
        }
        /// <summary>
        /// Calculates normals for all triangles specifyed by the given parameters.
        /// </summary>
        /// <param name="startVertex">The vertex index on which to start.</param>
        /// <param name="vertexCount">Total count of vertices to be updated.</param>
        public void CalculateNormals(int startVertex, int vertexCount)
        {
            if ((startVertex < 0) || (startVertex >= m_rawGeometry.Count))
            {
                throw new ArgumentException("startVertex");
            }
            if (vertexCount + startVertex > m_rawGeometry.Count)
            {
                throw new ArgumentException("vertexCount");
            }

            for (int actVertexIndex = startVertex; actVertexIndex < startVertex + vertexCount; actVertexIndex++)
            {
                // Find all triangles connected to this vertex and get normals from them
                Vector3 finalNormalHelper  = Vector3.Zero;
                Vector3 finalNormalHelper2 = Vector3.Zero;
                int     normalCount        = 0;

                int surfaceCount = m_surfaces.Count;
                for (int actSurfaceIndex = 0; actSurfaceIndex < surfaceCount; actSurfaceIndex++)
                {
                    VertexStructureSurface actSurface = m_surfaces[actSurfaceIndex];
                    int triangleCount = actSurface.CountTriangles;
                    for (int loopTriangle = 0; loopTriangle < triangleCount; loopTriangle++)
                    {
                        int triangleStartIndex = loopTriangle * 3;
                        if ((actSurface.IndicesInternal[triangleStartIndex] == actVertexIndex) ||
                            (actSurface.IndicesInternal[triangleStartIndex + 1] == actVertexIndex) ||
                            (actSurface.IndicesInternal[triangleStartIndex + 2] == actVertexIndex))
                        {
                            GeometryData geo1 = m_rawGeometry[actSurface.IndicesInternal[triangleStartIndex]];
                            GeometryData geo2 = m_rawGeometry[actSurface.IndicesInternal[triangleStartIndex + 1]];
                            GeometryData geo3 = m_rawGeometry[actSurface.IndicesInternal[triangleStartIndex + 2]];

                            finalNormalHelper += Vector3Ex.CalculateTriangleNormal(geo1.Position, geo2.Position, geo3.Position, false);

                            normalCount++;
                        }
                    }
                }

                // Calculate final normal
                if (normalCount > 0)
                {
                    GeometryData actGeometry = m_rawGeometry[actVertexIndex];
                    actGeometry.Normal            = finalNormalHelper / finalNormalHelper.Length();
                    m_rawGeometry[actVertexIndex] = actGeometry;
                    normalCount = 0;
                }
            }
        }
        /// <summary>
        /// Tries to get an existing surface using given MaterialProperties.
        /// If none exists, then a new surface is created.
        /// </summary>
        /// <param name="name">The internal name of the material.</param>
        /// <param name="triangleCapacity">The triangle capacity.</param>
        public VertexStructureSurface CreateOrGetExistingSurface(string name, int triangleCapacity = 512)
        {
            foreach (VertexStructureSurface actSurface in m_surfaces)
            {
                if (actSurface.MaterialProperties.Name == name)
                {
                    return(actSurface);
                }
            }

            VertexStructureSurface result = CreateSurface(triangleCapacity);

            result.MaterialProperties.Name = name;
            return(result);
        }
        /// <summary>
        /// Tries to get an existing surface using given MaterialProperties.
        /// If none exists, then a new surface is created.
        /// </summary>
        /// <param name="matProperties">The material properties.</param>
        /// <param name="triangleCapacity">The triangle capacity.</param>
        public VertexStructureSurface CreateOrGetExistingSurface(MaterialProperties matProperties, int triangleCapacity = 512)
        {
            foreach (VertexStructureSurface actSurface in m_surfaces)
            {
                if (actSurface.MaterialProperties == matProperties)
                {
                    return(actSurface);
                }
            }

            VertexStructureSurface result = CreateSurface(triangleCapacity);

            result.MaterialProperties = matProperties;
            return(result);
        }
        ///// <summary>
        ///// Fits to centered cube.
        ///// </summary>
        //public void FitToCenteredCube()
        //{
        //    FitToCenteredCuboid(1f, 1f, 1f, FitToCuboidMode.MaintainAspectRatio, SpacialOriginLocation.Center);
        //}

        ///// <summary>
        ///// Fits to centered cube.
        ///// </summary>
        //public void FitToCenteredCube(float cubeSideLength)
        //{
        //    FitToCenteredCuboid(cubeSideLength, cubeSideLength, cubeSideLength, FitToCuboidMode.MaintainAspectRatio, SpacialOriginLocation.Center);
        //}

        ///// <summary>
        ///// Fits to centered cube.
        ///// </summary>
        //public void FitToCenteredCube(float cubeSideLength, FitToCuboidMode mode)
        //{
        //    FitToCenteredCuboid(cubeSideLength, cubeSideLength, cubeSideLength, mode, SpacialOriginLocation.Center);
        //}

        ///// <summary>
        ///// Fits to centered cube.
        ///// </summary>
        //public void FitToCenteredCube(float cubeSideLength, FitToCuboidMode mode, SpacialOriginLocation fitOrigin)
        //{
        //    FitToCenteredCuboid(cubeSideLength, cubeSideLength, cubeSideLength, mode, fitOrigin);
        //}

        ///// <summary>
        ///// Fits to centered cube.
        ///// </summary>
        //public void FitToCenteredCuboid(float cubeSideLengthX, float cubeSideLengthY, float cubeSideLengthZ, FitToCuboidMode fitMode, SpacialOriginLocation fitOrigin)
        //{
        //    //Get whole bounding box
        //    BoundingBox boundingBox = this.GenerateBoundingBox();
        //    Vector3 boundingBoxSize = boundingBox.GetSize();
        //    if (boundingBox.IsEmpty()) { return; }
        //    if (boundingBoxSize.X <= 0f) { return; }
        //    if (boundingBoxSize.Y <= 0f) { return; }
        //    if (boundingBoxSize.Z <= 0f) { return; }

        //    Vector3 targetCornerALocation = new Vector3(
        //        -boundingBoxSize.X / 2f,
        //        -boundingBoxSize.Y / 2f,
        //        -boundingBoxSize.Z / 2f);

        //    // Calculate resize factors
        //    float resizeFactorX = cubeSideLengthX / boundingBoxSize.X;
        //    float resizeFactorY = cubeSideLengthY / boundingBoxSize.Y;
        //    float resizeFactorZ = cubeSideLengthZ / boundingBoxSize.Z;
        //    if (fitMode == FitToCuboidMode.MaintainAspectRatio)
        //    {
        //        resizeFactorX = Math.Min(resizeFactorX, Math.Min(resizeFactorY, resizeFactorZ));
        //        resizeFactorY = resizeFactorX;
        //        resizeFactorZ = resizeFactorX;
        //    }

        //    targetCornerALocation.X = targetCornerALocation.X * resizeFactorX;
        //    targetCornerALocation.Y = targetCornerALocation.Y * resizeFactorY;
        //    targetCornerALocation.Z = targetCornerALocation.Z * resizeFactorZ;
        //    switch (fitOrigin)
        //    {
        //        case SpacialOriginLocation.LowerCenter:
        //            targetCornerALocation.Y = 0f;
        //            break;
        //    }

        //    //Bring the structure to origin based location and then scale it
        //    this.UpdateVerticesUsingRelocationBy(Vector3.Negate(boundingBox.CornerA));
        //    this.UpdateVerticesUsingRelocationFunc((actPosition) => new Vector3(
        //        actPosition.X * resizeFactorX,
        //        actPosition.Y * resizeFactorY,
        //        actPosition.Z * resizeFactorZ));
        //    this.UpdateVerticesUsingRelocationBy(targetCornerALocation);
        //}

        public void RemoveSurface(VertexStructureSurface surface)
        {
            m_surfaces.Remove(surface);
        }