# Example - Mesh Export

<span class="rvts6">The following C# program connects to a Voxel Farm server and exports the terrain surface within a 3D region as a mesh:</span>

<span class="rvts6">  
</span>

```c#
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using VoxelFarm;


namespace ExportMesh
{
    class Program
    {
        private static void Terrain2MeshOBJ(
            string webServer,
            string contentServerAddr,
            int contentServerPort,
            string projectId,
            string entityId,
            Region25D region,
            int lod,
            string outputFile)
        {
            // Create output file
            System.IO.StreamWriter fileOutput = new StreamWriter(outputFile);

            // Local variables to track OBJ output
            bool done = false;
            int totalFaces = 0;
            int vertexIndexOffset = 1;

            // Start work pool
            VoxelFarmWorkPool.Start(2 * Environment.ProcessorCount);

            // Create view
            VoxelFarmView view = new VoxelFarmView();

            // Print view debug log
            view.OnDebugLog = (message) =>
            {
                //Console.WriteLine(message);
            };

            // Also print any uncaught error
            VoxelFarmWorkPool.OnError = (Exception error) =>
            {
                Console.WriteLine(error.Message + " " + error.StackTrace);
                done = true;
            };

            // Set OnViewStarted event
            view.OnViewStarted = () =>
            {
                try
                {
                    // Use the supplied region to create a set of ranges of 10x10x10 cells
                    var ranges = region.breakdownRegion(lod, 10, view.AffineTransform);


                    // Iterate over each range of cells
                    int totalRanges = ranges.Count;
                    int completedRanges = 0;
                    foreach (var range in ranges)
                    {
                        // Output progress message
                        int progress = (100 * completedRanges++) / totalRanges;
                        string message = (totalFaces > 0) ? String.Format("{0:0,0} triangles exported...", totalFaces) : "Scanning for triangles...";
                        Console.WriteLine(progress + "% " + message);

                        // Ask the view to load the cell range
                        view.SetCellRange(range);

                        // Wait until the view completes processing the range
                        view.Join();

                        // Check that we still have a connection to the server
                        if (view.ConnectionLost() || !view.IsConnected())
                        {
                            Console.WriteLine("Lost connection to content server.");
                            done = true;
                        }
                    }
                    done = true;
                }
                catch (Exception error)
                {
                    Console.WriteLine(error.Message + " " + error.StackTrace);
                    done = true;
                }
            };


            // Define a callaback to handle mesh data
            view.OnReceiveMeshData = (data) =>
            {
                ManualResetEvent outputDone = new ManualResetEvent(false);
                VoxelFarmWorkPool.RunInMainThread(() => {

                    int level, xc, yc, zc;
                    VoxelFarmCell.Unpack(data.cellId, out level, out xc, out yc, out zc);
                    double scale = VoxelFarmConstant.CELL_SIZE * (1 << level);
                    double cellOffsetX = scale * xc;
                    double cellOffsetY = scale * yc;
                    double cellOffsetZ = scale * zc;

                    int vertCount = data.vertices.Length / 3;
                    int faceCount = data.faces.Length / 3;

                    for (int i = 0; i < vertCount; i++)
                    {
                        var wc = view.AffineTransform.VF_TO_WC(
                            new VoxelFarmAffineTransform.sAffineVector
                            {
                                X = data.vertices[3 * i + 0] * scale + cellOffsetX,
                                Y = data.vertices[3 * i + 1] * scale + cellOffsetY,
                                Z = data.vertices[3 * i + 2] * scale + cellOffsetZ
                            });

                        fileOutput.WriteLine("v " + (-wc.X) + " " + wc.Z + " " + wc.Y);
                    }

                    for (int i = 0; i < faceCount; i++)
                    {
                        fileOutput.WriteLine("f " +
                            (data.faces[3 * i + 0] + vertexIndexOffset) + " " +
                            (data.faces[3 * i + 1] + vertexIndexOffset) + " " +
                            (data.faces[3 * i + 2] + vertexIndexOffset));
                    }

                    vertexIndexOffset += vertCount;
                    totalFaces += faceCount;

                    outputDone.Set();
                });
                outputDone.WaitOne();
            };


            // Set server and project

            view.SetServer(webServer, contentServerAddr, contentServerPort, false);
            view.SetProjectId(projectId);

            // Load the project
            view.LoadProject((HttpStatusCode httpcode) =>
            {
                if (httpcode == HttpStatusCode.OK)
                {
                    // Find entity
                    var terrainEntity = view.GetEntity(entityId);
                    if (terrainEntity == null || terrainEntity["file_type"] != VoxelFarmEntityType.VoxelTerrain)
                    {
                        done = true;
                        return;
                    }

                    // Create view metadata
                    var components = new List<VoxelFarmMetaComponent>();
                    var componentMasks = new List<ushort>();
                    List<VoxelFarmMetaLayer> layerStack = new List<VoxelFarmMetaLayer>();
                    layerStack.Add(new VoxelFarmMetaLayerHM { Id = entityId, Config = terrainEntity["runtime"] });
                    var layers = new VoxelFarmMetaLayerStack(layerStack);
                    var surface = new VoxelFarmMetaSurfaceOperation { OpId = VoxelFarmMetaID.META_OP_NONE, OpA = layers };
                    components.Add(surface);
                    componentMasks.Add(0x02);
                    var componentMaterials = new List<ushort>();
                    componentMaterials.Add(0xFFFF);
                    var metadata = new VoxelFarmViewMeta(components, componentMasks, componentMaterials, null);

                    // Set view metadata, this will start the connection to the streaming server
                    view.SetViewMetaData(metadata);
                }
                else
                {
                    done = true;
                }
            });

            while (!done)
            {
                VoxelFarmWorkPool.RunNextMainThreadJob();
            }

            fileOutput.Close();
            VoxelFarmWorkPool.Stop();
            Console.WriteLine("Export complete.");
        }

        static void Main(string[] args)
        {
            if (args.Length != 8)
            {
                Console.WriteLine("Usage ExportMesh.exe <REST URL> <Streaming Server> <Streaming Port> <Project Id> <Entity Id> <Region> <LOD> <Output File>");
                return;
            }
          
            try
            {
                Region25D region = new Region25D();
                region.loadFromString(args[5]);
                Terrain2MeshOBJ(args[0], args[1], Convert.ToInt32(args[2]), args[3], args[4], region, Convert.ToInt32(args[6]), args[7]);
            }
            catch (Exception error)
            {
                Console.WriteLine(error.Message + " " + error.StackTrace);
            }
        }
    }
}
```

<span class="rvts6">The following command line tests this program over the Sta. Barbara Island dataset, requesting a mesh export for the full island at LOD 5 resolution:</span>

<span class="rvts6">ExportMesh.exe http://18.236.158.139 18.236.158.139 3333 blank 390CC9D2B934446DAEE5EFE9F7D64C4F 1,1.0000000000002274,300,-13253468.999999998,3937303,-13248860.999999998,3937303,-13248860.999999998,3932695,-13253468.999999998,3932695 5 f:\\scrap\\m1.obj</span>

<span class="rvts6"> </span><span class="rvts6">Note that this program requires the “vfcompression.dll” to be in the same folder as the .EXE, or be in one of the folders specified in the system PATH variable.</span>

<span class="rvts6">The program produces the following output to the console window:</span>

<span class="rvts19">0% Scanning for triangles...</span>

<span class="rvts19">4% 20,378 triangles exported...</span>

<span class="rvts19">8% 59,296 triangles exported...</span>

<span class="rvts19">12% 120,883 triangles exported...</span>

<span class="rvts19">16% 174,325 triangles exported...</span>

<span class="rvts19">20% 198,326 triangles exported...</span>

<span class="rvts19">24% 231,524 triangles exported...</span>

<span class="rvts19">28% 304,836 triangles exported...</span>

<span class="rvts19">32% 367,609 triangles exported...</span>

<span class="rvts19">36% 410,992 triangles exported...</span>

<span class="rvts19">40% 423,511 triangles exported...</span>

<span class="rvts19">44% 448,613 triangles exported...</span>

<span class="rvts19">48% 522,385 triangles exported...</span>

<span class="rvts19">52% 548,733 triangles exported...</span>

<span class="rvts19">56% 592,684 triangles exported...</span>

<span class="rvts19">60% 597,296 triangles exported...</span>

<span class="rvts19">64% 631,860 triangles exported...</span>

<span class="rvts19">68% 694,986 triangles exported...</span>

<span class="rvts19">72% 759,434 triangles exported...</span>

<span class="rvts19">76% 780,406 triangles exported...</span>

<span class="rvts19">80% 781,337 triangles exported...</span>

<span class="rvts19">84% 806,390 triangles exported...</span>

<span class="rvts19">88% 848,185 triangles exported...</span>

<span class="rvts19">92% 869,169 triangles exported...</span>

<span class="rvts19">96% 875,037 triangles exported...</span>

<span class="rvts19">Export complete.</span>

<span class="rvts6"> </span>

<span class="rvts6">The exported OBJ mesh looks like this:</span>