public static Bitmap GenerateCompositeMap(HeightData data, Bitmap baseMap, float heightmapIntensity, float hillshadeIntensity) { Bitmap result; if (baseMap == null) { result = new Bitmap(data.GridWidth, data.GridHeight); var graphics = Graphics.FromImage(result); graphics.FillRectangle(new SolidBrush(Color.Gray), new Rectangle(0, 0, baseMap.Width, baseMap.Height)); } else { result = baseMap; } if (heightmapIntensity > 0) { Bitmap hm = new ImageGenerator(data.GetDataGrid(), data.cellSize, ImageType.Heightmap, data.lowPoint, data.highPoint).image; result = OverlayBlend(result, hm, heightmapIntensity); } if (hillshadeIntensity > 0) { Bitmap hs = new ImageGenerator(data.GetDataGrid(), data.cellSize, ImageType.Hillshade, data.lowPoint, data.highPoint).image; result = OverlayBlend(result, hs, hillshadeIntensity); } return(result); }
// preserves 0 level!!! public static void StretchHeightValues(ref HeightData data) { // find minimum and maximum values short max = short.MinValue; short min = short.MaxValue; for (int i = 0; i < data.Length; i++) { if (data[i] > max) { max = data[i]; } if (data[i] < min) { min = data[i]; } } // is the ocean deeper than land is high? if (max < -min) { max = (short)-min; } for (int i = 0; i < data.Length; i++) { data[i] = max > 0 ? (short)((int)data[i] * (int)short.MaxValue / (int)max) : (short)0; } }
public void TestMCAAccuracy() { var heights = HeightmapImporter.ImportHeightmapRaw(Path.Combine(inputPath, sampleHeightmapFile), 0, 0, 512, 512); HeightData data = new HeightData(512, 512, null) { lowPoint = 0, highPoint = 255 }; for (int i = 0; i < 512; i++) { for (int j = 0; j < 512; j++) { data.SetHeight(i, j, heights[i, j]); } } var sampleLocations = GetSampleLocations(data.GridWidth, data.GridHeight); var sourceSamples = GetHeightSamples(data, sampleLocations); string mcaname = "accuracy-test-r.0.0.mca"; AssertExport(data, "MCR-RAW", mcaname); var reimported = ImportManager.ImportFile(Path.Combine(outputPath, mcaname)); var convSamples = GetHeightSamples(reimported, sampleLocations); AssertExport(data, "IMG_PNG-HM", "reconstructed_mca.png"); Assert.AreEqual(sourceSamples, convSamples); }
public static void ScaleHeightValues(ref HeightData data, short newMin, short newMax) { // find minimum and maximum values int max = short.MinValue; int min = short.MaxValue; int newMaxWork = newMax - newMin; for (int i = 0; i < data.Length; i++) { if (data[i] > max) { max = data[i]; } if (data[i] < min) { min = data[i]; } } max -= min; for (int i = 0; i < data.Length; i++) { data[i] = (short)((short)newMin + (short)(((int)data[i] - min) * newMaxWork / max)); } }
protected override void ModifyData(HeightData data) { if (newWidth > 0) { data.Resize(newWidth, adjustHeight); } }
public bool IsValid(HeightData d) { if (xMin < 0 || xMin >= d.GridWidth) { return(false); } if (yMin < 0 || yMin >= d.GridHeight) { return(false); } if (xMax < 0 || xMax >= d.GridWidth) { return(false); } if (yMax < 0 || yMax >= d.GridHeight) { return(false); } if (xMin > xMax) { return(false); } if (yMin > yMax) { return(false); } return(true); }
public HeightData Modify(HeightData inputData, bool keepOriginal) { HeightData data = keepOriginal ? new HeightData(inputData) : inputData; ModifyData(data); return(data); }
public static System.Drawing.Bitmap HeightDataToBitmap(HeightData data) { // create a blank bitmap System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(data.Width, data.Height); // lock the bitmap color data for byte access System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height); System.Drawing.Imaging.BitmapData locked = bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.WriteOnly, bitmap.PixelFormat); // prepare memory space for the new color data byte[] bytes = new byte[locked.Stride * bitmap.Height]; // get a pointer to the to first line (=first pixel) IntPtr ptr = locked.Scan0; // fill in the bytes for (int i = 0; i < bytes.Length; i += 4) { // we won't be able to display the height data lower than 0 -> crop them byte current = (byte)(data[i / 4] > 0 ? (data[i / 4] / 128) : 0); bytes[i + 0] = current; bytes[i + 1] = current; bytes[i + 2] = current; bytes[i + 3] = 255; } // copy the data into the bitmap System.Runtime.InteropServices.Marshal.Copy(bytes, 0, ptr, locked.Stride * bitmap.Height); // unlock the bits bitmap.UnlockBits(locked); return(bitmap); }
public static HeightData ImportHeightmap(string filepath, HeightmapType type) { ushort[,] hms = RegionImporter.GetHeightmap(filepath, type); HeightData asc = new HeightData(512, 512, filepath); for (int x = 0; x < 512; x++) { for (int z = 0; z < 512; z++) { asc.SetHeight(x, z, hms[x, 511 - z]); } } asc.filename = Path.GetFileNameWithoutExtension(filepath); asc.cellSize = 1; asc.nodata_value = -9999; asc.RecalculateValues(false); asc.lowPoint = 0; asc.highPoint = 255; asc.isValid = true; ConsoleOutput.WriteLine("Lowest: " + asc.lowestValue); ConsoleOutput.WriteLine("Hightest: " + asc.highestValue); asc.lowestValue = 0; asc.highestValue = 255; return(asc); }
bool WriteFileImage(HeightData source, string filename, FileFormat ff) { float[,] grid = source.GetDataGrid(); IExporter exporter = new ImageGenerator(grid, source.cellSize, ff.GetImageType(), source.lowPoint, source.highPoint); ExportUtility.WriteFile(exporter, filename, ff); return(true); }
private void SaveDataHeight() { HeightData d = new HeightData(); d.blurHeight = blurHeight.vars; d.heightmap = heightmap.vars; WriteParams(d, assetName, "Height.xml"); }
void Start() { sa = StartActions.GetStartActions(); if (sa == null) { Debug.LogError("EdgeTrigger: Startaction is null!"); } highData = transform.GetComponent <HeightData>(); }
public void ExportData() { Config config = this.GetConfig(); Export export = new Export(); export.width.Maximum = this.heightData.Width; export.width.Value = this.heightData.Width; export.height.Maximum = this.heightData.Height; export.height.Value = this.heightData.Height; if (config.exportRescaleMode) { export.subzeroMode2.Checked = true; } if (export.ShowDialog() == System.Windows.Forms.DialogResult.OK) { if (this.FileDialog(this.exportHeightmapDialog, ref config.lastExportedFile)) { string path = this.exportHeightmapDialog.FileName; string ext = path.Substring(path.LastIndexOf('.'), path.Length - path.LastIndexOf('.')).ToLower(); //config.lastExportedFile = path; config.exportRescaleMode = export.subzeroMode2.Checked; HeightData toExport = Main.GetResizedHeightData(this.heightData, (int)export.width.Value, (int)export.height.Value); // rescale the values if necessary if (ext != ".shd" && export.subzeroMode2.Checked) { Main.ScaleHeightValues(ref toExport, 0, short.MaxValue - 1); } if (ext == ".shd") { System.IO.BinaryWriter writer = new System.IO.BinaryWriter(System.IO.File.Open(path, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write)); writer.Write(toExport.Width); writer.Write(toExport.Height); for (int i = 0; i < toExport.Length; i++) { writer.Write(toExport[i]); } writer.Close(); } else { Main.HeightDataToBitmap(toExport).Save(path); } toExport.Dispose(); } } }
void ExportFile(HeightData data, string outPath) { try { string dir = Path.GetDirectoryName(outPath); string fname = Path.GetFileNameWithoutExtension(outPath); if (Directory.Exists(dir)) { HeightDataSplitter splitter = new HeightDataSplitter(data, exportSettings.fileSplitDims); for (int z = 0; z < splitter.NumDataY; z++) { for (int x = 0; x < splitter.NumDataX; x++) { exportNumX = x; exportNumZ = z; foreach (FileFormat format in exportSettings.outputFormats) { ExportJob exportJob = new ExportJob(splitter.GetDataChunk(x, z), format, exportSettings, dir, fname); if (splitter.NumChunks > 1) { exportJob.nameBuilder.gridNum = (x, z); } format.exportHandler.EditFileName(exportJob, exportJob.nameBuilder); string fullpath = exportJob.nameBuilder.GetFullPath(); WriteLine($"Creating file {fullpath} ..."); try { var startTime = DateTime.Now; exportJob.Export(); var span = DateTime.Now - startTime; if (span.TotalSeconds > 5) { WriteLine($"Time: {span.TotalSeconds:F2}"); } WriteSuccess($"{format.Identifier} file created successfully!"); } catch (Exception e) { throw new IOException($"Failed to write {format.Identifier} file!", e); } } } } } else { throw new IOException($"Directory '{dir}' does not exist!"); } if (FileExported != null) { FileExported(CurrentFileIndex, outputPath); } } catch (Exception e) { if (FileExportFailed != null) { FileExportFailed(CurrentFileIndex, outputPath, e); } } }
public static bool ValidateExportSettings(ExportSettings settings, HeightData data, FileFormat ff) { bool valid = true; foreach (var ex in exportHandlers) { valid &= ex.AreExportSettingsValid(settings, ff, data); } return(valid); }
void AssertExport(HeightData data, string filetype, string path) { var format = ExportUtility.GetFormatFromIdenfifier(filetype); path = Path.ChangeExtension(Path.Combine(outputPath, path), format.Extension); var job = new ExportJob(data, format, new ExportSettings(), outputPath, path); job.Export(); Assert.IsTrue(File.Exists(path), "Written file not found"); }
public float QueryHeightData(float x, float y) { if (HeightData != null) { return(Conversions.GetRelativeHeightFromColor(HeightData.GetPixel( (int)Mathf.Clamp((x * 256), 0, 255), (int)Mathf.Clamp((y * 256), 0, 255)), RelativeScale)); } return(0); }
public ExportJob(HeightData heightData, FileFormat fileFormat, ExportSettings exportSettings, string targetDirectory, string filename) { data = heightData; settings = exportSettings; format = fileFormat; if (Path.GetExtension(filename).Equals("." + fileFormat.Extension, StringComparison.OrdinalIgnoreCase)) { filename = filename.Substring(0, filename.Length - 1 - fileFormat.Extension.Length); } nameBuilder = new FileNameBuilder(targetDirectory, filename, fileFormat); }
public void TestASCExport() { HeightData data = ASCImporter.Import(Path.Combine(inputPath, sampleASCFile)); var sampleLocations = GetSampleLocations(data.GridWidth, data.GridHeight); var sourceSamples = GetHeightSamples(data, sampleLocations); AssertExport(data, "ASC", sampleASCFile); data = ASCImporter.Import(Path.Combine(outputPath, sampleASCFile)); var exportedSamples = GetHeightSamples(data, sampleLocations); Assert.AreEqual(sourceSamples, exportedSamples); }
public void ClearData3D() { this.Output3dButtonsOff(); // terminate the model calculation worker thread if (this.modelThread != null) { this.modelThread.Abort(); this.HideBuildingModel(); } // release the height data if(this.heightData != null) this.heightData.Dispose(); if (this.textureBase != null) this.textureBase.Dispose(); this.heightData = null; this.textureBase = null; this.outputs3d.Items.Clear(); // remove "Maps:" entries from the texture list for (int i = 0; i < this.texture.Items.Count; i++) { char c = ((string)this.texture.Items[i])[0]; if (((string)this.texture.Items[i])[0] == 'M') { this.texture.Items.RemoveAt(i); // the indexes got shifted by deleting the current item i--; } } // free Video-RAM if (this.vertexBufferHandle != 0) { GL.DeleteBuffers(1, ref this.vertexBufferHandle); GL.DeleteBuffers(1, ref this.indexBufferHandle); } if (this.textureHandle != 0) { GL.DeleteTexture(this.textureHandle); } this.vertexBufferHandle = 0; this.textureHandle = 0; // let the viewport show empty screen this.viewport.Invalidate(); }
public void Execute(int i) { int x, z; Utils.IndexDeflattenizer2D(i, TotalBlockNumberX, out x, out z); Result[i] = new HeightData() { Bedrock = GenerateBedrockHeight(x, z), Stone = GenerateStoneHeight(x, z), Dirt = GenerateDirtHeight(x, z) }; }
protected override void ModifyData(HeightData data) { if (newLow == 0 && newHigh == 0) { data.RecalculateValues(true); } else { data.lowPoint = newLow; data.highPoint = newHigh; data.RecalculateValues(false); } }
public HeightData ApplyModificationChain(HeightData inputData) { HeightData data = new HeightData(inputData) { wasModified = true }; for (int i = 0; i < exportSettings.modificationChain.Count; i++) { data = exportSettings.modificationChain[i].Modify(data, true); } return(data); }
protected override void ModifyData(HeightData data) { for (int y = 0; y < data.GridHeight; y++) { for (int x = 0; x < data.GridWidth; x++) { var value = data.GetHeight(x, y); value = (value - scalePivot) * scaleMultiplier + scalePivot; data.SetHeight(x, y, value); } } data.RecalculateValues(true); }
/// <summary> /// Initializes a new instance of the <see cref="RichCell"/> class. /// </summary> /// <param name="parent">The cell matrix that owns this cell.</param> /// <param name="position">The position.</param> /// <param name="matrixPosX">The matrix position x.</param> /// <param name="matrixPosZ">The matrix position z.</param> /// <param name="blocked">if set to <c>true</c> the cell will appear permanently blocked.</param> public RichCell(CellMatrix parent, Vector3 position, int matrixPosX, int matrixPosZ, bool blocked) : base(parent, position, matrixPosX, matrixPosZ, blocked) { //While a bit redundant (e.g. index 4 being self) it makes it faster to index _heightData = new HeightData[9]; for (int i = 0; i < 9; i++) { //We use this to indicate an uninitialized state _heightData[i].slope = 100f; } //Worst case scenario for checking all directions _worstCase = new HeightData(); }
public RichCell(CellMatrix parent, Vector3 position, int matrixPosX, int matrixPosZ, bool blocked) : base(parent, position, matrixPosX, matrixPosZ, blocked) { //While a bit redundant (e.g. index 4 being self) it makes it faster to index _heightData = new HeightData[9]; for (int i = 0; i < 9; i++) { //We use this to indicate an uninitialized state _heightData[i].slope = 100f; } //Worst case scenario for checking all directions _worstCase = new HeightData(); }
private void LoadDataHeight() { if (File.Exists(GetSavePath(assetName) + "Height.xml")) { HeightData d = ReadParams <HeightData>(assetName, "Height.xml"); blurHeight.SetPara(d.blurHeight); heightmap.SetPara(d.heightmap); } else { blurHeight.ResetPara(); heightmap.ResetPara(); } }
public HeightDataSplitter(HeightData data, int splitIntervalX, int splitIntervalY) { intervalX = splitIntervalX; intervalY = splitIntervalY; if (intervalX < 2) { intervalX = int.MaxValue; } if (intervalY < 2) { intervalY = int.MaxValue; } sourceData = data; }
static HeightData CreateBaseData(FileStream stream, string filename, out int ncols, out int nrows) { ncols = ExtractInt(ReadHeaderLine(stream), "ncols"); nrows = ExtractInt(ReadHeaderLine(stream), "nrows"); WriteLine("Dimensions: " + ncols + "x" + nrows); HeightData d = new HeightData(ncols, nrows, filename); var xllcorner = ExtractFloat(ReadHeaderLine(stream), "xllcorner"); var yllcorner = ExtractFloat(ReadHeaderLine(stream), "yllcorner"); d.lowerCornerPos = new Vector2(xllcorner, yllcorner); d.cellSize = ExtractFloat(ReadHeaderLine(stream), "cellsize"); d.nodata_value = ExtractFloat(ReadHeaderLine(stream), "NODATA_value"); return(d); }
public void TestMCAFileHandling() { HeightData data = ImportManager.ImportFile(Path.Combine(inputPath, sampleMCAFile)); data.lowPoint = 0; data.highPoint = 255; //var sampleLocations = GetSampleLocations(data.GridWidth, data.GridHeight); //var sourceSamples = GetHeightSamples(data, sampleLocations); currentJob.exportSettings.SetCustomSetting("mcaOffsetX", 16); currentJob.exportSettings.SetCustomSetting("mcaOffsetZ", 26); AssertExport(data, "MCR", sampleMCAFile); AssertExport(data, "IMG_PNG-HS", sampleMCAFile); AssertExport(data, "IMG_PNG-HM", sampleMCAFile); }
static BlockTypes DetermineType(int worldX, int worldY, int worldZ, HeightData height) { if (worldY == 0) { return(BlockTypes.Bedrock); } // check if this suppose to be a cave if (FractalFunc(worldX, worldY, worldZ, CaveSmooth, CaveOctaves) < CaveProbability) { return(BlockTypes.Air); } // bedrock if (worldY <= height.Bedrock) { return(BlockTypes.Bedrock); } // stone if (worldY <= height.Stone) { if (FractalFunc(worldX, worldY, worldZ, DiamondSmooth, DiamondOctaves) < DiamondProbability && worldY < DiamondMaxHeight) { return(BlockTypes.Diamond); } if (FractalFunc(worldX, worldY, worldZ, RedstoneSmooth, RedstoneOctaves) < RedstoneProbability && worldY < RedstoneMaxHeight) { return(BlockTypes.Redstone); } return(BlockTypes.Stone); } // dirt if (worldY == height.Dirt) { return(BlockTypes.Grass); } if (worldY < height.Dirt) { return(BlockTypes.Dirt); } return(BlockTypes.Air); }
public static HeightData LoadHeightmapFromImageFile(string path){ Config config = Main.Get().GetConfig(); HeightData heights; string ext = path.Substring(path.LastIndexOf('.'), path.Length - path.LastIndexOf('.')).ToLower(); if (ext == ".shd") { // byte-by-byte binary reading System.IO.BinaryReader reader = new System.IO.BinaryReader(System.IO.File.Open(path, System.IO.FileMode.Open, System.IO.FileAccess.Read)); // read first eight bytes with map dimensions int width = reader.ReadInt32(); int height = reader.ReadInt32(); heights = new HeightData((UInt16) width,(UInt16) height); // read the double bytes containing the height data for (int i = 0; i < width * height; i++) { heights[i] = reader.ReadInt16(); } reader.Close(); reader.Dispose(); } else { // read the bitmap file System.Drawing.Bitmap bitmap; try { bitmap = new System.Drawing.Bitmap(path); } catch(ArgumentException){ return null; } System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height); System.Drawing.Imaging.BitmapData data = bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bitmap.PixelFormat); heights = new HeightData((UInt16) bitmap.Width, (UInt16)bitmap.Height); // prepare memory space for the color data byte[] bytes = new byte[data.Stride * bitmap.Height]; int pixelSize = data.Stride / data.Width; // get a pointer to the to first line (=first pixel) IntPtr ptr = data.Scan0; // create a byte copy of the heightmap data System.Runtime.InteropServices.Marshal.Copy(ptr, bytes, 0, data.Stride * bitmap.Height); // create the color data for (int i = 0; i < bytes.Length; i += pixelSize) { heights[i / pixelSize] = (short)((short)bytes[i] * 128); } bitmap.UnlockBits(data); bitmap.Dispose(); } HeightData heights2 = Main.GetResizedHeightData(heights, Math.Min(heights.Width, (int)config.mapDetailLevel), Math.Min(heights.Height, (int)config.mapDetailLevel)); return heights2; }
internal void SetHeightData(int idx, HeightData data) { _heightData[idx] = data; }
public void ShowImage() { Config config = this.GetConfig(); try { this.AddStatus("Loading"); int oldImageWidth = 0; int oldImageHeight = 0; // save original output image dimensions, so we can deetect their change if (this.output.Image != null) { oldImageWidth = this.output.Image.Width; oldImageHeight = this.output.Image.Height; } // if the image being loaded doesn't exist, cancel try { // load imported or internal if (this.currentImportedFile != null) { this.data = Main.LoadHeightmapFromImageFile(this.currentImportedFile); if (this.data == null) throw new Exception(); } else { this.data = (HeightData)this.maps[this.outputs.SelectedItem]; } currentImage = HeightDataToBitmap(this.data); } catch (Exception e) { this.RemoveStatus("Loading"); return; } // apply overlay pattern? if (this.overlays.SelectedIndex > 0) { string overlayPath = config.OverlayDirectory + "/" + (string)this.overlays.Items[this.overlays.SelectedIndex]; System.Drawing.Bitmap overlay = new System.Drawing.Bitmap(overlayPath); this.currentImageWithOverlay = this.ApplyOverlay(this.data, overlay); overlay.Dispose(); } // decide which image (gray or overlay) to display if (this.overlays.SelectedIndex > 0 && this.toggleOverlay.Checked) { this.output.Image = this.currentImageWithOverlay; } else { this.output.Image = this.currentImage; } // detect size change (reset the view if size changed to prevent the image shrinking avay from the screen) if (oldImageWidth > this.output.Image.Width || oldImageHeight > this.output.Image.Width || oldImageHeight == 0) { this.output.Width = this.output.Image.Width; this.output.Height = this.output.Image.Height; } } catch (OutOfMemoryException) { this.OutOfMemory(); } this.RemoveStatus("Loading"); }
public static System.Drawing.Bitmap HeightDataToBitmap(HeightData data){ // create a blank bitmap System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(data.Width, data.Height); // lock the bitmap color data for byte access System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height); System.Drawing.Imaging.BitmapData locked = bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.WriteOnly, bitmap.PixelFormat); // prepare memory space for the new color data byte[] bytes = new byte[locked.Stride * bitmap.Height]; // get a pointer to the to first line (=first pixel) IntPtr ptr = locked.Scan0; // fill in the bytes for (int i = 0; i < bytes.Length; i += 4) { // we won't be able to display the height data lower than 0 -> crop them byte current = (byte)(data[i / 4] > 0 ? (data[i / 4] / 128) : 0); bytes[i + 0] = current; bytes[i + 1] = current; bytes[i + 2] = current; bytes[i + 3] = 255; } // copy the data into the bitmap System.Runtime.InteropServices.Marshal.Copy(bytes, 0, ptr, locked.Stride * bitmap.Height); // unlock the bits bitmap.UnlockBits(locked); return bitmap; }
internal void SetHeightData(int dx, int dz, HeightData data) { var idx = (dx + (3 * dz) + 4); _heightData[idx] = data; }
// preserves 0 level!!! public static void StretchHeightValues(ref HeightData data){ // find minimum and maximum values short max = short.MinValue; short min = short.MaxValue; for(int i = 0; i < data.Length; i++){ if(data[i] > max) max = data[i]; if(data[i] < min) min = data[i]; } // is the ocean deeper than land is high? if(max < -min) max = (short) -min; for (int i = 0; i < data.Length; i++){ data[i] = max > 0 ? (short)((int)data[i] * (int)short.MaxValue / (int)max) : (short)0; } }
public static void ScaleHeightValues(ref HeightData data, short newMin, short newMax) { // find minimum and maximum values int max = short.MinValue; int min = short.MaxValue; int newMaxWork = newMax - newMin; for (int i = 0; i < data.Length; i++) { if (data[i] > max) max = data[i]; if (data[i] < min) min = data[i]; } max -= min; for (int i = 0; i < data.Length; i++) { data[i] = (short)((short)newMin + (short)(((int)data[i] - min) * newMaxWork / max)); } }
public static HeightData GetResizedHeightData(HeightData data, int width, int height) { HeightData resized = new HeightData((UInt16)width, (UInt16)height); // use nearest neighbor scaling algorithm for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { resized[x, y] = data[x * data.Width / width, y * data.Height / height]; } } return resized; }
public System.Drawing.Bitmap ApplyOverlay(HeightData heights, System.Drawing.Bitmap overlayBitmap) { // prepare byte access to the overlay bitmap System.Drawing.Rectangle OverlayRect = new System.Drawing.Rectangle(0, 0, overlayBitmap.Width, overlayBitmap.Height); System.Drawing.Imaging.BitmapData overlayData = overlayBitmap.LockBits(OverlayRect, System.Drawing.Imaging.ImageLockMode.ReadOnly, overlayBitmap.PixelFormat); // create a blank bitmap and prepare it for byte access System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(heights.Width, heights.Height, overlayData.PixelFormat); System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height); System.Drawing.Imaging.BitmapData data = bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, overlayBitmap.PixelFormat); // prepare memory space for the newly created color data byte[] bytes = new byte[data.Stride * bitmap.Height]; byte[] overlayCopy = new byte[overlayData.Stride * overlayBitmap.Height]; int pixelSize = overlayData.Stride / overlayBitmap.Width; // get a pointer to the to first line (=first pixel) IntPtr ptr = data.Scan0; IntPtr overlayPtr = overlayData.Scan0; // create a byte copy of the heightmap data System.Runtime.InteropServices.Marshal.Copy(overlayPtr, overlayCopy, 0, overlayData.Stride * overlayBitmap.Height); // create the color data // standard format overlay (positive values only) if (overlayBitmap.Width == 256) { for (int y = 0; y < heights.Height; y++) { for (int x = 0; x < heights.Width; x++) { int index = y * data.Stride + x * pixelSize; int current = (heights[x + y * heights.Width] / 128); if (current < 0) current = 0; // prevent water bleeding onto the coastline if (heights[x + y * heights.Width] > 0 && current == 0) current = 1; for (int channelIndex = 0; channelIndex < pixelSize; channelIndex++) { bytes[index + channelIndex] = overlayCopy[current * pixelSize + channelIndex]; } } } } // extended overlay (positive AND negative values) else { for (int y = 0; y < heights.Height; y++) { for(int x = 0; x < heights.Width; x++) { int index = y * data.Stride + x * pixelSize; int current = 255 + (heights[x + y * heights.Width] / 128); if (current < 0 || current > 511) { throw new Exception("This cannot happen"); } // prevent water bleeding onto the coastline if (current == 255 && heights[x + y * heights.Width] > 0) current = 256; for (int channelIndex = 0; channelIndex < pixelSize; channelIndex++) { bytes[index + channelIndex] = overlayCopy[current * pixelSize + channelIndex]; } } } } // copy the data into the bitmap System.Runtime.InteropServices.Marshal.Copy(bytes, 0, ptr, data.Stride * bitmap.Height); // unlock the bits bitmap.UnlockBits(data); return bitmap; }
public void SetTerrain(HeightData original){ Config config = this.GetConfig(); try { // store original's size int originalHeight = original.Height; int originalWidth = original.Width; // load the overlay pattern //System.Drawing.Bitmap overlayBitmap = new System.Drawing.Bitmap("../overlays/Topographic.bmp"); // prepare memory space for the newly created color data this.heightData = Main.GetResizedHeightData(original, Math.Min(original.Width, (int)config.ModelDetailLevel), Math.Min(original.Height, (int)config.ModelDetailLevel)); this.textureBase = Main.GetResizedHeightData(original, Math.Min(original.Width, (int)config.TextureDetailLevel), Math.Min(original.Height, (int)config.TextureDetailLevel)); // release some memory (to prevent OutOfMemory exception) // original = null; // dimension multipliers float fWidth = 100f / (float)this.heightData.Width; float fHeight = 100f / (float)this.heightData.Height; float texFWidth = fWidth; float texFHeight = fHeight; float offsetX = 0; float offsetY = 0; // adjust the multipliers for non-square bitmaps if (originalHeight > originalWidth) { offsetY = (float)((float)(this.heightData.Height - this.heightData.Width) * 100f / (float)this.heightData.Height) / 2f; fWidth *= (float)originalWidth / (float)originalHeight; } else if (originalHeight < originalWidth) { offsetY = (float)((float)(this.heightData.Width - this.heightData.Height) * 100f / (float)this.heightData.Width) / 2f; fHeight *= (float)originalHeight / (float)originalWidth; } // the vertex array for the model Vertex[] vertices = new Vertex[this.heightData.Length ]; // fill in vertex data (only position and texcoords for now) for (int y = 0; y < this.heightData.Height; y++) { float fy = (float)y; // precalculate some stuff that stays constant for whole row float yPos = offsetY + (fy + 0.5f) * fHeight; float texYPos = (fy + 0.5f) * texFHeight; for (int x = 0; x < this.heightData.Width; x++) { float fx = (float)x; int vertexIndex = x + y * this.heightData.Width; vertices[vertexIndex].Position.X = offsetX + fx * fWidth; vertices[vertexIndex].Position.Y = yPos; vertices[vertexIndex].Position.Z = (float)((float)this.heightData[x, y] * 0.005f / 128f); if (!this.config.enableTerrainUnderZero && vertices[vertexIndex].Position.Z < 0) vertices[vertexIndex].Position.Z = 0; vertices[vertexIndex].TexCoord.X = (fx + 0.5f) * texFWidth / 100f; vertices[vertexIndex].TexCoord.Y = texYPos / 100f; } } uint[] indices = new uint[this.heightData.Length * 6]; // build index array for (int y = 0; y < this.heightData.Height - 1; y++) { for (int x = 0; x < this.heightData.Width - 1; x++) { float fx = (float)x; int vertexIndex = (x + y * this.heightData.Width) * 6; // first triangle indices[vertexIndex] = (uint)(x + y * this.heightData.Width); indices[vertexIndex + 1] = (uint)(x + 1 + y * this.heightData.Width); indices[vertexIndex + 2] = (uint)(x + (y + 1) * this.heightData.Width); // second triangle indices[vertexIndex + 3] = (uint)(x + 1 + (y + 1) * this.heightData.Width); indices[vertexIndex + 4] = (uint)(x + (y + 1) * this.heightData.Width); indices[vertexIndex + 5] = (uint)(x + 1 + y * this.heightData.Width); } } // build face normals Vector3[] faceNormals = new Vector3[(this.heightData.Width - 1) * (this.heightData.Height - 1) * 2]; for (int y = 0; y < this.heightData.Height - 1; y++) { for (int x = 0; x < this.heightData.Width - 1; x++) { faceNormals[(x + y * (this.heightData.Width - 1)) * 2] = this.CalculateNormal(vertices[x + (y + 1) * this.heightData.Width].Position, vertices[x + y * this.heightData.Width].Position, vertices[(x + 1) + y * this.heightData.Width].Position); faceNormals[(x + y * (this.heightData.Width - 1)) * 2 + 1] = this.CalculateNormal(vertices[x + (y + 1) * this.heightData.Width].Position, vertices[x + y * this.heightData.Width].Position, vertices[(x + 1) + (y + 1) * this.heightData.Width].Position); } } // build vertex normals for (int y = 0; y < this.heightData.Height; y++) { for (int x = 0; x < this.heightData.Width; x++) { int faceCount = 0; // upper left triangle if (x > 0 && y > 0) { vertices[x + y * this.heightData.Width].Normal = faceNormals[((x - 1) + (y - 1) * (this.heightData.Width - 1)) * 2 + 1] ; faceCount++; } // bottom left triangles if (x > 0 && y < this.heightData.Height - 1) { vertices[x + y * this.heightData.Width].Normal += faceNormals[((x - 1) + y * (this.heightData.Width - 1)) * 2]; vertices[x + y * this.heightData.Width].Normal += faceNormals[((x - 1) + y * (this.heightData.Width - 1)) * 2 + 1]; faceCount += 2; } // upper right triangles if (x < this.heightData.Width - 1 && y > 0) { vertices[x + y * this.heightData.Width].Normal += faceNormals[(x + (y - 1) * (this.heightData.Width - 1)) * 2]; vertices[x + y * this.heightData.Width].Normal += faceNormals[(x + (y - 1) * (this.heightData.Width - 1)) * 2 + 1]; faceCount += 2; } if (x < this.heightData.Width - 1 && y < this.heightData.Height - 1) { vertices[x + y * this.heightData.Width].Normal += faceNormals[(x + y * (this.heightData.Width - 1)) * 2]; faceCount++; } vertices[x + y * this.heightData.Width].Normal /= faceCount; } } // release the context from the GUI thread this.Invoke(new System.Windows.Forms.MethodInvoker(delegate() { viewport.Context.MakeCurrent(null); })); // grab the context for this thread viewport.MakeCurrent(); // delete the previous buffer content if (this.vertexBufferHandle != 0) { GL.DeleteBuffers(1, ref this.vertexBufferHandle); } // allocate the buffer GL.GenBuffers(1, out this.vertexBufferHandle); GL.GenBuffers(1, out this.indexBufferHandle); // tell that we are using that buffer GL.BindBuffer(BufferTarget.ArrayBuffer, this.vertexBufferHandle); GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertices.Length * 8 * sizeof(float)), vertices, BufferUsageHint.StaticDraw); GL.BindBuffer(BufferTarget.ElementArrayBuffer, this.indexBufferHandle); // upload the data into the buffer into GPU GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(indices.Length * sizeof(uint)), indices, BufferUsageHint.StaticDraw); // make sure the massive vertex array is gone from RAM vertices = null; indices = null; // release the context from current thread viewport.Context.MakeCurrent(null); try { this.Invoke(new System.Windows.Forms.MethodInvoker(delegate() { try { // regrab the context for the GUI thread viewport.MakeCurrent(); // rebuild the texture this.ApplyTexture(); // UI stuff this.Output3dButtonsOn(); this.viewport.Invalidate(); this.HideBuildingModel(); } catch (Exception e) { } })); } // this might throw exceptions in case the main thread was terminated while this thread is running catch (Exception e) { }; } catch (OutOfMemoryException) { try{ this.Invoke(new System.Windows.Forms.MethodInvoker(delegate() { this.HideBuildingModel(); this.OutOfMemory(); })); } catch{ return; }; } }