/// <summary> /// Creates a Terr heightmap from a Bitmap /// </summary> /// <param name="oldTerr">Source terr</param> /// <param name="heightmap">Heightmap Bitmap</param> /// <param name="targetHmaps">Flags to determine which Heightmaps shall be changed</param> /// <returns></returns> public static Terr FromBitmap(this Terr oldTerr, Bitmap heightmap, TargetHeightmaps targetHmaps) { if (heightmap.Width != oldTerr.Width || heightmap.Height != oldTerr.Height) { throw new ArgumentException( "Heightmap measures wrong. Expected: " + oldTerr.Width + "x" + oldTerr.Height + " (Image: " + heightmap.Width + "x" + heightmap.Height + ")"); } if ((targetHmaps & (TargetHeightmaps.FirstHeightmap | TargetHeightmaps.SecondHeightmap)) == TargetHeightmaps.None) { throw new ArgumentException("No valid TargetHeightmap specified"); } oldTerr = oldTerr.Decompress(); bool keepFirstHmap = (targetHmaps & TargetHeightmaps.FirstHeightmap) == TargetHeightmaps.None; bool keepSecondHmap = (targetHmaps & TargetHeightmaps.SecondHeightmap) == TargetHeightmaps.None; Terr newTerr = new Terr(); newTerr.Width = oldTerr.Width; newTerr.Height = oldTerr.Height; if (keepFirstHmap) { oldTerr.CopyFirstHmap(newTerr); } // This scary loop iterates row by row over all 8x8 blocks for (int h = 0; h < heightmap.Height; h += 8) { for (int w = 0; w < heightmap.Width; w += 8) { // Single 8x8 Block Terrblock block = new Terrblock(); if (!keepFirstHmap) { newTerr.BlocksHmap1.Add(block); } if (!keepSecondHmap) { newTerr.BlocksHmap2.Add(block); } int minHeight = int.MaxValue; byte[] newOffsets = new byte[64]; for (int y = 0; y < 8; ++y) { if (h + y >= heightmap.Height) { // Image height not multiple of 8 break; } for (int x = 0; x < 8; ++x) { if (w + x >= heightmap.Width) { // Image width not multiple of 8 break; } int height = heightmap.GetPixel(w + x, h + y).R; minHeight = Math.Min(minHeight, height); newOffsets[x + y * 8] = (byte)height; } } // Adjust offsets based on minimum for (int i = 0; i < 64; ++i) { newOffsets[i] -= (byte)(minHeight); } // Scale to 65535 (65535 / 255 = 257) minHeight *= 257; newTerr.Offsets.Add(newOffsets); block.Minimum = minHeight; block.OffsetIndex = newTerr.Offsets.Count - 1; } } if (keepSecondHmap) { oldTerr.CopySecondHmap(newTerr); } return newTerr; }
public static Bitmap ToBitmap(this Terr oldTerr, TargetHeightmaps targetHmaps, SmoothingAlgorithm salg) { bool firstHeightmap = (targetHmaps & TargetHeightmaps.FirstHeightmap) == TargetHeightmaps.FirstHeightmap; bool secondHeightmap = (targetHmaps & TargetHeightmaps.SecondHeightmap) == TargetHeightmaps.SecondHeightmap; if (firstHeightmap && secondHeightmap) { throw new ArgumentException("Both TargetHeightmaps specified"); } else if (!firstHeightmap && !secondHeightmap) { throw new ArgumentException("No valid TargetHeightmaps specified"); } IList<Terrblock> blocks; if (firstHeightmap) { blocks = oldTerr.BlocksHmap1; } else { blocks = oldTerr.BlocksHmap2; } Bitmap heightmap = new Bitmap(oldTerr.Width, oldTerr.Height); // This scary loop iterates row by row over all 8x8 blocks int row = 0; int col = 0; for (int i = 0; i < blocks.Count; ++i) { Terrblock block = blocks[i]; byte[] offsets = oldTerr.Offsets[block.OffsetIndex]; ++col; if (col * 8 >= heightmap.Width) { col = 0; row++; } // Single 8x8 Block for (int y = 0; y < 8; ++y) { int targetY = row * 8 + y; if (targetY >= heightmap.Height) { break; } for (int x = 0; x < 8; ++x) { int targetX = col * 8 + x; if (targetX >= heightmap.Width) { break; } Color color; if (salg == SmoothingAlgorithm.Default) { // Downscale from 65535 Minimum to 255 color space int c = offsets[x + y * 8] + block.Minimum / 257; color = Color.FromArgb(c, c, c); } else if (salg == SmoothingAlgorithm.Rob) { // Robs heightmap smoothing code int c = 20 + ((offsets[x + y * 8] * 128 + block.Minimum) / 1024) * 2; color = Color.FromArgb(c, c, c); } else { throw new ArgumentException("Unsupported Smoothing Algorithm"); } heightmap.SetPixel(targetX, targetY, color); } } } return heightmap; }