using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Media.Media3D;
using System.Windows.Media;
using System.Windows;

namespace Generate3DMesh
{
    // Example 17-30. Creating a mesh: initialization

    class MeshBuilder
    {
        public static MeshGeometry3D BuildMeshFromPoints(double[,] data,
                            double textureWidth, double textureHeight)
        {
            Point3DCollection points;
            PointCollection textureCoordinates;
            Int32Collection triangleIndices;
            BuildMeshData(data, textureWidth, textureHeight,
                       out points, out textureCoordinates, out triangleIndices);
            points.Freeze();
            textureCoordinates.Freeze();
            triangleIndices.Freeze();

            MeshGeometry3D mesh = new MeshGeometry3D();
            mesh.Positions = points;
            mesh.TextureCoordinates = textureCoordinates;
            mesh.TriangleIndices = triangleIndices;

            return mesh;
        }


        // Example 17-31. Building the mesh data

        static void BuildMeshData(double[,] data,
                        double textureWidth, double textureHeight,
                        out Point3DCollection points,
                        out PointCollection textureCoordinates,
                        out Int32Collection triangleIndices)
        {

            // 1: initialization
            int width = data.GetLength(0);
            int height = data.GetLength(1);

            int pointCount = width * height;
            points = new Point3DCollection(pointCount);
            textureCoordinates = new PointCollection(pointCount);

            int triangleCount = 2 * (width - 1) * (height - 1);
            triangleIndices = new Int32Collection(3 * triangleCount);


            // 2: iteration
            for (int yDataIndex = 0; yDataIndex < height; ++yDataIndex)
            {
                double yProportion = yDataIndex; yProportion /= (height - 1);
                // Adding points from top to bottom.
                // In 3D up means increasing Y, but in
                // 2D 0 is at the top.
                double outY = 0.5 - yProportion;
                double textureY = textureHeight * yProportion;

                for (int xDataIndex = 0; xDataIndex < width; ++xDataIndex)
                {
                    double xProportion = xDataIndex; xProportion /= (width - 1);
                    double outX = xProportion - 0.5;
                    double textureX = textureWidth * xProportion;


                    // 3: adding points
                    points.Add(new Point3D(outX, outY, data[xDataIndex, yDataIndex]));
                    textureCoordinates.Add(new Point(textureX, textureY));


                    // Add triangles for everything but the last row and column.
                    if (xDataIndex < (width - 1) && yDataIndex < (height - 1))
                    {
                        int topLeftIndex = xDataIndex + yDataIndex * width;
                        int bottomLeftIndex = topLeftIndex + width;

                        triangleIndices.Add(bottomLeftIndex);
                        triangleIndices.Add(bottomLeftIndex + 1);
                        triangleIndices.Add(topLeftIndex);

                        triangleIndices.Add(bottomLeftIndex + 1);
                        triangleIndices.Add(topLeftIndex + 1);
                        triangleIndices.Add(topLeftIndex);
                    }
                }
            }
        }

        // End of Example 17-31

    }

    // End of Example 17-30
}
