Exemplo n.º 1
0
        public static List <Point2d> GetSettlementLocations(WaterTableField wtf, IField2d <float> wateriness,
                                                            float noiseScale = 0.1f, float noiseBlur = 3f, float noiseContribution = 0.15f)
        {
            IField2d <float> noise = new BlurredField(new MountainNoise(wtf.Width, wtf.Height, noiseScale), noiseBlur);
            Transformation2d <float, float, float> combination = new Transformation2d <float, float, float>(wateriness, noise, (w, n) => w + noiseContribution * n);

            List <Point2d> locations = new List <Point2d>();

            for (int y = 1; y < combination.Height - 1; y++)
            {
                for (int x = 1; x < combination.Width - 1; x++)
                {
                    if (wtf[y, x] > 0f &&
                        combination[y - 1, x - 1] < combination[y, x] &&
                        combination[y - 1, x + 0] < combination[y, x] &&
                        combination[y - 1, x + 1] < combination[y, x] &&
                        combination[y + 0, x + 1] < combination[y, x] &&
                        combination[y + 1, x + 1] < combination[y, x] &&
                        combination[y + 1, x + 0] < combination[y, x] &&
                        combination[y + 1, x - 1] < combination[y, x] &&
                        combination[y + 0, x - 1] < combination[y, x])
                    {
                        locations.Add(new Point2d(x, y));
                    }
                }
            }

            return(locations);
        }
Exemplo n.º 2
0
        public void Resize(int width, int height)
        {
            GL.Viewport(0, 0, width, height); // tell OpenGL to use the whole window for drawing

            //TODO: Save the view port aspect ratio for use in rendering
            _windowAspectRatio = height / (float)width;

            var viewport = Transformation2d.Combine(Transformation2d.Translate(Vector2.One), Transformation2d.Scale(width / 2f, height / 2f));

            InvViewportMatrix = viewport.Inverted();
            GL.Ortho(0, width, height, 0, -1, 1);
            UpdateMatrix();
        }
Exemplo n.º 3
0
        public void OutputMapForRectangle(Rectangle sourceRect, Bitmap bmp, string dir = "C:\\Users\\Justin Murray\\Desktop\\terrain\\", string name = "submap")
        {
            // Hack that adds buffers, use to work around unidentified bugs and differences of behavior near edges.
            Rectangle rect = new Rectangle(
                sourceRect.Left - sourceRect.Width / 20,
                sourceRect.Top - sourceRect.Height / 20,
                sourceRect.Width * 11 / 10,
                sourceRect.Height * 11 / 10);

            int width  = (int)Math.Ceiling(bmp.Width * 1.1f);
            int height = (int)Math.Ceiling(bmp.Height * 1.1f);

            IField2d <float> waterTable = new BlurredField(new SubContinuum <float>(width, height, new ContinuousField(this.wtf), rect), 0.5f * width / rect.Width);
            IField2d <float> mountains  = new SubContinuum <float>(width, height, this.mountainNoise, rect);
            // TODO: hills?

            IField2d <float> roughness = new BlurredField(new SubContinuum <float>(width, height, new ContinuousField(this.args.roughnessDrawing), rect), 0.5f * width / rect.Width);

            IField2d <float> riverbeds = GetRiverFieldForRectangle(width, height, rect);
            IField2d <float> damping   = GetDampingFieldForRectangle(rect, riverbeds);

            IField2d <float> heightmap;
            {
                IField2d <float> dampedNoise       = new Transformation2d <float, float, float>(mountains, damping, (m, d) => Math.Max(1f - d, 0f) * m);
                IField2d <float> scaledDampedNoise = new Transformation2d <float, float, float>(dampedNoise, roughness, (n, r) => n * r * this.args.mountainHeightMaxInMeters);
                IField2d <float> groundHeight      = new Transformation2d <float, float, float>(waterTable, scaledDampedNoise, (w, m) => w + m);

                // TODO: Erode the groundHeight.

                heightmap = new Transformation2d <float, float, float>(groundHeight, riverbeds, Math.Min);

                //DEBUG
                heightmap = Erosion.DropletHydraulic(
                    heightmap,
                    2 * heightmap.Width * heightmap.Height,
                    100,
                    maxHeight: this.args.baseHeightMaxInMeters + this.args.mountainHeightMaxInMeters,
                    radius: (int)(this.args.erosionRadiusInMeters / (this.args.metersPerPixel * sourceRect.Width / heightmap.Width))
                    );
            }

            IField2d <float> riverField  = new SubField <float>(riverbeds, new Rectangle(bmp.Width / 20, bmp.Height / 20, bmp.Width, bmp.Height));
            IField2d <float> heightField = new SubField <float>(heightmap, new Rectangle(bmp.Width / 20, bmp.Height / 20, bmp.Width, bmp.Height));

            // TODO: DEBUG
            OutputAsOBJ(heightField, new Transformation2d <float, bool>(riverField, r => !float.IsPositiveInfinity(r)), sourceRect, bmp, dir, name);
            OutputAsPreciseHeightmap(heightField, riverField, dir + name + ".png");
        }
Exemplo n.º 4
0
        private static ContinuousField InitializeDistanceFromWater(WaterTableField wtf, Args args)
        {
            var dists = new Transformation2d <Point2d, float>(wtf.DrainageField, (x, y, p) =>
            {
                if (wtf.HydroField[y, x] != HydrologicalField.LandType.Land)
                {
                    return(0f);
                }

                // We subtract 1 to compute the distance as water-adjacent as well as on-the-water.
                // This is a slight bit of a hack, but helps account for problems at varying resolutions.
                return(args.metersPerPixel * (Point2d.Distance(new Point2d(x, y), p) - 1f));
            });

            return(new ContinuousField(dists));
        }
Exemplo n.º 5
0
        internal void PlacePath(float x, float y, KeyboardState keyboard)
        {
            var cam = _view.Camera;
            var fromViewportToWorld = Transformation2d.Combine(cam.InvViewportMatrix, cam.CameraMatrix.Inverted());
            var pixelCoordinates    = new Vector2(x, y);
            var world = pixelCoordinates.Transform(fromViewportToWorld);

            if (world.X < 0 || _model.Grid.Columns < world.X)
            {
                return;
            }
            if (world.Y < 0 || _model.Grid.Rows < world.Y)
            {
                return;
            }
            var column = (int)Math.Truncate(world.X);
            var row    = (int)Math.Truncate(world.Y);
            var cell   = _model.CheckCell(column, row);

            if (cell == Grid.CellType.Empty)
            {
                //Path setzen
                if (keyboard.IsKeyDown(Keys.Space))
                {
                    if (cell != Grid.CellType.Empty)
                    {
                        return;
                    }
                    else
                    {
                        if (_model.PlacePath(column, row))
                        {
                            return;
                        }
                    }
                    return;
                }
            }
        }
Exemplo n.º 6
0
        public void OutputAsOBJ(IField2d <float> heights, IField2d <bool> riverField, Rectangle rect, Bitmap bmp, string outputDir, string outputName = "terrain")
        {
            using (var objWriter = new StreamWriter(File.OpenWrite(outputDir + outputName + ".obj")))
            {
                objWriter.WriteLine("mtllib " + outputName + ".mtl");
                objWriter.WriteLine("o " + outputName + "_o");

                float             metersPerPixel = this.args.metersPerPixel * rect.Width / heights.Width;
                IField2d <vFloat> verts          = new Transformation2d <float, vFloat>(heights,
                                                                                        (x, y, z) => new vFloat(x * metersPerPixel, -y * metersPerPixel, z));

                // One vertex per pixel.
                for (int y = 0; y < verts.Height; y++)
                {
                    for (int x = 0; x < verts.Width; x++)
                    {
                        vFloat v = verts[y, x];
                        objWriter.WriteLine("v " + v[0] + " " + v[1] + " " + v[2]);
                    }
                }

                // Normal of the vertex is the cross product of skipping vectors in X and Y.  If skipping is unavailable, use the local vector.
                for (int y = 0; y < verts.Height; y++)
                {
                    for (int x = 0; x < verts.Width; x++)
                    {
                        int xl = Math.Max(x - 1, 0);
                        int xr = Math.Min(x + 1, verts.Width - 1);
                        int yl = Math.Max(y - 1, 0);
                        int yr = Math.Min(y + 1, verts.Height - 1);

                        vFloat xAxis = verts[y, xr] - verts[y, xl];
                        vFloat yAxis = verts[yr, x] - verts[yl, x];

                        vFloat n = vFloat.Cross3d(xAxis, yAxis);
                        if (n[2] < 0f)
                        {
                            n = -n;
                        }
                        n = n.norm();

                        objWriter.WriteLine("vn " + n[0] + " " + n[1] + " " + n[2]);
                    }
                }

                // Texture coordinate is trivial.
                for (int y = 0; y < verts.Height; y++)
                {
                    for (int x = 0; x < verts.Width; x++)
                    {
                        objWriter.WriteLine("vt " + (1f * x / (verts.Width - 1)) + " " + (1f - 1f * y / (verts.Height - 1)));
                    }
                }

                objWriter.WriteLine("g " + outputName + "_g");
                objWriter.WriteLine("usemtl " + outputName + "_mtl");

                // Now the faces.  Since we're not optimizing at all, this is incredibly simple.
                // TODO: Fix bug where including edge pixels causes tris to go across entire map for some reason.  For now, just workaround.
                for (int y = 1; y < verts.Height - 2; y++)
                {
                    for (int x = 1; x < verts.Width - 2; x++)
                    {
                        int tl = y * verts.Width + x;
                        int tr = tl + 1;
                        int bl = tl + verts.Width;
                        int br = bl + 1;

                        objWriter.WriteLine("f " +
                                            tl + "/" + tl + "/" + tl + " " +
                                            br + "/" + br + "/" + br + " " +
                                            tr + "/" + tr + "/" + tr);

                        objWriter.WriteLine("f " +
                                            tl + "/" + tl + "/" + tl + " " +
                                            bl + "/" + bl + "/" + bl + " " +
                                            br + "/" + br + "/" + br);
                    }
                }
            }

            using (var mtlWriter = new StreamWriter(File.OpenWrite(outputDir + outputName + ".mtl")))
            {
                mtlWriter.WriteLine("newmtl " + outputName + "_mtl");
                mtlWriter.WriteLine("Ka 0.000000 0.000000 0.000000");
                mtlWriter.WriteLine("Kd 0.800000 0.800000 0.800000");
                mtlWriter.WriteLine("Ks 0.200000 0.200000 0.200000");
                mtlWriter.WriteLine("Ns 1.000000");
                mtlWriter.WriteLine("d 1.000000");
                mtlWriter.WriteLine("illum 1");
                mtlWriter.WriteLine("map_Kd " + outputName + ".jpg");
            }

            for (int x = 0, y = 0; y < heights.Height; y += ++x / heights.Width, x %= heights.Width)
            {
                float value = heights[y, x];
                Color color;
                if (riverField[y, x])
                {
                    color = Color.DodgerBlue;
                }
                else if (value > 2250f)
                {
                    color = Lerp(Color.Gray, Color.White, (value - 2250f) / 1750f);
                }
                else if (value > 1250f)
                {
                    color = Lerp(Color.Red, Color.Gray, (value - 1250f) / 1000f);
                }
                else if (value > 750f)
                {
                    color = Lerp(Color.Yellow, Color.Red, (value - 750f) / 500f);
                }
                else if (value > 250f)
                {
                    color = Lerp(Color.Green, Color.Yellow, (value - 250f) / 500f);
                }
                else if (value > 5f)
                {
                    color = Lerp(Color.DarkGreen, Color.Green, (value - 5f) / 245f);
                }
                else
                {
                    color = Color.DodgerBlue;
                }
                bmp.SetPixel(x, y, color);
            }
            bmp.Save(outputDir + outputName + ".jpg");
        }
Exemplo n.º 7
0
        internal void Click(float x, float y, KeyboardState keyboard)
        {
            var cam = _view.Camera;
            var fromViewportToWorld = Transformation2d.Combine(cam.InvViewportMatrix, cam.CameraMatrix.Inverted());
            var pixelCoordinates    = new Vector2(x, y);
            var world = pixelCoordinates.Transform(fromViewportToWorld);

            if (world.X < 0 || _model.Grid.Columns < world.X)
            {
                return;
            }
            if (world.Y < 0 || _model.Grid.Rows < world.Y)
            {
                return;
            }
            var column = (int)Math.Truncate(world.X);
            var row    = (int)Math.Truncate(world.Y);
            var cell   = _model.CheckCell(column, row);

            if (_model.gameOver == false)
            {
                //Sniper verkaufen
                if (cell == Grid.CellType.Sniper && keyboard.IsKeyDown(Keys.Delete))
                {
                    foreach (Tower tower in _model.towers.ToList())
                    {
                        if (tower.Center.X == column && tower.Center.Y == row)
                        {
                            _model.ClearCell(column, row, tower);
                            Console.WriteLine("sold sniper, new balance: " + _model.cash);
                        }
                        else
                        {
                            continue;
                        }
                    }
                    return;
                }

                //Rifle verkaufen
                if (cell == Grid.CellType.Rifle && keyboard.IsKeyDown(Keys.Delete))
                {
                    //Sell Rifle
                    foreach (Tower tower in _model.towers.ToList())
                    {
                        if (tower.Center.X == column && tower.Center.Y == row)
                        {
                            _model.ClearCell(column, row, tower);
                            Console.WriteLine("sold rifle, new balance: " + _model.cash);
                        }
                        else
                        {
                            continue;
                        }
                    }
                    return;
                }

                //Bouncer verkaufen
                if (cell == Grid.CellType.Bouncer && keyboard.IsKeyDown(Keys.Delete))
                {
                    foreach (Tower tower in _model.towers.ToList())
                    {
                        if (tower.Center.X == column && tower.Center.Y == row)
                        {
                            _model.ClearCell(column, row, tower);
                            Console.WriteLine("sold sniper, new balance: " + _model.cash);
                        }
                        else
                        {
                            continue;
                        }
                    }
                    return;
                }

                //Schauen ob Cell leer ist
                if (cell == Grid.CellType.Empty)
                {
                    //Sniper kaufen
                    if (keyboard.IsKeyDown(Keys.D2))
                    {
                        if (cell != Grid.CellType.Empty)
                        {
                            return;
                        }
                        else
                        {
                            _model.PlaceSniper(column, row);
                        }
                        return;
                    }
                    //Rifle kaufen
                    if (keyboard.IsKeyDown(Keys.D1))
                    {
                        if (cell != Grid.CellType.Empty)
                        {
                            return;
                        }
                        else
                        {
                            _model.PlaceRifle(column, row);
                        }
                        return;
                    }
                    //Bouncer kaufen
                    if (keyboard.IsKeyDown(Keys.D3))
                    {
                        if (cell != Grid.CellType.Empty)
                        {
                            return;
                        }
                        else
                        {
                            _model.PlaceBouncer(column, row);
                        }
                        return;
                    }
                }
            }
        }
Exemplo n.º 8
0
        internal void ShowTowerSample(float x, float y, KeyboardState keyboard)
        {
            var cam = _view.Camera;
            var fromViewportToWorld = Transformation2d.Combine(cam.InvViewportMatrix, cam.CameraMatrix.Inverted());
            var pixelCoordinates    = new Vector2(x, y);
            var world = pixelCoordinates.Transform(fromViewportToWorld);

            if (world.X < 0 || _model.Grid.Columns < world.X)
            {
                return;
            }
            if (world.Y < 0 || _model.Grid.Rows < world.Y)
            {
                return;
            }
            var column = (int)Math.Truncate(world.X);
            var row    = (int)Math.Truncate(world.Y);
            var cell   = _model.CheckCell(column, row);

            if (cell == Grid.CellType.Empty)
            {
                if (keyboard.IsKeyDown(Keys.D2))
                {
                    if (cell != Grid.CellType.Empty)
                    {
                        return;
                    }
                    else
                    {
                        _view.sampleSniper = true;
                        _view.sampleColRow = new Vector2(column, row);
                    }//Snake
                    return;
                }
                else
                {
                    _view.sampleSniper = false;
                }
                if (keyboard.IsKeyDown(Keys.D1))
                {
                    if (cell != Grid.CellType.Empty)
                    {
                        return;
                    }
                    else
                    {
                        _view.sampleRifle  = true;
                        _view.sampleColRow = new Vector2(column, row);
                    }//Snake
                    return;
                }
                else
                {
                    _view.sampleRifle = false;
                }
                if (keyboard.IsKeyDown(Keys.D3))
                {
                    if (cell != Grid.CellType.Empty)
                    {
                        return;
                    }
                    else
                    {
                        _view.sampleBouncer = true;
                        _view.sampleColRow  = new Vector2(column, row);
                    }//Snake
                    return;
                }
                else
                {
                    _view.sampleBouncer = false;
                }
            }
        }
Exemplo n.º 9
0
        public static void RunZoomedInScenario()
        {
            // 32x32 up to 1024x1024 will, from the fifth-of-a-mile-per-pixel source, get us approximately 10m per pixel.
            // 16x16 would get us 5
            // 8x8 would get us 2.5
            // 4x4 would get us 1.25
            // 2x2 would get us .75
            // 1x1 would get us .375, which is slightly over 1 foot.
            // I think 16x16 is the sweet spot.  That's just over 9 square miles per small map.
            const int   SMALL_MAP_SIDE_LEN    = 64;
            const float STARTING_SCALE        = 0.005f * SMALL_MAP_SIDE_LEN / 32;
            const int   SMALL_MAP_RESIZED_LEN = 1024;

            Random random = new Random();

            WaterTableArgs args = new WaterTableArgs();
            Bitmap         bmp  = new Bitmap(args.inputPath + "rivers.png");

            IField2d <float> baseMap = new Utils.FieldFromBitmap(new Bitmap(args.inputPath + "base_heights.png"));

            baseMap = new ReResField(baseMap, (float)bmp.Width / baseMap.Width);

            var wtf = Utils.GenerateWaters(bmp, baseMap);

            Utils.OutputAsColoredMap(wtf, wtf.RiverSystems, bmp, args.outputPath + "colored_map.png");

            var hasWater     = new Transformation2d <HydrologicalField.LandType, float>(wtf.HydroField, t => t == HydrologicalField.LandType.Land ? 0f : 1f);
            var noiseDamping = new Transformation2d(new BlurredField(hasWater, 2f), v => 3.5f * v);

            // Create the spline map.
            SparseField2d <List <SplineTree> > relevantSplines = new SparseField2d <List <SplineTree> >(wtf.Width, wtf.Height, null);
            {
                //HashSet<TreeNode<Point2d>> relevantRivers = new HashSet<TreeNode<Point2d>>();
                foreach (var system in wtf.RiverSystems)
                {
                    SplineTree tree = null;

                    foreach (var p in system.value)
                    {
                        if (relevantSplines[p.value.y, p.value.x] == null)
                        {
                            relevantSplines[p.value.y, p.value.x] = new List <SplineTree>();
                        }
                        relevantSplines[p.value.y, p.value.x].Add(tree ?? (tree = new SplineTree(system.value, wtf, random)));
                    }
                }
            }

            Rectangle rect       = new Rectangle(518 + 15, 785 + 45, SMALL_MAP_SIDE_LEN, SMALL_MAP_SIDE_LEN);
            var       smallMap   = new SubField <float>(wtf, rect);
            var       scaledUp   = new BlurredField(new ReResField(smallMap, SMALL_MAP_RESIZED_LEN / smallMap.Width), SMALL_MAP_RESIZED_LEN / (4 * SMALL_MAP_SIDE_LEN));
            var       smallDamp  = new SubField <float>(noiseDamping, rect);
            var       scaledDamp = new BlurredField(new ReResField(smallDamp, SMALL_MAP_RESIZED_LEN / smallMap.Width), SMALL_MAP_RESIZED_LEN / (4 * SMALL_MAP_SIDE_LEN));

            // Do spline-y things.
            Field2d <float>   riverbeds;
            List <SplineTree> splines = new List <SplineTree>();
            {
                // Collect a comprehensive list of the spline trees for the local frame.
                for (int y = rect.Top - 1; y <= rect.Bottom + 1; y++)
                {
                    for (int x = rect.Left - 1; x <= rect.Right + 1; x++)
                    {
                        List <SplineTree> trees = relevantSplines[y, x];
                        if (trees != null)
                        {
                            splines.AddRange(trees);
                        }
                    }
                }

                // Crafts the actual river kernel.  Probably not the best way to go about this.
                riverbeds = new Field2d <float>(new ConstantField <float>(SMALL_MAP_RESIZED_LEN, SMALL_MAP_RESIZED_LEN, float.MaxValue));
                foreach (var s in splines)
                {
                    var samples = s.GetSamplesPerControlPoint(1f * SMALL_MAP_RESIZED_LEN / SMALL_MAP_SIDE_LEN);

                    int priorX = int.MinValue;
                    int priorY = int.MinValue;

                    foreach (var p in samples)
                    {
                        int x = (int)((p[0] - rect.Left) * SMALL_MAP_RESIZED_LEN / SMALL_MAP_SIDE_LEN);
                        int y = (int)((p[1] - rect.Top) * SMALL_MAP_RESIZED_LEN / SMALL_MAP_SIDE_LEN);

                        if (x == priorX && y == priorY)
                        {
                            continue;
                        }
                        else
                        {
                            priorX = x;
                            priorY = y;
                        }

                        if (0 <= x && x < SMALL_MAP_RESIZED_LEN && 0 <= y && y < SMALL_MAP_RESIZED_LEN)
                        {
                            const int r = 1024 / SMALL_MAP_SIDE_LEN;

                            for (int j = -r; j <= r; j++)
                            {
                                for (int i = -r; i <= r; i++)
                                {
                                    int xx = x + i;
                                    int yy = y + j;

                                    if (0 <= xx && xx < SMALL_MAP_RESIZED_LEN && 0 <= yy && yy < SMALL_MAP_RESIZED_LEN)
                                    {
                                        float dSq = i * i + j * j;
                                        riverbeds[yy, xx] = Math.Min(riverbeds[yy, xx], p[2] + dSq / (512f * 32 / SMALL_MAP_SIDE_LEN));
                                        //scaledDamp[yy, xx] = 1f;
                                        //scaledUp[yy, xx] = Math.Min(scaledUp[yy, xx], p[2] + (float)Math.Sqrt(xx * xx + yy * yy) / 1f);
                                    }
                                }
                            }
                        }
                    }
                }
                //Utils.OutputField(riverbeds, new Bitmap(riverbeds.Width, riverbeds.Height), args.outputPath + "river_field.png");
            }

            var mountainous  = new ScaleTransform(new MountainNoise(1024, 1024, STARTING_SCALE), 1f);
            var hilly        = new ScaleTransform(new Simplex2D(1024, 1024, STARTING_SCALE * 4), 0.1f);
            var terrainNoise = new Transformation2d <float, float, float>(mountainous, hilly, (x, y, m, h) =>
            {
                float a  = scaledUp[y, x];
                float sh = Math.Max(-2f * Math.Abs(a - 0.2f) / 3f + 1f, 0f);
                float sm = Math.Min(1.3f * a, 1f);
                return(h * sh + m * sm);
            });

            IField2d <float> combined =
                new NormalizedComposition2d <float>(
                    new Transformation2d <float, float, float>(riverbeds,
                                                               new Composition2d <float>(scaledUp,
                                                                                         new Transformation2d <float, float, float>(scaledDamp, terrainNoise, (s, m) => (1 - Math.Min(1, s)) * m)
                                                                                         ),
                                                               (r, c) => r == float.MaxValue ? c : Math.Min(r, c))
                    );

            Bitmap img = new Bitmap(combined.Width, combined.Height);

            Utils.OutputField(combined, img, args.outputPath + "combined.png");

            Utils.OutputAsOBJ(combined, splines, rect, img, args.outputPath);
        }