public TerrainBlock(Terrain terrain, int depth, bool planet, GraphicsDevice GraphicsDevice, Effect effect, Vector3 blockOffset = new Vector3())
        {
            this.GraphicsDevice = GraphicsDevice;
            this.effect = effect;

            this.waterSphere = new BoundingSphere(Vector3.Zero, Terrain.PlanetRadius + Planet.HeightMag);

            if (blockOffset == Vector3.Zero)
                this.blockOffset = new Vector3(0, 0, (terrain.width) * (long)Math.Pow(2, depth));
            else
                this.blockOffset = new Vector3(blockOffset.X, blockOffset.Y, (terrain.width - 1) * (long)Math.Pow(2, depth) + 1);
            this.planet = planet;
            this.depth = depth;
            this.pWidth = terrain.width;
            this.busy = false;
            this.baseTexture = terrain.baseTexture;
            this.children = new TerrainBlock[4];
            this.terrain = new Terrain[4];
            if (planet)
                this.SplitMainTerrainPlanet(terrain);
            else
                this.SplitMainTerrainFlat(terrain);
            this.visible = true;

            //this.SplitChildren(Vector3.Zero);
        }
        public TerrainBlock(Terrain terrain, int depth, GraphicsDevice GraphicsDevice, Effect effect, PlanetBlock planetBlock,
                            Planet.GetNeighbourDelegate method, Point location,TerrainBlock parent, Vector3 blockOffset = new Vector3())
        {
            this.GraphicsDevice = GraphicsDevice;
            this.effect = effect;
            this.depth = depth;
            this.planet = true;
            this.waterSphere = new BoundingSphere(Vector3.Zero, Terrain.PlanetRadius + Planet.HeightMag);
            this.GetNeighbour = method;
            this.location = location;
            this.parent = parent;
            if (blockOffset == Vector3.Zero)
                this.blockOffset = new Vector3(0, 0, Planet.PlanetRes);
            else
                this.blockOffset = new Vector3(blockOffset.X, blockOffset.Y, blockOffset.Z);
            this.planet = planet;
            this.pWidth = terrain.Size;
            this.busy = false;
            this.baseTexture = terrain.baseTexture;
            this.children = new TerrainBlock[BlockRes, BlockRes];
            this.terrain = new Terrain[BlockRes, BlockRes];
            if (planet)
                this.SplitMainTerrainPlanet(terrain);
            this.visible = true;

            //this.SplitChildren(Vector3.Zero);
        }
        public void SplitMainTerrainPlanet(Terrain terrain)
        {
            int size = (Planet.PlanetRes - 1) / 2 + 1;

            int td = -1;
            terrain.loadChildBorders(this.GetNeighbour(location, this.parent), td);
            terrain.PostNormalize();

            for (int x = 0; x < BlockRes; x++)
                for (int y = 0; y < BlockRes; y++)
                {
                    this.terrain[x, y] = new Terrain(terrain.CellSize, terrain.Height, terrain.TextureTiling, size,
                                            new Vector3(terrain.Position.X, terrain.Position.Y, terrain.Position.Z),
                                            effect, terrain.baseTexture, terrain.type, this.depth);
                }

            float[,][,] heights = new float[BlockRes, BlockRes][,];
            VertexPositionNormalTexture[,][] subCopy = new VertexPositionNormalTexture[BlockRes, BlockRes][];

            for (int x = 0; x < BlockRes; x++)
                for (int y = 0; y < BlockRes; y++)
                {
                    heights[x, y] = new float[size, size];
                    subCopy[x, y] = new VertexPositionNormalTexture[size * size];

                    for (int x1 = 0; x1 < size; x1++)
                        for (int y1 = 0; y1 < size; y1++)
                        {
                            int a = x1 + (size - 1) * x;
                            int b = y1 + (size - 1) * y;
                            subCopy[x, y][convertFromXY(x1, y1, size) ] = terrain.vertices[convertFromXY(a, b, terrain.Size)];
                            heights[x, y][x1, y1] = terrain.heightMaps[a, b];
                        }
                }

            for (int x = 0; x < BlockRes; x++)
                for (int y = 0; y < BlockRes; y++)
                {
                    this.terrain[x, y].CopyCustom(subCopy[x, y], heights[x, y]);
                    this.terrain[x, y].GlobalRot = terrain.GlobalRot;
                }
        }
        public void SplitChildrenPlanet(object input)
        {
            Vector3 position = (Vector3)input;
            if (this.depth >= maxDepth)
                return;

            if (this.busy)
                return;

            this.busy = true;
            for (int x = 0; x < BlockRes; x++)
                for (int y = 0; y < BlockRes; y++)
                {
                    int t = this.terrain[x, y].Size - 1;
                    Vector3 a = this.terrain[x, y].Center + this.terrain[x, y].Position;//c
                    Vector3 b = this.terrain[x, y].GetAdjustedPos(this.terrain[x, y].vertices[0].Position) + this.terrain[x, y].Position;//NW
                    Vector3 c = this.terrain[x, y].GetAdjustedPos(this.terrain[x, y].vertices[t].Position) + this.terrain[x, y].Position;//NE
                    Vector3 d = this.terrain[x, y].GetAdjustedPos(this.terrain[x, y].vertices[this.terrain[x, y].vertices.Count() - 1].Position) + this.terrain[x, y].Position;//SE
                    Vector3 e = this.terrain[x, y].GetAdjustedPos(this.terrain[x, y].vertices[this.terrain[x, y].vertices.Count() - t - 1].Position) + this.terrain[x, y].Position;//SW
                    //float d = (Vector3.Cross((a - b), (b - position))).Length() / (a - b).Length();
                    if (((a - position).Length() > Terrain.PlanetRadius / (1.1f * (Math.Pow(2, this.depth))) &&
                        (b - position).Length() > Terrain.PlanetRadius / (1.1f * (Math.Pow(2, this.depth))) &&
                        (c - position).Length() > Terrain.PlanetRadius / (1.1f * (Math.Pow(2, this.depth))) &&
                        (d - position).Length() > Terrain.PlanetRadius / (1.1f * (Math.Pow(2, this.depth))) &&
                        (e - position).Length() > Terrain.PlanetRadius / (1.1f * (Math.Pow(2, this.depth)))) ||
                        waterSphere.Contains(new BoundingBox(b, d)) == ContainmentType.Contains)
                    {
                        if (this.children[x, y] != null)
                        {
                            this.children[x, y].nullChildren();
                            this.children[x, y] = null;
                        }
                        continue;
                    }

                    if (children[x, y] == null)
                    {
                        int size = Planet.PlanetRes;
                        Terrain tmp = new Terrain(terrain[x, y].CellSize / 4.0f, terrain[x, y].Height, terrain[x, y].TextureTiling, size,
                                                  new Vector3(terrain[x, y].Position.X, terrain[x, y].Position.Y, terrain[x, y].Position.Z),
                                                  effect, baseTexture, Terrain.Type.CubeFace, this.depth + 1);

                        float[,] heights = new float[size, size];
                        for (int x1 = 0; x1 < size; x1++)
                            for (int y1 = 0; y1 < size; y1++)
                                heights[x1, y1] = this.terrain[x, y].heightMaps[x1 / 2, y1 / 2];

                        Vector3 blcOff = new Vector3(blockOffset.X, blockOffset.Y, (blockOffset.Z - 1) * 2 + 1);
                        blcOff.X *= 2;
                        blcOff.Y *= 2;
                        blcOff.X += (size - 1) * x;
                        blcOff.Y += (size - 1) * y;

                        tmp.GenerateCustom(new Fractal(size, (this.depth + 1) * 8).stepFrac(heights, 1), blcOff);
                        tmp.GlobalRot = terrain[x, y].GlobalRot;

                        TerrainBlock tb = new TerrainBlock(tmp, this.depth + 1, GraphicsDevice, effect, this.planetBlock, this.GetNeighbour, new Point(x, y), this, blcOff);
                        children[x, y] = tb;
                    }

                    if (children[x, y] != null)
                        children[x, y].SplitChildrenPlanet(position);
                }

            this.busy = false;
        }
        public Planet(GraphicsDevice GraphicsDevice, ContentManager Content)
        {
            this.isWater = false;
            Effect effect = Content.Load<Effect>(@"effects/PPModel");
            Texture2D texture = Content.Load<Texture2D>(@"textures/base");

            Vector3 pos = Vector3.Zero;
            top = new Terrain(4096, HeightMag, 1f, PlanetRes, pos, effect, texture, Terrain.Type.CubeFace);
            top.GenerateFractual();

            float[][] borders = new float[4][];
            borders[2] = top.MyHeightBorders[0].ToArray();

            left = new Terrain(4096, HeightMag, 1f, PlanetRes, pos, effect, texture, Terrain.Type.CubeFace);
            left.GenerateFractualSlice(new Vector3(0, 0, 90), borders, Fractal.BorderType.Right);

            borders = new float[4][];
            borders[0] = top.MyHeightBorders[2].ToArray();

            right = new Terrain(4096, HeightMag, 1f, PlanetRes, pos, effect, texture, Terrain.Type.CubeFace);
            right.GenerateFractualSlice(new Vector3(0, 0, -90), borders, Fractal.BorderType.Left);

            borders = new float[4][];
            borders[0] = left.MyHeightBorders[3].ToArray();
            borders[1] = top.MyHeightBorders[3].ToArray();
            borders[2] = right.MyHeightBorders[3].ToArray();

            Array.Reverse(borders[0]);

            front = new Terrain(4096, HeightMag, 1f, PlanetRes, pos, effect, texture, Terrain.Type.CubeFace);
            front.GenerateFractualSlice(new Vector3(90, 0, 0), borders, Fractal.BorderType.Left | Fractal.BorderType.Top | Fractal.BorderType.Right);

            borders = new float[4][];
            borders[0] = left.MyHeightBorders[1].ToArray();
            borders[2] = right.MyHeightBorders[1].ToArray();
            borders[3] = top.MyHeightBorders[1].ToArray();

            Array.Reverse(borders[2]);

            back = new Terrain(4096, HeightMag, 1f, PlanetRes, pos, effect, texture, Terrain.Type.CubeFace);
            back.GenerateFractualSlice(new Vector3(-90, 0, 0), borders, Fractal.BorderType.Left | Fractal.BorderType.Bottom | Fractal.BorderType.Right);

            borders = new float[4][];
            borders[0] = left.MyHeightBorders[0].ToArray();
            borders[1] = front.MyHeightBorders[3].ToArray();
            borders[2] = right.MyHeightBorders[2].ToArray();
            borders[3] = back.MyHeightBorders[1].ToArray();

            Array.Reverse(borders[0]);
            Array.Reverse(borders[2]);

            bottom = new Terrain(4096, HeightMag, 1f, PlanetRes, pos, effect, texture, Terrain.Type.CubeFace);
            bottom.GenerateFractualSlice(new Vector3(180, 0, 0), borders, Fractal.BorderType.All);

            ///////////////////
            top.loadPosBorders(left.MyRawHeightBorders[2], Fractal.BorderType.Left, false);
            top.loadPosBorders(right.MyRawHeightBorders[0], Fractal.BorderType.Right, false);
            top.loadPosBorders(front.MyRawHeightBorders[1], Fractal.BorderType.Bottom, false);
            top.loadPosBorders(back.MyRawHeightBorders[3], Fractal.BorderType.Top, false);
            top.PostNormalize();

            left.loadPosBorders(top.MyRawHeightBorders[0], Fractal.BorderType.Right, false);
            left.loadPosBorders(front.MyRawHeightBorders[0], Fractal.BorderType.Bottom, true);
            left.loadPosBorders(back.MyRawHeightBorders[0], Fractal.BorderType.Top, false);
            left.loadPosBorders(bottom.MyRawHeightBorders[0], Fractal.BorderType.Left, true);
            left.PostNormalize();

            right.loadPosBorders(top.MyRawHeightBorders[2], Fractal.BorderType.Left, false);
            right.loadPosBorders(front.MyRawHeightBorders[2], Fractal.BorderType.Bottom, false);
            right.loadPosBorders(back.MyRawHeightBorders[2], Fractal.BorderType.Top, true);
            right.loadPosBorders(bottom.MyRawHeightBorders[2], Fractal.BorderType.Right, true);
            right.PostNormalize();

            front.loadPosBorders(top.MyRawHeightBorders[3], Fractal.BorderType.Top, false);
            front.loadPosBorders(left.MyRawHeightBorders[3], Fractal.BorderType.Left, true);
            front.loadPosBorders(right.MyRawHeightBorders[3], Fractal.BorderType.Right, false);
            front.loadPosBorders(bottom.MyRawHeightBorders[1], Fractal.BorderType.Bottom, false);
            front.PostNormalize();

            back.loadPosBorders(top.MyRawHeightBorders[1], Fractal.BorderType.Bottom, false);
            back.loadPosBorders(right.MyRawHeightBorders[1], Fractal.BorderType.Right, true);
            back.loadPosBorders(left.MyRawHeightBorders[1], Fractal.BorderType.Left, false);
            back.loadPosBorders(bottom.MyRawHeightBorders[3], Fractal.BorderType.Top, false);
            back.PostNormalize();

            bottom.loadPosBorders(left.MyRawHeightBorders[0], Fractal.BorderType.Left, true);
            bottom.loadPosBorders(front.MyRawHeightBorders[3], Fractal.BorderType.Top, false);
            bottom.loadPosBorders(right.MyRawHeightBorders[2], Fractal.BorderType.Right, true);
            bottom.loadPosBorders(back.MyRawHeightBorders[1], Fractal.BorderType.Bottom, false);
            bottom.PostNormalize();

            topBlock = new TerrainBlock(top, 0, GraphicsDevice, effect, TerrainBlock.PlanetBlock.Top, this.GetNeighbourTerrain, new Point(), null);
            leftBlock = new TerrainBlock(left, 0, GraphicsDevice, effect, TerrainBlock.PlanetBlock.Left, this.GetNeighbourTerrain, new Point(), null);
            rightBlock = new TerrainBlock(right, 0, GraphicsDevice, effect, TerrainBlock.PlanetBlock.Right, this.GetNeighbourTerrain, new Point(), null);
            frontBlock = new TerrainBlock(front, 0, GraphicsDevice, effect, TerrainBlock.PlanetBlock.Front, this.GetNeighbourTerrain, new Point(), null);
            backBlock = new TerrainBlock(back, 0, GraphicsDevice, effect, TerrainBlock.PlanetBlock.Back, this.GetNeighbourTerrain, new Point(), null);
            bottomBlock = new TerrainBlock(bottom, 0, GraphicsDevice, effect, TerrainBlock.PlanetBlock.Bottom, this.GetNeighbourTerrain, new Point(), null);

            topBlock.GetNeighbour = this.GetNeighbourTerrain;
            leftBlock.GetNeighbour = this.GetNeighbourTerrain;
            rightBlock.GetNeighbour = this.GetNeighbourTerrain;
            frontBlock.GetNeighbour = this.GetNeighbourTerrain;
            backBlock.GetNeighbour = this.GetNeighbourTerrain;
            bottomBlock.GetNeighbour = this.GetNeighbourTerrain;

            water = new Planet(GraphicsDevice, Content, true);
        }
        public Planet(GraphicsDevice GraphicsDevice, ContentManager Content, bool water)
        {
            this.isWater = true;
            Effect effect = Content.Load<Effect>(@"effects/PPModel");
            Texture2D texture = Content.Load<Texture2D>(@"textures/red");

            Vector3 pos = Vector3.Zero;
            top = new Terrain(4096, HeightMag + WaterLevel, 1f, 65, pos, effect, texture, Terrain.Type.WaterCubeFace);
            top.GenerateEmptySlice();

            left = new Terrain(4096, HeightMag + WaterLevel, 1f, 65, pos, effect, texture, Terrain.Type.WaterCubeFace);
            left.GenerateEmptySlice(new Vector3(0, 0, 90));

            right = new Terrain(4096, HeightMag + WaterLevel, 1f, 65, pos, effect, texture, Terrain.Type.WaterCubeFace);
            right.GenerateEmptySlice(new Vector3(0, 0, -90));

            front = new Terrain(4096, HeightMag + WaterLevel, 1f, 65, pos, effect, texture, Terrain.Type.WaterCubeFace);
            front.GenerateEmptySlice(new Vector3(90, 0, 0));

            back = new Terrain(4096, HeightMag + WaterLevel, 1f, 65, pos, effect, texture, Terrain.Type.WaterCubeFace);
            back.GenerateEmptySlice(new Vector3(-90, 0, 0));

            bottom = new Terrain(4096, HeightMag + WaterLevel, 1f, 65, pos, effect, texture, Terrain.Type.WaterCubeFace);
            bottom.GenerateEmptySlice(new Vector3(180, 0, 0));
        }
        public Planet(GraphicsDevice GraphicsDevice, ContentManager Content, Vector3 sunPosition)
        {
            this.isWater = false;

            Vector3 pos = Vector3.Zero;
            top = new Terrain(4096, HeightMag, 1f, PlanetRes, pos, new Vector3(1, -1, 0), GraphicsDevice, Content.Load<Effect>(@"effects/Terrain"), Content.Load<Texture2D>(@"textures/base"), Terrain.Type.CubeFace);
            top.GenerateFractual();
            top.LightPosition = sunPosition;

            topBlock = new TerrainBlock(top, 0, true, GraphicsDevice, Content.Load<Effect>(@"effects/Terrain"));

            //l,t,r,b
            float[,] borders = new float[4, PlanetRes];
            for (int i = 0; i < 4; i++)
                for (int c = 0; c < PlanetRes; c++)
                    if (i == 2)
                        borders[i, c] = top.heightMaps[0, c];

            left = new Terrain(4096, HeightMag, 1f, PlanetRes, pos, new Vector3(1, -1, 0), GraphicsDevice, Content.Load<Effect>(@"effects/Terrain"), Content.Load<Texture2D>(@"textures/base"), Terrain.Type.CubeFace);
            left.GenerateFractualSlice(new Vector3(0, 0, 90), borders, Fractal.BorderType.Right);
            left.LightPosition = sunPosition;

            leftBlock = new TerrainBlock(left, 0, true, GraphicsDevice, Content.Load<Effect>(@"effects/Terrain"));

            //l,t,r,b
            borders = new float[4, PlanetRes];
            for (int i = 0; i < 4; i++)
                for (int c = 0; c < PlanetRes; c++)
                    if (i == 0)
                        borders[i, c] = top.heightMaps[(PlanetRes - 1), c];

            right = new Terrain(4096, HeightMag, 1f, PlanetRes, pos, new Vector3(1, -1, 0), GraphicsDevice, Content.Load<Effect>(@"effects/Terrain"), Content.Load<Texture2D>(@"textures/base"), Terrain.Type.CubeFace);
            right.GenerateFractualSlice(new Vector3(0, 0, -90), borders, Fractal.BorderType.Left);
            right.LightPosition = sunPosition;

            rightBlock = new TerrainBlock(right, 0, true, GraphicsDevice, Content.Load<Effect>(@"effects/Terrain"));

            //l,t,r,b
            borders = new float[4, PlanetRes];
            for (int i = 0; i < 4; i++)
                for (int c = 0; c < PlanetRes; c++)
                    if (i == 0)
                        borders[i, c] = left.heightMaps[(PlanetRes - 1) - c, (PlanetRes - 1)];
                    else if (i == 1)
                        borders[i, c] = top.heightMaps[c, (PlanetRes - 1)];
                    else if (i == 2)
                        borders[i, c] = right.heightMaps[c, (PlanetRes - 1)];

            front = new Terrain(4096, HeightMag, 1f, PlanetRes, pos, new Vector3(1, -1, 0), GraphicsDevice, Content.Load<Effect>(@"effects/Terrain"), Content.Load<Texture2D>(@"textures/base"), Terrain.Type.CubeFace);
            front.GenerateFractualSlice(new Vector3(90, 0, 0), borders, Fractal.BorderType.Left | Fractal.BorderType.Top | Fractal.BorderType.Right);
            front.LightPosition = sunPosition;

            frontBlock = new TerrainBlock(front, 0, true, GraphicsDevice, Content.Load<Effect>(@"effects/Terrain"));

            //l,t,r,b
            borders = new float[4, PlanetRes];
            for (int i = 0; i < 4; i++)
                for (int c = 0; c < PlanetRes; c++)
                    if (i == 0)
                        borders[i, c] = left.heightMaps[c, 0];
                    else if (i == 2)
                        borders[i, c] = right.heightMaps[(PlanetRes - 1) - c, 0];
                    else if (i == 3)
                        borders[i, c] = top.heightMaps[c, 0];

            back = new Terrain(4096, HeightMag, 1f, PlanetRes, pos, new Vector3(1, -1, 0), GraphicsDevice, Content.Load<Effect>(@"effects/Terrain"), Content.Load<Texture2D>(@"textures/base"), Terrain.Type.CubeFace);
            back.GenerateFractualSlice(new Vector3(-90, 0, 0), borders, Fractal.BorderType.Left | Fractal.BorderType.Bottom | Fractal.BorderType.Right);
            back.LightPosition = sunPosition;

            backBlock = new TerrainBlock(back, 0, true, GraphicsDevice, Content.Load<Effect>(@"effects/Terrain"));

            //l,t,r,b
            borders = new float[4, PlanetRes];
            for (int i = 0; i < 4; i++)
                for (int c = 0; c < PlanetRes; c++)
                    if (i == 0)
                        borders[i, c] = left.heightMaps[0, (PlanetRes - 1) - c];
                    else if (i == 1)
                        borders[i, c] = front.heightMaps[c, (PlanetRes - 1)];
                    else if (i == 2)
                        borders[i, c] = right.heightMaps[(PlanetRes - 1), (PlanetRes - 1) - c];
                    else if (i == 3)
                        borders[i, c] = back.heightMaps[c, 0];

            bottom = new Terrain(4096, HeightMag, 1f, PlanetRes, pos, new Vector3(1, -1, 0), GraphicsDevice, Content.Load<Effect>(@"effects/Terrain"), Content.Load<Texture2D>(@"textures/base"), Terrain.Type.CubeFace);
            bottom.GenerateFractualSlice(new Vector3(180, 0, 0), borders, Fractal.BorderType.All);
            bottom.LightPosition = sunPosition;

            bottomBlock = new TerrainBlock(bottom, 0, true, GraphicsDevice, Content.Load<Effect>(@"effects/Terrain"));

            water = new Planet(GraphicsDevice, Content, true, sunPosition);
        }
        public Planet(GraphicsDevice GraphicsDevice, ContentManager Content, bool water, Vector3 sunPosition)
        {
            this.isWater = true;

            Vector3 pos = Vector3.Zero;
            top = new Terrain(4096, HeightMag, 1f, 65, pos, new Vector3(1, -1, 0), GraphicsDevice, Content.Load<Effect>(@"effects/Terrain"), Content.Load<Texture2D>(@"textures/red"), Terrain.Type.WaterCubeFace);
            top.GenerateEmptySlice();

            left = new Terrain(4096, HeightMag, 1f, 65, pos, new Vector3(1, -1, 0), GraphicsDevice, Content.Load<Effect>(@"effects/Terrain"), Content.Load<Texture2D>(@"textures/red"), Terrain.Type.WaterCubeFace);
            left.GenerateEmptySlice(new Vector3(0, 0, 90));

            right = new Terrain(4096, HeightMag, 1f, 65, pos, new Vector3(1, -1, 0), GraphicsDevice, Content.Load<Effect>(@"effects/Terrain"), Content.Load<Texture2D>(@"textures/red"), Terrain.Type.WaterCubeFace);
            right.GenerateEmptySlice(new Vector3(0, 0, -90));

            front = new Terrain(4096, HeightMag, 1f, 65, pos, new Vector3(1, -1, 0), GraphicsDevice, Content.Load<Effect>(@"effects/Terrain"), Content.Load<Texture2D>(@"textures/red"), Terrain.Type.WaterCubeFace);
            front.GenerateEmptySlice(new Vector3(90, 0, 0));

            back = new Terrain(4096, HeightMag, 1f, 65, pos, new Vector3(1, -1, 0), GraphicsDevice, Content.Load<Effect>(@"effects/Terrain"), Content.Load<Texture2D>(@"textures/red"), Terrain.Type.WaterCubeFace);
            back.GenerateEmptySlice(new Vector3(-90, 0, 0));

            bottom = new Terrain(4096, HeightMag, 1f, 65, pos, new Vector3(1, -1, 0), GraphicsDevice, Content.Load<Effect>(@"effects/Terrain"), Content.Load<Texture2D>(@"textures/red"), Terrain.Type.WaterCubeFace);
            bottom.GenerateEmptySlice(new Vector3(180, 0, 0));

            top.LightPosition = sunPosition;
            left.LightPosition = sunPosition;
            right.LightPosition = sunPosition;
            front.LightPosition = sunPosition;
            back.LightPosition = sunPosition;
            bottom.LightPosition = sunPosition;
        }
        public void SplitMainTerrainPlanet(Terrain terrain)
        {
            this.terrain[0] = new Terrain(terrain.cellSize, terrain.height, terrain.textureTiling, terrain.width / 2 + 1,
                                     new Vector3(terrain.Position.X, terrain.Position.Y, terrain.Position.Z),
                                     terrain.lightDirection, GraphicsDevice, effect, terrain.baseTexture, terrain.type);
            this.terrain[1] = new Terrain(terrain.cellSize, terrain.height, terrain.textureTiling, terrain.width / 2 + 1,
                                     new Vector3(terrain.Position.X, terrain.Position.Y, terrain.Position.Z),
                                     terrain.lightDirection, GraphicsDevice, effect, terrain.baseTexture, terrain.type);
            this.terrain[2] = new Terrain(terrain.cellSize, terrain.height, terrain.textureTiling, terrain.width / 2 + 1,
                                     new Vector3(terrain.Position.X, terrain.Position.Y, terrain.Position.Z),
                                     terrain.lightDirection, GraphicsDevice, effect, terrain.baseTexture, terrain.type);
            this.terrain[3] = new Terrain(terrain.cellSize, terrain.height, terrain.textureTiling, terrain.width / 2 + 1,
                                     new Vector3(terrain.Position.X, terrain.Position.Y, terrain.Position.Z),
                                     terrain.lightDirection, GraphicsDevice, effect, terrain.baseTexture, terrain.type);

            int size = terrain.width / 2;
            float[,] heights0 = new float[size + 1, size + 1];
            float[,] heights1 = new float[size + 1, size + 1];
            float[,] heights2 = new float[size + 1, size + 1];
            float[,] heights3 = new float[size + 1, size + 1];
            for (int x = 0; x <= size; x++)
                for (int y = 0; y <= size; y++)
                {
                    heights0[x, y] = terrain.heightMaps[x, y];
                    heights1[x, y] = terrain.heightMaps[x + size, y];
                    heights2[x, y] = terrain.heightMaps[x, y + size];
                    heights3[x, y] = terrain.heightMaps[x + size, y + size];
                }

            this.terrain[0].GenerateCustom(heights0, terrain.LightPosition, new Vector3(blockOffset.X, blockOffset.Y, blockOffset.Z));
            this.terrain[1].GenerateCustom(heights1, terrain.LightPosition, new Vector3(blockOffset.X + size, blockOffset.Y, blockOffset.Z));
            this.terrain[2].GenerateCustom(heights2, terrain.LightPosition, new Vector3(blockOffset.X, blockOffset.Y + size, blockOffset.Z));
            this.terrain[3].GenerateCustom(heights3, terrain.LightPosition, new Vector3(blockOffset.X + size, blockOffset.Y + size, blockOffset.Z));

            this.terrain[0].GlobalRot = terrain.GlobalRot;
            this.terrain[1].GlobalRot = terrain.GlobalRot;
            this.terrain[2].GlobalRot = terrain.GlobalRot;
            this.terrain[3].GlobalRot = terrain.GlobalRot;
        }
        public void SplitMainTerrainFlat(Terrain terrain)
        {
            float sizeOffset = terrain.cellSize * (terrain.width / 4);

            this.terrain[0] = new Terrain(terrain.cellSize, terrain.height, terrain.textureTiling, terrain.width / 2 + 1,
                                     new Vector3(terrain.Position.X, terrain.Position.Y, terrain.Position.Z),
                                     terrain.lightDirection, GraphicsDevice, effect, terrain.baseTexture, terrain.type);
            this.terrain[1] = new Terrain(terrain.cellSize, terrain.height, terrain.textureTiling, terrain.width / 2 + 1,
                                     new Vector3(terrain.Position.X + sizeOffset, terrain.Position.Y, terrain.Position.Z),
                                     terrain.lightDirection, GraphicsDevice, effect, terrain.baseTexture, terrain.type);
            this.terrain[2] = new Terrain(terrain.cellSize, terrain.height, terrain.textureTiling, terrain.width / 2 + 1,
                                     new Vector3(terrain.Position.X, terrain.Position.Y, terrain.Position.Z + sizeOffset),
                                     terrain.lightDirection, GraphicsDevice, effect, terrain.baseTexture, terrain.type);
            this.terrain[3] = new Terrain(terrain.cellSize, terrain.height, terrain.textureTiling, terrain.width / 2 + 1,
                                     new Vector3(terrain.Position.X + sizeOffset, terrain.Position.Y, terrain.Position.Z + sizeOffset),
                                     terrain.lightDirection, GraphicsDevice, effect, terrain.baseTexture, terrain.type);

            int size = terrain.width / 2;
            float[,] heights0 = new float[size + 1, size + 1];
            float[,] heights1 = new float[size + 1, size + 1];
            float[,] heights2 = new float[size + 1, size + 1];
            float[,] heights3 = new float[size + 1, size + 1];
            for (int x = 0; x <= size; x++)
                for (int y = 0; y <= size; y++)
                {
                    heights0[x, y] = terrain.heightMaps[x, y];
                    heights1[x, y] = terrain.heightMaps[x + size, y];
                    heights2[x, y] = terrain.heightMaps[x, y + size];
                    heights3[x, y] = terrain.heightMaps[x + size, y + size];
                }

            this.terrain[0].GenerateCustom(heights0);
            this.terrain[1].GenerateCustom(heights1);
            this.terrain[2].GenerateCustom(heights2);
            this.terrain[3].GenerateCustom(heights3);
        }
        public void SplitChildrenPlanet(object input)
        {
            Vector3 position = (Vector3)input;
            if (this.depth >= maxDepth)
                return;

            if (this.busy)
                return;

            this.busy = true;
            for (int i = 0; i < 4; i++)
            {
                int t = this.terrain[i].width - 1;
                Vector3 a = this.terrain[i].Center + this.terrain[i].Position;//c
                Vector3 b = this.terrain[i].getAdjustedPos(this.terrain[i].vertices[0].Position) + this.terrain[i].Position;//NW
                Vector3 c = this.terrain[i].getAdjustedPos(this.terrain[i].vertices[t].Position) + this.terrain[i].Position;//NE
                Vector3 d = this.terrain[i].getAdjustedPos(this.terrain[i].vertices[this.terrain[i].vertices.Count() - 1].Position) + this.terrain[i].Position;//SE
                Vector3 e = this.terrain[i].getAdjustedPos(this.terrain[i].vertices[this.terrain[i].vertices.Count() - t - 1].Position) + this.terrain[i].Position;//SW
                //float d = (Vector3.Cross((a - b), (b - position))).Length() / (a - b).Length();
                if (((a - position).Length() > this.terrain[i].width * this.terrain[i].cellSize * (2.5f - (0 * depth)) &&
                    (b - position).Length() > this.terrain[i].width * this.terrain[i].cellSize * (2.5f - (0 * depth)) &&
                    (c - position).Length() > this.terrain[i].width * this.terrain[i].cellSize * (2.5f - (0 * depth)) &&
                    (d - position).Length() > this.terrain[i].width * this.terrain[i].cellSize * (2.5f - (0 * depth)) &&
                    (e - position).Length() > this.terrain[i].width * this.terrain[i].cellSize * (2.5f - (0 * depth))) ||
                    waterSphere.Contains(new BoundingBox(b, d)) == ContainmentType.Contains)
                {
                    if (this.children[i] != null)
                    {
                        this.children[i].nullChildren();
                        this.children[i] = null;
                    }
                    continue;
                }

                if (children[i] == null)
                {
                    Terrain tmp = new Terrain(terrain[i].cellSize / 2.0f, terrain[i].height, terrain[i].textureTiling, (int)(terrain[i].width * 2 - 1),
                                              new Vector3(terrain[i].Position.X, terrain[i].Position.Y, terrain[i].Position.Z),
                                              terrain[i].lightDirection, GraphicsDevice, effect, baseTexture, Terrain.Type.CubeFace);

                    int size = terrain[i].width * 2 - 1;
                    float[,] heights = new float[size, size];
                    for (int x = 0; x < size; x += 2)
                        for (int y = 0; y < size; y += 2)
                            heights[x, y] = terrain[i].heightMaps[x / 2, y / 2];

                    Vector3 blcOff = new Vector3(blockOffset.X, blockOffset.Y, -1);

                    switch (i)
                    {
                        case 0:
                            blcOff.X *= 2;
                            blcOff.Y *= 2;
                            break;
                        case 1:
                            blcOff.X *= 2;
                            blcOff.X += size - 1;
                            blcOff.Y *= 2;
                            break;
                        case 2:
                            blcOff.X *= 2;
                            blcOff.Y *= 2;
                            blcOff.Y += size - 1;
                            break;
                        case 3:
                            blcOff.X *= 2;
                            blcOff.X += size - 1;
                            blcOff.Y *= 2;
                            blcOff.Y += size - 1;
                            break;
                    }

                    tmp.GenerateCustom(new Fractal(size, this.depth + 8).singleStep(heights), terrain[i].LightPosition, blcOff);
                    tmp.GlobalRot = terrain[i].GlobalRot;

                    TerrainBlock tb = new TerrainBlock(tmp, this.depth + 1, this.planet, GraphicsDevice, effect, blcOff);
                    children[i] = tb;
                }

                if (children[i] != null)
                    children[i].SplitChildren(position);
            }

            this.busy = false;
        }
        public void SplitChildren(object input)
        {
            if (this.planet)
            {
                this.SplitChildrenPlanet(input);
                return;
            }

            Vector3 position = (Vector3)input;
            if (this.depth >= maxDepth)
                return;

            if (this.busy)
                return;

            this.busy = true;
            for (int i = 0; i < 4; i++)
            {
                int t = this.terrain[i].width - 1;
                Vector3 a = this.terrain[i].Center + this.terrain[i].Position;//c
                Vector3 b = this.terrain[i].getAdjustedPos(this.terrain[i].vertices[0].Position) + this.terrain[i].Position;//NW
                Vector3 c = this.terrain[i].getAdjustedPos(this.terrain[i].vertices[t].Position) + this.terrain[i].Position;//NE
                Vector3 d = this.terrain[i].getAdjustedPos(this.terrain[i].vertices[this.terrain[i].vertices.Count() - 1].Position) + this.terrain[i].Position;//SE
                Vector3 e = this.terrain[i].getAdjustedPos(this.terrain[i].vertices[this.terrain[i].vertices.Count() - t - 1].Position) + this.terrain[i].Position;//SW
                //float d = (Vector3.Cross((a - b), (b - position))).Length() / (a - b).Length();
                if ((a - position).Length() > this.terrain[i].width * this.terrain[i].cellSize * (1.75f + (0.075f * depth)) &&
                    (b - position).Length() > this.terrain[i].width * this.terrain[i].cellSize * (1.25f + (0.075f * depth)) &&
                    (c - position).Length() > this.terrain[i].width * this.terrain[i].cellSize * (1.25f + (0.075f * depth)) &&
                    (d - position).Length() > this.terrain[i].width * this.terrain[i].cellSize * (1.25f + (0.075f * depth)) &&
                    (e - position).Length() > this.terrain[i].width * this.terrain[i].cellSize * (1.25f + (0.075f * depth)))
                {
                    if (this.children[i] != null)
                    {
                        this.children[i].nullChildren();
                        this.children[i] = null;
                    }
                    continue;
                }

                float sizeOffset = (float)terrain[i].cellSize * ((float)terrain[i].width / 8.0f);
                Terrain tmp = new Terrain(terrain[i].cellSize / 2.0f, terrain[i].height, terrain[i].textureTiling, (int)(terrain[i].width * 2 - 1),
                                          new Vector3(terrain[i].Position.X - sizeOffset, terrain[i].Position.Y, terrain[i].Position.Z - sizeOffset),
                                          terrain[i].lightDirection,GraphicsDevice,effect, baseTexture);

                int size = terrain[i].width * 2 - 1;
                float[,] heights = new float[size, size];
                for (int x = 0; x < size; x += 2)
                    for (int y = 0; y < size; y += 2)
                        heights[x, y] = terrain[i].heightMaps[x / 2, y / 2];

                if (children[i] == null)
                {
                    tmp.GenerateCustom(new Fractal(size, this.depth + 8).singleStep(heights));

                    TerrainBlock tb = new TerrainBlock(tmp, this.depth + 1, this.planet, GraphicsDevice, effect);
                    children[i] = tb;
                }

                if (children[i] != null)
                    children[i].SplitChildren(position);
            }

            this.busy = false;
        }