public static void Save(AD2Editor map)
    {
        string saveLocation = getSaveLocation();

        generateObjectsXML(map, saveLocation);
        generateMapXML(map, saveLocation);
        RenderTarget2D cmap = saveRenderedCollideMap(map, saveLocation);

        generatePathfindingMesh(map, cmap, saveLocation);

        //move over basemap as well
        Stream stream = File.Create(saveLocation + "\\base.png");

        map.baseMap.SaveAsPng(stream, map.baseMap.Width, map.baseMap.Height);
        stream.Dispose();


        //Don't forget about objects.
        string[] files = Directory.GetFiles(map.objectDirectory);

        System.IO.Directory.CreateDirectory(saveLocation + "\\objects\\");
        foreach (string file in files)
        {
            string targetPath = saveLocation + "\\objects\\";
            string destFile   = System.IO.Path.Combine(targetPath, Path.GetFileName(file));
            System.IO.File.Copy(file, destFile, true);
        }
    }
    public static RenderTarget2D saveRenderedCollideMap(AD2Editor l, string saveloc)
    {
        //create a new file
        RenderTarget2D map = new RenderTarget2D(Renderer.GraphicsDevice, l.baseMap.Width, l.baseMap.Height);

        //GraphicsDevice oldDevice =
        Renderer.GraphicsDevice.SetRenderTarget(map);

        SpriteBatch b = new SpriteBatch(Renderer.GraphicsDevice);

        b.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend,
                SamplerState.LinearClamp, DepthStencilState.Default,
                RasterizerState.CullNone);

        b.Draw(l.collideMap, new Rectangle(0, 0, map.Width, map.Height), Color.White);
        for (int i = 0; i != l.objectsList.Length; i++)
        {
            foreach (AD2Object a in l.objectsList[i])
            {
                b.Draw(a.collide, new Rectangle(a.X, a.Y, a.t.Width, a.t.Height), Color.White);
            }
        }

        b.End();

        Renderer.GraphicsDevice.SetRenderTarget(null);

        Stream stream = File.Create(saveloc + "/collide.png");

        //Save as PNG
        map.SaveAsPng(stream, map.Width, map.Height);
        stream.Dispose();
        return(map);
    }
    public static void generateMapXML(AD2Editor map, string saveLoc)
    {
        string       file = saveLoc + "//map.xml";
        StreamWriter tw   = new StreamWriter(file);

        tw.WriteLine("<Map>");
        tw.WriteLine("    <base>base.png</base>");
        tw.WriteLine("    <collision>collide.png</collision>");
        tw.WriteLine("    <object>objects/object.xml</object>");
        tw.WriteLine("    <collisionKeyR>255</collisionKeyR>");
        tw.WriteLine("    <collisionKeyG>0</collisionKeyG>");
        tw.WriteLine("    <collisionKeyB>255</collisionKeyB>");
        tw.WriteLine("</Map>");
        tw.Close();
    }
    public static void generateObjectsXML(AD2Editor map, string saveLoc)
    {
        //create a new file
        string path = saveLoc + "/objects/";

        Directory.CreateDirectory(path);
        string file = path + "object.xml";
        //File.Create(file).Close();
        StreamWriter tw = new StreamWriter(file);

        tw.WriteLine("<Obj>");
        for (int i = 0; i != map.objectsList.Length; i++)
        {
            foreach (AD2Object a in map.objectsList[i])
            {
                tw.WriteLine("    <object>" + a.name + "," + a.X + "," + a.Y + "</object>");
            }
        }
        tw.WriteLine("</Obj>");
        tw.Close();
    }
    public static void generatePathfindingMesh(AD2Editor map, RenderTarget2D collmap, string saveloc)
    {
        Color[] pixels = new Color[collmap.Width * collmap.Height];
        collmap.GetData(pixels);
        //All of the places we can walk.
        bool[,] notWalkable = new bool[map.baseMap.Width, map.baseMap.Height];

        for (int x = 0; x != collmap.Width; x++)
        {
            for (int y = 0; y != collmap.Height; y++)
            {
                //BAD: Assumes 255/0/255 magic pank
                if (pixels[x + y * collmap.Width].R == 255 && pixels[x + y * collmap.Width].G == 0 && pixels[x + y * collmap.Width].B == 255)
                {
                    for (int height = MaxCharacterHeight; height >= 0; height--)
                    {
                        for (int width = MaxCharacterHeight; width >= 0; width--)
                        {
                            if (y - height < 0 || x - width < 0)
                            {
                                continue;
                            }
                            notWalkable[x - width, y - height] = true;
                        }
                    }
                }
            }
        }

        //Cannot walk along the far sides of map either.
        for (int x = 0; x != map.baseMap.Width; x++)
        {
            for (int y = 0; y != map.baseMap.Height; y++)
            {
                if (x > map.baseMap.Width - MaxCharacterHeight || y > map.baseMap.Height - MaxCharacterHeight)
                {
                    notWalkable[x, y] = true;
                }
            }
        }

        //step two: Generate a List of pathfinding node origins.
        bool[,] nodeClaimed = new bool[map.baseMap.Width, map.baseMap.Height];
        int[,] nodeOwner    = new int[map.baseMap.Width, map.baseMap.Height];

        LinkedList <RPFNode> seeds = new LinkedList <RPFNode>();

        Utils.Log("Generating Seeds...");
        int nextMeshRegionID = 0;

        for (int xStart = 0; xStart < map.baseMap.Width; xStart += RangedPathFindingNodeDistance)
        {
            for (int yStart = 0; yStart < map.baseMap.Height; yStart += RangedPathFindingNodeDistance)
            {
                if (!notWalkable[xStart, yStart])
                {
                    nodeClaimed[xStart, yStart] = true;
                    RPFNode newNode = new RPFNode(xStart, yStart, nextMeshRegionID);
                    seeds.AddFirst(newNode);
                    nextMeshRegionID++;
                }
            }
        }


        Utils.Log("Growing Seeds...");
        LinkedList <RPFNode> rootRegions = new LinkedList <RPFNode>();

        //step 3: Grow nodes until they can grow no longer.
        while (seeds.Count > 0)
        {
            foreach (RPFNode seed in seeds)
            {
                //grow frontiers
                LinkedList <int[]> oldFrontier = seed.frontier;
                seed.frontier = new LinkedList <int[]>();
                foreach (int[] coord in oldFrontier)
                {
                    LinkedList <int[]> dirs = new LinkedList <int[]>();
                    dirs.AddFirst(new int[2] {
                        -1, 0
                    });
                    dirs.AddFirst(new int[2] {
                        1, 0
                    });
                    dirs.AddFirst(new int[2] {
                        0, 1
                    });
                    dirs.AddFirst(new int[2] {
                        0, -1
                    });
                    foreach (int[] d in dirs)
                    {
                        int dx = d[0];
                        int dy = d[1];
                        if (map.collide(0, 0, map.baseMap.Width, map.baseMap.Height, coord[0] + dx, coord[1] + dy) && !nodeClaimed[coord[0] + dx, coord[1] + dy] && !notWalkable[coord[0] + dx, coord[1] + dy])
                        {
                            int[] newcoord = new int[2] {
                                coord[0] + dx, coord[1] + dy
                            };
                            seed.frontier.AddFirst(newcoord);
                            seed.nodesInSet.AddFirst(newcoord);
                            nodeClaimed[newcoord[0], newcoord[1]] = true;
                            nodeOwner[newcoord[0], newcoord[1]]   = seed.ID;
                        }
                    }
                }
            }

            //remove nodes who have no frontier to grow.
            LinkedList <RPFNode> toRemove = new LinkedList <RPFNode>();
            foreach (RPFNode seed in seeds)
            {
                if (seed.frontier.Count == 0)
                {
                    toRemove.AddFirst(seed);
                }
            }

            foreach (RPFNode n in toRemove)
            {
                seeds.Remove(n);
                rootRegions.AddFirst(n);
            }
        }


        //step 4: find neighbors.
        Utils.Log("Finding Neighbors...");
        foreach (RPFNode region in rootRegions)
        {
            foreach (int[] node in region.nodesInSet)
            {
                //look for neigthbors.
                LinkedList <int[]> dirs = new LinkedList <int[]>();
                dirs.AddFirst(new int[2] {
                    -1, 0
                });
                dirs.AddFirst(new int[2] {
                    1, 0
                });
                dirs.AddFirst(new int[2] {
                    0, 1
                });
                dirs.AddFirst(new int[2] {
                    0, -1
                });
                foreach (int[] d in dirs)
                {
                    int dx = d[0];
                    int dy = d[1];
                    if (map.collide(0, 0, map.baseMap.Width, map.baseMap.Height, node[0] + dx, node[1] + dy))
                    {
                        if (nodeOwner[node[0] + dx, node[1] + dy] != region.ID)
                        {
                            //We have an edge.
                            if (!region.edges.Contains(nodeOwner[node[0] + dx, node[1] + dy]))
                            {
                                region.edges.AddFirst(nodeOwner[node[0] + dx, node[1] + dy]);
                            }
                        }
                    }
                }
            }
        }

        //Step 5: The graph is complete, we have regions that can reach other regions. Write to XML.
        //create a new file
        Utils.Log("Printing...");
        string path = saveloc + "/mesh.xml";

        File.Create(path).Close();
        StreamWriter tw = new StreamWriter(path);

        tw.WriteLine("<PathMesh>");
        foreach (RPFNode node in rootRegions)
        {
            foreach (int neighbor in node.edges)
            {
                tw.WriteLine("    <Region" + node.ID + "Edge>" + neighbor + "</Region" + node.ID + "Edge>");
            }
            foreach (int[] pixel in node.nodesInSet)
            {
                tw.WriteLine("    <Region" + node.ID + "Pixel>" + pixel[0] + "," + pixel[1] + "</Region" + node.ID + "Pixel>");
            }
        }
        tw.WriteLine("    <MeshRegionCount>" + nextMeshRegionID + " </MeshRegionCount>");
        tw.WriteLine("</PathMesh>");
        tw.Close();
    }
 static void Main()
 {
     using (var game = new AD2Editor())
         game.Run();
 }