From ff1a6c64ddf7a87eec5ad125a127122b9896f1d0 Mon Sep 17 00:00:00 2001 From: Nicolas Perrier Date: Mon, 19 Sep 2022 15:01:30 +0200 Subject: [PATCH] Feature/magick.net (#69) * Started to implement MagickImage and removed all FileToVoxCommon namespace * Heightmap is now working with 16-bit per channel * Fixed the average which depend on the number of channel per pixel * Create static method Quantize to centralize all vertifications * Removed JsonPresets folder * Removed SimpleSingleton * Removed dependency to the old Quantizer which depends on Bitmap (not compatible on Mac). WIP quantizer, not really best results * Removed folder Quantizer * Fixed parsing pixel color in MultipleImageToSchematic * Clean code * Removed dependency to System.Drawing also in PaletteSchematicConverter --- .editorconfig | 1 + FileToVox.sln | 21 +- FileToVoxCommon/FileToVoxCommon.csproj | 15 - FileToVoxCommon/FileToVoxCommon.csproj.user | 6 - .../Generator/Heightmap/Data/HeightmapData.cs | 123 ----- .../Generator/Shaders/Data/ShaderCase.cs | 34 -- .../Shaders/Data/ShaderColorDenoiser.cs | 48 -- .../Generator/Shaders/Data/ShaderData.cs | 57 --- .../Generator/Shaders/Data/ShaderFill.cs | 53 -- .../Generator/Shaders/Data/ShaderFixHoles.cs | 30 -- .../Generator/Shaders/Data/ShaderFixLonely.cs | 11 - .../Generator/Shaders/Data/ShaderPatina.cs | 96 ---- .../Shaders/Json/ShaderStepDataConverter.cs | 57 --- .../Generator/StepData/StepData.cs | 6 - FileToVoxCommon/Json/JsonBaseImportData.cs | 19 - .../Json/JsonBaseImportDataConverter.cs | 56 -- .../PublishProfiles/MainBuildCommon.pubxml | 12 - .../MainBuildCommon.pubxml.user | 6 - .../Converter/Image/DirectBitmap.cs | 108 ---- .../Converter/Image/ImageToSchematic.cs | 58 ++- .../Image/MultipleImageToSchematic.cs | 46 +- .../Converter/Image/PNGToSchematic.cs | 62 --- .../Converter/Image/TIFtoSchematic.cs | 104 ---- .../Converter/Json/JsonToSchematic.cs | 71 --- .../PaletteSchematicConverter.cs | 8 +- .../PointCloud/PointCloudToSchematic.cs | 1 + .../Extensions/FctExtensions.cs | 78 +-- SchematicToVoxCore/Extensions/Grayscale.cs | 43 -- SchematicToVoxCore/Extensions/Quantization.cs | 136 ++--- SchematicToVoxCore/FileToVox.csproj | 47 +- .../Generator/Heightmap/HeightmapGenerator.cs | 52 -- SchematicToVoxCore/Generator/IGenerator.cs | 9 - .../Shaders/ApplyShaders/ApplyShaderCase.cs | 67 --- .../ApplyShaders/ApplyShaderColorDenoiser.cs | 196 ------- .../Shaders/ApplyShaders/ApplyShaderFill.cs | 173 ------- .../ApplyShaders/ApplyShaderFillHoles.cs | 303 ----------- .../Shaders/ApplyShaders/ApplyShaderLonely.cs | 47 -- .../Shaders/ApplyShaders/ApplyShaderPatina.cs | 306 ----------- .../Generator/Shaders/IShaderGenerator.cs | 10 - .../Generator/Shaders/ShaderGenerator.cs | 40 -- .../Generator/Shaders/ShaderUtils.cs | 48 -- .../Generator/Terrain/Chunk/VoxelChunk.cs | 127 ----- .../Generator/Terrain/Data/BiomeSettings.cs | 76 --- .../Generator/Terrain/Data/ModelSettings.cs | 27 - .../Data/TerrainGeneratorDataSettings.cs | 77 --- .../Terrain/Data/WorldTerrainData.cs | 21 - .../Generator/Terrain/Entities/CachedChunk.cs | 9 - .../Generator/Terrain/Environment/Chunk.cs | 88 ---- .../Terrain/Environment/ChunksManager.cs | 261 ---------- .../Generator/Terrain/Environment/Trees.cs | 198 -------- .../Terrain/Environment/Vegetation.cs | 103 ---- .../Generator/Terrain/TerrainEnvironment.cs | 160 ------ .../Generator/Terrain/TerrainGenerator.cs | 41 -- .../Terrain/TerrainGeneratorSettings.cs | 385 -------------- .../Generator/Terrain/Utility/FastHashSet.cs | 297 ----------- .../Terrain/Utility/HeightMapCache.cs | 96 ---- .../Generator/Terrain/Utility/NoiseTools.cs | 77 --- .../Generator/Terrain/Utility/WorldRandom.cs | 106 ---- .../JsonPresets/heightmapGenerator.json | 18 - .../JsonPresets/noise/NoiseBase.png | Bin 17204 -> 0 bytes .../JsonPresets/noise/NoiseDetail.png | Bin 182772 -> 0 bytes .../JsonPresets/noise/NoiseMoisture.png | Bin 103546 -> 0 bytes .../JsonPresets/shaderGenerator.json | 37 -- .../JsonPresets/terrainGenerator.json | 202 -------- SchematicToVoxCore/Main/SimpleSingleton.cs | 27 - SchematicToVoxCore/Merger/SchematicMerger.cs | 192 ------- SchematicToVoxCore/Program.cs | 28 +- SchematicToVoxCore/Quantizer/CubeCut.cs | 18 - SchematicToVoxCore/Quantizer/IQuantizer.cs | 9 - .../Quantizer/QuantizedPalette.cs | 20 - SchematicToVoxCore/Quantizer/Quantizer.cs | 92 ---- SchematicToVoxCore/Quantizer/QuantizerBase.cs | 478 ------------------ SchematicToVoxCore/Utils/ImageUtils.cs | 251 ++++----- 73 files changed, 324 insertions(+), 5861 deletions(-) create mode 100644 .editorconfig delete mode 100644 FileToVoxCommon/FileToVoxCommon.csproj delete mode 100644 FileToVoxCommon/FileToVoxCommon.csproj.user delete mode 100644 FileToVoxCommon/Generator/Heightmap/Data/HeightmapData.cs delete mode 100644 FileToVoxCommon/Generator/Shaders/Data/ShaderCase.cs delete mode 100644 FileToVoxCommon/Generator/Shaders/Data/ShaderColorDenoiser.cs delete mode 100644 FileToVoxCommon/Generator/Shaders/Data/ShaderData.cs delete mode 100644 FileToVoxCommon/Generator/Shaders/Data/ShaderFill.cs delete mode 100644 FileToVoxCommon/Generator/Shaders/Data/ShaderFixHoles.cs delete mode 100644 FileToVoxCommon/Generator/Shaders/Data/ShaderFixLonely.cs delete mode 100644 FileToVoxCommon/Generator/Shaders/Data/ShaderPatina.cs delete mode 100644 FileToVoxCommon/Generator/Shaders/Json/ShaderStepDataConverter.cs delete mode 100644 FileToVoxCommon/Generator/StepData/StepData.cs delete mode 100644 FileToVoxCommon/Json/JsonBaseImportData.cs delete mode 100644 FileToVoxCommon/Json/JsonBaseImportDataConverter.cs delete mode 100644 FileToVoxCommon/Properties/PublishProfiles/MainBuildCommon.pubxml delete mode 100644 FileToVoxCommon/Properties/PublishProfiles/MainBuildCommon.pubxml.user delete mode 100644 SchematicToVoxCore/Converter/Image/DirectBitmap.cs delete mode 100644 SchematicToVoxCore/Converter/Image/PNGToSchematic.cs delete mode 100644 SchematicToVoxCore/Converter/Image/TIFtoSchematic.cs delete mode 100644 SchematicToVoxCore/Converter/Json/JsonToSchematic.cs delete mode 100644 SchematicToVoxCore/Extensions/Grayscale.cs delete mode 100644 SchematicToVoxCore/Generator/Heightmap/HeightmapGenerator.cs delete mode 100644 SchematicToVoxCore/Generator/IGenerator.cs delete mode 100644 SchematicToVoxCore/Generator/Shaders/ApplyShaders/ApplyShaderCase.cs delete mode 100644 SchematicToVoxCore/Generator/Shaders/ApplyShaders/ApplyShaderColorDenoiser.cs delete mode 100644 SchematicToVoxCore/Generator/Shaders/ApplyShaders/ApplyShaderFill.cs delete mode 100644 SchematicToVoxCore/Generator/Shaders/ApplyShaders/ApplyShaderFillHoles.cs delete mode 100644 SchematicToVoxCore/Generator/Shaders/ApplyShaders/ApplyShaderLonely.cs delete mode 100644 SchematicToVoxCore/Generator/Shaders/ApplyShaders/ApplyShaderPatina.cs delete mode 100644 SchematicToVoxCore/Generator/Shaders/IShaderGenerator.cs delete mode 100644 SchematicToVoxCore/Generator/Shaders/ShaderGenerator.cs delete mode 100644 SchematicToVoxCore/Generator/Shaders/ShaderUtils.cs delete mode 100644 SchematicToVoxCore/Generator/Terrain/Chunk/VoxelChunk.cs delete mode 100644 SchematicToVoxCore/Generator/Terrain/Data/BiomeSettings.cs delete mode 100644 SchematicToVoxCore/Generator/Terrain/Data/ModelSettings.cs delete mode 100644 SchematicToVoxCore/Generator/Terrain/Data/TerrainGeneratorDataSettings.cs delete mode 100644 SchematicToVoxCore/Generator/Terrain/Data/WorldTerrainData.cs delete mode 100644 SchematicToVoxCore/Generator/Terrain/Entities/CachedChunk.cs delete mode 100644 SchematicToVoxCore/Generator/Terrain/Environment/Chunk.cs delete mode 100644 SchematicToVoxCore/Generator/Terrain/Environment/ChunksManager.cs delete mode 100644 SchematicToVoxCore/Generator/Terrain/Environment/Trees.cs delete mode 100644 SchematicToVoxCore/Generator/Terrain/Environment/Vegetation.cs delete mode 100644 SchematicToVoxCore/Generator/Terrain/TerrainEnvironment.cs delete mode 100644 SchematicToVoxCore/Generator/Terrain/TerrainGenerator.cs delete mode 100644 SchematicToVoxCore/Generator/Terrain/TerrainGeneratorSettings.cs delete mode 100644 SchematicToVoxCore/Generator/Terrain/Utility/FastHashSet.cs delete mode 100644 SchematicToVoxCore/Generator/Terrain/Utility/HeightMapCache.cs delete mode 100644 SchematicToVoxCore/Generator/Terrain/Utility/NoiseTools.cs delete mode 100644 SchematicToVoxCore/Generator/Terrain/Utility/WorldRandom.cs delete mode 100644 SchematicToVoxCore/JsonPresets/heightmapGenerator.json delete mode 100644 SchematicToVoxCore/JsonPresets/noise/NoiseBase.png delete mode 100644 SchematicToVoxCore/JsonPresets/noise/NoiseDetail.png delete mode 100644 SchematicToVoxCore/JsonPresets/noise/NoiseMoisture.png delete mode 100644 SchematicToVoxCore/JsonPresets/shaderGenerator.json delete mode 100644 SchematicToVoxCore/JsonPresets/terrainGenerator.json delete mode 100644 SchematicToVoxCore/Main/SimpleSingleton.cs delete mode 100644 SchematicToVoxCore/Merger/SchematicMerger.cs delete mode 100644 SchematicToVoxCore/Quantizer/CubeCut.cs delete mode 100644 SchematicToVoxCore/Quantizer/IQuantizer.cs delete mode 100644 SchematicToVoxCore/Quantizer/QuantizedPalette.cs delete mode 100644 SchematicToVoxCore/Quantizer/Quantizer.cs delete mode 100644 SchematicToVoxCore/Quantizer/QuantizerBase.cs diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..5f28270 --- /dev/null +++ b/.editorconfig @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/FileToVox.sln b/FileToVox.sln index 1adfac1..eaf793a 100644 --- a/FileToVox.sln +++ b/FileToVox.sln @@ -1,11 +1,14 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29418.71 +# Visual Studio Version 17 +VisualStudioVersion = 17.3.32819.101 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileToVox", "SchematicToVoxCore\FileToVox.csproj", "{F24C61D3-C2D6-4208-BB30-79236DA8019E}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileToVoxCommon", "FileToVoxCommon\FileToVoxCommon.csproj", "{F0315853-7D9C-43CA-90CB-B30F1639F216}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{42D54E36-6326-4537-8827-99C339BC16A2}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -29,18 +32,6 @@ Global {F24C61D3-C2D6-4208-BB30-79236DA8019E}.Release|x64.Build.0 = Release|Any CPU {F24C61D3-C2D6-4208-BB30-79236DA8019E}.Release|x86.ActiveCfg = Release|Any CPU {F24C61D3-C2D6-4208-BB30-79236DA8019E}.Release|x86.Build.0 = Release|Any CPU - {F0315853-7D9C-43CA-90CB-B30F1639F216}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F0315853-7D9C-43CA-90CB-B30F1639F216}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F0315853-7D9C-43CA-90CB-B30F1639F216}.Debug|x64.ActiveCfg = Debug|Any CPU - {F0315853-7D9C-43CA-90CB-B30F1639F216}.Debug|x64.Build.0 = Debug|Any CPU - {F0315853-7D9C-43CA-90CB-B30F1639F216}.Debug|x86.ActiveCfg = Debug|Any CPU - {F0315853-7D9C-43CA-90CB-B30F1639F216}.Debug|x86.Build.0 = Debug|Any CPU - {F0315853-7D9C-43CA-90CB-B30F1639F216}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F0315853-7D9C-43CA-90CB-B30F1639F216}.Release|Any CPU.Build.0 = Release|Any CPU - {F0315853-7D9C-43CA-90CB-B30F1639F216}.Release|x64.ActiveCfg = Release|Any CPU - {F0315853-7D9C-43CA-90CB-B30F1639F216}.Release|x64.Build.0 = Release|Any CPU - {F0315853-7D9C-43CA-90CB-B30F1639F216}.Release|x86.ActiveCfg = Release|Any CPU - {F0315853-7D9C-43CA-90CB-B30F1639F216}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/FileToVoxCommon/FileToVoxCommon.csproj b/FileToVoxCommon/FileToVoxCommon.csproj deleted file mode 100644 index 889925d..0000000 --- a/FileToVoxCommon/FileToVoxCommon.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - net5.0 - 0.0.2 - Zarbuz - - - - - - - - - diff --git a/FileToVoxCommon/FileToVoxCommon.csproj.user b/FileToVoxCommon/FileToVoxCommon.csproj.user deleted file mode 100644 index 43590e1..0000000 --- a/FileToVoxCommon/FileToVoxCommon.csproj.user +++ /dev/null @@ -1,6 +0,0 @@ - - - - <_LastSelectedProfileId>E:\Documents\FileToVox\FileToVoxCommon\Properties\PublishProfiles\MainBuildCommon.pubxml - - \ No newline at end of file diff --git a/FileToVoxCommon/Generator/Heightmap/Data/HeightmapData.cs b/FileToVoxCommon/Generator/Heightmap/Data/HeightmapData.cs deleted file mode 100644 index 98b42dc..0000000 --- a/FileToVoxCommon/Generator/Heightmap/Data/HeightmapData.cs +++ /dev/null @@ -1,123 +0,0 @@ -using System; -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; -using System.IO; -using FileToVoxCommon.Json; -using FileToVoxCore.Schematics; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; - -namespace FileToVoxCommon.Generator.Heightmap.Data -{ - public class HeightmapData : JsonBaseImportData - { - public HeightmapStep[] Steps { get; set; } - public override GeneratorType GeneratorType { get; set; } = GeneratorType.Heightmap; - } - - public enum PlacementMode - { - [Display(Name = "Additive", Description = "Adds the result of the heightmap generation to the final result")] - ADDITIVE = 0, - [Display(Name = "Replace", Description = "Replaces the color of the voxels that matches the previous generation step")] - REPLACE = 1, - [Display(Name = "Substract", Description = "Removes voxels that match with the previous generation step")] - SUBSTRACT = 2, - [Display(Name = "TopOnly", Description = "Add voxels only if there are voxels from the previous step")] - TOP_ONLY - } - - - - public class HeightmapStep : StepData.StepData - { - public string TexturePath { get; set; } - public string ColorTexturePath { get; set; } - - [Description("Height: The desired height")] - [Range(1, 1000)] - public int Height { get; set; } - - [Description("Offset: Offset to shift the base of the generation")] - [Range(1, 1000)] - public int Offset { get; set; } - - [Description("OffsetMerge: Offset to offset the base of the generation with respect to the previous step. Only valid for a placementMode at 'TOP_ONLY'")] - [Range(1, 1000)] - public int OffsetMerge { get; set; } - - [Description("EnableColor: Activate yes or no colors. If ColorTexturePath is not specified, then the rendering will only be shades of gray")] - public bool EnableColor { get; set; } - - [Description("ColorLimit: Limit the number of colors imported")] - [Range(1, 256)] - public int ColorLimit { get; set; } = 256; - - [Description("Excavate: Removes all voxels which are not visible (all voxels which do not have at least one empty voxel as a neighbor)")] - public bool Excavate { get; set; } - - [Description("Reverse: Reverse the direction of generation")] - public bool Reverse { get; set; } - - [JsonConverter(typeof(StringEnumConverter))] - public PlacementMode PlacementMode { get; set; } - - [JsonConverter(typeof(StringEnumConverter))] - public RotationMode RotationMode { get; set; } - - public void ValidateSettings() - { - if (string.IsNullOrEmpty(TexturePath)) - { - throw new ArgumentException("[ERROR] Missing TexturePath"); - } - - TexturePath = Path.GetFullPath(TexturePath); - if (!string.IsNullOrEmpty(TexturePath) && !File.Exists(TexturePath)) - { - throw new ArgumentException("[ERROR] The TexturePath is invalid: " + TexturePath); - } - - if (!string.IsNullOrEmpty(ColorTexturePath)) - { - ColorTexturePath = Path.GetFullPath(ColorTexturePath); - if (!File.Exists(ColorTexturePath)) - { - throw new ArgumentException("[ERROR] The TexturePath is invalid: " + ColorTexturePath); - } - } - - if (Offset < 0) - { - Offset = 0; - } - - if (Height < 0) - { - Height = 1; - } - - if (ColorLimit < 0) - { - ColorLimit = 256; - } - } - - public void DisplayInfo() - { - Console.WriteLine("[INFO] ###############################"); - Console.WriteLine("[INFO] TexturePath: " + TexturePath); - Console.WriteLine("[INFO] ColorTexturePath: " + ColorTexturePath); - Console.WriteLine("[INFO] Height: " + Height); - Console.WriteLine("[INFO] Offset: " + Offset); - Console.WriteLine("[INFO] OffsetMerge: " + OffsetMerge); - Console.WriteLine("[INFO] EnableColor: " + EnableColor); - Console.WriteLine("[INFO] ColorLimit: " + ColorLimit); - Console.WriteLine("[INFO] Excavate: " + Excavate); - Console.WriteLine("[INFO] Reverse: " + Reverse); - Console.WriteLine("[INFO] PlacementMode: " + PlacementMode); - Console.WriteLine("[INFO] RotationMode: " + RotationMode); - Console.WriteLine("[INFO] ###############################"); - } - } -} diff --git a/FileToVoxCommon/Generator/Shaders/Data/ShaderCase.cs b/FileToVoxCommon/Generator/Shaders/Data/ShaderCase.cs deleted file mode 100644 index 96d986f..0000000 --- a/FileToVoxCommon/Generator/Shaders/Data/ShaderCase.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; - -namespace FileToVoxCommon.Generator.Shaders.Data -{ - public class ShaderCase : ShaderStep - { - [Description("Iterations: Set the number of times the shader will be applied for this step")] - [Range(1, 10)] - public int Iterations { get; set; } = 1; - - [Description("TargetColorIndex: The index of the color target. If value is set to -1, then the shader is applied to all colors")] - [Range(-1, 256)] - public int TargetColorIndex { get; set; } = -1; - - public override ShaderType ShaderType { get; set; } = ShaderType.CASE; - public override void DisplayInfo() - { - base.DisplayInfo(); - Console.WriteLine("[INFO] Iterations: " + Iterations); - Console.WriteLine("[INFO] TargetColorIndex: " + TargetColorIndex); - } - - public override void ValidateSettings() - { - if (Iterations < 0) - { - Console.WriteLine("[WARNING] Negative value found for Iterations, replace to 1..."); - Iterations = 1; - } - } - } -} diff --git a/FileToVoxCommon/Generator/Shaders/Data/ShaderColorDenoiser.cs b/FileToVoxCommon/Generator/Shaders/Data/ShaderColorDenoiser.cs deleted file mode 100644 index 04a27ab..0000000 --- a/FileToVoxCommon/Generator/Shaders/Data/ShaderColorDenoiser.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; - -namespace FileToVoxCommon.Generator.Shaders.Data -{ - public class ShaderColorDenoiser : ShaderStep - { - public override ShaderType ShaderType { get; set; } = ShaderType.COLOR_DENOISER; - - [Description("Iterations: Set the number of times the shader will be applied for this step")] - [Range(1, 10)] - public int Iterations { get; set; } = 1; - - [Description("StrictMode: Indicates whether the algorithm is in strict mode or not. If so, the 4 adjacent voxels must all be the same color to replace the color of the voxel. Otherwise the algorithm calculates the distance between the index of the color of the voxel and that of the adjacent voxels. If the average distance is less than or equal to the 'colorRange' parameter then the color is replaced by the dominant color of adjacent voxels.")] - public bool StrictMode { get; set; } = true; - - [Description("ColorRange: Specifies the maximum distance between the color indexes of the palette")] - [Range(0, 256)] - public int ColorRange { get; set; } - - public override void DisplayInfo() - { - base.DisplayInfo(); - Console.WriteLine("[INFO] Iterations: " + Iterations); - Console.WriteLine("[INFO] StrictMode: " + StrictMode); - if (!StrictMode) - { - Console.WriteLine("[INFO] ColorRange: " + ColorRange); - } - } - - public override void ValidateSettings() - { - if (Iterations < 0) - { - Console.WriteLine("[WARNING] Negative value found for Iterations, replace to 1..."); - Iterations = 1; - } - - if (!StrictMode && ColorRange < 0) - { - Console.WriteLine("[WARNING] Negative value found for ColorRange, replace to 1..."); - ColorRange = 1; - } - } - } -} diff --git a/FileToVoxCommon/Generator/Shaders/Data/ShaderData.cs b/FileToVoxCommon/Generator/Shaders/Data/ShaderData.cs deleted file mode 100644 index fd89858..0000000 --- a/FileToVoxCommon/Generator/Shaders/Data/ShaderData.cs +++ /dev/null @@ -1,57 +0,0 @@ -using FileToVoxCommon.Generator.Shaders.Json; -using FileToVoxCommon.Json; -using Newtonsoft.Json; -using System; -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; -using Newtonsoft.Json.Converters; - -namespace FileToVoxCommon.Generator.Shaders.Data -{ - public class ShaderData : JsonBaseImportData - { - public ShaderStep[] Steps { get; set; } - public override GeneratorType GeneratorType { get; set; } = GeneratorType.Shader; - } - - public enum ShaderType - { - [Display(Name = "Case", Description = "This shader case surrounds / encases the voxels which match your selected color with a chosen color")] - CASE = 0, - - [Display(Name = "Color Denoiser", Description = "This shader allows you to replace the color of a voxel according to the adjacent voxels")] - COLOR_DENOISER = 1, - - [Display(Name = "Fix Holes", Description = "This shader is used to fill the holes. A hole is an \"empty\" voxel of which at least 4 adjacent voxels are not empty")] - FIX_HOLES = 2, - - [Display(Name = "Fix Lonely", Description = "This shader removes all voxels that have no adjacent voxels")] - FIX_LONELY = 3, - - [Display(Name = "Patina", Description = "This shader will grow a patina on your voxels. It won't create new voxels, just change the color. This voxel is based on the patStar shader")] - PATINA = 4, - - [Display(Name = "Fill", Description = "This shader will fill all voxels in function of some conditions")] - FILL = 5, - - [Display(Name = "Replace", Description = "This shader will replace all voxels in function of some conditions")] - REPLACE = 6 - } - - [JsonConverter(typeof(ShaderStepDataConverter))] - - public abstract class ShaderStep : StepData.StepData - { - [Browsable(false)] - [JsonConverter(typeof(StringEnumConverter))] - public abstract ShaderType ShaderType { get; set; } - - public virtual void DisplayInfo() - { - Console.WriteLine("[INFO] ShaderType: " + ShaderType); - } - - public abstract void ValidateSettings(); - - } -} diff --git a/FileToVoxCommon/Generator/Shaders/Data/ShaderFill.cs b/FileToVoxCommon/Generator/Shaders/Data/ShaderFill.cs deleted file mode 100644 index a34233b..0000000 --- a/FileToVoxCommon/Generator/Shaders/Data/ShaderFill.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; -using FileToVoxCore.Schematics; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; - -namespace FileToVoxCommon.Generator.Shaders.Data -{ - public enum FillDirection - { - [Display(Name = "Above", Description = "Will fill all voxels above the specific limit")] - PLUS = 0, - - [Display(Name = "Below", Description = "Will fill all voxels below the specific limit")] - MINUS = 1 - } - - public class ShaderFill : ShaderStep - { - [Description("TargetColorIndex: The index of the color target to fill all voxels. If value is -1, then it will delete voxels")] - [Range(-1, 256)] - public int TargetColorIndex { get; set; } = -1; - - [Range(1, 2000)] - public int Limit { get; set; } = 1; - - [Description("FillWay: The way voxels should be filled")] - [JsonConverter(typeof(StringEnumConverter))] - public FillDirection FillDirection { get; set; } = FillDirection.MINUS; - - [Description("RotationMode: The way voxels should be filled")] - [JsonConverter(typeof(StringEnumConverter))] - public RotationMode RotationMode { get; set; } = RotationMode.Y; - - [Description("Replace: Should replace or not voxels already present during fill ?")] - public bool Replace { get; set; } - - public override ShaderType ShaderType { get; set; } = ShaderType.FILL; - public override void ValidateSettings() - { - - } - - public override void DisplayInfo() - { - base.DisplayInfo(); - Console.WriteLine("[INFO] FillDirection: " + FillDirection); - Console.WriteLine("[INFO] RotationMode: " + RotationMode); - Console.WriteLine("[INFO] TargetColorIndex: " + TargetColorIndex); - } - } -} diff --git a/FileToVoxCommon/Generator/Shaders/Data/ShaderFixHoles.cs b/FileToVoxCommon/Generator/Shaders/Data/ShaderFixHoles.cs deleted file mode 100644 index afb8d42..0000000 --- a/FileToVoxCommon/Generator/Shaders/Data/ShaderFixHoles.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; - -namespace FileToVoxCommon.Generator.Shaders.Data -{ - public class ShaderFixHoles :ShaderStep - { - public override ShaderType ShaderType { get; set; } = ShaderType.FIX_HOLES; - - [Description("Iterations: Set the number of times the shader will be applied for this step")] - [Range(1, 10)] - public int Iterations { get; set; } = 1; - - public override void DisplayInfo() - { - base.DisplayInfo(); - Console.WriteLine("[INFO] Iterations: " + Iterations); - } - - public override void ValidateSettings() - { - if (Iterations < 0) - { - Console.WriteLine("[WARNING] Negative value found for Iterations, replace to 1..."); - Iterations = 1; - } - } - } -} diff --git a/FileToVoxCommon/Generator/Shaders/Data/ShaderFixLonely.cs b/FileToVoxCommon/Generator/Shaders/Data/ShaderFixLonely.cs deleted file mode 100644 index f3d26b2..0000000 --- a/FileToVoxCommon/Generator/Shaders/Data/ShaderFixLonely.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace FileToVoxCommon.Generator.Shaders.Data -{ - public class ShaderFixLonely : ShaderStep - { - public override ShaderType ShaderType { get; set; } = ShaderType.FIX_LONELY; - - public override void ValidateSettings() - { - } - } -} diff --git a/FileToVoxCommon/Generator/Shaders/Data/ShaderPatina.cs b/FileToVoxCommon/Generator/Shaders/Data/ShaderPatina.cs deleted file mode 100644 index fe6f5a1..0000000 --- a/FileToVoxCommon/Generator/Shaders/Data/ShaderPatina.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System; -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; - -namespace FileToVoxCommon.Generator.Shaders.Data -{ - public class ShaderPatina : ShaderStep - { - [Description("Iterations: Set the number of times the shader will be applied for this step")] - [Range(1, 10)] - public int Iterations { get; set; } = 1; - - [Description("TargetColorIndex: The index of the color target")] - [Range(0, 256)] - public int TargetColorIndex { get; set; } = 0; - - [Description("AdditionalColorRange: The additional index range")] - [Range(0, 256)] - public int AdditionalColorRange { get; set; } - - [Description("Seed: Using the shader on the same scene will always yield the exact same result as long as you don't change this value. Play with this to yield different patterns on the same scene.")] - [Range(0, 100000)] - public int Seed { get; set; } - - [Description("Density: This defines the probability that a voxel is painted in one step. The higher the value the more aggressive the spread of the patina")] - [Range(0.0f, 1.0f)] - public float Density { get; set; } - - [Description("Thickness: This influences the color placement pattern of the patina. Just play around with it. Higher values might cause MagicaVoxel to crash due to high computational effort")] - [Range(1, 100)] - public int Thickness { get; set; } - - public override ShaderType ShaderType { get; set; }= ShaderType.PATINA; - public override void DisplayInfo() - { - base.DisplayInfo(); - Console.WriteLine("[INFO] Iterations: " + Iterations); - Console.WriteLine("[INFO] TargetColorIndex: " + TargetColorIndex); - Console.WriteLine("[INFO] AdditionalColorRange: " + AdditionalColorRange); - Console.WriteLine("[INFO] Seed: " + Seed); - Console.WriteLine("[INFO] Density: " + Density); - Console.WriteLine("[INFO] Thickness: " + Thickness); - } - - public override void ValidateSettings() - { - if (Iterations < 0) - { - Console.WriteLine("[WARNING] Negative value found for Iterations, replace to 1..."); - Iterations = 1; - } - - if (TargetColorIndex < 0) - { - Console.WriteLine("[WARNING] Negative value found for TargetColorIndex, replace to 0..."); - TargetColorIndex = 0; - } - - int additionalColorRange = Math.Abs(AdditionalColorRange); - if (TargetColorIndex - additionalColorRange < 0) - { - Console.WriteLine("[WARNING] TargetColorIndex - " + additionalColorRange + " < 0"); - AdditionalColorRange = 0; - } - else if (TargetColorIndex + additionalColorRange > 255) - { - Console.WriteLine($"[WARNING] TargetColorIndex: ${TargetColorIndex} + " + additionalColorRange + " > 255"); - AdditionalColorRange = 0; - } - - if (Density < 0 || Density > 1) - { - Console.WriteLine($"[WARNING] Density must be between 0 and 1"); - Density = 0.30f; - } - - if (Seed < 0) - { - Console.WriteLine("[WARNING] Negative value found for Seed, replace to 123..."); - Seed = 123; - } - - if (Thickness < 0 || Thickness > 100) - { - Console.WriteLine("[WARNING] Thickness value must be between 0 and 100"); - Thickness = 4; - } - - if (Thickness > 100) - { - Console.WriteLine("[WARNING] Value > 100 found for Thickness, replace to 100 ..."); - Thickness = 100; - } - } - } -} diff --git a/FileToVoxCommon/Generator/Shaders/Json/ShaderStepDataConverter.cs b/FileToVoxCommon/Generator/Shaders/Json/ShaderStepDataConverter.cs deleted file mode 100644 index 8718727..0000000 --- a/FileToVoxCommon/Generator/Shaders/Json/ShaderStepDataConverter.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using FileToVoxCommon.Generator.Shaders.Data; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Newtonsoft.Json.Serialization; - -namespace FileToVoxCommon.Generator.Shaders.Json -{ - public class ShaderStepConcreteClassConverter : DefaultContractResolver - { - protected override JsonConverter ResolveContractConverter(Type objectType) - { - if (typeof(ShaderStep).IsAssignableFrom(objectType) && !objectType.IsAbstract) - return null; // pretend TableSortRuleConvert is not specified (thus avoiding a stack overflow) - return base.ResolveContractConverter(objectType); - } - } - - class ShaderStepDataConverter : JsonConverter - { - static JsonSerializerSettings SpecifiedSubclassConversion = new JsonSerializerSettings() { ContractResolver = new ShaderStepConcreteClassConverter() }; - public override bool CanWrite => false; - - public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) - { - throw new NotImplementedException(); - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - JObject jo = JObject.Load(reader); - Enum.TryParse(jo["ShaderType"].ToString(), out ShaderType shaderType); - switch (shaderType) - { - case ShaderType.PATINA: - return JsonConvert.DeserializeObject(jo.ToString(), SpecifiedSubclassConversion); - case ShaderType.CASE: - return JsonConvert.DeserializeObject(jo.ToString(), SpecifiedSubclassConversion); - case ShaderType.FIX_HOLES: - return JsonConvert.DeserializeObject(jo.ToString(), SpecifiedSubclassConversion); - case ShaderType.FIX_LONELY: - return JsonConvert.DeserializeObject(jo.ToString(), SpecifiedSubclassConversion); - case ShaderType.COLOR_DENOISER: - return JsonConvert.DeserializeObject(jo.ToString(), SpecifiedSubclassConversion); - case ShaderType.FILL: - return JsonConvert.DeserializeObject(jo.ToString(), SpecifiedSubclassConversion); - default: - throw new Exception(); - } - } - - public override bool CanConvert(Type objectType) - { - return (objectType == typeof(ShaderStep)); - } - } -} diff --git a/FileToVoxCommon/Generator/StepData/StepData.cs b/FileToVoxCommon/Generator/StepData/StepData.cs deleted file mode 100644 index c9bf6e5..0000000 --- a/FileToVoxCommon/Generator/StepData/StepData.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace FileToVoxCommon.Generator.StepData -{ - public abstract class StepData - { - } -} diff --git a/FileToVoxCommon/Json/JsonBaseImportData.cs b/FileToVoxCommon/Json/JsonBaseImportData.cs deleted file mode 100644 index 0253e1e..0000000 --- a/FileToVoxCommon/Json/JsonBaseImportData.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; - -namespace FileToVoxCommon.Json -{ - public enum GeneratorType - { - Terrain, - Heightmap, - Shader - } - - [JsonConverter(typeof(JsonBaseImportDataConverter))] - public abstract class JsonBaseImportData - { - [JsonConverter(typeof(StringEnumConverter))] - public abstract GeneratorType GeneratorType { get; set; } - } -} diff --git a/FileToVoxCommon/Json/JsonBaseImportDataConverter.cs b/FileToVoxCommon/Json/JsonBaseImportDataConverter.cs deleted file mode 100644 index e2b91e8..0000000 --- a/FileToVoxCommon/Json/JsonBaseImportDataConverter.cs +++ /dev/null @@ -1,56 +0,0 @@ -using FileToVoxCommon.Generator.Heightmap.Data; -using FileToVoxCommon.Generator.Shaders.Data; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Newtonsoft.Json.Serialization; -using System; - -namespace FileToVoxCommon.Json -{ - public class JsonBaseImportConcreteClassConverter : DefaultContractResolver - { - protected override JsonConverter ResolveContractConverter(Type objectType) - { - if (typeof(JsonBaseImportData).IsAssignableFrom(objectType) && !objectType.IsAbstract) - return null; // pretend TableSortRuleConvert is not specified (thus avoiding a stack overflow) - return base.ResolveContractConverter(objectType); - } - } - - public class JsonBaseImportDataConverter : JsonConverter - { - static JsonSerializerSettings SpecifiedSubclassConversion = new JsonSerializerSettings() { ContractResolver = new JsonBaseImportConcreteClassConverter() }; - - public override bool CanConvert(Type objectType) - { - return (objectType == typeof(JsonBaseImportData)); - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - JObject jo = JObject.Load(reader); - Enum.TryParse(jo["GeneratorType"].ToString(), out GeneratorType generatorType); - switch (generatorType) - { - //case GeneratorType.Terrain: - // return JsonConvert.DeserializeObject(jo.ToString(), SpecifiedSubclassConversion); - case GeneratorType.Heightmap: - return JsonConvert.DeserializeObject(jo.ToString(), SpecifiedSubclassConversion); - case GeneratorType.Shader: - return JsonConvert.DeserializeObject(jo.ToString(), SpecifiedSubclassConversion); - default: - throw new Exception(); - } - } - - public override bool CanWrite - { - get { return false; } - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - throw new NotImplementedException(); // won't be called because CanWrite returns false - } - } -} diff --git a/FileToVoxCommon/Properties/PublishProfiles/MainBuildCommon.pubxml b/FileToVoxCommon/Properties/PublishProfiles/MainBuildCommon.pubxml deleted file mode 100644 index b8769c2..0000000 --- a/FileToVoxCommon/Properties/PublishProfiles/MainBuildCommon.pubxml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - Release - Any CPU - bin\Release\net5.0\publish\ - FileSystem - - \ No newline at end of file diff --git a/FileToVoxCommon/Properties/PublishProfiles/MainBuildCommon.pubxml.user b/FileToVoxCommon/Properties/PublishProfiles/MainBuildCommon.pubxml.user deleted file mode 100644 index a32fee2..0000000 --- a/FileToVoxCommon/Properties/PublishProfiles/MainBuildCommon.pubxml.user +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/SchematicToVoxCore/Converter/Image/DirectBitmap.cs b/SchematicToVoxCore/Converter/Image/DirectBitmap.cs deleted file mode 100644 index e0741a5..0000000 --- a/SchematicToVoxCore/Converter/Image/DirectBitmap.cs +++ /dev/null @@ -1,108 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Imaging; - -namespace FileToVox.Converter.Image -{ - public class DirectBitmap : IDisposable - { - #region Fields - - public int[] Bits { get; } - public bool Disposed { get; private set; } - public int Length { get; } - public int Width { get; } - public int Height { get; private set; } - public Dictionary Heights { get; private set; } - - - #endregion - - public DirectBitmap(Bitmap bitmap, int height) - { - if (bitmap == null) - { - return; - } - - Width = bitmap.Width; - Length = bitmap.Height; - Height = height; - Bits = new int[Width * Length]; - Heights = new Dictionary(); - BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, - PixelFormat.Format32bppRgb); - - unsafe - { - ImageToSchematic.RGB* p = (ImageToSchematic.RGB*) data.Scan0; - int last = p->argb; - int h = bitmap.Height; - int w = bitmap.Width; - for (int y = 0; y < h; ++y) - { - for (int x = 0; x < w; ++x) - { - int c = p->argb; - if (c == last) - { - SetPixel(x, y, c); - } - else - { - SetPixel(x, y, c); - last = c; - } - - ++p; - } - } - } - } - - public void SetPixel(int x, int y, Color color) - { - int index = x + (y * Width); - int col = color.ToArgb(); - - Bits[index] = col; - } - - public void SetPixel(int x, int y, int color) - { - int index = x + (y * Width); - Bits[index] = color; - - if (Height != 1) - { - Color result = Color.FromArgb(color); - int intensity = result.R + result.G + result.B; - float position = intensity / (float)765; - Heights[index] = (int)(position * Height); - } - } - - public Color GetPixel(int x, int y) - { - int index = x + (y * Width); - int col = Bits[index]; - Color result = Color.FromArgb(col); - - return result; - } - - public int GetHeight(int x, int y) - { - int index = x + (y * Width); - return Heights[index]; - } - - public void Dispose() - { - if (Disposed) return; - - Disposed = true; - } - } -} \ No newline at end of file diff --git a/SchematicToVoxCore/Converter/Image/ImageToSchematic.cs b/SchematicToVoxCore/Converter/Image/ImageToSchematic.cs index 70c56be..bee843e 100644 --- a/SchematicToVoxCore/Converter/Image/ImageToSchematic.cs +++ b/SchematicToVoxCore/Converter/Image/ImageToSchematic.cs @@ -1,9 +1,12 @@ -using System.Runtime.InteropServices; +using FileToVox.Utils; using FileToVoxCore.Schematics; +using ImageMagick; +using System; +using System.IO; namespace FileToVox.Converter.Image { - public abstract class ImageToSchematic : AbstractToSchematic + public class ImageToSchematic : AbstractToSchematic { protected readonly bool Excavate; protected readonly int MaxHeight; @@ -11,18 +14,7 @@ public abstract class ImageToSchematic : AbstractToSchematic protected readonly string ColorPath; protected readonly int ColorLimit; - [StructLayout(LayoutKind.Explicit)] - public struct RGB - { - // Structure of pixel for a 24 bpp bitmap - [FieldOffset(0)] public byte blue; - [FieldOffset(1)] public byte green; - [FieldOffset(2)] public byte red; - [FieldOffset(3)] public byte alpha; - [FieldOffset(0)] public int argb; - } - - protected ImageToSchematic(string path, string colorPath, int height, bool excavate, bool color, int colorLimit) : base(path) + public ImageToSchematic(string path, string colorPath, int height, bool excavate, bool color, int colorLimit) : base(path) { ColorPath = colorPath; MaxHeight = height; @@ -31,7 +23,39 @@ protected ImageToSchematic(string path, string colorPath, int height, bool excav ColorLimit = colorLimit; } - protected abstract Schematic WriteSchematicMain(); - - } + public override Schematic WriteSchematic() + { + if (!File.Exists(PathFile)) + { + Console.WriteLine("[ERROR] The file path is invalid for path : " + PathFile); + return null; + } + + if (!string.IsNullOrEmpty(ColorPath) && !File.Exists(ColorPath)) + { + Console.WriteLine("[ERROR] The color path is invalid"); + return null; + } + + MagickImage image = new MagickImage(PathFile); + MagickImage colorImage = null; + + if (!string.IsNullOrEmpty(ColorPath)) + { + colorImage = new MagickImage(ColorPath); + } + + LoadImageParam loadImageParam = new LoadImageParam() + { + TexturePath = PathFile, + ColorLimit = ColorLimit, + ColorTexturePath = ColorPath, + EnableColor = Color, + Excavate = Excavate, + Height = MaxHeight, + }; + return ImageUtils.WriteSchematicFromImage(image, colorImage, loadImageParam); + + } + } } diff --git a/SchematicToVoxCore/Converter/Image/MultipleImageToSchematic.cs b/SchematicToVoxCore/Converter/Image/MultipleImageToSchematic.cs index 3146910..1145d2b 100644 --- a/SchematicToVoxCore/Converter/Image/MultipleImageToSchematic.cs +++ b/SchematicToVoxCore/Converter/Image/MultipleImageToSchematic.cs @@ -1,6 +1,7 @@ using FileToVox.Extensions; using FileToVoxCore.Schematics; -using FileToVoxCore.Utils; +using ImageMagick; +using nQuant; using System; using System.Collections.Generic; using System.Drawing; @@ -27,27 +28,34 @@ public override Schematic WriteSchematic() Console.WriteLine("[INFO] Total images to process: " + mImages.Count); List blocks = new List(); - Bitmap bitmapColor = null; + IPixelCollection pixelsColor = null; + int colorWidth = 0; if (mInputColorFile != null) { - bitmapColor = new Bitmap(mInputColorFile); + MagickImage bitmapColor = new MagickImage(mInputColorFile); if (bitmapColor.Width > 256 || bitmapColor.Height > 1) { throw new ArgumentException("[ERROR] The input color file must have a dimension of 256x1 px"); } + + colorWidth = bitmapColor.Width; + pixelsColor = bitmapColor.GetPixels(); } for (int i = 0; i < mImages.Count; i++) { string file = mImages[i]; Console.WriteLine("[INFO] Reading file: " + file); - Bitmap bitmap = new Bitmap(file); - DirectBitmap directBitmap = new DirectBitmap(bitmap, 1); - for (int x = 0; x < directBitmap.Width; x++) + MagickImage bitmap = new MagickImage(file); + IPixelCollection pixels = bitmap.GetPixels(); + + for (int x = 0; x < bitmap.Width; x++) { - for (int y = 0; y < directBitmap.Length; y++) + for (int y = 0; y < bitmap.Height; y++) { - Color color = directBitmap.GetPixel(x, y); + IPixel pixel = pixels.GetPixel(x, y); + Color color = Color.FromArgb(pixel.GetChannel(4), pixel.GetChannel(0), pixel.GetChannel(1), pixel.GetChannel(2)); + if (color != Color.Empty && color != Color.Transparent && color != Color.Black && (color.R != 0 && color.G != 0 && color.B != 0)) { if (mInputColorFile != null) @@ -55,12 +63,12 @@ public override Schematic WriteSchematic() double distance = Math.Sqrt(Math.Pow((height / 2) - x, 2) + Math.Pow((height / 2) - y, 2)); float range = (float)Math.Abs(distance / (height / 2)); // range = range > 1 ? 1 : range; - color = bitmapColor.GetPixel((int)(range * (bitmapColor.Width - 1)), 0); + color = pixelsColor.GetPixel((int)(range * (colorWidth - 1)), 0).GetPixelColor(); } if (mExcavate) { - CheckNeighbor(ref blocks, directBitmap, color, i, x, y); + CheckNeighbor(ref blocks, bitmap, color, i, x, y); } else { @@ -69,7 +77,6 @@ public override Schematic WriteSchematic() } } } - directBitmap.Dispose(); } List list = Quantization.ApplyQuantization(blocks, mColorLimit); @@ -79,14 +86,19 @@ public override Schematic WriteSchematic() return schematic; } - private void CheckNeighbor(ref List blocks, DirectBitmap bitmap, Color color, int i, int x, int y) + private void CheckNeighbor(ref List blocks, MagickImage bitmap, Color color, int i, int x, int y) { - if (x - 1 >= 0 && x + 1 < bitmap.Width && y - 1 >= 0 && y + 1 < bitmap.Length) + var pixels = bitmap.GetPixels(); + + if (x - 1 >= 0 && x + 1 < bitmap.Width && y - 1 >= 0 && y + 1 < bitmap.Height) { - Color left = bitmap.GetPixel(x - 1, y); - Color top = bitmap.GetPixel(x, y - 1); - Color right = bitmap.GetPixel(x + 1, y); - Color bottom = bitmap.GetPixel(x, y + 1); + Color left = pixels.GetPixel(x - 1, y).GetPixelColor(); + + Color top = pixels.GetPixel(x, y - 1).GetPixelColor(); + + Color right = pixels.GetPixel(x + 1, y).GetPixelColor(); + + Color bottom = pixels.GetPixel(x, y + 1).GetPixelColor(); bool leftColor = left != Color.Empty && left != Color.Transparent && left != Color.Black && (left.R != 0 && left.G != 0 && left.B != 0); bool topColor = top != Color.Empty && top != Color.Transparent && top != Color.Black && (top.R != 0 && top.G != 0 && top.B != 0); diff --git a/SchematicToVoxCore/Converter/Image/PNGToSchematic.cs b/SchematicToVoxCore/Converter/Image/PNGToSchematic.cs deleted file mode 100644 index 8538d27..0000000 --- a/SchematicToVoxCore/Converter/Image/PNGToSchematic.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using System.Drawing; -using System.IO; -using FileToVox.Utils; -using FileToVoxCommon.Generator.Heightmap.Data; -using FileToVoxCore.Schematics; -using FileToVoxCore.Utils; - -namespace FileToVox.Converter.Image -{ - public class PNGToSchematic : ImageToSchematic - { - public PNGToSchematic(string path, string colorPath, int height, bool excavate, bool color, int colorLimit) - : base(path, colorPath, height, excavate, color, colorLimit) - { - } - - protected override Schematic WriteSchematicMain() - { - if (!File.Exists(PathFile)) - { - Console.WriteLine("[ERROR] The file path is invalid for path : " + PathFile); - return null; - } - - if (!string.IsNullOrEmpty(ColorPath) && !File.Exists(ColorPath)) - { - Console.WriteLine("[ERROR] The color path is invalid"); - return null; - } - - Bitmap bitmap = new Bitmap(new FileInfo(PathFile).FullName); - Bitmap bitmapColor = null; - if (!string.IsNullOrEmpty(ColorPath)) - { - bitmapColor = new Bitmap(new FileInfo(ColorPath).FullName); - } - - HeightmapStep heightmapStep = new HeightmapStep() - { - TexturePath = PathFile, - ColorLimit = ColorLimit, - ColorTexturePath = ColorPath, - EnableColor = Color, - Excavate = Excavate, - Height = MaxHeight, - Offset = 0, - Reverse = false, - PlacementMode = PlacementMode.ADDITIVE, - RotationMode = RotationMode.Y - }; - - return ImageUtils.WriteSchematicFromImage(bitmap, bitmapColor, heightmapStep); - } - - public override Schematic WriteSchematic() - { - return WriteSchematicMain(); - //return WriteSchematicFromImage(Path, ColorPath, ColorLimit, Color); - } - } -} diff --git a/SchematicToVoxCore/Converter/Image/TIFtoSchematic.cs b/SchematicToVoxCore/Converter/Image/TIFtoSchematic.cs deleted file mode 100644 index 06d1241..0000000 --- a/SchematicToVoxCore/Converter/Image/TIFtoSchematic.cs +++ /dev/null @@ -1,104 +0,0 @@ -using BitMiracle.LibTiff.Classic; -using System; -using System.Drawing; -using System.Drawing.Imaging; -using System.IO; -using FileToVox.Utils; -using FileToVoxCommon.Generator.Heightmap.Data; -using FileToVoxCore.Schematics; -using FileToVoxCore.Utils; - -namespace FileToVox.Converter.Image -{ - public class TIFtoSchematic : ImageToSchematic - { - public TIFtoSchematic(string path, string colorPath, int height, bool excavate, bool color, int colorLimit) : base(path, colorPath, height, excavate, color, colorLimit) - { - } - - public override Schematic WriteSchematic() - { - return WriteSchematicMain(); - } - - protected override Schematic WriteSchematicMain() - { - if (!File.Exists(PathFile)) - { - Console.WriteLine("[ERROR] The file path is invalid for path : " + PathFile); - return null; - } - - if (!string.IsNullOrEmpty(ColorPath) && !File.Exists(ColorPath)) - { - Console.WriteLine("[ERROR] The color path is invalid"); - return null; - } - - Bitmap bitmap = ConvertTifToBitmap(PathFile); - Bitmap bitmapColor = null; - if (!string.IsNullOrEmpty(ColorPath)) - { - bitmapColor = ConvertTifToBitmap(ColorPath); - } - - HeightmapStep heightmapStep = new HeightmapStep() - { - TexturePath = PathFile, - ColorLimit = ColorLimit, - ColorTexturePath = ColorPath, - EnableColor = Color, - Excavate = Excavate, - Height = MaxHeight, - Offset = 0, - PlacementMode = PlacementMode.ADDITIVE, - RotationMode = RotationMode.Y - }; - - return ImageUtils.WriteSchematicFromImage(bitmap, bitmapColor, heightmapStep); - } - - private Bitmap ConvertTifToBitmap(string path) - { - using (Tiff tiff = Tiff.Open(path, "r")) - { - FieldValue[] value = tiff.GetField(TiffTag.IMAGEWIDTH); - int width = value[0].ToInt(); - - value = tiff.GetField(TiffTag.IMAGELENGTH); - int height = value[0].ToInt(); - - int[] raster = new int[height * width]; - if (!tiff.ReadRGBAImage(width, height, raster)) - { - throw new Exception("Could not read image"); - } - - Bitmap bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb); - Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); - BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); - byte[] bytes = new byte[bmpData.Stride * bmpData.Height]; - - for (int y = 0; y < bmp.Height; y++) - { - int rasterOffset = y * bmp.Width; - int bitsOffset = (bmp.Height - y - 1) * bmpData.Stride; - - for (int x = 0; x < bmp.Width; x++) - { - int rgba = raster[rasterOffset++]; - bytes[bitsOffset++] = (byte)((rgba >> 16) & 0xff); - bytes[bitsOffset++] = (byte)((rgba >> 8) & 0xff); - bytes[bitsOffset++] = (byte)(rgba & 0xff); - bytes[bitsOffset++] = (byte)((rgba >> 24) & 0xff); - } - } - - System.Runtime.InteropServices.Marshal.Copy(bytes, 0, bmpData.Scan0, bytes.Length); - bmp.UnlockBits(bmpData); - - return bmp; - } - } - } -} diff --git a/SchematicToVoxCore/Converter/Json/JsonToSchematic.cs b/SchematicToVoxCore/Converter/Json/JsonToSchematic.cs deleted file mode 100644 index b9c116e..0000000 --- a/SchematicToVoxCore/Converter/Json/JsonToSchematic.cs +++ /dev/null @@ -1,71 +0,0 @@ -using FileToVox.Generator; -using FileToVox.Generator.Heightmap; -using FileToVox.Generator.Shaders; -using FileToVox.Generator.Terrain; -using FileToVoxCommon.Generator.Heightmap.Data; -using FileToVoxCommon.Generator.Shaders.Data; -using FileToVoxCommon.Json; -using Newtonsoft.Json; -using System; -using System.IO; -using FileToVoxCore.Schematics; -using WorldTerrainData = FileToVox.Generator.Terrain.Data.WorldTerrainData; - -namespace FileToVox.Converter.Json -{ - public class JsonToSchematic : AbstractToSchematic - { - private IGenerator mGenerator; - private Schematic mSchematic; - public JsonToSchematic(string path) : base(path) - { - ParseFile(); - } - - public JsonToSchematic(string path, Schematic schematic) : base(path) - { - mSchematic = schematic; - ParseFile(); - } - - private void ParseFile() - { - try - { - JsonBaseImportData data = JsonConvert.DeserializeObject(File.ReadAllText(PathFile)); - if (data != null) - { - Console.WriteLine("[INFO] GeneratorType: " + data.GeneratorType); - switch (data.GeneratorType) - { - case GeneratorType.Terrain: - string directoryName = System.IO.Path.GetDirectoryName(PathFile); - WorldTerrainData worldTerrainData = data as WorldTerrainData; - worldTerrainData.DirectoryPath = directoryName; - mGenerator = new TerrainGenerator(worldTerrainData); - break; - case GeneratorType.Heightmap: - HeightmapData heightmapData = data as HeightmapData; - mGenerator = new HeightmapGenerator(heightmapData, mSchematic); - break; - case GeneratorType.Shader: - ShaderData shaderData = data as ShaderData; - mGenerator = new ShaderGenerator(shaderData, mSchematic); - break; - } - } - } - catch (Exception e) - { - Console.WriteLine("[ERROR] Failed to parse the JSON file: " + e.Message); - } - } - - public override Schematic WriteSchematic() - { - return mGenerator.WriteSchematic(); - } - - } - -} diff --git a/SchematicToVoxCore/Converter/PaletteSchematic/PaletteSchematicConverter.cs b/SchematicToVoxCore/Converter/PaletteSchematic/PaletteSchematicConverter.cs index 222f278..74fd00c 100644 --- a/SchematicToVoxCore/Converter/PaletteSchematic/PaletteSchematicConverter.cs +++ b/SchematicToVoxCore/Converter/PaletteSchematic/PaletteSchematicConverter.cs @@ -5,25 +5,27 @@ using System.Collections.Generic; using System.Drawing; using System.Linq; +using ImageMagick; using Color = FileToVoxCore.Drawing.Color; namespace FileToVox.Converter.PaletteSchematic { public class PaletteSchematicConverter { - private List _colors; + private readonly List _colors; public PaletteSchematicConverter(string palettePath) { _colors = new List(); - Bitmap bitmap = new Bitmap(palettePath); + MagickImage bitmap = new MagickImage(palettePath); + IPixelCollection pixels = bitmap.GetPixels(); for (int x = 0; x < bitmap.Width; x++) { for (int y = 0; y < bitmap.Height; y++) { if (_colors.Count < 256) { - _colors.Add(bitmap.GetPixel(x, y).ToFileToVoxCoreColor()); + _colors.Add(pixels.GetPixel(x, y).GetPixelColor().ToFileToVoxCoreColor()); } } } diff --git a/SchematicToVoxCore/Converter/PointCloud/PointCloudToSchematic.cs b/SchematicToVoxCore/Converter/PointCloud/PointCloudToSchematic.cs index 7c7180c..5471c24 100644 --- a/SchematicToVoxCore/Converter/PointCloud/PointCloudToSchematic.cs +++ b/SchematicToVoxCore/Converter/PointCloud/PointCloudToSchematic.cs @@ -94,6 +94,7 @@ protected void VoxelizeData(BodyDataDTO data) progressbar.Report(i / (float)data.BodyVertices.Count); } } + Console.WriteLine("[INFO] Done."); //minX = vertices.MinBy(t => t.X); diff --git a/SchematicToVoxCore/Extensions/FctExtensions.cs b/SchematicToVoxCore/Extensions/FctExtensions.cs index 929835f..187ed85 100644 --- a/SchematicToVoxCore/Extensions/FctExtensions.cs +++ b/SchematicToVoxCore/Extensions/FctExtensions.cs @@ -1,67 +1,22 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Imaging; -using FileToVox.Converter.Image; -using FileToVoxCore.Schematics; -using FileToVoxCore.Schematics.Tools; -using FileToVoxCore.Utils; -using FileToVoxCore.Drawing; +using ImageMagick; using Color = FileToVoxCore.Drawing.Color; namespace FileToVox.Extensions { - public static class FctExtensions + public static class FctExtensions { - public static int CountColor(this Bitmap bitmap) - { - Console.WriteLine("[INFO] Check total different colors..."); - //Make a clone of the bitmap to avoid lock bitmaps in the rest of the code - Bitmap clone = new Bitmap(bitmap.Width, bitmap.Height, PixelFormat.Format32bppArgb); - using (Graphics gr = Graphics.FromImage(clone)) - { - gr.DrawImage(bitmap, new Rectangle(0, 0, clone.Width, clone.Height)); - } - - BitmapData data = clone.LockBits(new Rectangle(0, 0, clone.Width, clone.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb); + public static byte ParsedChannel(this ushort channel) + { + return (byte)((channel / (float)ushort.MaxValue) * 255); + } - Dictionary counts = new Dictionary(); - unsafe - { - ImageToSchematic.RGB* p = (ImageToSchematic.RGB*)data.Scan0; - int last = p->argb; - counts.Add(last, 1); - int h = clone.Height; - int w = clone.Width; - int index = 0; - using (ProgressBar progressBar = new ProgressBar()) - { - for (int y = 0; y < h; ++y) - { - for (int x = 0; x < w; ++x) - { - int c = p->argb; - if (c == last) counts[last] += 1; - else - { - if (!counts.ContainsKey(c)) - counts.Add(c, 1); - else - counts[c]++; - last = c; - } - progressBar.Report(index++ / (float)(w * h)); - ++p; - } - } - } - } - - Console.WriteLine("[INFO] Done. (" + counts.Count + ")"); - return counts.Count; - } + public static System.Drawing.Color GetPixelColor(this IPixel pixel) + { + Color color = Color.FromArgb(pixel.GetChannel(3).ParsedChannel(), pixel.GetChannel(0).ParsedChannel(), pixel.GetChannel(1).ParsedChannel(), pixel.GetChannel(2).ParsedChannel()); + return color.ToSystemDrawingColor(); + } - public static uint ColorToUInt(this Color color) + public static uint ColorToUInt(this Color color) { return (uint)((color.A << 24) | (color.R << 16) | (color.G << 8) | (color.B << 0)); @@ -97,15 +52,6 @@ public static Color UIntToColor(this uint color) return Color.FromArgb(a, r, g, b); } - public static List ApplyOffset(this List list, Vector3 vector) - { - for (int i = 0; i < list.Count; i++) - { - list[i] = new Voxel((ushort)(list[i].X - vector.X), (ushort)(list[i].Y - vector.Y), (ushort)(list[i].Z - vector.Z), list[i].Color); - } - - return list; - } } diff --git a/SchematicToVoxCore/Extensions/Grayscale.cs b/SchematicToVoxCore/Extensions/Grayscale.cs deleted file mode 100644 index a82a8f9..0000000 --- a/SchematicToVoxCore/Extensions/Grayscale.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.Drawing; -using System.Drawing.Imaging; - -namespace FileToVox.Extensions -{ - public static class Grayscale - { - public static Bitmap MakeGrayscale3(Bitmap original) - { - //create a blank bitmap the same size as original - Bitmap newBitmap = new Bitmap(original.Width, original.Height); - - //get a graphics object from the new image - Graphics g = Graphics.FromImage(newBitmap); - - //create the grayscale ColorMatrix - ColorMatrix colorMatrix = new ColorMatrix( - new float[][] - { - new float[] {.3f, .3f, .3f, 0, 0}, - new float[] {.59f, .59f, .59f, 0, 0}, - new float[] {.11f, .11f, .11f, 0, 0}, - new float[] {0, 0, 0, 1, 0}, - new float[] {0, 0, 0, 0, 1} - }); - - //create some image attributes - ImageAttributes attributes = new ImageAttributes(); - - //set the color matrix attribute - attributes.SetColorMatrix(colorMatrix); - - //draw the original image on the new image - //using the grayscale color matrix - g.DrawImage(original, new Rectangle(0, 0, original.Width, original.Height), - 0, 0, original.Width, original.Height, GraphicsUnit.Pixel, attributes); - - //dispose the Graphics object - g.Dispose(); - return newBitmap; - } - } -} diff --git a/SchematicToVoxCore/Extensions/Quantization.cs b/SchematicToVoxCore/Extensions/Quantization.cs index 705d173..75bdf01 100644 --- a/SchematicToVoxCore/Extensions/Quantization.cs +++ b/SchematicToVoxCore/Extensions/Quantization.cs @@ -1,74 +1,90 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using FileToVoxCore.Extensions; -using FileToVoxCore.Schematics; +using FileToVoxCore.Schematics; using FileToVoxCore.Utils; +using ImageMagick; +using System; +using System.Collections.Generic; +using System.Linq; using Color = FileToVoxCore.Drawing.Color; namespace FileToVox.Extensions { - public static class Quantization - { - public static List ApplyQuantization(List blocks, int colorLimit) - { - Quantizer.Quantizer quantizer = new Quantizer.Quantizer(); - try - { - if (blocks.Count == 0) - { - Console.WriteLine("[WARNING] No voxels to quantize, skipping this part..."); - return blocks; - } + public static class Quantization + { + + public static void Quantize(MagickImage image, QuantizeSettings settings) + { + if (Program.DisableQuantization()) + { + Console.WriteLine("[WARNING] By disabling quantization, only the first 255 unique colors will be taken into account"); + } + image.Quantize(settings); + } + + public static List ApplyQuantization(List voxels, int colorLimit) + { + if (voxels.Count == 0) + { + Console.WriteLine("[WARNING] No voxels to quantize, skipping this part..."); + return voxels; + } + + if (Program.DisableQuantization()) + { + Console.WriteLine("[WARNING] By disabling quantization, only the first 255 unique colors will be taken into account"); + return voxels; + } + + colorLimit = Math.Min(colorLimit, 256); + Console.WriteLine("[INFO] Started quantization of all colors ..."); + using (ProgressBar progressBar = new ProgressBar()) + { - Console.WriteLine("[INFO] Started quantization of all colors ..."); - using (ProgressBar progressBar = new ProgressBar()) - { - using (Bitmap bitmap = CreateBitmapFromColors(blocks)) - { - using (Bitmap quantized = quantizer.QuantizeImage(bitmap, 10, 70, colorLimit)) - { - //Console.WriteLine(quantized.PixelFormat); - //Bitmap reducedBitmap = new Bitmap(quantized); - int width = quantized.Size.Width; - for (int i = 0; i < blocks.Count; i++) - { - int x = i % width; - int y = i / width; - blocks[i] = new Voxel(blocks[i].X, blocks[i].Y, blocks[i].Z, quantized.GetPixel(x, y).ColorToUInt()); - progressBar.Report(i / (float)blocks.Count); - } - } - } + Dictionary histo = new Dictionary(); + foreach (Color color in voxels.Select(voxel => voxel.Color.UIntToColor())) + { + if (histo.ContainsKey(color)) + { + histo[color]++; + } + else + { + histo[color] = 1; + } + } - } + IOrderedEnumerable> result1 = histo.OrderByDescending(a => a.Value); + List mostUsedColor = result1.Select(x => x.Key).Take(colorLimit).ToList(); + Dictionary dist = new Dictionary(); + Dictionary mapping = new Dictionary(); + foreach (KeyValuePair p in result1) + { + dist.Clear(); + foreach (Color pp in mostUsedColor) + { + double temp = Math.Abs(p.Key.R - pp.R) + + Math.Abs(p.Key.G - pp.G) + + Math.Abs(p.Key.B - pp.B); + dist.Add(pp, temp); + } + KeyValuePair min = dist.OrderBy(k => k.Value).FirstOrDefault(); + mapping.Add(p.Key, min.Key); + } - Console.WriteLine("[INFO] Done."); - } - catch (Exception e) - { - Console.WriteLine(e); - } + for (int i = 0; i < voxels.Count; i++) + { + Color c = voxels[i].Color.UIntToColor(); + Color replaceColor = mapping[c]; - return blocks; - } + voxels[i] = new Voxel(voxels[i].X, voxels[i].Y, voxels[i].Z, replaceColor.ColorToUInt()); + progressBar.Report(i / (float)voxels.Count); + } - private static Bitmap CreateBitmapFromColors(List blocks) - { - int width = blocks.Count; + } - Bitmap bitmap = new Bitmap(width, 1); + Console.WriteLine("[INFO] Done."); + return voxels; + } - for (int i = 0; i < blocks.Count; i++) - { - Voxel voxel = blocks[i]; - Color color = voxel.Color.UIntToColor(); - int x = i % width; - int y = i / width; - bitmap.SetPixel(x, y, color.ToSystemDrawingColor()); - } - return bitmap; - } - } + } } diff --git a/SchematicToVoxCore/FileToVox.csproj b/SchematicToVoxCore/FileToVox.csproj index d7837e5..f8d7c75 100644 --- a/SchematicToVoxCore/FileToVox.csproj +++ b/SchematicToVoxCore/FileToVox.csproj @@ -7,7 +7,7 @@ true win-x64;linux-x64;osx-x64 Zarbuz - 1.15.1 + 1.16 https://github.com/Zarbuz/FileToVox https://github.com/Zarbuz/FileToVox true @@ -30,9 +30,15 @@ + + + + + + @@ -40,12 +46,6 @@ - - - true - - - ..\packages\MoreLinq.dll @@ -53,24 +53,21 @@ - - PreserveNewest - - - Always - - - Always - - - Always - - - PreserveNewest - - - PreserveNewest - + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + Always diff --git a/SchematicToVoxCore/Generator/Heightmap/HeightmapGenerator.cs b/SchematicToVoxCore/Generator/Heightmap/HeightmapGenerator.cs deleted file mode 100644 index 08ecd19..0000000 --- a/SchematicToVoxCore/Generator/Heightmap/HeightmapGenerator.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using System.Drawing; -using System.IO; -using FileToVox.Utils; -using FileToVoxCommon.Generator.Heightmap.Data; -using FileToVoxCore.Schematics; -using FileToVoxCore.Utils; - -namespace FileToVox.Generator.Heightmap -{ - public class HeightmapGenerator : IGenerator - { - private HeightmapData mHeightmapData; - private Schematic mSchematic; - public HeightmapGenerator(HeightmapData heightmapData, Schematic schematic) - { - mHeightmapData = heightmapData; - mSchematic = schematic; - } - - public Schematic WriteSchematic() - { - Schematic finalSchematic = new Schematic(); - if (mSchematic != null) - { - finalSchematic = new Schematic(mSchematic.GetAllVoxels()); - } - - Console.WriteLine("[INFO] Count steps: " + mHeightmapData.Steps.Length); - for (int index = 0; index < mHeightmapData.Steps.Length; index++) - { - Console.WriteLine("[INFO] Start parse heightmap for step : " + index); - HeightmapStep step = mHeightmapData.Steps[index]; - step.ValidateSettings(); - step.DisplayInfo(); - - Bitmap bitmap = new Bitmap(new FileInfo(step.TexturePath).FullName); - Bitmap bitmapColor = null; - if (!string.IsNullOrEmpty(step.ColorTexturePath)) - { - bitmapColor = new Bitmap(new FileInfo(step.ColorTexturePath).FullName); - } - - - Schematic schematicStep = ImageUtils.WriteSchematicFromImage(bitmap, bitmapColor, step); - finalSchematic = SchematicMerger.Merge(finalSchematic, schematicStep, step); - } - - return finalSchematic; - } - } -} diff --git a/SchematicToVoxCore/Generator/IGenerator.cs b/SchematicToVoxCore/Generator/IGenerator.cs deleted file mode 100644 index 5727dc4..0000000 --- a/SchematicToVoxCore/Generator/IGenerator.cs +++ /dev/null @@ -1,9 +0,0 @@ -using FileToVoxCore.Schematics; - -namespace FileToVox.Generator -{ - public interface IGenerator - { - Schematic WriteSchematic(); - } -} diff --git a/SchematicToVoxCore/Generator/Shaders/ApplyShaders/ApplyShaderCase.cs b/SchematicToVoxCore/Generator/Shaders/ApplyShaders/ApplyShaderCase.cs deleted file mode 100644 index dfc5b6e..0000000 --- a/SchematicToVoxCore/Generator/Shaders/ApplyShaders/ApplyShaderCase.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Collections.Generic; -using FileToVoxCommon.Generator.Shaders.Data; -using FileToVoxCore.Schematics; -using FileToVoxCore.Utils; - -namespace FileToVox.Generator.Shaders -{ - public class ApplyShaderCase : IShaderGenerator - { - private ShaderCase mShaderCase; - - public Schematic ApplyShader(Schematic schematic, ShaderStep shaderStep) - { - mShaderCase = shaderStep as ShaderCase; - for (int i = 0; i < mShaderCase.Iterations; i++) - { - Console.WriteLine("[INFO] Process iteration: " + i); - schematic = ProcessShaderCase(schematic, mShaderCase); - } - Console.WriteLine("[INFO] Done."); - return schematic; - } - - private Schematic ProcessShaderCase(Schematic schematic, ShaderCase shaderCase) - { - List allVoxels = schematic.GetAllVoxels(); - - using (ProgressBar progressBar = new ProgressBar()) - { - int index = 0; - foreach (Voxel voxel in allVoxels) - { - int x = voxel.X; - int y = voxel.Y; - int z = voxel.Z; - - if (x == 0 || y == 0 || z == 0) - continue; - - for (int minX = x - 1; minX < x + 1; minX++) - { - for (int minY = y - 1; minY < y + 1; minY++) - { - for (int minZ = z - 1; minZ < z + 1; minZ++) - { - if (!schematic.ContainsVoxel(minX, minY, minZ)) - { - if (shaderCase.TargetColorIndex != -1 && schematic.GetPaletteIndex(voxel.Color) == shaderCase.TargetColorIndex || shaderCase.TargetColorIndex == -1) - { - schematic.AddVoxel(minX, minY, minZ, voxel.Color); - } - } - } - } - } - - progressBar.Report(index++ / (float) allVoxels.Count); - } - } - - return schematic; - } - - - } -} diff --git a/SchematicToVoxCore/Generator/Shaders/ApplyShaders/ApplyShaderColorDenoiser.cs b/SchematicToVoxCore/Generator/Shaders/ApplyShaders/ApplyShaderColorDenoiser.cs deleted file mode 100644 index 348b473..0000000 --- a/SchematicToVoxCore/Generator/Shaders/ApplyShaders/ApplyShaderColorDenoiser.cs +++ /dev/null @@ -1,196 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using FileToVoxCommon.Generator.Shaders.Data; -using FileToVoxCore.Schematics; -using FileToVoxCore.Utils; - -namespace FileToVox.Generator.Shaders.ApplyShaders -{ - public class ApplyShaderColorDenoiser : IShaderGenerator - { - private bool mShouldBreak; - public Schematic ApplyShader(Schematic schematic, ShaderStep shaderStep) - { - ShaderColorDenoiser shaderColorDenoiser = shaderStep as ShaderColorDenoiser; - for (int i = 0; i < shaderColorDenoiser.Iterations; i++) - { - Console.WriteLine("[INFO] Process iteration: " + i); - if (shaderColorDenoiser.StrictMode) - { - schematic = ProcessShaderColorDenoiserWithStrictMode(schematic); - } - else - { - schematic = ProcessShaderColorDenoiserWithColorRange(schematic, shaderColorDenoiser.ColorRange); - } - if (mShouldBreak) - { - break; - } - } - - return schematic; - } - - private Schematic ProcessShaderColorDenoiserWithStrictMode(Schematic schematic) - { - int colorChanged = 0; - int index = 0; - using (ProgressBar progressBar = new ProgressBar()) - { - List voxels = schematic.GetAllVoxels(); - foreach (Voxel voxel in voxels) - { - int x = voxel.X; - int y = voxel.Y; - int z = voxel.Z; - - uint left = schematic.GetColorAtVoxelIndex(x - 1, y, z); - uint right = schematic.GetColorAtVoxelIndex(x + 1, y, z); - - uint top = schematic.GetColorAtVoxelIndex(x, y + 1, z); - uint bottom = schematic.GetColorAtVoxelIndex(x, y - 1, z); - - uint front = schematic.GetColorAtVoxelIndex(x, y, z + 1); - uint back = schematic.GetColorAtVoxelIndex(x, y, z - 1); - progressBar.Report(index++ / (float)voxels.Count); - - - if (left == right && left == front && left == back && left != 0 && voxel.Color != left) - { - schematic.ReplaceVoxel(voxel, left); - colorChanged++; - continue; - } - - if (left == right && left == top && left == bottom && left != 0 && voxel.Color != left) - { - schematic.ReplaceVoxel(voxel, left); - colorChanged++; - continue; - } - - if (front == back && front == top && front == bottom && front != 0 && voxel.Color != front) - { - schematic.ReplaceVoxel(voxel, front); - colorChanged++; - continue; - } - } - } - - if (colorChanged == 0) - { - mShouldBreak = true; - Console.WriteLine("[INFO] NO COLORS CHANGED, BREAK"); - } - - Console.WriteLine("[INFO] Color changed: " + colorChanged); - Console.WriteLine("[INFO] Done."); - return schematic; - } - - private Schematic ProcessShaderColorDenoiserWithColorRange(Schematic schematic, int colorRange) - { - int colorChanged = 0; - int index = 0; - using (ProgressBar progressBar = new ProgressBar()) - { - List voxels = schematic.GetAllVoxels(); - foreach (Voxel voxel in voxels) - { - progressBar.Report(index++ / (float)voxels.Count); - - int x = voxel.X; - int y = voxel.Y; - int z = voxel.Z; - - Voxel left = null; - Voxel right= null; - Voxel top = null; - Voxel bottom= null; - Voxel front= null; - Voxel back= null; - - if (schematic.GetVoxel(x - 1, y, z, out Voxel v)) - { - left = v; - } - - if (schematic.GetVoxel(x + 1, y, z, out v)) - { - right = v; - } - - if (schematic.GetVoxel(x, y + 1, z, out v)) - { - top = v; - } - - if (schematic.GetVoxel(x, y - 1, z, out v)) - { - bottom = v; - } - - if (schematic.GetVoxel(x, y, z + 1, out v)) - { - front = v; - } - - if (schematic.GetVoxel(x, y, z - 1, out v)) - { - back = v; - } - - List list = new List() {right, left, top, bottom, front, back}; - list = list.Where(v => v != null).ToList(); - if (DistanceAverage(schematic, voxel, list) <= colorRange) - { - schematic.ReplaceVoxel(voxel, GetDominantColor(list)); - colorChanged++; - } - - - } - } - - if (colorChanged == 0) - { - mShouldBreak = true; - Console.WriteLine("[INFO] NO COLORS CHANGED, BREAK"); - } - - Console.WriteLine("[INFO] Color changed: " + colorChanged); - Console.WriteLine("[INFO] Done."); - return schematic; - } - - private uint GetDominantColor(List voxels) - { - Dictionary mostUsedColors = new Dictionary(); - foreach (Voxel voxel in voxels) - { - if (!mostUsedColors.ContainsKey(voxel.Color)) - { - mostUsedColors.Add(voxel.Color, 0); - } - mostUsedColors[voxel.Color]++; - } - - return mostUsedColors.OrderByDescending(t => t.Value).First().Key; - } - - private float DistanceAverage(Schematic schematic, Voxel currentVoxel, List voxels) - { - float sum = voxels.Where(v => v != null).Aggregate(0, (current, voxel) => current + Distance(schematic.GetPaletteIndex(currentVoxel.Color), schematic.GetPaletteIndex(voxel.Color))); - sum /= voxels.Count(v => v != null); - return sum; - } - - private int Distance(int currentVoxelColorIndex, int targetVoxelColorIndex) - { - return Math.Abs(currentVoxelColorIndex - targetVoxelColorIndex); - } - } -} diff --git a/SchematicToVoxCore/Generator/Shaders/ApplyShaders/ApplyShaderFill.cs b/SchematicToVoxCore/Generator/Shaders/ApplyShaders/ApplyShaderFill.cs deleted file mode 100644 index d2a2782..0000000 --- a/SchematicToVoxCore/Generator/Shaders/ApplyShaders/ApplyShaderFill.cs +++ /dev/null @@ -1,173 +0,0 @@ -using System; -using System.Collections.Generic; -using FileToVoxCommon.Generator.Shaders.Data; -using FileToVoxCore.Schematics; -using FileToVoxCore.Utils; - -namespace FileToVox.Generator.Shaders.ApplyShaders -{ - public class ApplyShaderFill : IShaderGenerator - { - public Schematic ApplyShader(Schematic schematic, ShaderStep shaderStep) - { - ShaderFill shaderFill = shaderStep as ShaderFill; - if (shaderFill.TargetColorIndex == -1) - { - schematic = ProcessSchematicInDeleteMode(schematic, shaderFill); - } - else - { - switch (shaderFill.RotationMode) - { - case RotationMode.X: - schematic = ProcessSchematicInXAxis(schematic, shaderFill); - break; - case RotationMode.Y: - schematic = ProcessSchematicInYAxis(schematic, shaderFill); - break; - case RotationMode.Z: - schematic = ProcessSchematicInZAxis(schematic, shaderFill); - break; - } - } - - return schematic; - } - - private Schematic ProcessSchematicInDeleteMode(Schematic schematic, ShaderFill shaderFill) - { - List allVoxels = schematic.GetAllVoxels(); - - using (ProgressBar progressBar = new ProgressBar()) - { - int index = 0; - foreach (Voxel voxel in allVoxels) - { - int x = voxel.X; - int y = voxel.Y; - int z = voxel.Z; - - bool shouldDelete = false; - switch (shaderFill.RotationMode) - { - case RotationMode.X: - shouldDelete = shaderFill.FillDirection == FillDirection.PLUS ? x >= shaderFill.Limit : x <= shaderFill.Limit; - break; - case RotationMode.Y: - shouldDelete = shaderFill.FillDirection == FillDirection.PLUS ? y >= shaderFill.Limit : y <= shaderFill.Limit; - break; - case RotationMode.Z: - shouldDelete = shaderFill.FillDirection == FillDirection.PLUS ? z >= shaderFill.Limit : z <= shaderFill.Limit; - break; - default: - throw new ArgumentOutOfRangeException(); - } - - if (shouldDelete) - { - schematic.RemoveVoxel(x, y, z); - } - - progressBar.Report(index++ / (float)allVoxels.Count); - } - } - - return schematic; - } - - private Schematic ProcessSchematicInXAxis(Schematic schematic, ShaderFill shaderFill) - { - int min = shaderFill.Limit; - uint color = schematic.GetColorAtPaletteIndex(shaderFill.TargetColorIndex); - for (int y = 0; y < schematic.Height; y++) - { - for (int z = 0; z < schematic.Length; z++) - { - if (shaderFill.FillDirection == FillDirection.PLUS) - { - for (int x = min; x < schematic.Width; x++) - { - schematic.AddVoxel(x, y, z, color, shaderFill.Replace); - } - } - else - { - for (int x = min; x >= 0; x--) - { - schematic.AddVoxel(x, y, z, color, shaderFill.Replace); - } - } - } - } - - return schematic; - } - - private Schematic ProcessSchematicInYAxis(Schematic schematic, ShaderFill shaderFill) - { - int min = shaderFill.Limit; - uint color = schematic.GetColorAtPaletteIndex(shaderFill.TargetColorIndex); - if (shaderFill.FillDirection == FillDirection.PLUS) - { - for (int y = min; y < schematic.Height; y++) - { - for (int z = 0; z < schematic.Length; z++) - { - for (int x = 0; x < schematic.Width; x++) - { - schematic.AddVoxel(x, y, z, color, shaderFill.Replace); - } - } - - } - } - else - { - for (int y = min; y >= 0; y--) - { - for (int z = 0; z < schematic.Length; z++) - { - for (int x = 0; x < schematic.Width; x++) - { - schematic.AddVoxel(x, y, z, color, shaderFill.Replace); - } - } - } - } - - return schematic; - } - - private Schematic ProcessSchematicInZAxis(Schematic schematic, ShaderFill shaderFill) - { - int min = shaderFill.Limit; - uint color = schematic.GetColorAtPaletteIndex(shaderFill.TargetColorIndex); - for (int y = 0; y < schematic.Height; y++) - { - if (shaderFill.FillDirection == FillDirection.PLUS) - { - for (int z = min; z < schematic.Length; z++) - { - for (int x = 0; x < schematic.Width; x++) - { - schematic.AddVoxel(x, y, z, color, shaderFill.Replace); - } - } - } - else - { - for (int z = min; z >= 0; z--) - { - for (int x = 0; x < schematic.Width; x++) - { - schematic.AddVoxel(x, y, z, color, shaderFill.Replace); - } - } - } - } - - - return schematic; - } - } -} diff --git a/SchematicToVoxCore/Generator/Shaders/ApplyShaders/ApplyShaderFillHoles.cs b/SchematicToVoxCore/Generator/Shaders/ApplyShaders/ApplyShaderFillHoles.cs deleted file mode 100644 index 13e270c..0000000 --- a/SchematicToVoxCore/Generator/Shaders/ApplyShaders/ApplyShaderFillHoles.cs +++ /dev/null @@ -1,303 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using FileToVoxCommon.Generator.Shaders.Data; -using FileToVoxCore.Schematics; -using FileToVoxCore.Utils; - -namespace FileToVox.Generator.Shaders -{ - public class ApplyShaderFixHoles : IShaderGenerator - { - private bool mShouldBreak; - public Schematic ApplyShader(Schematic schematic, ShaderStep shaderStep) - { - ShaderFixHoles shaderFixHoles = shaderStep as ShaderFixHoles; - for (int i = 0; i < shaderFixHoles.Iterations; i++) - { - Console.WriteLine("[INFO] Process iteration: " + i); - schematic = ProcessShaderFixHoles(schematic); - if (mShouldBreak) - { - break; - } - } - - return schematic; - } - - private Schematic ProcessShaderFixHoles(Schematic schematic) - { - List allVoxels = schematic.GetAllVoxels(); - int index = 0; - int fixedHoles = 0; - int total = (int)(schematic.RegionDict.Values.Count(region => region.BlockDict.Count > 0) * MathF.Pow(Schematic.CHUNK_SIZE, 3)); - Console.WriteLine("[INFO] Count voxel before: " + allVoxels.Count); - using (ProgressBar progressBar = new ProgressBar()) - { - foreach (Region region in schematic.RegionDict.Values.Where(region => region.BlockDict.Count > 0)) - { - for (int x = region.X; x < region.X + Schematic.CHUNK_SIZE; x++) - { - for (int y = region.Y; y < region.Y + Schematic.CHUNK_SIZE; y++) - { - for (int z = region.Z; z < region.Z + Schematic.CHUNK_SIZE; z++) - { - progressBar.Report(index++ / (float)total); - - if (!region.GetVoxel(x, y, z, out Voxel voxel)) - { - uint left = region.GetColorAtVoxelIndex(x - 1, y, z); - uint left2 = region.GetColorAtVoxelIndex(x - 2, y, z); - - uint right = region.GetColorAtVoxelIndex(x + 1, y, z); - uint right2 = region.GetColorAtVoxelIndex(x + 1, y, z); - - uint top = region.GetColorAtVoxelIndex(x, y + 1, z); - uint bottom = region.GetColorAtVoxelIndex(x, y - 1, z); - - uint front = region.GetColorAtVoxelIndex(x, y, z + 1); - uint front2 = region.GetColorAtVoxelIndex(x, y, z + 2); - - uint back = region.GetColorAtVoxelIndex(x, y, z - 1); - uint back2 = region.GetColorAtVoxelIndex(x, y, z - 2); - - //1x1 - if (left != 0 && right != 0 && front != 0 && back != 0) - { - schematic.AddVoxel(x, y, z, left); - fixedHoles++; - continue; - } - - if (left != 0 && right != 0 && top != 0 && bottom != 0) - { - schematic.AddVoxel(x, y, z, top); - fixedHoles++; - continue; - } - - if (front != 0 && back != 0 && top != 0 && bottom != 0) - { - schematic.AddVoxel(x, y, z, front); - fixedHoles++; - continue; - } - - //Edges horizontal bottom - if (left != 0 && right != 0 && bottom != 0 && front != 0) - { - schematic.AddVoxel(x, y, z, front); - fixedHoles++; - continue; - } - - if (left != 0 && right != 0 && bottom != 0 && back != 0) - { - schematic.AddVoxel(x, y, z, back); - fixedHoles++; - continue; - } - - if (front != 0 && back != 0 && bottom != 0 && left != 0) - { - schematic.AddVoxel(x, y, z, front); - fixedHoles++; - continue; - } - - if (front != 0 && back != 0 && bottom != 0 && right != 0) - { - schematic.AddVoxel(x, y, z, right); - fixedHoles++; - continue; - } - - //Edges horizontal top - if (left != 0 && right != 0 && top != 0 && front != 0) - { - schematic.AddVoxel(x, y, z, front); - fixedHoles++; - continue; - } - - if (left != 0 && right != 0 && top != 0 && back != 0) - { - schematic.AddVoxel(x, y, z, back); - fixedHoles++; - continue; - } - - if (front != 0 && back != 0 && top != 0 && left != 0) - { - schematic.AddVoxel(x, y, z, front); - fixedHoles++; - continue; - } - - if (front != 0 && back != 0 && top != 0 && right != 0) - { - schematic.AddVoxel(x, y, z, right); - fixedHoles++; - continue; - } - - - //Edges vertical (4) - if (left != 0 && top != 0 && bottom != 0 && front != 0) - { - schematic.AddVoxel(x, y, z, left); - fixedHoles++; - continue; - } - - if (left != 0 && top != 0 && bottom != 0 && back != 0) - { - schematic.AddVoxel(x, y, z, back); - fixedHoles++; - continue; - } - - if (right != 0 && top != 0 && bottom != 0 && front != 0) - { - schematic.AddVoxel(x, y, z, right); - fixedHoles++; - continue; - } - - if (right != 0 && top != 0 && bottom != 0 && back != 0) - { - schematic.AddVoxel(x, y, z, back); - fixedHoles++; - continue; - } - - /* - - ** - *10* - ** - - */ - - uint frontRight = region.GetColorAtVoxelIndex(x + 1, y, z + 1); - uint backRight = region.GetColorAtVoxelIndex(x + 1, y, z - 1); - - - if (left != 0 && front != 0 && right == 0 && right2 != 0 && back != 0 && frontRight != 0 && backRight != 0) - { - schematic.AddVoxel(x, y, z, left); - fixedHoles++; - continue; - } - - /* - - ** - *01* - ** - - */ - uint frontLeft = region.GetColorAtVoxelIndex(x - 1, y, z + 1); - uint backLeft = region.GetColorAtVoxelIndex(x - 1, y, z - 1); - - if (right != 0 && front != 0 && back != 0 && left == 0 && frontLeft != 0 && left2 != 0 && backLeft != 0) - { - schematic.AddVoxel(x, y, z, right); - fixedHoles++; - continue; - } - - /* - - * - *1* - *0* - * - - */ - - if (left != 0 && right != 0 && front != 0 && back == 0 && backLeft != 0 && backRight != 0 && back2 != 0) - { - schematic.AddVoxel(x, y, z, right); - fixedHoles++; - continue; - } - - /* - - * - *0* - *1* - * - - */ - - if (left != 0 && right != 0 && front == 0 && back != 0 && frontLeft != 0 && frontRight != 0 && front2 != 0) - { - schematic.AddVoxel(x, y, z, right); - fixedHoles++; - continue; - } - - /* - - ** - *10* - *00* - ** - - */ - - uint backRight2 = region.GetColorAtVoxelIndex(x + 2, y, z - 1); - uint back2Right = region.GetColorAtVoxelIndex(x + 1, y, z - 2); - - - if (left != 0 && front != 0 && right == 0 && frontRight != 0 && right2 != 0 && - back == 0 && backLeft != 0 && backRight == 0 && back2 != 0 && backRight2 != 0 && - back2Right != 0) - { - schematic.AddVoxel(x, y, z, left); - fixedHoles++; - continue; - } - - /* - - ** - *01* - *00* - ** - - */ - - uint backLeft2 = region.GetColorAtVoxelIndex(x - 2, y, z - 1); - uint back2Left = region.GetColorAtVoxelIndex(x - 1, y, z - 2); - - if (right != 0 && front != 0 && left == 0 && left2 != 0 && frontLeft != 0 && - back == 0 && backRight != 0 && backLeft == 0 && backLeft2 != 0 && back2 != 0 && - back2Left != 0) - { - schematic.AddVoxel(x, y, z, right); - fixedHoles++; - continue; - } - } - } - } - } - } - } - - if (fixedHoles == 0) - { - mShouldBreak = true; - Console.WriteLine("[INFO] NO VOXEL CHANGED, BREAK"); - } - - Console.WriteLine("[INFO] Fixed holes: " + fixedHoles); - Console.WriteLine("[INFO] Done."); - return schematic; - } - } -} diff --git a/SchematicToVoxCore/Generator/Shaders/ApplyShaders/ApplyShaderLonely.cs b/SchematicToVoxCore/Generator/Shaders/ApplyShaders/ApplyShaderLonely.cs deleted file mode 100644 index 8edae0c..0000000 --- a/SchematicToVoxCore/Generator/Shaders/ApplyShaders/ApplyShaderLonely.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using FileToVoxCommon.Generator.Shaders.Data; -using FileToVoxCore.Schematics; -using FileToVoxCore.Utils; - -namespace FileToVox.Generator.Shaders -{ - public class ApplyShaderFixLonely : IShaderGenerator - { - public Schematic ApplyShader(Schematic schematic, ShaderStep shaderStep) - { - List allVoxels = schematic.GetAllVoxels(); - - int index = 0; - using (ProgressBar progressBar = new ProgressBar()) - { - foreach (Voxel voxel in allVoxels) - { - int x = voxel.X; - int y = voxel.Y; - int z = voxel.Z; - - if (x == 0 || y == 0 || z == 0) - continue; - - if (schematic.GetColorAtVoxelIndex(x - 1, y, z) == 0 - && schematic.GetColorAtVoxelIndex(x + 1, y, z) == 0 - && schematic.GetColorAtVoxelIndex(x, y - 1, z) == 0 - && schematic.GetColorAtVoxelIndex(x, y + 1, z) == 0 - && schematic.GetColorAtVoxelIndex(x, y, z - 1) == 0 - && schematic.GetColorAtVoxelIndex(x, y, z + 1) == 0) - { - schematic.RemoveVoxel(x, y, z); - } - - progressBar.Report(index++ / (float)allVoxels.Count); - - } - } - Console.WriteLine("[INFO] Done."); - return schematic; - } - - } -} diff --git a/SchematicToVoxCore/Generator/Shaders/ApplyShaders/ApplyShaderPatina.cs b/SchematicToVoxCore/Generator/Shaders/ApplyShaders/ApplyShaderPatina.cs deleted file mode 100644 index 2813fa3..0000000 --- a/SchematicToVoxCore/Generator/Shaders/ApplyShaders/ApplyShaderPatina.cs +++ /dev/null @@ -1,306 +0,0 @@ -using System; -using System.Collections.Generic; -using FileToVoxCommon.Generator.Shaders.Data; -using FileToVoxCore.Schematics; -using FileToVoxCore.Utils; - -namespace FileToVox.Generator.Shaders -{ - // Based on Patina by @Patrick Seeber : https://github.com/patStar/voxelShader/blob/master/shader/patina.txt - public class ApplyShaderPatina : IShaderGenerator - { - private bool mShouldBreak; - private ShaderPatina mShaderPatina; - - public Schematic ApplyShader(Schematic schematic, ShaderStep shaderStep) - { - mShaderPatina = shaderStep as ShaderPatina; - for (int i = 0; i < mShaderPatina.Iterations; i++) - { - Console.WriteLine("[INFO] Process iteration: " + i); - schematic = ProcessShaderPatina(schematic); - if (mShouldBreak) - { - break; - } - } - - Console.WriteLine("[INFO] Done."); - return schematic; - } - - - private Schematic ProcessShaderPatina(Schematic schematic) - { - using (ProgressBar progressBar = new ProgressBar()) - { - int index = 0; - List allVoxels = schematic.GetAllVoxels(); - int colorChanged = 0; - foreach (Voxel voxel in allVoxels) - { - if (Grows(schematic, voxel)) - { - uint newColor = GetCrowColor(schematic, voxel); - if (voxel.Color != newColor) - { - schematic.ReplaceVoxel(voxel, newColor); - colorChanged++; - } - } - - progressBar.Report(index++ / (float)(allVoxels.Count)); - } - Console.WriteLine("COLOR CHANGED: " + colorChanged); - - if (colorChanged == 0) - { - mShouldBreak = true; - Console.WriteLine("[INFO] NO COLORS CHANGED, BREAK"); - } - } - - return schematic; - } - - private bool IsGrowColor(Schematic schematic, Voxel voxel) - { - int paletteIndex = schematic.GetPaletteIndex(voxel.Color); - return paletteIndex >= MathF.Min(mShaderPatina.TargetColorIndex, mShaderPatina.TargetColorIndex + mShaderPatina.AdditionalColorRange) && paletteIndex <= MathF.Max(mShaderPatina.TargetColorIndex, mShaderPatina.TargetColorIndex + mShaderPatina.AdditionalColorRange); - } - - private float Random(Voxel voxel, float seed) - { - int x = voxel.X + 1; - int y = voxel.Y + 1; - int z = voxel.Z + 1; - float n = x * y * z + seed; - return MathF.Abs(Fract(MathF.Sin((1 / MathF.Tan(n) + seed * 1235.342f)))); - } - - private float Fract(float value) - { - float result = value - MathF.Floor(value); - return result; - } - - private float MinDistanceToWall(Schematic schematic, Voxel voxel, int distance) - { - float minDistance = distance + 1; - - for (int x = -distance; x <= distance; x++) - { - for (int y = -distance; y <= distance; y++) - { - for (int z = -distance; z <= distance; z++) - { - if (schematic.GetVoxel(voxel.X + x, voxel.Y + y, voxel.Z + z, out Voxel foundVoxel)) - { - if (!IsGrowColor(schematic, foundVoxel)) - { - float d = MathF.Sqrt(MathF.Pow(x, 2) + MathF.Pow(y, 2) + MathF.Pow(z, 2)); - if (minDistance > d) - { - minDistance = d; - } - } - } - } - } - } - - return minDistance; - } - - private uint GetCrowColor(Schematic schematic, Voxel voxel) - { - float distance = MinDistanceToWall(schematic, voxel, mShaderPatina.Thickness); - float index = mShaderPatina.TargetColorIndex + mShaderPatina.AdditionalColorRange * (distance / MathF.Sqrt(MathF.Pow(mShaderPatina.Thickness, 2) * 3)); - return schematic.GetColorAtPaletteIndex((int)index); - } - private bool HasWallNextToIt(Schematic schematic, Voxel voxel, int distance) - { - for (int x = -distance; x <= distance; x++) - { - for (int y = -distance; y <= distance; y++) - { - for (int z = -distance; z <= distance; z++) - { - if (schematic.GetVoxel(voxel.X + x, voxel.Y + y, voxel.Z + z, out Voxel foundVoxel)) - { - if (!IsGrowColor(schematic, foundVoxel)) - { - return true; - } - } - } - } - } - - return false; - } - - private int GetFlatNeighbors(Schematic schematic, Voxel voxel) - { - int neighbors = 0; - - if (schematic.GetVoxel(voxel.X + 1, voxel.Y, voxel.Z + 1, out Voxel foundVoxel) && IsGrowColor(schematic, foundVoxel)) - { - neighbors++; - } - - if (schematic.GetVoxel(voxel.X + 1, voxel.Y, voxel.Z - 1, out foundVoxel) && IsGrowColor(schematic, foundVoxel)) - { - neighbors++; - } - - if (schematic.GetVoxel(voxel.X - 1, voxel.Y, voxel.Z + 1, out foundVoxel) && IsGrowColor(schematic, foundVoxel)) - { - neighbors++; - } - - if (schematic.GetVoxel(voxel.X - 1, voxel.Y, voxel.Z - 1, out foundVoxel) && IsGrowColor(schematic, foundVoxel)) - { - neighbors++; - } - - if (schematic.GetVoxel(voxel.X + 1, voxel.Y, voxel.Z, out foundVoxel) && IsGrowColor(schematic, foundVoxel)) - { - neighbors++; - } - - if (schematic.GetVoxel(voxel.X - 1, voxel.Y, voxel.Z, out foundVoxel) && IsGrowColor(schematic, foundVoxel)) - { - neighbors++; - } - - if (schematic.GetVoxel(voxel.X, voxel.Y - 1, voxel.Z, out foundVoxel) && IsGrowColor(schematic, foundVoxel)) - { - neighbors++; - } - - if (schematic.GetVoxel(voxel.X, voxel.Y + 1, voxel.Z, out foundVoxel) && IsGrowColor(schematic, foundVoxel)) - { - neighbors++; - } - - return neighbors; - } - - private int GetNeighbors(Schematic schematic, Voxel voxel) - { - int neighbors = 0; - - if (schematic.GetVoxel(voxel.X, voxel.Y + 1, voxel.Z, out Voxel foundVoxel) && IsGrowColor(schematic, foundVoxel)) - { - neighbors++; - } - - if (schematic.GetVoxel(voxel.X, voxel.Y - 1, voxel.Z, out foundVoxel) && IsGrowColor(schematic, foundVoxel)) - { - neighbors++; - } - - if (schematic.GetVoxel(voxel.X + 1, voxel.Y, voxel.Z, out foundVoxel) && IsGrowColor(schematic, foundVoxel)) - { - neighbors++; - } - - if (schematic.GetVoxel(voxel.X - 1, voxel.Y, voxel.Z, out foundVoxel) && IsGrowColor(schematic, foundVoxel)) - { - neighbors++; - } - - if (schematic.GetVoxel(voxel.X, voxel.Y, voxel.Z - 1, out foundVoxel) && IsGrowColor(schematic, foundVoxel)) - { - neighbors++; - } - - if (schematic.GetVoxel(voxel.X, voxel.Y, voxel.Z + 1, out foundVoxel) && IsGrowColor(schematic, foundVoxel)) - { - neighbors++; - } - - return neighbors; - } - - private bool GrowsDown(Schematic schematic, Voxel voxel) - { - if (schematic.GetVoxel(voxel.X, voxel.Y + 1, voxel.Z, out Voxel foundVoxel) && IsGrowColor(schematic, foundVoxel)) - { - return true; - } - - if (schematic.GetVoxel(voxel.X + 1, voxel.Y, voxel.Z, out foundVoxel) && IsGrowColor(schematic, foundVoxel)) - { - return true; - } - - if (schematic.GetVoxel(voxel.X - 1, voxel.Y, voxel.Z, out foundVoxel) && IsGrowColor(schematic, foundVoxel)) - { - return true; - } - - if (schematic.GetVoxel(voxel.X, voxel.Y, voxel.Z - 1, out foundVoxel) && IsGrowColor(schematic, foundVoxel)) - { - return true; - } - - if (schematic.GetVoxel(voxel.X, voxel.Y, voxel.Z + 1, out foundVoxel) && IsGrowColor(schematic, foundVoxel)) - { - return true; - } - - return false; - } - - private bool Grows(Schematic schematic, Voxel voxel) - { - int neighbors = GetNeighbors(schematic, voxel); - float r = Random(voxel, mShaderPatina.Seed + neighbors); - - if (HasWallNextToIt(schematic, voxel, 1)) - { - int x = voxel.X + 1; - int z = voxel.Z + 1; - if (schematic.GetVoxel(voxel.X, voxel.Y - 1, voxel.Z, out Voxel foundVoxel) && IsGrowColor(schematic, foundVoxel) && (x + z) % 13 == 0) - { - return true; - } - - if (schematic.GetVoxel(voxel.X, voxel.Y + 1, voxel.Z, out foundVoxel) && IsGrowColor(schematic, foundVoxel) && (x + z) % 27 == 0) - { - return true; - } - - if (schematic.GetVoxel(voxel.X, voxel.Y - 2, voxel.Z, out foundVoxel) && IsGrowColor(schematic, foundVoxel) && (x + z) % 13 == 0) - { - return true; - } - - if (schematic.GetVoxel(voxel.X, voxel.Y + 2, voxel.Z, out foundVoxel) && IsGrowColor(schematic, foundVoxel) && (x + z) % 27 == 0) - { - return true; - } - - if (GetFlatNeighbors(schematic, voxel) > 3) - { - return true; - } - } - - if (r < mShaderPatina.Density - MinDistanceToWall(schematic, voxel, mShaderPatina.Thickness) / mShaderPatina.Thickness * (mShaderPatina.Density / 2) - && HasWallNextToIt(schematic, voxel, mShaderPatina.Thickness) - && neighbors > 0 - && (GrowsDown(schematic, voxel) || Random(voxel, mShaderPatina.Seed + 5.567f) < 0.3f)) - { - return true; - } - - return false; - - } - - - } -} diff --git a/SchematicToVoxCore/Generator/Shaders/IShaderGenerator.cs b/SchematicToVoxCore/Generator/Shaders/IShaderGenerator.cs deleted file mode 100644 index d0bd876..0000000 --- a/SchematicToVoxCore/Generator/Shaders/IShaderGenerator.cs +++ /dev/null @@ -1,10 +0,0 @@ -using FileToVoxCommon.Generator.Shaders.Data; -using FileToVoxCore.Schematics; - -namespace FileToVox.Generator.Shaders -{ - public interface IShaderGenerator - { - Schematic ApplyShader(Schematic schematic, ShaderStep shaderStep); - } -} diff --git a/SchematicToVoxCore/Generator/Shaders/ShaderGenerator.cs b/SchematicToVoxCore/Generator/Shaders/ShaderGenerator.cs deleted file mode 100644 index ef135e6..0000000 --- a/SchematicToVoxCore/Generator/Shaders/ShaderGenerator.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using FileToVoxCommon.Generator.Shaders.Data; -using FileToVoxCore.Schematics; - -namespace FileToVox.Generator.Shaders -{ - public class ShaderGenerator : IGenerator - { - private ShaderData mShaderData; - private Schematic mSchematic; - - public ShaderGenerator(ShaderData shaderData, Schematic schematic) - { - mShaderData = shaderData; - mSchematic = schematic; - } - - public Schematic WriteSchematic() - { - if (mSchematic == null) - { - Console.WriteLine("[WARNING] Current schematic is null"); - mSchematic = new Schematic(); - } - - Console.WriteLine("[INFO] Count steps: " + mShaderData.Steps.Length); - for (int index = 0; index < mShaderData.Steps.Length; index++) - { - Console.WriteLine("[INFO] Start parse shader for step : " + index); - ShaderStep step = mShaderData.Steps[index]; - step.ValidateSettings(); - step.DisplayInfo(); - - mSchematic = ShaderUtils.ApplyShader(mSchematic, step); - } - - return mSchematic; - } - } -} diff --git a/SchematicToVoxCore/Generator/Shaders/ShaderUtils.cs b/SchematicToVoxCore/Generator/Shaders/ShaderUtils.cs deleted file mode 100644 index 74c0541..0000000 --- a/SchematicToVoxCore/Generator/Shaders/ShaderUtils.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using FileToVox.Generator.Shaders.ApplyShaders; -using FileToVoxCommon.Generator.Shaders.Data; -using FileToVoxCore.Schematics; - -namespace FileToVox.Generator.Shaders -{ - public static class ShaderUtils - { - #region PublicMethods - - public static Schematic ApplyShader(Schematic schematic, ShaderStep shaderStep) - { - IShaderGenerator shaderGenerator; - - switch (shaderStep.ShaderType) - { - case ShaderType.FIX_HOLES: - shaderGenerator = new ApplyShaderFixHoles(); - break; - case ShaderType.FIX_LONELY: - shaderGenerator = new ApplyShaderFixLonely(); - break; - case ShaderType.CASE: - shaderGenerator = new ApplyShaderCase(); - break; - case ShaderType.PATINA: - shaderGenerator = new ApplyShaderPatina(); - break; - case ShaderType.COLOR_DENOISER: - shaderGenerator = new ApplyShaderColorDenoiser(); - break; - case ShaderType.FILL: - shaderGenerator = new ApplyShaderFill(); - break; - default: - throw new NotImplementedException(); - } - - return shaderGenerator.ApplyShader(schematic, shaderStep); - } - - - - #endregion - - } -} diff --git a/SchematicToVoxCore/Generator/Terrain/Chunk/VoxelChunk.cs b/SchematicToVoxCore/Generator/Terrain/Chunk/VoxelChunk.cs deleted file mode 100644 index c7dd1b2..0000000 --- a/SchematicToVoxCore/Generator/Terrain/Chunk/VoxelChunk.cs +++ /dev/null @@ -1,127 +0,0 @@ -using FileToVoxCore.Schematics; -using FileToVoxCore.Schematics.Tools; - -namespace FileToVox.Generator.Terrain.Chunk -{ - public class VoxelChunk - { - public Voxel[] Voxels; - public Vector3 Position; - - private VoxelChunk mTop; - private VoxelChunk mBottom; - private VoxelChunk mLeft; - private VoxelChunk mForward; - private VoxelChunk mRight; - private VoxelChunk mBack; - - public VoxelChunk Top - { - get - { - if (mTop == null) - { - Vector3 topPosition = Position; - topPosition.Y += TerrainEnvironment.CHUNK_SIZE; - TerrainEnvironment.Instance.GetChunk(topPosition, out mTop); - if (mTop != null) - mTop.mBottom = this; - } - return mTop; - } - set => mTop = value; - } - - - public VoxelChunk Bottom - { - get - { - if (mBottom == null) - { - Vector3 bottomPosition = Position; - bottomPosition.Y -= TerrainEnvironment.CHUNK_SIZE; - TerrainEnvironment.Instance.GetChunk(bottomPosition, out mBottom, false); - if (mBottom != null) - mBottom.mTop = this; - } - return mBottom; - } - set => mBottom = value; - } - - - public VoxelChunk Left - { - get - { - if (mLeft == null) - { - Vector3 leftPosition = Position; - leftPosition.X -= TerrainEnvironment.CHUNK_SIZE; - TerrainEnvironment.Instance.GetChunk(leftPosition, out mLeft, false); - if (mLeft != null) - mLeft.mRight = this; - } - return mLeft; - } - set => mLeft = value; - } - - - public VoxelChunk Right - { - get - { - if (mRight == null) - { - Vector3 rightPosition = Position; - rightPosition.X += TerrainEnvironment.CHUNK_SIZE; - TerrainEnvironment.Instance.GetChunk(rightPosition, out mRight, false); - if (mRight != null) - mRight.mLeft = this; - } - return mRight; - } - set => mRight = value; - } - - - public VoxelChunk Forward - { - get - { - if (mForward == null) - { - Vector3 forwardPosition = Position; - forwardPosition.Z += TerrainEnvironment.CHUNK_SIZE; - TerrainEnvironment.Instance.GetChunk(forwardPosition, out mForward, false); - if (mForward != null) - mForward.mBack = this; - } - return mForward; - } - set => mForward = value; - } - - - public VoxelChunk Back - { - get - { - if (mBack == null) - { - Vector3 backPosition = Position; - backPosition.Z -= TerrainEnvironment.CHUNK_SIZE; - TerrainEnvironment.Instance.GetChunk(backPosition, out mBack, false); - if (mBack != null) - mBack.mForward = this; - } - return mBack; - } - set => mBack = value; - } - - - } -} diff --git a/SchematicToVoxCore/Generator/Terrain/Data/BiomeSettings.cs b/SchematicToVoxCore/Generator/Terrain/Data/BiomeSettings.cs deleted file mode 100644 index e1c47fc..0000000 --- a/SchematicToVoxCore/Generator/Terrain/Data/BiomeSettings.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System; -using FileToVoxCore.Drawing; -using Newtonsoft.Json; - -namespace FileToVox.Generator.Terrain.Data -{ - [Serializable] - public struct BiomeZone - { - public float AltitudeMin { get; set; } - public float AltitudeMax { get; set; } - public float MoistureMin { get; set; } - public float MoistureMax { get; set; } - - [JsonIgnore] - public BiomeSettings Biome; - } - - [Serializable] - public struct BiomeTree - { - public ModelSettings Bits { get; set; } - public float Probability { get; set; } - } - - public struct BiomeVegetation - { - public Color Color { get; set; } - public float Probability { get; set; } - } - - [Serializable] - public class BiomeSettings : FileToVoxCommon.Generator.StepData.StepData - { - public BiomeZone[] Zones { get; set; } - public Color VoxelTop { get; set; } - public Color VoxelDirt { get; set; } - - public float TreeDensity { get; set; } - public BiomeTree[] Trees { get; set; } - - public float VegetationDensity { get; set; } - public BiomeVegetation[] Vegetation { get; set; } - - [JsonIgnore] public int BiomeGeneration; - public void ValidateSettings(WorldTerrainData world) - { - if (Trees == null) - { - Trees = new BiomeTree[0]; - } - - if (Vegetation == null) - { - Vegetation = new BiomeVegetation[0]; - } - - if (Zones != null) - { - for (int i = 0; i < Zones.Length; i++) - { - BiomeZone zone = Zones[i]; - zone.Biome = this; - - if (zone.MoistureMin == 0 && zone.MoistureMax == 0) - { - zone.MoistureMax = 1; - } - - Zones[i] = zone; - } - } - - } - } -} diff --git a/SchematicToVoxCore/Generator/Terrain/Data/ModelSettings.cs b/SchematicToVoxCore/Generator/Terrain/Data/ModelSettings.cs deleted file mode 100644 index 721d2b1..0000000 --- a/SchematicToVoxCore/Generator/Terrain/Data/ModelSettings.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Drawing; - -namespace FileToVox.Generator.Terrain.Data -{ - public class ModelSettings - { - public int SizeX { get; set; } - public int SizeY { get; set; } - public int SizeZ { get; set; } - - public int OffsetX { get; set; } - public int OffsetY { get; set; } - public int OffsetZ { get; set; } - - public ModelBit[] Bits { get; set; } - } - - [Serializable] - public struct ModelBit - { - public int VoxelIndex { get; set; } - public Color Color { get; set; } - public bool IsEmpty { get; set; } - - } -} diff --git a/SchematicToVoxCore/Generator/Terrain/Data/TerrainGeneratorDataSettings.cs b/SchematicToVoxCore/Generator/Terrain/Data/TerrainGeneratorDataSettings.cs deleted file mode 100644 index 0c449fb..0000000 --- a/SchematicToVoxCore/Generator/Terrain/Data/TerrainGeneratorDataSettings.cs +++ /dev/null @@ -1,77 +0,0 @@ -using FileToVoxCore.Drawing; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; - -namespace FileToVox.Generator.Terrain.Data -{ - public enum TerrainStepType - { - SampleHeightMapTexture, - SampleRidgeNoiseFromTexture, - Constant, - Copy, - Random, - Invert, - Shift, - BeachMask, - AddAndMultiply, - MultiplyAndAdd, - Exponential, - Threshold, - FlattenOrRaise, - BlendAdditive, - BlendMultiply, - Clamp, - Select, - Fill - } - - public struct StepData - { - public bool Enabled { get; set; } - - [JsonConverter(typeof(StringEnumConverter))] - public TerrainStepType OperationType { get; set; } - public string NoiseTexturePath { get; set; } - public float Frequency { get; set; } - public float NoiseRangeMin { get; set; } - public float NoiseRangeMax { get; set; } - public int InputIndex0 { get; set; } - public int InputIndex1 { get; set; } - public float Threshold { get; set; } - public float ThresholdShift { get; set; } - public float ThresholdParam { get; set; } - public float Param { get; set; } - public float Param2 { get; set; } - public float Weight0 { get; set; } - public float Weight1 { get; set; } - public float Min { get; set; } - public float Max { get; set; } - - [JsonIgnore] public float[] NoiseValues { get; set; } - [JsonIgnore] public int NoiseTextureSize { get; set; } - [JsonIgnore] public float Value { get; set; } - [JsonIgnore] public string LastTextureLoaded { get; set; } - } - - public class TerrainGeneratorDataSettings - { - #region Fields - - public float MaxHeight { get; set; } = 100; - public float MinHeight { get; set; } - public int WaterLevel { get; set; } = 25; - public StepData[] Steps { get; set; } - public float SeaDepthMultiplier { get; set; } - public float BeachWidth { get; set; } = 0.001f; - public Color WaterColor { get; set; } - public Color ShoreColor { get; set; } - public Color BedrockColor { get; set; } - public string MoisturePath { get; set; } - public float MoistureScale { get; set; } = 0.2f; - - - - #endregion - } -} diff --git a/SchematicToVoxCore/Generator/Terrain/Data/WorldTerrainData.cs b/SchematicToVoxCore/Generator/Terrain/Data/WorldTerrainData.cs deleted file mode 100644 index 1eb8044..0000000 --- a/SchematicToVoxCore/Generator/Terrain/Data/WorldTerrainData.cs +++ /dev/null @@ -1,21 +0,0 @@ -using FileToVoxCommon.Json; -using Newtonsoft.Json; - -namespace FileToVox.Generator.Terrain.Data -{ - public class WorldTerrainData : JsonBaseImportData - { - public override GeneratorType GeneratorType { get; set; } = GeneratorType.Terrain; - public int Width { get; set; } - public int Length { get; set; } - - public int Seed { get; set; } - public BiomeSettings[] Biomes { get; set; } - - public BiomeSettings DefaultBiome { get; set; } - - public TerrainGeneratorDataSettings TerrainGeneratorDataSettings { get; set; } - - [JsonIgnore] public string DirectoryPath { get; set; } - } -} diff --git a/SchematicToVoxCore/Generator/Terrain/Entities/CachedChunk.cs b/SchematicToVoxCore/Generator/Terrain/Entities/CachedChunk.cs deleted file mode 100644 index 3503971..0000000 --- a/SchematicToVoxCore/Generator/Terrain/Entities/CachedChunk.cs +++ /dev/null @@ -1,9 +0,0 @@ -using FileToVox.Generator.Terrain.Chunk; - -namespace FileToVox.Generator.Terrain.Entities -{ - public class CachedChunk - { - public VoxelChunk Chunk; - } -} diff --git a/SchematicToVoxCore/Generator/Terrain/Environment/Chunk.cs b/SchematicToVoxCore/Generator/Terrain/Environment/Chunk.cs deleted file mode 100644 index ef94349..0000000 --- a/SchematicToVoxCore/Generator/Terrain/Environment/Chunk.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System.Runtime.CompilerServices; -using FileToVox.Generator.Terrain.Chunk; -using FileToVox.Generator.Terrain.Entities; -using FileToVoxCore.Schematics; -using FileToVoxCore.Schematics.Tools; - -namespace FileToVox.Generator.Terrain -{ - public partial class TerrainEnvironment - { - private readonly object mLockLastChunkFetch = new object(); - private int mLastChunkFetchX, mLastChunkFetchY, mLastChunkFetchZ; - private VoxelChunk mLastChunkFetch; - - private VoxelChunk CreateChunk(int hash, int chunkX, int chunkY, int chunkZ) - { - Vector3 position = new Vector3(chunkX * CHUNK_SIZE + CHUNK_HALF_SIZE, chunkY * CHUNK_SIZE + CHUNK_HALF_SIZE, chunkZ * CHUNK_SIZE + CHUNK_HALF_SIZE); - - if (!mCachedChunks.TryGetValue(hash, out CachedChunk cachedChunk)) - { - cachedChunk = new CachedChunk(); - mCachedChunks[hash] = cachedChunk; - } - - VoxelChunk chunk = new VoxelChunk(); - chunk.Voxels = new Voxel[CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE]; - for (int i = 0; i < chunk.Voxels.Length; i++) - { - chunk.Voxels[i] = new Voxel(); - } - - chunk.Position = position; - - (WorldTerrainData.TerrainGeneratorDataSettings as TerrainGeneratorSettings).PaintChunk(chunk); - cachedChunk.Chunk = chunk; - return chunk; - } - - [MethodImpl(256)] // equals to MethodImplOptions.AggressiveInlining - private int GetChunkHash(int chunkX, int chunkY, int chunkZ) - { - int x00 = Schematic.MAX_WORLD_LENGTH * Schematic.MAX_WORLD_HEIGHT * (chunkX + Schematic.MAX_WORLD_WIDTH); - int y00 = Schematic.MAX_WORLD_LENGTH * (chunkY + Schematic.MAX_WORLD_HEIGHT); - return x00 + y00 + chunkZ; - } - - private bool GetChunkFast(int chunkX, int chunkY, int chunkZ, out VoxelChunk chunk, bool createIfNotAvailable = false) - { - lock (mLockLastChunkFetch) - { - if (mLastChunkFetchX == chunkX && mLastChunkFetchY == chunkY && mLastChunkFetchZ == chunkZ && mLastChunkFetch != null) - { - chunk = mLastChunkFetch; - return true; - } - } - int hash = GetChunkHash(chunkX, chunkY, chunkZ); - bool exists = mCachedChunks.TryGetValue(hash, out CachedChunk cachedChunk); - chunk = exists ? cachedChunk.Chunk : null; - - if (createIfNotAvailable) - { - if (!exists) - { - chunk = CreateChunk(hash, chunkX, chunkY, chunkZ); - exists = true; - } - if (chunk == null) - { - chunk = CreateChunk(hash, chunkX, chunkY, chunkZ); - } - } - if (exists) - { - lock (mLockLastChunkFetch) - { - mLastChunkFetchX = chunkX; - mLastChunkFetchY = chunkY; - mLastChunkFetchZ = chunkZ; - mLastChunkFetch = chunk; - } - return chunk != null; - } - chunk = null; - return false; - } - } -} diff --git a/SchematicToVoxCore/Generator/Terrain/Environment/ChunksManager.cs b/SchematicToVoxCore/Generator/Terrain/Environment/ChunksManager.cs deleted file mode 100644 index fee23f7..0000000 --- a/SchematicToVoxCore/Generator/Terrain/Environment/ChunksManager.cs +++ /dev/null @@ -1,261 +0,0 @@ -using FileToVox.Generator.Terrain.Entities; -using FileToVox.Generator.Terrain.Utility; -using System; -using System.Collections.Generic; -using FileToVoxCore.Schematics; -using FileToVoxCore.Schematics.Tools; -using FileToVoxCore.Utils; -using BiomeSettings = FileToVox.Generator.Terrain.Data.BiomeSettings; -using BiomeZone = FileToVox.Generator.Terrain.Data.BiomeZone; -using TerrainGeneratorDataSettings = FileToVox.Generator.Terrain.Data.TerrainGeneratorDataSettings; - -namespace FileToVox.Generator.Terrain -{ - public class BiomeLookUp - { - public BiomeZone Zone; - public bool UniqueZone; - public List OverlappingZones = new List(); - - public BiomeLookUp(BiomeZone biome, bool uniqueZone) - { - Zone = biome; - UniqueZone = uniqueZone; - } - - public BiomeSettings GetBiome(float altitude, float moisture) - { - if (UniqueZone) - { - return Zone.Biome; - } - - for (int i = 0; i < OverlappingZones.Count; i++) - { - if (altitude >= OverlappingZones[i].AltitudeMin && altitude < OverlappingZones[i].AltitudeMax && - moisture >= OverlappingZones[i].MoistureMin && moisture < OverlappingZones[i].MoistureMax) - { - return OverlappingZones[i].Biome; - } - } - - return Zone.Biome; - } - } - - public struct HeightMapInfo - { - public float Moisture; - public int GroundLevel; - public BiomeSettings Biome; - } - - public partial class TerrainEnvironment - { - #region Fields - private Dictionary mCachedChunks; - private int mVisibleXMin, mVisibleXMax, mVisibleYMin, mVisibleYMax, mVisibleZMin, mVisibleZMax; - - private HeightMapCache mHeightMapCache; - private BiomeLookUp[] mBiomeLookUps; - #endregion - - #region PublicMethods - - public void InitChunkManager() - { - mCachedChunks = new Dictionary(); - - InitHeightMap(); - InitBiomes(); - - NoiseTools.SeedOffset = WorldRandom.GetVector3(Vector3.zero, 1024); - - if (WorldTerrainData != null) - { - if (WorldTerrainData.TerrainGeneratorDataSettings == null) - { - WorldTerrainData.TerrainGeneratorDataSettings = new TerrainGeneratorDataSettings(); //TODO - } - - (WorldTerrainData.TerrainGeneratorDataSettings as TerrainGeneratorSettings).Initialize(); - } - } - - public void DisposeAll() - { - mLastChunkFetch = null; - - if (mCachedChunks != null) - { - mCachedChunks.Clear(); - mCachedChunks = null; - } - - // Clear heightmap - mHeightMapCache?.Clear(); - } - - public void CheckChunksInRange() - { - //MV has a max size of 2000x2000 - int width = Math.Min(Math.Max(WorldTerrainData.Width, WorldTerrainData.Length), Schematic.MAX_WORLD_WIDTH); - int chunkXZDistance = (width / CHUNK_SIZE) / 2; - int chunkYDistance = (Schematic.MAX_WORLD_HEIGHT / CHUNK_SIZE) / 2; - - mVisibleXMin = -chunkXZDistance; - mVisibleXMax = chunkXZDistance; - - mVisibleZMin = -chunkXZDistance; - mVisibleZMax = chunkXZDistance; - - mVisibleYMin = -chunkYDistance; - mVisibleYMax = chunkYDistance; - CheckNewNearChunks(); - } - - public void GetHeightMapInfo(float x, float z, HeightMapInfo[] heightChunkData) - { - int ix = FastMath.FloorToInt(x); - int iz = FastMath.FloorToInt(z); - - TerrainGeneratorDataSettings tg = WorldTerrainData.TerrainGeneratorDataSettings; - for (int zz = 0; zz < CHUNK_SIZE; zz++) - { - for (int xx = 0; xx < CHUNK_SIZE; xx++) - { - if (!mHeightMapCache.TryGetValue(ix + xx, iz + zz, out HeightMapInfo[] heights, out int heightsIndex)) - { - (tg as TerrainGeneratorSettings).GetHeightAndMoisture(ix + xx, iz + zz, out float altitude, out float moisture); - if (altitude > 1f) - altitude = 1f; - else if (altitude < 0f) - altitude = 0f; - if (moisture > 1f) - moisture = 1f; - else if (moisture < 0f) - moisture = 0f; - int biomeIndex = (int)(altitude * 20) * 21 + (int)(moisture * 20f); - float groundLevel = altitude * tg.MaxHeight; - heights[heightsIndex].GroundLevel = (int)groundLevel; - heights[heightsIndex].Moisture = moisture; - heights[heightsIndex].Biome = mBiomeLookUps[biomeIndex].GetBiome(groundLevel, moisture); - } - heightChunkData[zz * CHUNK_SIZE + xx] = heights[heightsIndex]; - } - } - } - - #endregion - - #region PrivateMethods - - private void InitHeightMap() - { - int poolSize = (30 + 10) * 2 * CHUNK_SIZE / 128 + 1; - poolSize *= poolSize; - mHeightMapCache = new HeightMapCache(poolSize); - } - - private void InitBiomes() - { - mBiomeLookUps = new BiomeLookUp[441]; - if (WorldTerrainData == null) - return; - - if (WorldTerrainData.Biomes == null || WorldTerrainData.Biomes.Length == 0) - { - WorldTerrainData.DefaultBiome = new BiomeSettings(); //TODO - } - - BiomeZone defaultBiome = new BiomeZone(); - if (WorldTerrainData.DefaultBiome != null) - { - WorldTerrainData.DefaultBiome.ValidateSettings(WorldTerrainData); - if (WorldTerrainData.DefaultBiome.Zones != null && WorldTerrainData.DefaultBiome.Zones.Length > 0) - { - defaultBiome = WorldTerrainData.DefaultBiome.Zones[0]; - } - } - - for (int i = 0; i < mBiomeLookUps.Length; i++) - { - mBiomeLookUps[i] = new BiomeLookUp(defaultBiome, true); - } - - if (WorldTerrainData.Biomes == null) - return; - - for (int i = 0; i < WorldTerrainData.Biomes.Length; i++) - { - BiomeSettings biome = WorldTerrainData.Biomes[i]; - if (biome == null) - continue; - biome.ValidateSettings(WorldTerrainData); - if (biome.Zones == null) - continue; - - for (int j = 0; j < biome.Zones.Length; j++) - { - BiomeZone zone = biome.Zones[j]; - for (int elevation = 0; elevation <= 20; elevation++) - { - for (int moisture = 0; moisture <= 20; moisture++) - { - float m0 = moisture / 20f; - float m1 = (moisture + 1) / 20f; - if (m0 <= zone.MoistureMax && m1 >= zone.MoistureMin) - { - int lookupIndex = elevation * 21 + moisture; - if (!mBiomeLookUps[lookupIndex].OverlappingZones.Contains(zone)) - { - mBiomeLookUps[lookupIndex].OverlappingZones.Add(zone); - if (mBiomeLookUps[lookupIndex].OverlappingZones.Count > 1) - { - mBiomeLookUps[lookupIndex].UniqueZone = false; - } - } - - mBiomeLookUps[lookupIndex].Zone = zone; - if (zone.MoistureMin > m0 || zone.MoistureMax < 1) - { - mBiomeLookUps[lookupIndex].UniqueZone = false; - } - } - } - } - } - } - - for (int i = 0; i < mBiomeLookUps.Length; i++) - { - if (!mBiomeLookUps[i].UniqueZone && !mBiomeLookUps[i].OverlappingZones.Contains(defaultBiome)) - { - mBiomeLookUps[i].OverlappingZones.Add(defaultBiome); - } - } - - } - - private void CheckNewNearChunks() - { - for (int x = mVisibleXMin; x <= mVisibleXMax; x++) - { - int x00 = Schematic.MAX_WORLD_LENGTH * Schematic.MAX_WORLD_HEIGHT * (x + Schematic.MAX_WORLD_WIDTH); - for (int y = mVisibleYMin; y <= mVisibleYMax; y++) - { - int y00 = Schematic.MAX_WORLD_LENGTH * (y + Schematic.MAX_WORLD_HEIGHT); - int h00 = x00 + y00; - for (int z = mVisibleZMin; z <= mVisibleZMax; z++) - { - int hash = h00 + z; - CreateChunk(hash, x, y, z); - } - } - } - } - #endregion - - - } -} diff --git a/SchematicToVoxCore/Generator/Terrain/Environment/Trees.cs b/SchematicToVoxCore/Generator/Terrain/Environment/Trees.cs deleted file mode 100644 index 121d6d1..0000000 --- a/SchematicToVoxCore/Generator/Terrain/Environment/Trees.cs +++ /dev/null @@ -1,198 +0,0 @@ -using FileToVox.Extensions; -using FileToVox.Generator.Terrain.Chunk; -using FileToVoxCore.Extensions; -using FileToVoxCore.Schematics.Tools; -using System; -using System.Collections.Generic; -using BiomeTree = FileToVox.Generator.Terrain.Data.BiomeTree; -using ModelSettings = FileToVox.Generator.Terrain.Data.ModelSettings; - -namespace FileToVox.Generator.Terrain -{ - public partial class TerrainEnvironment - { - private struct TreeRequest - { - public VoxelChunk Chunk; - public Vector3 ChunkOriginalPosition; - public Vector3 RootPosition; - public ModelSettings Tree; - } - - private const int TREES_CREATION_BUFFER_SIZE = 20000; - private TreeRequest[] mTreeRequests; - private int mTreeRequestLast, mTreeRequestFirst; - private List mTreeChunkRefreshRequests; - - private void InitTrees() - { - if (mTreeRequests == null || mTreeRequests.Length != TREES_CREATION_BUFFER_SIZE) - { - mTreeRequests = new TreeRequest[TREES_CREATION_BUFFER_SIZE]; - } - mTreeRequestLast = -1; - mTreeRequestFirst = -1; - if (mTreeChunkRefreshRequests == null) - { - mTreeChunkRefreshRequests = new List(); - } - else - { - mTreeChunkRefreshRequests.Clear(); - } - } - - public ModelSettings GetTree(BiomeTree[] trees, float random) - { - float acumProb = 0; - int index = 0; - for (int t = 0; t < trees.Length; t++) - { - acumProb += trees[t].Probability; - if (random < acumProb) - { - index = t; - break; - } - } - - return trees[index].Bits; - } - - public void RequestTreeCreation(VoxelChunk chunk, Vector3 position, ModelSettings treeModel) - { - if (treeModel == null) - return; - - mTreeRequestLast++; - if (mTreeRequestLast >= mTreeRequests.Length) - { - mTreeRequestLast = 0; - } - if (mTreeRequestLast != mTreeRequestFirst) - { - mTreeRequests[mTreeRequestLast].Chunk = chunk; - mTreeRequests[mTreeRequestLast].ChunkOriginalPosition = chunk.Position; - mTreeRequests[mTreeRequestLast].RootPosition = position; - mTreeRequests[mTreeRequestLast].Tree = treeModel; - } - } - - private void CheckTreeRequests() - { - for (int k = 0; k < 10000; k++) - { - if (mTreeRequestFirst == mTreeRequestLast) - return; - mTreeRequestFirst++; - if (mTreeRequestFirst >= mTreeRequests.Length) - { - mTreeRequestFirst = 0; - } - VoxelChunk chunk = mTreeRequests[mTreeRequestFirst].Chunk; - if (chunk != null && chunk.Position == mTreeRequests[mTreeRequestFirst].ChunkOriginalPosition) - { - Random random = new Random(); - CreateTree(mTreeRequests[mTreeRequestFirst].RootPosition, mTreeRequests[mTreeRequestFirst].Tree, random.Next(0, 4)); - } - } - } - - private void CreateTree(Vector3 position, ModelSettings tree, int rotation) - { - if (tree == null) - { - return; - } - - Vector3 pos = new Vector3(); - mTreeChunkRefreshRequests.Clear(); - VoxelChunk lastChunk = null; - int modelOneYRow = tree.SizeZ * tree.SizeX; - int modelOneZRow = tree.SizeX; - int halfSizeX = tree.SizeX / 2; - int halfSizeZ = tree.SizeZ / 2; - - for (int b = 0; b < tree.Bits.Length; b++) - { - int bitIndex = tree.Bits[b].VoxelIndex; - int py = bitIndex / modelOneYRow; - int remy = bitIndex - py * modelOneYRow; - int pz = remy / modelOneZRow; - int px = remy - pz * modelOneZRow; - - // Random rotation - int tmp; - switch (rotation) - { - case 0: - tmp = px; - px = halfSizeZ - pz; - pz = tmp - halfSizeX; - break; - case 1: - tmp = px; - px = pz - halfSizeZ; - pz = tmp - halfSizeX; - break; - case 2: - tmp = px; - px = pz - halfSizeZ; - pz = halfSizeX - tmp; - break; - default: - px -= halfSizeX; - pz -= halfSizeZ; - break; - } - - pos.X = position.X + tree.OffsetX + px; - pos.Y = position.Y + tree.OffsetY + py; - pos.Z = position.Z + tree.OffsetZ + pz; - - if (GetVoxelIndex(pos, out VoxelChunk chunk, out int voxelIndex)) - { - if (chunk.Voxels[voxelIndex].Color != 0) - { - chunk.Voxels[voxelIndex].Color = tree.Bits[b].Color.ColorToUInt(); - if (py == 0) - { - if (voxelIndex >= ONE_Y_ROW) - { - if (chunk.Voxels[voxelIndex - ONE_Y_ROW].Color != 0) - { - chunk.Voxels[voxelIndex - ONE_Y_ROW].Color = tree.Bits[b].Color.ColorToUInt(); - } - } - else - { - VoxelChunk bottom = chunk.Bottom; - if (bottom != null) - { - int bottomIndex = voxelIndex + (CHUNK_SIZE - 1) * ONE_Y_ROW; - if (bottom.Voxels[bottomIndex].Color != 0) - { - chunk.Voxels[bottomIndex].Color = tree.Bits[b].Color.ColorToUInt(); - - if (!mTreeChunkRefreshRequests.Contains(bottom)) - mTreeChunkRefreshRequests.Add(bottom); - } - } - } - } - if (chunk != lastChunk) - { - lastChunk = chunk; - if (!mTreeChunkRefreshRequests.Contains(chunk)) - { - mTreeChunkRefreshRequests.Add(chunk); - } - } - } - } - } - - - } - } -} diff --git a/SchematicToVoxCore/Generator/Terrain/Environment/Vegetation.cs b/SchematicToVoxCore/Generator/Terrain/Environment/Vegetation.cs deleted file mode 100644 index cdc17ea..0000000 --- a/SchematicToVoxCore/Generator/Terrain/Environment/Vegetation.cs +++ /dev/null @@ -1,103 +0,0 @@ -using FileToVox.Extensions; -using FileToVox.Generator.Terrain.Chunk; -using FileToVoxCore.Extensions; -using FileToVoxCore.Schematics.Tools; -using BiomeSettings = FileToVox.Generator.Terrain.Data.BiomeSettings; -using Color = FileToVoxCore.Drawing.Color; - -namespace FileToVox.Generator.Terrain -{ - public partial class TerrainEnvironment - { - private struct VegetationRequest - { - public VoxelChunk Chunk; - public int VoxelIndex; - public FileToVoxCore.Drawing.Color vd; - public Vector3 ChunkOriginalPosition; - } - - private VegetationRequest[] mVegetationRequests; - - private int mVegetationRequestLast, mVegetationRequestFirst; - private const int VEGETATION_CREATION_BUFFER_SIZE = 20000; - - private void InitVegetation() - { - if (mVegetationRequests == null || mVegetationRequests.Length != VEGETATION_CREATION_BUFFER_SIZE) - { - mVegetationRequests = new VegetationRequest[VEGETATION_CREATION_BUFFER_SIZE]; - } - mVegetationRequestLast = -1; - mVegetationRequestFirst = -1; - } - - public void RequestVegetationCreation(VoxelChunk chunk, int voxelIndex, Color vd) - { - if (chunk == null) - { - return; - } - mVegetationRequestLast++; - if (mVegetationRequestLast >= mVegetationRequests.Length) - { - mVegetationRequestLast = 0; - } - if (mVegetationRequestLast != mVegetationRequestFirst) - { - mVegetationRequests[mVegetationRequestLast].Chunk = chunk; - mVegetationRequests[mVegetationRequestLast].ChunkOriginalPosition = chunk.Position; - mVegetationRequests[mVegetationRequestLast].VoxelIndex = voxelIndex; - mVegetationRequests[mVegetationRequestLast].vd = vd; - } - } - - void CheckVegetationRequests() - { - for (int k = 0; k < 10000; k++) - { - if (mVegetationRequestFirst == mVegetationRequestLast) - return; - mVegetationRequestFirst++; - if (mVegetationRequestFirst >= mVegetationRequests.Length) - { - mVegetationRequestFirst = 0; - } - VoxelChunk chunk = mVegetationRequests[mVegetationRequestFirst].Chunk; - if (chunk != null && chunk.Position == mVegetationRequests[mVegetationRequestFirst].ChunkOriginalPosition) - { - CreateVegetation(chunk, mVegetationRequests[mVegetationRequestFirst].VoxelIndex, mVegetationRequests[mVegetationRequestFirst].vd); - } - } - } - - public FileToVoxCore.Drawing.Color GetVegetation(BiomeSettings biome, float random) - { - float acumProb = 0; - int index = 0; - for (int t = 0; t < biome.Vegetation.Length; t++) - { - acumProb += biome.Vegetation[t].Probability; - if (random < acumProb) - { - index = t; - break; - } - } - return biome.Vegetation[index].Color; - } - - private void CreateVegetation(VoxelChunk chunk, int voxelIndex, Color vd) - { - if (chunk != null) - { - // Updates current chunk - if (chunk.Voxels[voxelIndex].Color == 0) - { - chunk.Voxels[voxelIndex].Color = vd.ColorToUInt(); - //ChunkRequestRefresh(chunk, false, true); - } - } - } - } -} diff --git a/SchematicToVoxCore/Generator/Terrain/TerrainEnvironment.cs b/SchematicToVoxCore/Generator/Terrain/TerrainEnvironment.cs deleted file mode 100644 index 3d2fd5b..0000000 --- a/SchematicToVoxCore/Generator/Terrain/TerrainEnvironment.cs +++ /dev/null @@ -1,160 +0,0 @@ -using FileToVox.Generator.Terrain.Chunk; -using FileToVox.Generator.Terrain.Utility; -using FileToVox.Main; -using System; -using FileToVoxCore.Schematics; -using FileToVoxCore.Schematics.Tools; -using FileToVoxCore.Utils; -using WorldTerrainData = FileToVox.Generator.Terrain.Data.WorldTerrainData; - -namespace FileToVox.Generator.Terrain -{ - public partial class TerrainEnvironment : SimpleSingleton - { - public const int CHUNK_SIZE = 16; - public const int CHUNK_HALF_SIZE = CHUNK_SIZE / 2; - public const int ONE_Y_ROW = CHUNK_SIZE * CHUNK_SIZE; - public const int ONE_Z_ROW = CHUNK_SIZE; - - public WorldTerrainData WorldTerrainData { get; private set; } - - public void MainInitialize(WorldTerrainData terrainData) - { - WorldTerrainData = terrainData; - WorldRandom.Randomize(WorldTerrainData.Seed); - InitTrees(); - InitVegetation(); - InitChunkManager(); - } - - public void StartGeneration() - { - CheckChunksInRange(); - CheckTreeRequests(); - CheckVegetationRequests(); - } - - public bool GetChunk(Vector3 position, out VoxelChunk chunk, bool forceCreation = false) - { - FastMath.FloorToInt(position.X / CHUNK_SIZE, position.Y / CHUNK_SIZE, position.Z / CHUNK_SIZE, out int chunkX, out int chunkY, out int chunkZ); - return GetChunkFast(chunkX, chunkY, chunkZ, out chunk, forceCreation); - } - - public bool GetVoxelIndex(Vector3 position, out VoxelChunk chunk, out int voxelIndex, bool createChunkIfNotExists = true) - { - FastMath.FloorToInt(position.X / CHUNK_SIZE, position.Y / CHUNK_SIZE, position.Z / CHUNK_SIZE, out int chunkX, out int chunkY, out int chunkZ); - - if (GetChunkFast(chunkX, chunkY, chunkZ, out chunk, createChunkIfNotExists)) - { - int py = (int)(position.Y - chunkY * CHUNK_SIZE); - int pz = (int)(position.Z - chunkZ * CHUNK_SIZE); - int px = (int)(position.X - chunkX * CHUNK_SIZE); - voxelIndex = py * ONE_Y_ROW + pz * ONE_Z_ROW + px; - return true; - } - - voxelIndex = 0; - return false; - } - - public Vector3 GetChunkPosition(Vector3 position) - { - FastMath.FloorToInt(position.X / CHUNK_SIZE, position.Y / CHUNK_SIZE, position.Z / CHUNK_SIZE, out int x, out int y, out int z); - - x = x * CHUNK_SIZE + CHUNK_HALF_SIZE; - y = y * CHUNK_SIZE + CHUNK_HALF_SIZE; - z = z * CHUNK_SIZE + CHUNK_HALF_SIZE; - return new Vector3(x, y, z); - } - - public Schematic CreateSchematic(Vector3 boxMin, Vector3 boxMax) - { - Vector3 position = new Vector3(); - Vector3 chunkMinPos = GetChunkPosition(boxMin); - Vector3 chunkMaxPos = GetChunkPosition(boxMax); - - int minX = (int)boxMin.X; - int minY = (int)boxMin.Y; - int minZ = (int)boxMin.Z; - int maxX = (int)boxMax.X; - int maxY = (int)boxMax.Y; - int maxZ = (int)boxMax.Z; - - Schematic schematic = new Schematic(); - - for (float y = chunkMinPos.Y; y <= chunkMaxPos.Y; y += CHUNK_SIZE) - { - position.Y = y; - for (float z = chunkMinPos.Z; z <= chunkMaxPos.Z; z += CHUNK_SIZE) - { - position.Z = z; - for (float x = chunkMinPos.X; x <= chunkMaxPos.X; x += CHUNK_SIZE) - { - position.X = x; - if (GetChunk(position, out VoxelChunk chunk, false)) - { - FastMath.FloorToInt(chunk.Position.X, chunk.Position.Y, chunk.Position.Z, out int chunkMinX, out int chunkMinY, out int chunkMinZ); - chunkMinX -= CHUNK_HALF_SIZE; - chunkMinY -= CHUNK_HALF_SIZE; - chunkMinZ -= CHUNK_HALF_SIZE; - for (int vy = 0; vy < CHUNK_SIZE; vy++) - { - int wy = chunkMinY + vy; - if (wy < minY || wy > maxY) - continue; - int my = wy - minY; - int voxelIndexY = vy * ONE_Y_ROW; - for (int vz = 0; vz < CHUNK_SIZE; vz++) - { - int wz = chunkMinZ + vz; - if (wz < minZ || wz > maxZ) - continue; - int mz = wz - minZ; - int voxelIndex = voxelIndexY + vz * ONE_Z_ROW; - for (int vx = 0; vx < CHUNK_SIZE; vx++, voxelIndex++) - { - int wx = chunkMinX + vx; - if (wx < minX || wx > maxX) - continue; - int mx = wx - minX; - schematic.AddVoxel(mx, my, mz, chunk.Voxels[voxelIndex].Color); - } - } - } - } - else - { - int chunkMinY = (int)Math.Floor(y) - CHUNK_HALF_SIZE; - int chunkMinZ = (int)Math.Floor(z) - CHUNK_HALF_SIZE; - int chunkMinX = (int)Math.Floor(x) - CHUNK_HALF_SIZE; - for (int vy = 0; vy < CHUNK_SIZE; vy++) - { - int wy = chunkMinY + vy; - if (wy < minY || wy > maxY) - continue; - int my = wy - minY; - for (int vz = 0; vz < CHUNK_SIZE; vz++) - { - int wz = chunkMinZ + vz; - if (wz < minZ || wz > maxZ) - continue; - int mz = wz - minZ; - for (int vx = 0; vx < CHUNK_SIZE; vx++) - { - int wx = chunkMinX + vx; - if (wx < minX || wx > maxX) - continue; - int mx = wx - minX; - schematic.RemoveVoxel(mx, my, mz); - } - } - } - } - } - } - } - - return schematic; - } - } -} diff --git a/SchematicToVoxCore/Generator/Terrain/TerrainGenerator.cs b/SchematicToVoxCore/Generator/Terrain/TerrainGenerator.cs deleted file mode 100644 index c0abc49..0000000 --- a/SchematicToVoxCore/Generator/Terrain/TerrainGenerator.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using FileToVoxCore.Schematics; -using FileToVoxCore.Schematics.Tools; -using WorldTerrainData = FileToVox.Generator.Terrain.Data.WorldTerrainData; - -namespace FileToVox.Generator.Terrain -{ - public class TerrainGenerator : IGenerator - { - public TerrainGenerator(WorldTerrainData worldTerrainData) - { - TerrainEnvironment.Instance.MainInitialize(worldTerrainData); - } - - public Schematic WriteSchematic() - { - TerrainEnvironment.Instance.StartGeneration(); - Schematic schematic = GetSchematic(); - TerrainEnvironment.Instance.DisposeAll(); - return schematic; - } - - private Schematic GetSchematic() - { - int width = Math.Min(Math.Max(TerrainEnvironment.Instance.WorldTerrainData.Width, TerrainEnvironment.Instance.WorldTerrainData.Length), 2000); - int chunkXZDistance = width / 2; - int chunkYDistance = 1000 / 2; - - int visibleXMin = -chunkXZDistance; - int visibleXMax = chunkXZDistance - 1; - - int visibleZMin = -chunkXZDistance; - int visibleZMax = chunkXZDistance - 1; - - int visibleYMin = -chunkYDistance; - int visibleYMax = chunkYDistance - 1; - - return TerrainEnvironment.Instance.CreateSchematic(new Vector3(visibleXMin, visibleYMin, visibleZMin), new Vector3(visibleXMax, visibleYMax, visibleZMax)); - } - } -} diff --git a/SchematicToVoxCore/Generator/Terrain/TerrainGeneratorSettings.cs b/SchematicToVoxCore/Generator/Terrain/TerrainGeneratorSettings.cs deleted file mode 100644 index 993f0c9..0000000 --- a/SchematicToVoxCore/Generator/Terrain/TerrainGeneratorSettings.cs +++ /dev/null @@ -1,385 +0,0 @@ -using FileToVox.Generator.Terrain.Chunk; -using FileToVox.Generator.Terrain.Utility; -using System; -using FileToVoxCore.Extensions; -using FileToVoxCore.Schematics; -using FileToVoxCore.Schematics.Tools; -using BiomeSettings = FileToVox.Generator.Terrain.Data.BiomeSettings; -using TerrainGeneratorDataSettings = FileToVox.Generator.Terrain.Data.TerrainGeneratorDataSettings; -using TerrainStepType = FileToVox.Generator.Terrain.Data.TerrainStepType; -using FileToVox.Extensions; - -namespace FileToVox.Generator.Terrain -{ - public class TerrainGeneratorSettings : TerrainGeneratorDataSettings - { - #region Fields - protected float[] mMoistureValues; - protected int mNoiseMoistureTextureSize; - protected HeightMapInfo[] mHeightChunkData; - protected string mLastMoistureTextureLoaded; - protected float mSeaLevelAlignedWithInt, mBeachLevelAlignedWithInt; - protected int mGeneration; - - #endregion - - - #region StaticConst - - public const int ONE_Y_ROW = TerrainEnvironment.CHUNK_SIZE * TerrainEnvironment.CHUNK_SIZE; - - #endregion - - - #region PublicMethods - - public void Initialize() - { - mSeaLevelAlignedWithInt = (WaterLevel / MaxHeight); - mBeachLevelAlignedWithInt = (WaterLevel + 1) / MaxHeight; - if (Steps != null) - { - for (int i = 0; i < Steps.Length; i++) - { - if (!String.IsNullOrEmpty(Steps[i].NoiseTexturePath)) - { - bool repeated = false; - for (int j = 0; j < i - 1; j++) - { - if (Steps[i].NoiseTexturePath == Steps[j].NoiseTexturePath) - { - Steps[i].NoiseValues = Steps[j].NoiseValues; - Steps[i].NoiseTextureSize = Steps[j].NoiseTextureSize; - repeated = true; - break; - } - } - - if (!repeated && (Steps[i].NoiseTextureSize == 0 || Steps[i].NoiseValues == null || Steps[i].LastTextureLoaded == null || Steps[i].NoiseTexturePath != Steps[i].LastTextureLoaded)) - { - Steps[i].LastTextureLoaded = Steps[i].NoiseTexturePath; - - Steps[i].NoiseValues = NoiseTools.LoadNoiseTexture(Steps[i].NoiseTexturePath, out int NoiseTextureSize); - Steps[i].NoiseTextureSize = NoiseTextureSize; - } - } - - if (Steps[i].InputIndex0 < 0 || Steps[i].InputIndex0 >= Steps.Length) - { - Steps[i].InputIndex0 = 0; - } - - if (Steps[i].InputIndex1 < 0 || Steps[i].InputIndex1 >= Steps.Length) - { - Steps[i].InputIndex1 = 0; - } - } - } - - if (!String.IsNullOrEmpty(MoisturePath) && (mNoiseMoistureTextureSize == 0 || mMoistureValues == null || mLastMoistureTextureLoaded == null || mLastMoistureTextureLoaded != MoisturePath)) - { - mLastMoistureTextureLoaded = MoisturePath; - mMoistureValues = NoiseTools.LoadNoiseTexture(MoisturePath, out int noiseMoistureTextureSize); - mNoiseMoistureTextureSize = noiseMoistureTextureSize; - } - - if (mHeightChunkData == null) - { - mHeightChunkData = new HeightMapInfo[TerrainEnvironment.CHUNK_SIZE * TerrainEnvironment.CHUNK_SIZE]; - } - } - - public void GetHeightAndMoisture(float x, float z, out float altitude, out float moisture) - { - bool allowBeach = true; - if (Steps != null && Steps.Length > 0) - { - float value = 0; - for (int k = 0; k < Steps.Length; k++) - { - if (Steps[k].Enabled) - { - switch (Steps[k].OperationType) - { - case TerrainStepType.SampleHeightMapTexture: - value = NoiseTools.GetNoiseValueBilinear(Steps[k].NoiseValues, Steps[k].NoiseTextureSize, x * Steps[k].Frequency, z * Steps[k].Frequency); - value = value * (Steps[k].NoiseRangeMax - Steps[k].NoiseRangeMin) + Steps[k].NoiseRangeMin; - break; - case TerrainStepType.SampleRidgeNoiseFromTexture: - value = NoiseTools.GetNoiseValueBilinear(Steps[k].NoiseValues, Steps[k].NoiseTextureSize, x * Steps[k].Frequency, z * Steps[k].Frequency, true); - value = value * (Steps[k].NoiseRangeMax - Steps[k].NoiseRangeMin) + Steps[k].NoiseRangeMin; - break; - case TerrainStepType.Shift: - value += Steps[k].Param; - break; - case TerrainStepType.BeachMask: - { - int i1 = Steps[k].InputIndex0; - if (Steps[i1].Value > Steps[k].Threshold) - { - allowBeach = false; - } - } - break; - case TerrainStepType.AddAndMultiply: - value = (value + Steps[k].Param) * Steps[k].Param2; - break; - case TerrainStepType.MultiplyAndAdd: - value = (value * Steps[k].Param) + Steps[k].Param2; - break; - case TerrainStepType.Exponential: - if (value < 0) - value = 0; - value = (float)Math.Pow(value, Steps[k].Param); - break; - case TerrainStepType.Constant: - value = Steps[k].Param; - break; - case TerrainStepType.Invert: - value = 1f - value; - break; - case TerrainStepType.Copy: - { - int i1 = Steps[k].InputIndex0; - value = Steps[i1].Value; - } - break; - case TerrainStepType.Random: - value = WorldRandom.GetValue(x, z); - break; - case TerrainStepType.BlendAdditive: - { - int i1 = Steps[k].InputIndex0; - int i2 = Steps[k].InputIndex1; - value = Steps[i1].Value * Steps[k].Weight0 + Steps[i2].Value * Steps[k].Weight1; - } - break; - case TerrainStepType.BlendMultiply: - { - int i1 = Steps[k].InputIndex0; - int i2 = Steps[k].InputIndex1; - value = Steps[i1].Value * Steps[i2].Value; - } - break; - case TerrainStepType.Threshold: - { - int i1 = Steps[k].InputIndex0; - if (Steps[i1].Value >= Steps[k].Threshold) - { - value = Steps[i1].Value + Steps[k].ThresholdShift; - } - else - { - value = Steps[k].ThresholdParam; - } - } - break; - case TerrainStepType.FlattenOrRaise: - if (value >= Steps[k].Threshold) - { - value = (value - Steps[k].Threshold) * Steps[k].ThresholdParam + Steps[k].Threshold; - } - break; - case TerrainStepType.Clamp: - if (value < Steps[k].Min) - value = Steps[k].Min; - else if (value > Steps[k].Max) - value = Steps[k].Max; - break; - case TerrainStepType.Select: - { - int i1 = Steps[k].InputIndex0; - if (Steps[i1].Value < Steps[k].Min) - { - value = Steps[k].ThresholdParam; - } - else if (Steps[i1].Value > Steps[k].Max) - { - value = Steps[k].ThresholdParam; - } - else - { - value = Steps[i1].Value; - } - } - break; - case TerrainStepType.Fill: - { - int i1 = Steps[k].InputIndex0; - if (Steps[i1].Value >= Steps[k].Min && Steps[i1].Value <= Steps[k].Max) - { - value = Steps[k].ThresholdParam; - } - } - break; - } - } - Steps[k].Value = value; - } - altitude = value; - } - else - { - altitude = -9999; - } - - // Moisture - moisture = NoiseTools.GetNoiseValueBilinear(mMoistureValues, mNoiseMoistureTextureSize, x * MoistureScale, z * MoistureScale); - - if (altitude < mBeachLevelAlignedWithInt && altitude >= mSeaLevelAlignedWithInt) - { - float depth = mBeachLevelAlignedWithInt - altitude; - if (depth > BeachWidth || !allowBeach) - { - altitude = mSeaLevelAlignedWithInt - 0.0001f; - } - } - - if (altitude < mSeaLevelAlignedWithInt) - { - float depth = mSeaLevelAlignedWithInt - altitude; - altitude = mSeaLevelAlignedWithInt - 0.0001f - depth * SeaDepthMultiplier; - } - - } - - public void PaintChunk(VoxelChunk chunk) - { - Vector3 position = chunk.Position; - if (position.Y + TerrainEnvironment.CHUNK_HALF_SIZE < MinHeight) - { - return; - } - - int bedrockRow = -1; - if (position.Y < MinHeight + TerrainEnvironment.CHUNK_HALF_SIZE) - { - bedrockRow = (int)(MinHeight - (position.Y - TerrainEnvironment.CHUNK_HALF_SIZE) + 1) * ONE_Y_ROW - 1; - } - - position.X -= TerrainEnvironment.CHUNK_HALF_SIZE; - position.Y -= TerrainEnvironment.CHUNK_HALF_SIZE; - position.Z -= TerrainEnvironment.CHUNK_HALF_SIZE; - Vector3 pos = new Vector3(); - int waterLevel = WaterLevel > 0 ? WaterLevel : -1; - Voxel[] voxels = chunk.Voxels; - mGeneration++; - TerrainEnvironment.Instance.GetHeightMapInfo(position.X, position.Z, mHeightChunkData); - int shiftAmount = (int)MathF.Log(TerrainEnvironment.CHUNK_SIZE, 2); - - for (int arrayIndex = 0; arrayIndex < TerrainEnvironment.CHUNK_SIZE * TerrainEnvironment.CHUNK_SIZE; arrayIndex++) - { - float groundLevel = mHeightChunkData[arrayIndex].GroundLevel; - float surfaceLevel = waterLevel > groundLevel ? waterLevel : groundLevel; - if (surfaceLevel < pos.Y) - { - continue; - } - - BiomeSettings biome = mHeightChunkData[arrayIndex].Biome; - if (biome == null) - { - biome = TerrainEnvironment.Instance.WorldTerrainData.DefaultBiome; - if (biome == null) - continue; - } - - int y = (int)(surfaceLevel - position.Y); - if (y >= TerrainEnvironment.CHUNK_SIZE) - { - y = TerrainEnvironment.CHUNK_SIZE - 1; - } - - pos.Y = position.Y + y; - pos.X = position.X + (arrayIndex & (TerrainEnvironment.CHUNK_SIZE - 1)); - pos.Z = position.Z + (arrayIndex >> shiftAmount); - - int voxelIndex = y * ONE_Y_ROW + arrayIndex; - if (voxelIndex < 0) - { - continue; - } - if (pos.Y > groundLevel) - { - while (pos.Y > groundLevel && voxelIndex >= 0) - { - voxels[voxelIndex].Color = WaterColor.ColorToUInt(); - voxelIndex -= ONE_Y_ROW; - pos.Y--; - } - } - else if (pos.Y == groundLevel) - { - voxels[voxelIndex].Color = 0; - - if (voxels[voxelIndex].Color == 0) - { - if (pos.Y == waterLevel) - { - voxels[voxelIndex].Color = ShoreColor.ColorToUInt(); - } - else - { - //float moisture = mHeightChunkData[arrayIndex].Moisture; - //Color colorTop = biome.VoxelTop; - //Color newColor = Color.FromArgb((int) (colorTop.R * moisture), (int)(colorTop.G * moisture), (int)(colorTop.B * moisture)); - //voxels[voxelIndex].Color = newColor.ColorToUInt(); - - voxels[voxelIndex].Color = biome.VoxelTop.ColorToUInt(); - - if (pos.Y > waterLevel) - { - float rdn = WorldRandom.GetValue(pos); - if (biome.TreeDensity > 0 && rdn < biome.TreeDensity && biome.Trees.Length > 0) - { - TerrainEnvironment.Instance.RequestTreeCreation(chunk, pos, TerrainEnvironment.Instance.GetTree(biome.Trees, rdn / biome.TreeDensity)); - } - else if (biome.VegetationDensity > 0 && rdn < biome.VegetationDensity && biome.Vegetation.Length > 0) - { - if (voxelIndex >= (TerrainEnvironment.CHUNK_SIZE - 1) * ONE_Y_ROW) - { - TerrainEnvironment.Instance.RequestVegetationCreation(chunk.Top, voxelIndex - ONE_Y_ROW * (TerrainEnvironment.CHUNK_SIZE - 1), TerrainEnvironment.Instance.GetVegetation(biome, rdn / biome.VegetationDensity)); - } - else - { - voxels[voxelIndex + ONE_Y_ROW].Color = TerrainEnvironment.Instance.GetVegetation(biome, rdn / biome.VegetationDensity).ColorToUInt(); - } - } - } - } - - voxelIndex -= ONE_Y_ROW; - pos.Y--; - } - } - - biome.BiomeGeneration = mGeneration; - - while (voxelIndex >= 0 && voxels[voxelIndex].Color == 0 && pos.Y <= waterLevel) - { - voxels[voxelIndex].Color = WaterColor.ColorToUInt(); - voxelIndex -= ONE_Y_ROW; - pos.Y--; - } - - for (; voxelIndex > bedrockRow; voxelIndex -= ONE_Y_ROW, pos.Y--) - { - if (voxels[voxelIndex].Color == 0) - { - voxels[voxelIndex].Color = biome.VoxelDirt.ColorToUInt(); - } - else if (voxels[voxelIndex].Color == 0 && pos.Y <= waterLevel) - { // hole under water level -> fill with water - voxels[voxelIndex].Color = WaterColor.ColorToUInt(); - } - } - if (bedrockRow >= 0 && voxelIndex >= 0) - { - voxels[voxelIndex].Color = BedrockColor.ColorToUInt(); - } - } - } - - #endregion - } -} diff --git a/SchematicToVoxCore/Generator/Terrain/Utility/FastHashSet.cs b/SchematicToVoxCore/Generator/Terrain/Utility/FastHashSet.cs deleted file mode 100644 index ae4479b..0000000 --- a/SchematicToVoxCore/Generator/Terrain/Utility/FastHashSet.cs +++ /dev/null @@ -1,297 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace FileToVox.Generator.Terrain.Utility -{ - public class FastHashSet - { - private int[] mHashes; - public DictionaryEntry[] Entries; - private readonly int mInitialsize = 89; - private const float Loadfactor = 1f; - - private static readonly int[] PrimeSizes = new int[] { 89, 179, 359, 719, 1439, 2879, 5779, 11579, 23159, 46327, - 92657, 185323, 370661, 741337, 1482707, 2965421, 5930887, 11861791, - 23723599, 47447201, 94894427, 189788857, 379577741, 759155483 - }; - - public struct DictionaryEntry - { - public int key; - public int next; - public V value; - } - - - public FastHashSet() - { - Initialize(); - } - - public FastHashSet(int capacity) - { - mInitialsize = FindNewSize(capacity); - Initialize(); - } - - public V GetAtPosition(int pos) - { - return Entries[pos].value; - } - - public void StoreAtPosition(int pos, V value) - { - Entries[pos].value = value; - } - - public int Add(object keyObj, V value, bool overwrite = true) - { - return Add(keyObj.GetHashCode(), value, overwrite); - } - - public int Add(int key, V value, bool overwrite = true) - { - if (Count >= Entries.Length) - { - Resize(); - } - - - key &= 0x7FFFFFFF; - - int hashPos = key % mHashes.Length; - - int entryLocation = mHashes[hashPos]; - - int storePos = Count; - - - if (entryLocation != -1) - { // already there - int currEntryPos = entryLocation; - - do - { - DictionaryEntry entry = Entries[currEntryPos]; - - // same key is in the dictionary - if (key == entry.key) - { - if (overwrite) - { - Entries[currEntryPos].value = value; - } - return currEntryPos; - } - - currEntryPos = entry.next; - } while (currEntryPos > -1); - } - - // new value - mHashes[hashPos] = storePos; - - Entries[storePos].next = entryLocation; - Entries[storePos].key = key; - Entries[storePos].value = value; - - Count++; - - return storePos; - } - - private void Resize() - { - int newSize = FindNewSize(mHashes.Length * 2 + 1); - int[] newHashes = new int[newSize]; - DictionaryEntry[] newEntries = new DictionaryEntry[newSize]; - - Array.Copy(Entries, newEntries, Count); - - for (int i = 0; i < newSize; i++) - { - newHashes[i] = -1; - } - for (int i = Count; i < newSize; i++) - { - newEntries[i].key = -1; - } - - for (int i = 0; i < Count; i++) - { - int key = newEntries[i].key; - if (key >= 0) - { - int hashPos = key % newSize; - int curPos = newHashes[hashPos]; - newHashes[hashPos] = i; - newEntries[i].next = curPos; - } - } - - mHashes = newHashes; - Entries = newEntries; - } - - private int FindNewSize(int desiredCapacity) - { - for (int i = 0; i < PrimeSizes.Length; i++) - { - if (PrimeSizes[i] >= desiredCapacity) - return PrimeSizes[i]; - } - - throw new NotImplementedException("Too large array"); - } - - public V Get(int key) - { - int pos = GetPosition(key); - - if (pos == -1) - throw new Exception("Key does not exist"); - - return Entries[pos].value; - } - - public int GetPosition(int key) - { - key &= 0x7FFFFFFF; - - int pos = key % mHashes.Length; - - int entryLocation = mHashes[pos]; - - if (entryLocation == -1) - return -1; - - int nextpos = entryLocation; - - do - { - DictionaryEntry entry = Entries[nextpos]; - - if (key == entry.key) - return nextpos; - - nextpos = entry.next; - - } while (nextpos != -1); - - return -1; - } - - public bool ContainsKey(int key) - { - return GetPosition(key) != -1; - } - - public bool TryGetValue(int key, out V value) - { - int pos = GetPosition(key); - - if (pos == -1) - { - value = default(V); - return false; - } - - value = Entries[pos].value; - - return true; - } - - public V this[int key] - { - get => Get(key); - set => Add(key, value, true); - } - - public void Add(KeyValuePair item) - { - Add(item.Key, item.Value, false); - } - - public void Clear() - { - Count = 0; - for (int i = 0; i < mHashes.Length; i++) - { - mHashes[i] = -1; - } - } - - private void Initialize() - { - this.mHashes = new int[mInitialsize]; - this.Entries = new DictionaryEntry[mInitialsize]; - Count = 0; - - for (int i = 0; i < Entries.Length; i++) - { - mHashes[i] = -1; - Entries[i].key = -1; - } - } - - public int Count { get; private set; } - - public bool IsReadOnly - { - get { return false; } - } - - - public void Remove(object keyObj) - { - uint key = (uint)keyObj.GetHashCode(); - Remove((int)key); - } - - - public void Remove(int key) - { - key &= 0x7FFFFFFF; - int hashPos = key % mHashes.Length; - - int entryLocation = mHashes[hashPos]; - - if (entryLocation == -1) - return; - - - int currEntryPos = entryLocation; - int prevEntryPos = entryLocation; - - do - { - DictionaryEntry entry = Entries[currEntryPos]; - - // key is in the dictionary - if (key == entry.key) - { - Entries[currEntryPos].key = -1; - Entries[prevEntryPos].next = Entries[currEntryPos].next; - if (entryLocation == currEntryPos) - { - mHashes[hashPos] = entry.next; - if (entryLocation + 1 == Count) - { - Count--; - } - } - return; - } - - prevEntryPos = currEntryPos; - currEntryPos = entry.next; - - } while (currEntryPos > -1); - } - - - - - } -} diff --git a/SchematicToVoxCore/Generator/Terrain/Utility/HeightMapCache.cs b/SchematicToVoxCore/Generator/Terrain/Utility/HeightMapCache.cs deleted file mode 100644 index 754fa93..0000000 --- a/SchematicToVoxCore/Generator/Terrain/Utility/HeightMapCache.cs +++ /dev/null @@ -1,96 +0,0 @@ -namespace FileToVox.Generator.Terrain.Utility -{ - public class HeightMapCache - { - private class HeightMapInfoPoolEntry - { - public int Uses; - public int Key; - public HeightMapInfo[] Heights; - } - - private HeightMapInfoPoolEntry[] mSectorsPool; - private FastHashSet mSectors; - private int mLastKey; - private int mLastSector; - - - public HeightMapCache(int poolSize) - { - mSectors = new FastHashSet(16); - mSectorsPool = new HeightMapInfoPoolEntry[poolSize]; - for (int i = 0; i < mSectorsPool.Length; i++) - { - mSectorsPool[i] = new HeightMapInfoPoolEntry(); - } - - mLastSector = -1; - } - - public bool TryGetValue(int x, int z, out HeightMapInfo[] Heights, out int heightIndex) - { - int fx = x >> 7; - int fz = z >> 7; - heightIndex = ((z - (fz << 7)) << 7) + (x - (fx << 7)); - int Key = ((fz + 1024) << 16) + (fx + 1024); - if (Key != mLastKey || mLastSector < 0) - { - if (!mSectors.TryGetValue(Key, out int poolIndex) || Key != mSectorsPool[poolIndex].Key) - { - int leastUsed = int.MaxValue; - for (int k = 0; k < mSectorsPool.Length; k++) - { - if (mSectorsPool[k].Uses < leastUsed) - { - leastUsed = mSectorsPool[k].Uses; - poolIndex = k; - } - } - - HeightMapInfoPoolEntry sector = mSectorsPool[poolIndex]; - if (sector.Key > 0) - { - mSectors.Remove(sector.Key); - } - - sector.Key = Key; - sector.Uses = 0; - mSectors[Key] = poolIndex; - - if (sector.Heights == null) - { - sector.Heights = new HeightMapInfo[16384]; - } - else - { - for (int k = 0; k < sector.Heights.Length; k++) - { - sector.Heights[k].Biome = null; - sector.Heights[k].Moisture = 0; - sector.Heights[k].GroundLevel = 0; - } - } - } - mLastKey = Key; - mLastSector = poolIndex; - } - - HeightMapInfoPoolEntry theSector = mSectorsPool[mLastSector]; - theSector.Uses++; - Heights = theSector.Heights; - return Heights[heightIndex].GroundLevel != 0; - } - - public void Clear() - { - mSectors.Clear(); - for (int k = 0; k < mSectorsPool.Length; k++) - { - mSectorsPool[k].Key = 0; - mSectorsPool[k].Uses = 0; - } - mLastKey = 0; - mLastSector = -1; - } - } -} diff --git a/SchematicToVoxCore/Generator/Terrain/Utility/NoiseTools.cs b/SchematicToVoxCore/Generator/Terrain/Utility/NoiseTools.cs deleted file mode 100644 index f83fcb2..0000000 --- a/SchematicToVoxCore/Generator/Terrain/Utility/NoiseTools.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System.Drawing; -using System.IO; -using FileToVoxCore.Schematics.Tools; - -namespace FileToVox.Generator.Terrain.Utility -{ - public static class NoiseTools - { - public static Vector3 SeedOffset; - - public static float[] LoadNoiseTexture(string path, out int textureSize) - { - string fullPath = Path.Combine(TerrainEnvironment.Instance.WorldTerrainData.DirectoryPath, path); - - if (!File.Exists(fullPath)) - { - textureSize = 0; - return null; - } - - Bitmap bitmap = new Bitmap(new FileInfo(fullPath).FullName); - textureSize = bitmap.Width; - - float[] values = new float[bitmap.Width * bitmap.Height]; - int index = 0; - for (int x = 0; x < bitmap.Width; x++) - { - for (int y = 0; y < bitmap.Height; y++) - { - values[index] = bitmap.GetPixel(x, y).R / (float)255; - index++; - } - } - - return values; - } - - public static float GetNoiseValueBilinear(float[] noiseArray, int textureSize, float x, float z, bool ridgeNoise = false) - { - if (textureSize == 0) - return 0; - - double zz = (double)z + textureSize * 10000f + SeedOffset.Z; - double xx = (double)x + textureSize * 10000f + SeedOffset.Z; - int posZInt = (int)zz; - int posXInt = (int)xx; - float fy = (float)(zz - posZInt); - float fx = (float)(xx - posXInt); - - int ty0 = posZInt % textureSize; - int tx0 = posXInt % textureSize; - - int ty = (ty0 == textureSize - 1) ? 0 : ty0 + 1; - float noiseUL = noiseArray[ty * textureSize + tx0]; - int tx = (tx0 == textureSize - 1) ? 0 : tx0 + 1; - float noiseUR = noiseArray[ty * textureSize + tx]; - float noiseBL = noiseArray[ty0 * textureSize + tx0]; - float noiseBR = noiseArray[ty0 * textureSize + tx]; - - float value = (1f - fx) * (fy * noiseUL + (1f - fy) * noiseBL) + fx * (fy * noiseUR + (1f - fy) * noiseBR); - - if (ridgeNoise) - { - value = 0.5f - value; - if (value < 0) - { - value = 2f * (0.5f + value); - } - else - { - value = 2f * (0.5f - value); - } - } - return value; - } - } -} diff --git a/SchematicToVoxCore/Generator/Terrain/Utility/WorldRandom.cs b/SchematicToVoxCore/Generator/Terrain/Utility/WorldRandom.cs deleted file mode 100644 index dcd4890..0000000 --- a/SchematicToVoxCore/Generator/Terrain/Utility/WorldRandom.cs +++ /dev/null @@ -1,106 +0,0 @@ -using System; -using FileToVoxCore.Schematics.Tools; - -namespace FileToVox.Generator.Terrain.Utility -{ - public static class WorldRandom - { - private const int RANDOM_TABLE_SIZE = 8192; // 2^13 - private const int RANDOM_TABLE_SIZE_MINUS_ONE = RANDOM_TABLE_SIZE - 1; - private const uint MAGIC1 = 2166136261; // 17 - private const uint MAGIC2 = 16777619; // 23 - - private static float[] RND; - private static uint RND_INDEX = 0; - - static WorldRandom() - { - Randomize(0); - } - - public static void Randomize(int seed) - { - Random random = new Random(seed); - if (RND == null || RND.Length == 0) - RND = new float[RANDOM_TABLE_SIZE]; - for (int k = 0; k < RND.Length; k++) - { - do - { - RND[k] = (float) random.NextDouble(); - } while (RND[k] == 1f); - } - } - - public static float GetValue(Vector3 position) - { - uint hash = MAGIC1; - hash = hash * MAGIC2 ^ (uint)position.X; - hash = hash * MAGIC2 ^ (uint)position.Y; - hash = hash * MAGIC2 ^ (uint)position.Z; - RND_INDEX = hash & RANDOM_TABLE_SIZE_MINUS_ONE; - return RND[RND_INDEX]; - } - - public static float GetValue(float x, float z) - { - uint hash = MAGIC1; - hash = hash * MAGIC2 ^ (uint)x; - hash = hash * MAGIC2 ^ (uint)z; - RND_INDEX = hash & RANDOM_TABLE_SIZE_MINUS_ONE; - return RND[RND_INDEX]; - } - - public static float GetValue(int someValue) - { - RND_INDEX = (uint)someValue & RANDOM_TABLE_SIZE_MINUS_ONE; - return RND[RND_INDEX]; - } - - public static int Range(int min, int max, Vector3 position) - { - float v = GetValue(position); - return (int)(min + (max - min) * 0.99999f * v); - } - public static int Range(int min, int max) - { - float v = GetValue(); - return (int)(min + (max - min) * 0.99999f * v); - } - - public static float Range(float min, float max) - { - float v = GetValue(); - return min + (max - min) * v; - } - - public static float Range(float min, float max, int seed) - { - float v = GetValue(seed); - return min + (max - min) * v; - } - - public static float GetValue() - { - RND_INDEX++; - RND_INDEX &= RANDOM_TABLE_SIZE_MINUS_ONE; - return RND[RND_INDEX]; - } - - public static Vector3 GetVector3(Vector3 position, float scale, float shift = 0) - { - float x = (GetValue(position) + shift) * scale; - float y = (GetValue() + shift) * scale; - float z = (GetValue() + shift) * scale; - return new Vector3(x, y, z); - } - - public static Vector3 GetVector3(Vector3 position, Vector3 scale, float shift = 0) - { - float x = (GetValue(position) + shift) * scale.X; - float y = (GetValue() + shift) * scale.Y; - float z = (GetValue() + shift) * scale.Z; - return new Vector3(x, y, z); - } - } -} diff --git a/SchematicToVoxCore/JsonPresets/heightmapGenerator.json b/SchematicToVoxCore/JsonPresets/heightmapGenerator.json deleted file mode 100644 index 2ec2da2..0000000 --- a/SchematicToVoxCore/JsonPresets/heightmapGenerator.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "GeneratorType": "Heightmap", - "steps": [ - { - "TexturePath": "", - "ColorTexturePath": "", - "Height": 200, - "Offset": 0, - "OffsetMerge": 0, - "ColorLimit": 256, - "EnableColor": true, - "Excavate": true, - "Reverse": false, - "PlacementMode": "ADDITIVE", - "RotationMode": "Y" - } - ] -} \ No newline at end of file diff --git a/SchematicToVoxCore/JsonPresets/noise/NoiseBase.png b/SchematicToVoxCore/JsonPresets/noise/NoiseBase.png deleted file mode 100644 index faef4353e2bfb2246cb1f20645787174c602eec3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17204 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%0Dk5N7v7sMuydfO27O5BQm8&rZxCX3;x2uh}z& zv}J+)Rh$uY@x`PG*={!pQLIxiG+4(aVns%!T+eL1U_Zxz_S4KR&G z*;Ee@Y;f(ZXXZisZ9_>POoMJNR5_+vxCIcJrBxG3F$*$EBL0GNA+8qtl8#5}&h>E` z9zW#Xtj{%Fw_Y^GhY-CdP5n2gUtcaVeux zm5x2)(1*LWmZBqfsjC$M>- z^Bkn%B*rAWE5U#I>MNH~?SA73$Ahv3`*~DA8((`r-ESbjnc?w86Wh)%#PEBgpxu$T zk#y>3R@yECzJ12y2jNn=-ga}*wqMlgs+MH5z%KmOK3^_eb}X#Z`kLI%XHRdw3G?cP zATuwicD_9sZu+M$qy9m;wZ>Hv&9g~zPRiIoQHJ;x2mD2Up z&B}_@q$f9cJ8;6_fm+5i%R8BkspQlbE4g)!$;rBY>M193Fer2^=!P5k7sXTOZ+WtZ z)(|fVyrUG7GRLbjb9Xlvo$i>Rn}GCoRQbv#HSaJ@H)c2H(wcLex$|e3cWH|!M4N~Y z*z}?tx=q&gDz7j9oWN9pd)USmN``sz*!JN)e+C-(Eq2$yAStbU(seM5%n=XyhnUjt z&EAnZL%5>a$Ls5u&)~Q1G#!MnWQHBA9ZQMK`s939&Lj}aW&NBlY!f21*DH89h>>zM z`33dRmx+7pBJR~SIl}i=HOscA1x#Q5-k3_q!fz}ZKmocGo1aTpJl3u~TPs?SnY271 zcx0QJ|Gy=U@X7EYs>1)OCpHMnxLXNL^pRi7M|V~je)c4NlkY=v$^!8ExATGWXo$_( zQw?w~*nUD9(Q4ClQR%a@-+J05chj)YOIF zx`3z{JmM?8a^q7wYuPbJO8Rh{=qfsm*5CiVx7$XygYQJt_ezE$E;$w(&oDqe3M!K5 zV5x*hXWtxC*Ut{G;V}~^*_iv>87*jGwev1w;0nxhZ=2_d&Xg_{MFRzE4Sbq1>$gha z8^axfUy)_}!=TS*_rOYFm#>;_Kbw}Wf})XWcrSh>^LuYhBiN+OYSU;owR!gqSI@7t zKL&Rs6q0fvR_R00ZO9kNF8c<*m87PZW?9Pn8w;c$uJw7Ys#Ma8IIolQ?(I>@DNz!E zvuGMT*>Z^M`Wn$*=BHbJ>MGZCNM&$2g4sZ{5kZ&p_*UJVNsnd+Imm@k@Sg&i3`uVR z`KrokQwo(SlGHzIbrgD`(g+QMKcbr?k7o}JBHqY@y&4`NXHkBk^1Bud+{Gdn4aSp? z#NMp(cpBk%6KNa;cbqh(lL0my&ap{sr9xks^5JsttN{bJ@n$OGKs;a}KADt;wxX=A z9MZ}l9FR(V!x+6AELP=BGj?~uF9a^8u|Icn!P;)~BPD&t$9SqCr(r9*RG{We!s1Co zo_Yb8gT&abdWp798sWxyeozE_er!5k!{V^+?6iaj>Uod7xz}K!&Pd-x23unqO2HSq zUbWtIE3j2gJ=vLjY`>>R#f}ZuH;mQI()UNHcWalhSP?1>wSJO|a^C|xm`a7?5a{x< zZQ)qbAKKtb#d)?XT{@O$O!Ue^ZNn8&KBa+OBVlu-^_@QOah)S=ax(_PcqE?Li`GN% zTk0)ovP}PhFKoN3)Tbi~b@CwZZG~+1&TQh*%xKf=_OPRv^294itNKKJ$(iu7LqmN^ zjayEi_Lb*yM26~m>Tdf4nhSD9IMUi{ZPAsr%1vEJhKn3%czw6~3Txf(37e(r3~PlT z;WpegR(;D;ZvCH9L8i-Y1W#vo#j6ru z#GGKV&*Ry2B)-)OPZ{)w&A1E#IkI_|>lSXa7~|3^jY>a88S~&64}v8CDG8OaxrNF= zAG=mD9e``Rt(yA6f5@GN$dBI@$6_ZkZE5&8 zfW)jWxo&{7uahirJ_LYp5dxma)6V~LaW_nWc@~h9-LDI*`&$`&MxCgcx$ShlPH$z1 z_(%1EOMJqGrqtg}U@Jhq%OQR5;$FJXFDJ@cG*az<^R%7N!NHzXDpQ?}rxZK>sQs24 zXmmU0MIz#Y#^GS4>y^*zwh_zoC1^bme=)<^%)gWj%Ru2iW=YfS=N!H$4#R z+Gb~?W8a~Diiynb1;tJdF9cn~##!7P?`|!XJ5x+14>bpFcfq!-_`9m2gG z^woKM%7a0eEim9lBU?1O3PqeF7O5+9jNToTVDS|v@qA)`jG6gwjZjhVsrWsaEJnTZ zo{{PA#pi-45b!kN=_FJQI%IimE5|386YZBpGW_+Fn*Jfo!5i+`-4@Fy=n`rXfVqIs zNNi;$Dpgs7GO&>ei%&UK^}`00XgjLIwgru8wY3H${J`Ckl|HuMD490nnWOA`#x`Wd zE&mwcU}h|=BR^!p-BC>EGYl{N97EIzsZF%DIk>=z&TXZJ!6qPrDODKe22b-Et*=d+ zpxA`JOTaXJ^f$_zgM$M~2dJj*gH@4j*e7419|@DlJvp$FirgDf77UrB|0A)dZY}c;1$rgPZfMuo;m`6(tu^E4xvl%Ik-}^s{xK@eK{p%|@IAXa- z<8Zt~IuyJsx?Ff8%-Z$prs4`Ivl=>3s%lGl(2 zlv8^s;E@MS6F1}7Fpjy3cG(5-yQnST)_2*7ey^K7LK20`1Ajms7>ty2wF6=UjdcFb zr4`*178}za$%{|OO-L1)9zCqjS%5E89EoYom7QF9dA7%zCxXvR3*rKHzs5U3UPN_&d{nt71viSb;yqV>eaZ@EX%Je)3I3(v%+qVuz%^f`qB=#()l}qy zEEY4RmCxtd)opim!^ch5AaGv!#I$1vtwZH=aRgiB&|%Tan&9@Fy8?JT+8BF?$mW;O zi|;hKsnz6G$al>9AB)ln%sG^CtyEfUI)rNZ6G{6{HJkme8ES#xAT*-r&#as`dqWoC z#%R2w&1*3AvIwb1ojsX19pG0gZD9xmn6(P84bM-)@sidyo;=jr($o+$n=;)60yuYepZcCnPJN{9Phr%(@_i1p(EA^F|$gkNwH(XTG79V zWa^}Mtl6x*>zB0NKcxrToAd|>l+Y6c1c}}Ezgxm_)eu*O48Uj9OCbN7z8lHhy+Qn* zu0UdOgaqTLu{6t`I9zGTJ2Jj~kM&L-nN#z`ZG@bK-^owM z1&6cU?4>p49X?&l62T`!2yfcrms-#J_h|Mz^xTSC&meW&g5SbH|MhjFTx~HnWeRs`wl(+6w z@AH{#^=~RYGSh}KttzvCs|RAO^D5nR&Y4f71rmDjd>PucUDYw3M*C)GlcI?UNc4}> z1=luQ^v@^ndBP?s{p^BAg7*W|ol!f`%o;hgPiZ9<2ao*hZh7PgLcN|jLdR;`OyfARs&0`QR4qie9Dl9#O4z&ScvwnXBQpFaLInsh#U zrzg%EQ`sMDcm|2x6E&Kc7kKd1*23lL6&FcV?vS7XF5xzCPyD{3>&gK!R zWHsR`6wVKz|1qr@*}3tBG05waF$3-A?>iVTwGF7~l3Fz(`f}jgZ4cm%avrG!r{wcV zqvs5BABB1}GDk~XhM4)B&}p0H&8CaQhCI7T9nokvvkx7ne1H4v5Rn8#`?+5JY3Ht9 zr;J;$LQ=#?38YZ~f79wI1oWlB@iwdfJ)>!uJ2Ktyvn&MU?3-vC3<|a*i3| zCD8n+e&_+)B1Lj0^W?F|OV)$`l!z746k^aTtj|^SAO{?OpKs*b8uIXdxNRUF^LU4G zKbMv}_0J}$D-~nYJEQhJCck@#W{ys_H9Xcf)Rb&J2h^t?YXh)hCjw%*iT&TcN<=6_ zv`|59Z_Wzx*+!=k`W2C+J+mn)wU2&n`r45Es=WywNA1^ZMnbn1=ch364fv~`1T{DR zA+N4sTaci53V1yVj4{Q1eiUw|!#s9NLP&OqG$rfRqB+C8j)DRA&`zCzv&8MIYk)FO z%~=qXxE_4m(9nRD&!fL5CVxotsp5eQghMFKIx1=2RR6yPqQ0MtZ$0;XEvEqeJWduI z0hVu7JT{GVb`{~#`Z|HaYRii<1H%K{lBqR>7W#o2*yPkvOTVz&t2U_`K zBGHMGz4wfZ|CIGce+*6C%T3Da$T7(;!?`>^3x6x0EN&lzvzEOZ2^nB-E82Fi(p1-v z()f1cPoyq#u1L7|O|(1)7`L;}{ROf0=(lG3FaaC7^~7Or>j|0}>hOpc8cdOn{=>5s zKX+T1NEG`Q5I+bAjdjAGRDIfSV-fuBWRV8tE~hWd`N;m9lf{u;K|hYxSB*PI4YI{M ztZuD5^9m9wxvRSm@%g-PU@?*gZ@M1^sw@z`fCqH{Gq=kLZ%pRE6Tfd&YWXOS%u8)A zRe67_*|Sotk~2W zpLpK?o1tbaJ?dth_qHQEw0S2Xf2Z zbR}vrZSRxUsC7%dMq&!h;=}snDXzgu8m2xm6kn!6#AnsJQ`~18WS(TzYR{E9yZ7A@ zfstWs(J7*pzm+V;^=jcv`i1%GUMaUwn~|fr4_hyOLpYKr*CK2B!4#^!#v+RLgYL;L zgz%$T5D;ak)%3&ljFm+fRO9l_tCgq20Y8D7RxesiZ|Q-zAXdBumOP8M)>P4{A3xkJ z{cXTRPR15X4zh(_>PYOwhg)X?^&!-wB4o=G2hTHGlY9L@pL@!z zz*?bT$25fE>~KYaI3ehh;Au@W4z1c4txkZflExyUVHe6D0u^56yueD6oysf}+~>>G zAW8w{e|L?ZI(+&mNK_gjnHwQ4VI&%H7<6G`GKETQjh?fd94UCHpX<(7Y0Q~9szSUA z_Z+I7{$9W%bMuqUvzEKivHX+8kY9Yp)5k|t>Q#~ziUa(cVXabY9PXLm4jX2&83DgN zk3CHTJ`74r_(?30_rW^H&IT!sVHb9ujr7Oztjg27=%T}o+>j+jI@3*MS?)PWSct;I z&gS8?Ddx(G{XQ21st10w!-3mTt!qnH-gjCd)v9{Wfw9DQ5_8D6B4PuxAEqT%!X%iu zp1h1;P5W>9oX5b*l8RcOq<|5w8=}05DqCXiLmG(f>rXAME zK|x7#%lKtXrnr?JCxY>L{@$Jf_MGLxFWoiNx9WvQrWNjk;<8hhrTibaD@)W-ub-da zS7yIx0@V`7A#Dw%i&3BXp9WN>E&8MdQ3CSd=clbZ@JZ>KLL%&-^4l~g+wwUa4366J z8E&Axm}D#asyb#67m|I#11t}7h)oSTZFzt{`REAu=T${)N#35We9lNsjtF!VgbsAl!4{hB^o*^J&(~1_Yb}vJ zq26KW-I8Zhy?3jPz+IO%>m11?5ooLg7DV0anyb++)EfXuXAzO`Fa!b~Y6Sd%sdwT^ zsNz;5p$v~b{0U}d8sWq;^1C)u#wN+ws$6iF9Przr!p^)+bO0qGHtR!uO-j%0&k~yC*(yq1ETy zGwvetTJ=GTi>HiExaiiYPo@&>2fS(-`Z?BNSv(=qd#$42wbKdHEZOKvf8;8nZ@xjgvCHa+~-2%@7F8P!46!gxwVIE9K_QfrW%SKoO5KDmS4sb_ zv#xq{833^r>g#fPMLy{9fPNK9waqzb`E$lBq(%DX1y@>+){|DjhC*;#ANz=iO|){Taf2RxzMy2%-{%A9<2DlSpcWem3>KfxvTu{VTrw;|5}{q+j3@)0V#$=t-E zRCzyNy6@AH%A?8K3w!z4OT?$C(3s=D~h$k(GW2;;FviBdgER-9_57b>n!L zmCO=HvBF3(Znc|2`Rjw}X?HCT8_2SC0WHZd;>1Aid=vc;U~8Fcdm>({M9y?STGg?CGKp5PvY&}>}ymS+v0}TYSD93h^ndqlcbTDN0b++$;nx9R?B^V#L@ZR+mt?c!9PTw?k6>H#mX<4F{;Hv8{Fm z?$Zq;s0@uerW?7Py=-EBbcowFY`d>3);>YM{CkD3V812n6I(F1y{Y*Xh*^BatHB4#(#{$Zzj#4$t?u%H-EqcT zqrNjfU?<)GOcfy8VKSHEI9?~WQQ1$Cb~(3U{I%`naqD)B(4$37IteM4zscfU0v(-4 zYcRuG6@Se)+2?2ssKR0xrY!wO{8yC~cwCZaL&;nh2AeP@2^>m(SHjSs^dH<Iu>}Up+*GlT#?&W^{O?@*fLfZ@q;$x5h++uYQTGx3@iZo7 z7BTGXiQ5?Zx|@&=4ECBmT5_^a=?iFYD_^>NUtY29u;=1U{B1}4n`k^6&2zK;Lx)s{ z1YBKJ%N>f=h%Xn{NHs0Pxg|qjPgh;^YH!k3wgDHE3{}9K7{W#Y%U%g?wA3o#We-ne z3ep3d6AIFQ^#pcfhSF;&i$beMVxDp4bg^+aqwM>_>}K2E?zP`51SGgvfFyvgP~5!3gZU?zW7 z!N%ar$7qzD?Cm6|_2#su_>3`SYjr!BX4>1>*vN`-vk4Ua;XbIBti>OT z_8&Qjxq(wC+yWp+U2re&Dt4Y(-!qAwzfx}q;Qhh2m2!VUd}khYHYNI2 zf``XnBl9ndCtH(YkvJgfmEKg_p+CLKPVa`3aZb`kp_~KFwUbDRaDJM4Pcg`*CH!Rm zU{6YgCEnTCDmV@Mb9<6+PA`aK@H1y8=%O+{L zQv10>4`IGAdr^kT93PYE=Wz8S`Vy1Z#D7vr06`M>U98>eKODdtCou(GjE`-_Qain(b5q@0PKPK!ZIuBMK*Rs!ee#aqlxVn zpB>PMv3j67%rOG>Lr0RssAJ}WbJLRcbnrO3U$B4 zK9)b$IYJ%WWPu}rc%=PYaJ*v&OVKh zpSN9|;b32e{dNO~0<(OeN3OgB><>rfT{7^AX0us5A7RtEf?AZeDi1LeYz-}8hvRsJ~AG)tIRj0SxU60m3^G>aA(b&87QpGk3qM~9k; zLD!jScYr+jSd>}QEj{1b2JhQ8S2raUg{uqP&N{NOn-T`=Lc*^tadIS(2725S!4;dY6MfU z7{KIZ)mTaX&g~{M-f4uGzf5aEos^9WnaM4IQhf(sq`c6Q}> zSezOmU7Q_BB!&9}(2(G4FeD+gNsl)E>HT8ae4M<2K1rBA-;C!*i+*fr+PGPlqFt+iv z)s3f;EPr8^?fMbW$m6o-)Ww_yO-D^sMcYvvO^&hZ32C@OLP3BP{1zjpAho5x`5#o3 znxxzp($%wQQkuUM^NA*v^h<@J*JGeyGhuh$NdFh{-VmN$VnnS)z!4w@qquHe4IdTNCKuIVY7+h<~-xZtOaCx z(Ep?9EZmxW-!`r&NGl+tM5Q|fQ5r!I>25|Njnp;)0VSjaX+#(;vBBsZA>AFL2GYIJ z1F3i4-*LQu!gD{*bKm!MUFZ2ZS$NfE*X(dxj-9~@pduP%HOx+`oamLqY`ZELqh!>W zxF@mYr(>@yqdr`rF-jB?mDcOA?>wRMsHkxjOlz;>f5FHN!*C$clzEh)HBdy+_qKZX z7|e#?-^rBPc^a@jKn~49*M0JIGWxHbz1dg(kuX)8MLNRhP$T5AMQ zLpv~U{$_g16*knI2)ZnU2(HxLcNd-fRCx9d*Q%uS#JBW$dE3^fni0LpzEIvEtFZ5W zcVklw??>82nX7guJ+png)l9|kDjxBidfB@~ySvphe>gps2>Hu+ehaTcQ=LmTV)_zA zt3qkcV#T#@zNBE1JWfp}Ga=iNNS}sn3i2Ng|K$YB9}bPsrud$;{XbiH+wh{s;tS;a-lQj(Uhy#u?XA-Rm44UB2ueO6nF;dF@Ywgqzq> z1iHFOKG@thp$p#SjK-Gp84>jaELEm!9be5En)PN7%c+s>*K0-2RwPB1SRC?dEt}o$WR5EQWGu6+|?`$w1(&D<~YSB{8 zUX|raw)B4-lj(1Q8yrfww{E@@s;Rhg1|)t`+Im7^azMvi-sY*+Wv~@c#}dl-_%*M= z?b>6hC`?ATPOgaCIX?9$H+8^8itRFkuX{m+(Wc(`pLVh&#Ci9?@F@JQDaBTzdEVVp z|Bf)&fH~yZT(WE(t=|R5YR2Pw*|+SxCcD!8JE&m!Z?)_+)`gWhQXi{y`7-R*%~$h> zG4Nuc`{M6*DUq_|Qk|foV{OPr^+=Iplt&%29~w?hjy}-7UvQS(J_wtb9g=8)4Z`!X zMPSUz)o`J{F-nJ4e??x@N4qNI5A)N8ou+}wQxn7&F)RNi@~8ydnMu&q`G3k#q}jbG z_55A+;Z->Q781@@^mX{T!<%W`+k0G6vbJ%|sVaj80{~5tj%4kWy^ZGSC#CKDw>P-f zkLaeNKNws43N<^pj-He}*@5b_vNyVjhRTL+atZ!bwSen?r|!Tx1x1ejgcqsmO8V?G zey#qgGN@ma40=#+CMh^s6(@|qL20Q8aw+3iqR%BCe26!4;jyEOEXFrCi4Q|oykhA{ zck6u7QVad--F@AW?lm*zhVq7Ag_#%)KxL?18Ra)>ot%XegDtf!&_W-8`)^L3+{-=i zqjue4m}cWS_&)TQQC$5G?Wjb9b+Xm(N?;i4w>wvIEf`ld#OnKL4{BcWWWud$%gV9{ z#ydNYHiO+}EpH+crdOyRWXCl?LLY8yeDKB`jYog$ZK9n%PJb-zkX!H`JRh zA-oRT!8M_;rz;z05PYQ1RGReGI@RRBp1|7@4CJf1Wl5zS^Xeka++n+bj?a&JZ^J%k zwQre9EZ2x$mHsrU@9Z^+EXj~;mzQvExs}s$sl!iWZb%F zEtw0K;csyj2;et01K;iLue5{mJSF6omqmZ^VJi=emB(lPj(@EGH-Y>IR48tjyUi_B z9PrHh1z>8H~KK&NM}XgP7!TK^mLc*HUT6w3Y-V@kJs~U zwz+E)8e%HA2KJhlXjAZg>AKQKtGMB!RbyJxsoC<`Dz&ob=@bW~*4WhEUuGZQa-*q> zil#S5vOanaDxhr6-?3YuFw2iri+{zFgC0hB80_1U9s4u*=Ky280=8d1@Yd*1n@U?y z$(zd;Oq$QC3KbC_Cy-CGTRyvKxUoNwz#H{rr*|Mim-tJIpghtDNbr+!PwBD#9L%$q zI+X28X#f~u%+>gG3m1_L00Naxsee{S{p22I^#M}K<6=ORRrLCqjSeLW0t$2fx2M8& zUf7=lm&=mz+-k{Nh6l#nfbl8Y&m%@F%Rze5QfP|h50St^9ZLtqji2&6uuIEFWa=;8 zec$r{sk}0Opt7u&&(mkmu)_t7&pE5FFET&I)2~{hX4ag!@3ZH4E}0l;j6`DtgKmZ+ za9s?LDbeT*aHoN?8O@0 zDG7bA{2CZvVgjA#s8LOclV}d*9WxwWY}a}k+m%A$R_8n^adC0Hc}sG4sN}cf8&s8K z5RddqrW49fQ&ePG0KV4VdFdZeTUx^Ryn=G?~~AE}IZSMI8S#R;ZS7UV}3J zsnI_?QwwNW>7vtW+m-2v&OEg`qqc(re}!JQz>TtrBABQuvCPNY2gO^7tS@7AB!d>K z0Mh~^Z`Tw&xf4IogsJ8eZJ2WTXRW>Uu{38Nj?drp!h$zd9-{~>9xH;8IMm4A%#>4kG7`Uz*WW9FIC%J2T%CnBe{;5N?&17Z(|DT z#pR_|XQS@jey0%uvz_L!v8ZA%(Db`r4Obm^4=RxKSVegl*3{R1(u_;wFAZaTc>Aol@z|M!)QkH?h~W7jX7p&nA9&`m52d zRStslw7uuh>SgBaV3uSxGL7}zA(|4Rg5pE4_q<4E0H}3_PyTSBz38U5Q z7&7cH?8Exp$1eSlt(VuSS-k zZkJ!$3W%-r)>Zy%H^uv){m%O4EAf*RKM7EU)OI=+odF);5bYmLd1(^P(-on5GQSDa za7`{=c%?nGV`ovJSodd-0XC79`wX!lep`K~JQxQRUj^)s22{FaC#YXuOI7mFSOO|t z#06r{O2DtC?jEEWoa!KA`W@aH8CJu?Eh<-U67(wN-s&1lP|*6pIQ^Ebd<7Q+mdpr^ z_J);Al5Y3kcR_uPu0B&DJSb*&NK;0fH-lb`uY3;HU|gNy0bkm5%TBR*&M(_Nv=E>s zQzi^|b(AiP=9xO93x4J|F5`20#!LY+8xUNqcduwTwO8q8rSd9q?$HMf`#96n)Ekbu>-olkP#+x*MIPTjsMLU+Rd(reLb*!JUr=>fi@ z`P~=U&_ZE5<-1dRb>2qL6=!C58a7Dm>G;-RJeq{w)ikF$2Ja>Y48`rkJEE%z{*bEn zE_FEFffdJ%?l;OAeLnMr6|6`7nzH6=AauZeKyTwvQqNAx8`^DBIgyL)o!8b#gL{iN zt#tN%0VKVlTTOE~RB!RX&Mi-fINlt0!jogOxi zINkmGv#*qY=yjH~lsmlv?;=(bWQzKP+%YjQ^(Fo1okZVI#dcWJ`4*)k zmEdIuGR1+IH1&=1?JM4ez|iw^MCs|~W3_!-^-9bs*Rw#b<`~zrXPV#W?Ni(f1YB!6 zeg~%#hK%|e5rm=0Gk_sg3SO_c*lp^#t$QChav@YxwHvsVQO?f4jgfQC|8Q}#_)K#7 z*T^kAva$7$TR+guVRXQ4{iBlc*5F^G#1ur``3?J^aa@s#@cW4iH1%QR=vo*ve=ByA z(nU_WnFhu%>b$`2W^Kb&rBE_YK-*F|0ckOMJ%Fh(;xtp(SQypRv`N?i_f$)Q1)Yu{ zQ=9)S@;TeKOIzdR09W%jj89gah?1jpV(!W5I#N zueDpu9g;V~UrR5a?Nrw{E2!QKctx-EBIE`diiiz=|7i|Eyu$nV2`^*&-Hve*ft4iQ zNu#v7WMBH5qbbdj5RQn9but2Umr_mbVIZ6u^F_g!XNLgVq9 zhi(nD8i5wSu0IQf_ZfhjZQdFlosumnSw0eYQHuz~HhfM#wHSMR@rf!nZaCOM*~Igr}LiBEG-9xQ{Sd@|7IN8rpbhNiJa_V=j z(KY2(5ySjlKG!;zY8`3v-6W&FziC5jF^x(12<&c4%8Y$Xywx^O*Jx4JTAFMU;8!0u z?hMv_)hw!lVkC`x`8I01B?0CXZwRz%{7F`!0j<@l`yqu(uvtTWQ@)}w63c_rV)E%$I4E< zT1J&77df+!F{04-*~d?lZawZ8qSLN8+V#Dv`*Pu*uba8@(gS)EDobiN00q0ckndWH zeMA-}^}A7aWB)`n`Wg9LIXNu~gT@O-l_G!0!400N_)&2Xh$$l6t{VDG@gHWqy$)xN$( zyQYvPif_ZYXI+~GV%Cha^9oF1>HckDA|=1bX9|a_J+>o-*{Xaa5q8v5<1qf|w-dg_ zos`kh?IFB%(8nX>k3f1S4t04x;S1R{_m(dO8eDCu)`PSZRHZ&cm;L0=7@$%E4~vB3 z-f=5EJd+b^xaQC01?U%QBJku~@3 zPlDU#W1PnJvm}UtoV6rK(GEQ>`|RCb znmt2}=^7JduQ0#8FXpVw?hj6B4}Tk(>s-6gYaWW7P(-y)clS5DJ4`yGqKoz!7=-LF zS$kCj^5RYf;_jk1`>`eBVuku?dW+F~8>{5>T8aWuzZl;t<{%B{fPqZUBt!vwEoQB@ zJz89dQA}f&9@9pQAv}0%!IrCH?p z%<)k+)ZJ*1$n28P?gS(B5Cm5;*ay=iW4A1dw*L4R&;!_MYz{?z7BTMCUwydS&hJ{h zqXFG(xV0pNVYKQ*D|gSVj52GHw~c_gDIcYhO_lCi@Wkmy?WS%`lrz33h`f&sMX;Yq zM3D=4(2iHFZZ-aDqC90<)SH4!X0DB+?w!<57w4WBi-->L;WOC?X|J*{Ms9X#j$ zZZb8GueiH*I0g8zB%^-w9r4o2fX;ht1CumITFkvs(A(9H#vtYPSfY2@Rd=;-I}tOS z>Yas~o{NNxY_m@3Cu?{1kZL|P@iQh*EsIGbcwz3VdA}a9=I1uX(4pz2#GtusnEZ( zn-{HWFEgOzsM$hjvGxyMc0Rw9{?aAJ40_wFHg@-3Wn~AgrcPuziPqMX-G{piAclB2 zt*pgNCnPTR5GWSc!V)eMm452tP$JSUN72}@I-7{lEGRfw(^sR{J!`82>RO0 z`#C}O@O5A*^*AylDjphDoXHadR-N9tRkTuH2*R7vV*Y+stsh=f%4+mwpRHye-El9v z)VaVUZY4hDHE=AYUM6n1N#lAI6a!kMdAzgr5$A1NNP7o8dX#~(pWJZT?9`xR;*AVV zo-8dl_fF7AdS?xMmZDzt1x1YC|M7~A_3rDmDeq#7NNMs53P4%6Uyr2#0*p;L2B3N* z9zk)gvU{)lThIfE+xw<-vW^-;>T8_5QnECOaV8AyH4~3nF)a;o*o}yrMidGqb;^Tx z4`y!2Ybzvr{C>E&wAuJhY#C?5pU>;6n@AiV9Iz3;{{+tcLH~X(NiRh>Ax3f;-{ToW>uA)k2(0}9x6+7-`n&;nNybQhvZsLTsVY0>gSzz!%bLq* zn?{=d5%_tYw@ANE4;U$!zGE%yq|;D($B1M9OX$=TJ#Mj4*@ExmSZHjod59NVkDcV= z7v_w<@>i2JMyF3_+UCAWrSRhZm>g$%ijhYFCVSd!YC}y?t4~5)AJ^k79r{_Esb8+2 z_wHa#v>)IVF8u@p4=(V0h#}&>`23;ZPV3ndXsJ<_MZ$@S%(RU@09oFkv^Bi*>W}Nn z+KYNpBb}FtWlS6Zd+=uW7pS$Z?uAQthMz*oPh;`}i`h^0({4FHyX=f7L4itjkL{6e z#Rk5`oaAu3P%6zi)SOBRw{ZnQB#Qz!5x^Rp)+2ImU(EQ~RIp2wSrsK1d}>RU=w0 zO(!+tmXCzrob}iI53UB}=?6;=)dk+e)j7Qz0maF}=;L@tmnRkVB@}fYjY<$aZCE>o zaCwt8t;Ra}e2&(Ua6mP#=K1WVck~~s9(;u|3}WJwyTs4(pbvs^mU_=rK#1{3ZiC?f zoYwt1?!%}9R{vN}B^ATCGI2AbIU48pm29C9>m!4Lp{AY>#l=mIKW101OCt?bmDFeKY~;V*h1%zb z%>oU@AZ_3MBi)6JEm-x7M*m$f(%qbYthnmA$>fSt7K$oHX(j3|RU3HI9s_5y{;Jdb z1+;v0?|aterJGsC0`;ZDAVcLoUzz*oD$lCFJ0IrzJWA#rR~>zZ#&h3XfU)IU@0EpV z-FZpo&AGIG|D*XYYEn-1OF9dA_mZqTg(3MJYC%}Ww9xkS8ZrV}5OhGdh>Vt~ zD(ai&3O}}OEtvrTavXQWxolR4HcK=MJ4%%)7#gl52=ci&2c7F={J$0e#~Xcn!cPXg zP`B5{`hKMFCXVtb{U&q`HzPVCH!YdzBP~|BVZ-in-to$#tp8BEid8ATw` zrqS(*LGnhd@SfXD@4rq%{hD*`!#Ztof+NZ`qgtWU6OvHm5Wtj(cE8;IG}R4bGLcz- zIfU2aJ#jkhu(OH(@H|!7bEPh$R$eg|*5NTX>c}$t^MlSz^WntE{z#o;6?gfk>TI*U zlt){yri*!YdSQ_h1)5JM;#jlx6=VJ6&Kxi}{kC$Al&(naAgX58kR9iYM{BIyEw@Jz zQSQ*ra#wygV*c2@#i>LdRcpjpwrhpa2sY|ckklQ&FFx;PQwdNq%jhuRL0_e5@vQt*M6Q7;V4k>;AJbsP^6 zMueA|ZIukZZPp+|p|3K5_>MpiqMWvZ7E4*gmI56A@4j^O9hw$vD#mU4e2D`g*PM(1 z#yyFp>VTEo)A_*4_nkq!CxidwP~J`AoIXZy=^(HLK$q_gGe`1*L!8jEJ5Kq$eE7>R z{fnx`oq9RT6HT9OPD*O8@tz;ggz&QVR-PONZhM(BkA;8|&KA28Ng6}#51ZbHn``YG z@AKZj^?k+pZ8)3O$g9iXaWBr?N6W-#L@Dj^`iTIwnqbwNGGsA@Dq%YNyhKz{Z!D*Q zmmMrxIBCbOs?<0>VyF8%-T^j(pA0i`6))rfhPeEFKvJs1-YKmW(T-a>iRN za2sn&zk*aSd_!%d>3uATU(9H|rCUN0S8Dn0)*sd-jpDA#2e^II`u@1kxfW5~%|M}8 zo1_>8WwO3*ow9rytb9WnuRyVbUnzo@L8k(8GL{aV(Hzl+Yq1y(@C$ zeQ#a(q=cX zcJ`YRx1r66%BvYg_HlgMX5Ua#%tW1As!q&lx3P5Laf34Rdhr+D>gHT;jo|#jobbla zbJ;!`70B&w%bp>xSk>WUz_0rA&7#iS?!$I37#0Y@yV*)_rUaEVG3;@43q4Kx`fm;a*2(RZ^Q^+NnUC|?CyD zN)7i&`Sqnc`$s_(3|E*8404_dB$X5Eav7N3N{k|DZlK;EjoASfqJ53n!cs%iHG!es zQn})%j6drdkoAnNc&+l>zH@UcmzjCsyVrz!MMf2=EXd%_m5-Z~!w9LBFpT|OBbPRI zuCFDbU5Hv(m=&ait|_kQJ~vHo-}ZRB$L62-1%CyOVWQ*$3s08{&wr)k#Njerd1 zr+d5dWA9XRogxxM3YZ(P{>!BbpQbM*OH)!`T*v$vA2R z)EF?kigFV;%hFVq6$TG=sx((0VOs;Q8%Y>1Wa)aeb6aA4#)pR|CnxDIOPJG@62mfV$&E_&7x*07hR1<^%lp*7`Aub3 zuSIcBCo8p|uTP4dS{S_ZTN{z@F1)pP=C%A$C)qDeD*6N^q(c7~5>!|F@9OF^1QAxl z)XOo*P%@Qs07cpqoBV_*sr{uPFbK}}w3DBza1e-yX3elO-nFV{ZBUs(pV9{4W168@ z)vB0SLY;>D(ecq0vG0sNkx3yfij{*Y3piUP$qi?{H??Pg#%Kq`=m=h^RJu$fHsfI6 zpKI76S!DPM?XbHUf6GbWtMFB(4xN3Jbv=OHp;r%_Q~B38N1(SYmicdUA?XeWzX?eu zzpsmS&i6umXuB0nuKYx_<9J%qHqU!Rbey8yy69F-Nk3IOfWEXk^vx0*Ddx_eC{|*s zJntxH_zF6^Q(3rI`HvXgQ0ouJT(s29ZO8KbdS7a6<~pOZJ@Wh|Of9qMn}OSPIg)qX z{-tmIGeP*&ox0;mnPZV5f%_#XXpUOG*YfA0nw4;HF30Wr&I-0;Ec{?gv$1VaCp->D ztQe+hrwjjH*!nF`R3K2sUyM*nVhGgJa@50t#ZV%DnK56ont}ghLVsy7JW!0g`Ywy3 zc`02hwvzV*9?WPl3`on(bN+D0L5>M zZ07%rE?%LV%Mbx#OorT)I(na+MgqIO;H;KPZJd&?Em$TwCqG%cPo8KXzO5n>pT|4Y z!~dYyU|}atOz$SUZZQrYD~@(iWdj|N){Spo_abO*XY&k|{)72^L7qNyQJuOp_~HI+CaGJ@Xh_)&4vGo$J8iAayR2Zv?q5GH6j^CnqmJSfeKjwq z+#`*BKmn8OgAyRL5K6)y!VFDG)K_ZE$&U7&dub-_XYn1hPU^E@-7&56P9;B=e80VU zB6>f1BvzMMD)z_A&Kw|!_7zj~R1cjA+GOw8KoI%)(WI$y?C~L3!UVVhXbluJF&uyfATRQq5K@*EBu3M5r&BPD%W; zcsoQv8^OZ+Wf=l=0Dgt;bivtx#?6L(q_6i-0y#yu7}zhN#j)VyI?Mv$x-UWq^@%!{ zMS1%k=EU>|PszEFgCaOBsYL}IwMRRLQV+n*J(RUmmB}@tEPS_wWXanZI=&apTmC!< z>v~kEix#VZ+B(Watzez9=qrI`9E2S z{`001RWuHZSF3*crUfKn_8lScYxBTUlzbt|id|Tt3d3GwyWd6Kc=9lnx5M)Z3UVr0 zW~}Bf8s?zn@Z3L%O4~Njd=-=q?M(cL-EyshO<3Mxg_$Bio8xgxH6L|F)#cHVm$JS9 zYcBWC)eq5XzY{pPTzvQOEQh9yD!g~0e%=27DEL5JG<9`KCP?B9;t!-5^&*KoQz>~x zJ>j#PzEZ{6o=;*)t@0RG^a&Gnxlo~FI64Wg+D?f+1R0dk%_y$8cB+}tD=I{bSg{ml1@(L^*V^8Kp(?p2FdLh^xt z=YGCZGo*6%P?9WhoglfYDRDQe_pJdbs*ilzLqkLH5Az4U!wJ%#gKqF!!~;-WOTTM- z%ly@7`&8NoBjqJq!iTZ9BSAObzW8a&wY2pRweh|Plmf!m?)!unj?SBNvGAdL4jYFqUL3B=a- zO}|J4a+j7k(QdPTsy#65>Yc698@>bGp$I^qtXUea|7TV=n?hfqXKAmClDDdC=@YPo zA}#7jP*PU-o1`pgdQk`AskF6}g`MeNU};tPJ)cm>x3hNsCg_36H@U#8dX_1UNn8N$ zx!tg_Cz@aix5Rp6J#|8z#OJRXl^H>juy?|fsxKD&SJrCwhGRVA$({Wa)i>MDKd4(O zQGBLj?pmMb#AuN_jc&7%Ciy>;*w1L^%5=g-8FO|qm`rf9jJ8Z@F5xv+tVwtj^vq(a zZfAu_agyTE-JNgB!21IIu>SfizLPo1^0_rMye=_C+;D4j#XxuWW>2*?g=%Rij8Fnn zq(!6$Li(Kim3XDo09?LgVjMkvrqpyMn3b6+_+QG;t_8*4SYiR*#{pwOZ+^d(pz-qL zrNew~CUxE2APcz6@Oh($(GOmZoZ*r(m*;o0(sC|h{oG0gzrkG)qyH^2n-y`5ZMG&%u_)y($kif)lCWe_xQ{oZw(w(@}cmZeWJtK}j zmDbsC=Au7Fl1wHauft-%HDX4BFsyC^Bd#E08`VI;b+k zil_Ydw2Zu*6)L_IF66s{X4IMrIhr@< z)@lxc4R1qQDMmgS2n+Y{NZCd)pL1_cywd}VYouSz5~VX)Nj zm5dtIvr*}woHapuc%f*RNlfndYETE$`Fh%!+dheA34$JDc-aBlJMT+}w0$iCQ)HN; z$w)A<%C4Gl0P@AmaMjh9>t>hvng{P)`DtbI30?a+JT`Pw#qPbv{e95-=?stQ zRRlq?4Of(-dM)46@IqLgsX}_tceYS`9bSAglMl*fs{_;NFMq)A7C ztPqpzh=To`Kfsms%!L-o^wIuF!|WHS8{NPA)7-UW`c}CFY_z|0PIqLs+gKi`3L~UW ztX@-zJ9xe_5dXakLMZy&>L{+R)pLaIwp5F@IzRcj^|G?)6h;`SYT>Te3oRP!bh^%C zj+1X)8`A5U7L#~*vvD==pSpFj+!6jCjSro3TE&}I`~xI*iRwBj7y7yHF!LK~C&Z!L zsGtvbqA8twbc4KR;A(J~y_xgq2hAR*<*ty#dv&}2^~}(1QE~e$Lk2#}y!aLD=u+}& z3S)BJO;?SEfI&5;tNu59cczzB-C=3QHH7@E3%v*CpgQD13tvm}bHv(_e{9eZnWD6Q zvp25Qdmc*TaIJt|{rL0ecVE1kuhr?3kF;HtwGAzmn}fNh@JJ4B0^5pRg>DtZ6q$F$ zU0uVXVKXRy45UUrJ{(^?`9KP#2Lb_Pq>-cD>>!b|=G3YyIN~Su`4xZcdx58J9z)Ct zWdROKjXPeZi>SpI_8z&L^VPEwRmIQ7;R5l$DQ$=Id6i+UUOCd6Y7=Gr*sX1#-ja>x^7(*@0_@b|*G{XYhEm!H34oS)wXu z-pL$I#2a*>g@Q-VbDtUyE6cN?=V^Yp4||Cff_4 zYG=|WlMR9|YyFnR-IAE&)1;LW$p5a3RBOYx;@;1Y@@y96nq{)}uoq(5gHUVM<0&OB zcMb0HrVYeu;hiplZ0mDWb?LZ31FrlyU-XmaLO>8WDq+m8a6k^0m*wpvrQf55e4uv2 zn6!^>#v8cfMrdbQ-8l1DvlkZu(AMWUlj`iB3x@b&SFtkJq{nj=Qp=fVhKzu z55skn$QNE{H9zk!JbKCiQTq(^s{0H4?1L;)Tndo$)vC!f^3Go|(U?vaeDx3`!Bohv z{c;RHvWHNhLNFh=mH4;UJ@Rbhh6U2KA80VXOiv;Uqx)AAPamXw zU(0Kq@qrFK^eu-iNrma3l)d>=T?r!4c-7mv5eQ*p@@R7yNY;|b^n8U6Q=}CVyGbGiCT(eq;GYcXU%Z~Vqwe7nCmTGF>^zN>!2 zhx&YG6WfJ&jZ8?>aOX;MBFhj-;48>Ew!%Si-boVZ5q^K;-Z84^@j8w7Z)Lj+EW_L$ zjFADm8#YxeB0N4JEBkkTx$e3fUQW$%t5qlT8o!0Nv{HXF^Vn~NXc)8RFD)THjR19B z1KvK~i+?}GJ}OrJFN-)25W|nnC+T9S4zn(GSpUZFG)HxVzxEyBdmR@y*O$P=Wt^e( z08xS872un|E2XiAkZWmCf4N^ju0yLDJ>ufE3Wn|ypg9iTbksL+dW0gG?`Yp+pFWO zpKQ!tDN4VO{LXzFG(9A}Otx-12Y~;S> z@44q|{d>4Hb}Han3&bOFz>K(DK}$}VAk9dJ%4EE(JVscLZb0wuEEL0t(|^BvygAa! zLngAb~Od!7W&*e8wK>;A>emGDADH0A=EWgz3aQa4YlLN8*HJjv-#rY=Dv zWfoiX*}}{EiHuL-O|>Apew*HON{MVV@m`@hL3CSemiZJU4`EAB7TlF!wt#1w-B8>- zi*)iRkir^L5q(neqqu)bKqI3=E?+d@d-*(Z|2C5z(>@Q<+_isHivq%G>!HnAjoirJ z{gIOMwIK!&G;2QKXV^`cE|iXke|f|!W&Nu4ZbxUiLxo+LN$k~EQm$mT=1sG_Oh(|( ztzDSm`w4}%rK*r-QSIja;j;{ue+cvCYIy0p&$NSzkNBHH^#&w7o60L9f^KB7H_+8g zqKxY%yn$KjQ+TKMm;8bM`{dxaFp&! ztr-WJ!rGy5vXNG%lf{JN@oA7XJLUi{ylyM?9|=Z#Ly_{})8dVnrLv$7r8-jlT{AiQj1lQDZ?P~3O{g>lutKu3g=kErDpTn zzd8$HN9yq#{x8f^;z+iq+`rW|zW8^`!iQ@$zbON}WFLe%0Xjn&ka?yA!y6Y;dR&kS z!g+<3{-3}0WPS+zIUCeeoMI$US$rXZB-nMJp-3pozxIigK$<6fZG3UG*q^3Y%Bs6d zsWclp3~Z=6n5zO7YOfSJvQ z6mYi0>u)jkv?q9-FRcVuMQbWK+n&{UlT!ztkM)x5KQ)2c{n`CsMkO?IfS3FTx?K3!&f1aqk*}! zcK$hU0CLcG`vf_^)&*YyFMqyj(ym2LgO}B0la~d)x@~pCB$v%p+&I0F?Y9M3e&2j~ zJB3#Y_>ktb(ImoC5x`Nw;E;_9J7X!{eXWnJZrYNjE-&o^%)SnMc3v^Y2$q{bJYtxW?m(YmRMh z1#3y;!8%wvOP|1k>rl)!`QB#s`&Bd(jZqIxWe?;jOlx^oUw$kG?>8{}lpYb?t;+80 zV^3o{s2$9O4s09@uwG;1D0ex?+3lc1vQB{F!wob;*84pKzP!E<=3~;x{p`8{7Yy z=W16?)g14F6gh-^v+=e0rw05dOPxt3&S>QW*fQ^sFf`Hxmy@zkQXgiU4!U;hn+(qV z0W992T5mvfSGaNkVNEug_y@=r8ceFM_k3N zM}_7$^p#n*3gTBBBIvebfn+j&NED)r8)M$yYdXJ?zQ-zrIN>+`SptVVfA-sJR;smf zYClfkj^ypa@o3^7%nd%U6Z3TM*mO_hf&9&|Vg0x2$O6#RB)dm~HrfG3j!0>cV#?)f zxi`jR#KWAPj9wa^-L(7qVKiAlNSCMZtrzSm?XaQ$Fr1Rd1kowZEDddrF3~y>0f=_qF@%PpY zJ`K~;H%^7`^9+cHMm>2dDLF~Zf+exCo#V+|yjbyk*!gjWrypylcA?^)RW{T3SXR|X6hNPzPmq-1Vbb1MP0?3 zX~U_0OB7Rq;T=`aCugBJfbLCQf)YnQ!_1XB^QAb_XT1cSrzniivF`w1?ygWM++K_X z3E~qxZifKVmrjQ|)!jI8!6B#2MTisC^r)M0>r)cM>qeqYsPJ9WN5+2;^yO7Dp2^=K;7l}u zCuHF#&)Ubkb!+Gs3nVcmTH!^(FZvPn3Z|fiB&O#*-4*4+H?oOgy-rsGk}U*5c@9h{ zmI1DP3JGD_3n~*hT~tK6-BLpH(8r@V&?XYXLMlUx;)!+mP@2d>K=k*Nf^L4%8j9HEiJ zRA!;OW%c_{TEd0u8>(@XFNzz~1b}AQ_~b5L%XLd70`hZkn50KkhEE+3Un#s}l!m?I zCjHQ}d_CRs_7gss=$)ll-w~yuD@@+t5Sn;_g_P;7?7+AEAe~R57Zd36c6SrS(sGkl6kCPT3*|-%p-&11@$fC~rZ&~nOEb&Hd zNWOxum&u;Knxxz2XI2?QiYiG;cmGL)@%lWu5YK)C=hjxuIu6gMh$3D`bqrvb#JUWx zUZqohnZU^0w?$?n=v%bWD1>;&7v=Z){9yU$zv8l(^blH|pw)N`g^!|~+u&>eJq#ut6!r)Sn2P-%XGzzaxL%>%)M}_QCwTxWK;N;a1F7EU zQfdSCM}i~1|1?JB`1F`=)Qes#Y@S*_;>9$)Bu-X0;5L7ex${n+CcE-4z{7n#BKCX9 z7E&r;2{yNH?wp`+`!pKExV7cEB2|>^a(bvmAfIriu9*3Cs6{D{Kah`jDroUjTWp|` za*f6ngxPW~C#nhK52qV5mOc85*~WLTe}tI=$(eu1$jUCV)F(#)4DCv|i> zi)`!{bvAbj2`umC%z^9p?M`toAJ zn&EsjH?X4F%i%9}ci$1eTW7VN0K#OXbDkR@&b(zFBW4~8f||7&bR5hSEZc>`9Qj#G zcy~XEbH5+{dd$dttjKGJr4vcY_nNcfmNu;~w^3+c29HS%QU^b#D9-MAM-6=1L%b$hY-T>*o+W zlX9MSPF$#F7?hXGCWKr}*qB5>T$J0(*mxTR{{!FWaYY&uZ6A5;_%A{~`zo0p_n%t` zgY7;*R=>UNNxhWl7xS;xPjk(&D_=au;iltyj)mCJ-u(9k#w*t35PC|Z{q8~+2yZOR zjMtHK9JF%;dFDp?Yx1#{*>^f-L-bT`cJK0VoS6`-2y5ES6YHaH*e_iMIp{Gw)>xFY znJelG!-QtUfy!17K^37-Oot*lM`rpGta__4D=h9wSic=435Qo`UB4wLk*z{QmT6CC zfm)(0B&FL$9QUo2W_i&v>Kw}doqhBEd;Be;R9)b21SO=rA>Kl7z&9WEL#CvSi6$mA zk>*4cI*TDyr7QcB=q{r_?G4$-#iU;J<;=(=^>M*+!;1Ev*q7udplZ{vb*!!qU7?>@ z!}gE+9BC`5c@gK4ec41$`iBfZ%+WUXwe1wl2+%KCD%)OOB!o_H8;v@(wUYcvem3$w z<01A3`l{Q4&#pE=B*CSD8Q_*{r2qwSO^D_(y(*OOjC5t1sUWiSf=bLlKEZ1;wW0h{K5>@|}R zno<`oFx#R9J_g{8HqE5${a}8h*64(CKKcDk9#S5D_YfP=;*H*t-&&Q!xl_!d7~DQ{ zMtA?^o;%`P^mN=K)R79q>`~)^n_b#$e);bD6lIzEKq@zJ(lKpjn7uy^Vem0vUL&rZ z8$5M+@n3(T?M3@%wioAB8eZ4OvH|~m%q}O0b5uIq3rhN#jh8=45#7_I?R-Te*M=$- zL(bi1N+!EI=%>CRE|#3B%!5*xWc%FD`K#SPjs9K32w}4u$*b(-BthOmV%plFZM6g+ zbET<9&&<^&&EnyjXT^7*Uh|7^)gNj;i~l3gU}rb!gKSgHDZc*N@Hu`H8|GCao8@Wt z;pPw`k*o}P8 z>CBGn^Za2!`PPkbVnJAEebPaK=pUY4fnHb=cuMHAwk@7n?hWWGMt@rNoZ`~RK!dkT zw#u+qP2R`>pG)Sp*gMzexba%IuG)QctK}t!bb94?iI!B3g*XV%~ z0%I`ghG%|XujfD554-RCy3RS*`?yZm(k;a~yRhzs(mydSQRSkbg~F#*5-V=LSS%U1 z;BJ%S!@L^ZpP>Cd)6f z9r=*^p~G?l>qgQQ7hsBh=OAA(t|Ggbi;>Jz$lgr@IdWn_g0$`52~hGy>ZsjsW5WPS z>f1Z+*W4)U?b_px11nqhOJZ)HwypKATDv~me`)Ks!M5+%VU2@HFYmlbH_ow3HdV8;% zL)XWhBUy5Y%^F&+D@uK)zS1V^r+>h7w^n>H6quJv|GOY{zUsX_&WoEv>g=<5{SJRB zLq10+;12;NpfpEmDLy+Cw=3P)d)>�jW8Kve+4WRT)>2MPw0lw1TiO~ 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%0DQ!p!vuDqq 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 bt&;x$wD74NchwLC00000NkvXXu0mjfMkLYF diff --git a/SchematicToVoxCore/JsonPresets/noise/NoiseMoisture.png b/SchematicToVoxCore/JsonPresets/noise/NoiseMoisture.png deleted file mode 100644 index caec3dd9455de01745d4574b2369a0aa968d5f7d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 103546 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

e$&FT~HDLdOY>id0| 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 where T : class, new() - { - #region ConstStatic - - private static T mInstance; - public static T Instance - { - get - { - if (mInstance == null) - { - mInstance = new T(); - } - - return mInstance; - } - } - - #endregion - } -} diff --git a/SchematicToVoxCore/Merger/SchematicMerger.cs b/SchematicToVoxCore/Merger/SchematicMerger.cs deleted file mode 100644 index cf46eee..0000000 --- a/SchematicToVoxCore/Merger/SchematicMerger.cs +++ /dev/null @@ -1,192 +0,0 @@ -using System; -using System.Collections.Generic; -using FileToVoxCommon.Generator.Heightmap.Data; -using FileToVoxCore.Schematics.Tools; -using FileToVoxCore.Utils; - -namespace FileToVoxCore.Schematics -{ - public static class SchematicMerger - { - public static Schematic Merge(Schematic schematicA, Schematic schematicB, HeightmapStep heightmapStep) - { - switch (heightmapStep.PlacementMode) - { - case PlacementMode.ADDITIVE: - return MergeAdditive(schematicA, schematicB); - case PlacementMode.REPLACE: - return MergeReplace(schematicA, schematicB); - case PlacementMode.SUBSTRACT: - return MergeSubstract(schematicA, schematicB); - case PlacementMode.TOP_ONLY: - return MergeTopOnly(schematicA, schematicB, heightmapStep); - default: - return MergeAdditive(schematicA, schematicB); - } - } - - private static Schematic MergeAdditive(Schematic schematicA, Schematic schematicB) - { - Console.WriteLine("[INFO] Start to merge schematic with additive mode"); - - using (ProgressBar progressbar = new ProgressBar()) - { - int index = 0; - List allVoxelsB = schematicB.GetAllVoxels(); - foreach (Voxel voxel in allVoxelsB) - { - schematicA.AddVoxel(voxel); - progressbar.Report(index++ / (float)allVoxelsB.Count); - } - } - - Console.WriteLine("[INFO] Done"); - - return schematicA; - } - - private static Schematic MergeReplace(Schematic schematicA, Schematic schematicB) - { - Console.WriteLine("[INFO] Start to merge schematic with replace mode"); - using (ProgressBar progressbar = new ProgressBar()) - { - int index = 0; - List allVoxelsB = schematicB.GetAllVoxels(); - foreach (var voxel in allVoxelsB) - { - if (schematicA.GetColorAtVoxelIndex(voxel.X, voxel.Y, voxel.Z) != 0) - { - schematicA.ReplaceVoxel(voxel.X, voxel.Y, voxel.Z, voxel.Color); - } - progressbar.Report(index++ / (float)allVoxelsB.Count); - } - } - - Console.WriteLine("[INFO] Done"); - return schematicA; - } - - private static Schematic MergeSubstract(Schematic schematicA, Schematic schematicB) - { - Console.WriteLine("[INFO] Start to merge schematic with subtract mode"); - - using (ProgressBar progressbar = new ProgressBar()) - { - int index = 0; - List allVoxelsB = schematicB.GetAllVoxels(); - foreach (var voxel in allVoxelsB) - { - if (schematicA.GetColorAtVoxelIndex(voxel.X, voxel.Y, voxel.Z) != 0) - { - schematicA.RemoveVoxel(voxel.X, voxel.Y, voxel.Z); - } - progressbar.Report(index++ / (float)allVoxelsB.Count); - - } - } - - Console.WriteLine("[INFO] Done"); - return schematicA; - } - - private static Schematic MergeTopOnly(Schematic schematicA, Schematic schematicB, HeightmapStep step) - { - Console.WriteLine("[INFO] Start to merge schematic with top only mode"); - List allVoxels = schematicA.GetAllVoxels(); - List allVoxelsB = schematicB.GetAllVoxels(); - using (ProgressBar progressbar = new ProgressBar()) - { - //int max = schematicA.Length * schematicA.Width; - int max = allVoxels.Count + allVoxelsB.Count; - int index = 0; - - Dictionary> tops = new Dictionary>(); - - foreach (Voxel voxel in allVoxels) - { - int x = voxel.X; - int y = voxel.Y; - int z = voxel.Z; - - if (x == 0 || y == 0 || z == 0) - continue; - - Vector3Int position; - int index2d = Schematic.GetVoxelIndex2DFromRotation(x, y, z,step.RotationMode); - - switch (step.RotationMode) - { - case RotationMode.X: - position = new Vector3Int(x + 1, y, z); - break; - case RotationMode.Y: - position = new Vector3Int(x, y + 1, z); - break; - case RotationMode.Z: - position = new Vector3Int(x, y, z + 1); - break; - default: - position = new Vector3Int(x, y + 1, z); - break; - } - if (schematicA.GetColorAtVoxelIndex(position) == 0) - { - if (!tops.ContainsKey(index2d)) - { - tops[index2d] = new List(); - } - - if (step.RotationMode == RotationMode.Y) - { - tops[index2d].Add(y); - } - else if (step.RotationMode == RotationMode.X) - { - tops[index2d].Add(x); - } - else if (step.RotationMode == RotationMode.Z) - { - tops[index2d].Add(z); - } - } - - progressbar.Report(index++ / (double)max); - } - - foreach (Voxel voxel in allVoxelsB) - { - int x = voxel.X; - int y = voxel.Y; - int z = voxel.Z; - - int index2d = Schematic.GetVoxelIndex2DFromRotation(x, y, z, step.RotationMode); - - if (tops.ContainsKey(index2d)) - { - foreach (int maxHeight in tops[index2d]) - { - switch (step.RotationMode) - { - case RotationMode.X: - schematicA.AddVoxel(x + maxHeight + step.OffsetMerge, y, z, voxel.Color); - break; - case RotationMode.Y: - schematicA.AddVoxel(x, y + maxHeight + step.OffsetMerge, z, voxel.Color); - break; - case RotationMode.Z: - schematicA.AddVoxel(x, y, z + maxHeight + step.OffsetMerge, voxel.Color); - break; - } - } - } - - progressbar.Report(index++ / (double)max); - - } - } - - Console.WriteLine("[INFO] Done"); - return schematicA; - } - } -} diff --git a/SchematicToVoxCore/Program.cs b/SchematicToVoxCore/Program.cs index 53abcb9..2c4d756 100644 --- a/SchematicToVoxCore/Program.cs +++ b/SchematicToVoxCore/Program.cs @@ -1,6 +1,6 @@ using FileToVox.Converter; using FileToVox.Converter.Image; -using FileToVox.Converter.Json; +using FileToVox.Converter.PaletteSchematic; using FileToVox.Converter.PointCloud; using FileToVoxCore.Schematics; using FileToVoxCore.Vox; @@ -10,7 +10,6 @@ using System.IO; using System.Linq; using System.Reflection; -using FileToVox.Converter.PaletteSchematic; namespace FileToVox { @@ -20,7 +19,6 @@ class Program private static string OUTPUT_PATH; private static string INPUT_COLOR_FILE; private static string INPUT_PALETTE_FILE; - private static string INPUT_SHADER_FILE; private static bool SHOW_HELP; private static bool EXCAVATE; @@ -37,7 +35,6 @@ public static void Main(string[] args) { {"i|input=", "input path", v => INPUT_PATH = v}, {"o|output=", "output path", v => OUTPUT_PATH = v}, - {"s|shaders=", "input shader path", v => INPUT_SHADER_FILE = v}, {"c|color", "enable color when generating heightmap", v => COLOR = v != null}, {"cm|color-from-file=", "load colors from file", v => INPUT_COLOR_FILE = v }, {"cl|color-limit=", "set the maximal number of colors for the palette", (int v) => COLOR_LIMIT =v }, @@ -126,8 +123,6 @@ private static void DisplayArguments() Console.WriteLine("[INFO] Specified input color file: " + INPUT_COLOR_FILE); if (INPUT_PALETTE_FILE != null) Console.WriteLine("[INFO] Specified palette file: " + INPUT_PALETTE_FILE); - if (INPUT_SHADER_FILE != null) - Console.WriteLine("[INFO] Specified shaders file: " + INPUT_SHADER_FILE); if (COLOR_LIMIT != 256) Console.WriteLine("[INFO] Specified color limit: " + COLOR_LIMIT); if (GRID_SIZE != 10) @@ -153,14 +148,6 @@ private static bool ProcessFile() string path = Path.GetFullPath(INPUT_PATH); bool isFolder = Directory.Exists(path); - if (!string.IsNullOrEmpty(INPUT_SHADER_FILE)) - { - string pathShaders = Path.GetFullPath(INPUT_SHADER_FILE); - if (!File.Exists(pathShaders)) - { - throw new FileNotFoundException("[ERROR] Input shaders file not found at: ", pathShaders); - } - } try { AbstractToSchematic converter; @@ -214,17 +201,14 @@ private static AbstractToSchematic GetConverter(string path) case ".ply": return new PLYToSchematic(path, GRID_SIZE, COLOR_LIMIT); case ".png": - return new PNGToSchematic(path, INPUT_COLOR_FILE, HEIGHT_MAP, EXCAVATE, COLOR, COLOR_LIMIT); + case ".tif": + return new ImageToSchematic(path, INPUT_COLOR_FILE, HEIGHT_MAP, EXCAVATE, COLOR, COLOR_LIMIT); case ".qb": return new QBToSchematic(path); case ".schematic": return new SchematicToSchematic(path, EXCAVATE); - case ".tif": - return new TIFtoSchematic(path, INPUT_COLOR_FILE, HEIGHT_MAP, EXCAVATE, COLOR, COLOR_LIMIT); case ".xyz": return new XYZToSchematic(path, GRID_SIZE, COLOR_LIMIT); - case ".json": - return new JsonToSchematic(path); case ".vox": return new VoxToSchematic(path); case ".obj": @@ -257,12 +241,6 @@ private static bool SchematicToVox(AbstractToSchematic converter) return writer.WriteModel(FormatOutputDestination(OUTPUT_PATH), converterPalette.GetPalette(), schematic); } - if (INPUT_SHADER_FILE != null) - { - JsonToSchematic jsonParser = new JsonToSchematic(INPUT_SHADER_FILE, schematic); - schematic = jsonParser.WriteSchematic(); - } - return writer.WriteModel(FormatOutputDestination(OUTPUT_PATH), null, schematic); } diff --git a/SchematicToVoxCore/Quantizer/CubeCut.cs b/SchematicToVoxCore/Quantizer/CubeCut.cs deleted file mode 100644 index 1f578e1..0000000 --- a/SchematicToVoxCore/Quantizer/CubeCut.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace FileToVox.Quantizer -{ - internal struct CubeCut - { - public readonly byte? Position; - public readonly float Value; - - public CubeCut(byte? cutPoint, float result) - { - this.Position = cutPoint; - this.Value = result; - } - } -} diff --git a/SchematicToVoxCore/Quantizer/IQuantizer.cs b/SchematicToVoxCore/Quantizer/IQuantizer.cs deleted file mode 100644 index db530c3..0000000 --- a/SchematicToVoxCore/Quantizer/IQuantizer.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Drawing; - -namespace FileToVox.Quantizer -{ - public interface IQuantizer - { - Bitmap QuantizeImage(Bitmap image, int alphaThreshold, int alphaFader, int macColorCount); - } -} diff --git a/SchematicToVoxCore/Quantizer/QuantizedPalette.cs b/SchematicToVoxCore/Quantizer/QuantizedPalette.cs deleted file mode 100644 index 5e8eef2..0000000 --- a/SchematicToVoxCore/Quantizer/QuantizedPalette.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Text; - -namespace FileToVox.Quantizer -{ - public class QuantizedPalette - { - public QuantizedPalette(int size) - { - this.Colors = (IList)new List(); - this.PixelIndex = new int[size]; - } - - public IList Colors { get; private set; } - - public int[] PixelIndex { get; private set; } - } -} diff --git a/SchematicToVoxCore/Quantizer/Quantizer.cs b/SchematicToVoxCore/Quantizer/Quantizer.cs deleted file mode 100644 index 446df74..0000000 --- a/SchematicToVoxCore/Quantizer/Quantizer.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Text; -using nQuant; - -namespace FileToVox.Quantizer -{ - public class Quantizer : QuantizerBase, IQuantizer - { - protected override QuantizedPalette GetQuantizedPalette( - int colorCount, - ColorData data, - IEnumerable cubes, - int alphaThreshold) - { - int pixelsCount1 = data.PixelsCount; - LookupData lookupData = this.BuildLookups(cubes, data); - IList quantizedPixels = data.QuantizedPixels; - for (int index = 0; index < pixelsCount1; ++index) - { - byte[] bytes = BitConverter.GetBytes(quantizedPixels[index]); - quantizedPixels[index] = lookupData.Tags[(int)bytes[3], (int)bytes[2], (int)bytes[1], (int)bytes[0]]; - } - int[] numArray1 = new int[colorCount + 1]; - int[] numArray2 = new int[colorCount + 1]; - int[] numArray3 = new int[colorCount + 1]; - int[] numArray4 = new int[colorCount + 1]; - int[] numArray5 = new int[colorCount + 1]; - QuantizedPalette quantizedPalette = new QuantizedPalette(pixelsCount1); - IList pixels = data.Pixels; - int pixelsCount2 = data.PixelsCount; - IList lookups = lookupData.Lookups; - int count = lookups.Count; - Dictionary dictionary = new Dictionary(); - for (int index1 = 0; index1 < pixelsCount2; ++index1) - { - Pixel pixel = pixels[index1]; - quantizedPalette.PixelIndex[index1] = -1; - if ((int)pixel.Alpha > alphaThreshold) - { - int argb = pixel.Argb; - int index2; - if (!dictionary.TryGetValue(argb, out index2)) - { - index2 = quantizedPixels[index1]; - int num1 = int.MaxValue; - for (int index3 = 0; index3 < count; ++index3) - { - Lookup lookup = lookups[index3]; - int num2 = (int)pixel.Alpha - lookup.Alpha; - int num3 = (int)pixel.Red - lookup.Red; - int num4 = (int)pixel.Green - lookup.Green; - int num5 = (int)pixel.Blue - lookup.Blue; - int num6 = num2 * num2 + num3 * num3 + num4 * num4 + num5 * num5; - if (num6 < num1) - { - num1 = num6; - index2 = index3; - } - } - dictionary[argb] = index2; - } - numArray1[index2] += (int)pixel.Alpha; - numArray2[index2] += (int)pixel.Red; - numArray3[index2] += (int)pixel.Green; - numArray4[index2] += (int)pixel.Blue; - ++numArray5[index2]; - quantizedPalette.PixelIndex[index1] = index2; - } - } - for (int index = 0; index < colorCount; ++index) - { - if (numArray5[index] > 0) - { - numArray1[index] /= numArray5[index]; - numArray2[index] /= numArray5[index]; - numArray3[index] /= numArray5[index]; - numArray4[index] /= numArray5[index]; - } - - if (numArray1[index] >= 0 && numArray2[index] >= 0 && numArray3[index] >= 0 && numArray4[index] >= 0) - { - Color color = Color.FromArgb(numArray1[index], numArray2[index], numArray3[index], numArray4[index]); - quantizedPalette.Colors.Add(color); - } - } - quantizedPalette.Colors.Add(Color.FromArgb(0, 0, 0, 0)); - return quantizedPalette; - } - } -} diff --git a/SchematicToVoxCore/Quantizer/QuantizerBase.cs b/SchematicToVoxCore/Quantizer/QuantizerBase.cs deleted file mode 100644 index 9a9ce8f..0000000 --- a/SchematicToVoxCore/Quantizer/QuantizerBase.cs +++ /dev/null @@ -1,478 +0,0 @@ -using FileToVox.Utils; -using nQuant; -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Imaging; -using System.Linq; -using System.Runtime.InteropServices; - -namespace FileToVox.Quantizer -{ - public abstract class QuantizerBase - { - private int mMaxColor = 256; - - public Bitmap QuantizeImage(Bitmap image, int alphaThreshold, int alphaFader, int maxColorCount) - { - if (image.PixelFormat != PixelFormat.Format32bppArgb) - { - image = image.ConvertToFormat32(); - } - - if (Program.DisableQuantization()) - { - Console.WriteLine("[WARNING] By disabling quantization, only the first 255 unique colors will be taken into account"); - return image; - } - - mMaxColor = maxColorCount + 1; - mMaxColor = Math.Min(mMaxColor, 256); - int colorCount = mMaxColor; - ColorData moments = QuantizerBase.CalculateMoments(QuantizerBase.BuildHistogram(image, alphaThreshold, alphaFader)); - IEnumerable cubes = this.SplitData(ref colorCount, moments); - QuantizedPalette quantizedPalette = this.GetQuantizedPalette(colorCount, moments, cubes, alphaThreshold); - return ProcessImagePixels((Image)image, quantizedPalette); - } - - private static Bitmap ProcessImagePixels(Image sourceImage, QuantizedPalette palette) - { - Bitmap bitmap = new Bitmap(sourceImage.Width, sourceImage.Height, PixelFormat.Format8bppIndexed); - ColorPalette palette1 = bitmap.Palette; - for (int index = 0; index < palette.Colors.Count; ++index) - palette1.Entries[index] = palette.Colors[index]; - bitmap.Palette = palette1; - BitmapData bitmapdata = (BitmapData)null; - try - { - bitmapdata = bitmap.LockBits(Rectangle.FromLTRB(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, bitmap.PixelFormat); - int num1 = bitmapdata.Stride < 0 ? -bitmapdata.Stride : bitmapdata.Stride; - int length1 = Math.Max(1, 1); - int length2 = num1 * bitmap.Height; - int num2 = 0; - byte[] source = new byte[length2]; - byte[] numArray = new byte[length1]; - int index1 = 0; - for (int index2 = 0; index2 < bitmap.Height; ++index2) - { - int num3 = 0; - for (int index3 = 0; index3 < bitmap.Width; ++index3) - { - int num4 = num3 >> 3; - numArray[0] = palette.PixelIndex[index1] == -1 ? (byte)(palette.Colors.Count - 1) : (byte)palette.PixelIndex[index1]; - ++index1; - for (int index4 = 0; index4 < length1; ++index4) - source[num2 + index4 + num4] = numArray[index4]; - num3 += 8; - } - num2 += num1; - } - Marshal.Copy(source, 0, bitmapdata.Scan0, length2); - } - finally - { - if (bitmapdata != null) - bitmap.UnlockBits(bitmapdata); - } - return bitmap; - } - - private static ColorData BuildHistogram( - Bitmap sourceImage, - int alphaThreshold, - int alphaFader) - { - int width = sourceImage.Width; - int height = sourceImage.Height; - BitmapData bitmapdata = sourceImage.LockBits(Rectangle.FromLTRB(0, 0, width, height), ImageLockMode.ReadOnly, sourceImage.PixelFormat); - ColorData colorData = new ColorData(32, width, height); - try - { - int pixelFormatSize = Image.GetPixelFormatSize(sourceImage.PixelFormat); - if (pixelFormatSize != 32) - throw new QuantizationException(string.Format("Thie image you are attempting to quantize does not contain a 32 bit ARGB palette. This image has a bit depth of {0} with {1} colors.", (object)pixelFormatSize, (object)sourceImage.Palette.Entries.Length)); - int num1 = bitmapdata.Stride < 0 ? -bitmapdata.Stride : bitmapdata.Stride; - int length = Math.Max(1, pixelFormatSize >> 3); - int num2 = 0; - byte[] destination = new byte[num1 * sourceImage.Height]; - byte[] numArray = new byte[length]; - Marshal.Copy(bitmapdata.Scan0, destination, 0, destination.Length); - for (int index1 = 0; index1 < height; ++index1) - { - int num3 = 0; - for (int index2 = 0; index2 < width; ++index2) - { - int num4 = num3 >> 3; - for (int index3 = 0; index3 < length; ++index3) - numArray[index3] = destination[num2 + index3 + num4]; - byte num5 = (byte)(((int)numArray[3] >> 3) + 1); - byte num6 = (byte)(((int)numArray[2] >> 3) + 1); - byte num7 = (byte)(((int)numArray[1] >> 3) + 1); - byte num8 = (byte)(((int)numArray[0] >> 3) + 1); - if ((int)numArray[3] > alphaThreshold) - { - if (numArray[3] < byte.MaxValue) - { - int num9 = (int)numArray[3] + (int)numArray[3] % alphaFader; - numArray[3] = num9 > (int)byte.MaxValue ? byte.MaxValue : (byte)num9; - num5 = (byte)(((int)numArray[3] >> 3) + 1); - } - ++colorData.Weights[(int)num5, (int)num6, (int)num7, (int)num8]; - colorData.MomentsRed[(int)num5, (int)num6, (int)num7, (int)num8] += (long)numArray[2]; - colorData.MomentsGreen[(int)num5, (int)num6, (int)num7, (int)num8] += (long)numArray[1]; - colorData.MomentsBlue[(int)num5, (int)num6, (int)num7, (int)num8] += (long)numArray[0]; - colorData.MomentsAlpha[(int)num5, (int)num6, (int)num7, (int)num8] += (long)numArray[3]; - colorData.Moments[(int)num5, (int)num6, (int)num7, (int)num8] += (float)((int)numArray[3] * (int)numArray[3] + (int)numArray[2] * (int)numArray[2] + (int)numArray[1] * (int)numArray[1] + (int)numArray[0] * (int)numArray[0]); - } - colorData.AddPixel(new Pixel(numArray[3], numArray[2], numArray[1], numArray[0]), BitConverter.ToInt32(new byte[4] - { - num5, - num6, - num7, - num8 - }, 0)); - num3 += pixelFormatSize; - } - num2 += num1; - } - } - finally - { - sourceImage.UnlockBits(bitmapdata); - } - return colorData; - } - - private static ColorData CalculateMoments(ColorData data) - { - for (int index1 = 1; index1 <= 32; ++index1) - { - long[,,] numArray1 = new long[33, 33, 33]; - long[,,] numArray2 = new long[33, 33, 33]; - long[,,] numArray3 = new long[33, 33, 33]; - long[,,] numArray4 = new long[33, 33, 33]; - long[,,] numArray5 = new long[33, 33, 33]; - float[,,] numArray6 = new float[33, 33, 33]; - for (int index2 = 1; index2 <= 32; ++index2) - { - long[] numArray7 = new long[33]; - long[] numArray8 = new long[33]; - long[] numArray9 = new long[33]; - long[] numArray10 = new long[33]; - long[] numArray11 = new long[33]; - float[] numArray12 = new float[33]; - for (int index3 = 1; index3 <= 32; ++index3) - { - long num1 = 0; - long num2 = 0; - long num3 = 0; - long num4 = 0; - long num5 = 0; - float num6 = 0.0f; - for (int index4 = 1; index4 <= 32; ++index4) - { - num1 += data.Weights[index1, index2, index3, index4]; - num2 += data.MomentsAlpha[index1, index2, index3, index4]; - num3 += data.MomentsRed[index1, index2, index3, index4]; - num4 += data.MomentsGreen[index1, index2, index3, index4]; - num5 += data.MomentsBlue[index1, index2, index3, index4]; - num6 += data.Moments[index1, index2, index3, index4]; - numArray7[index4] += num1; - numArray8[index4] += num2; - numArray9[index4] += num3; - numArray10[index4] += num4; - numArray11[index4] += num5; - numArray12[index4] += num6; - numArray1[index2, index3, index4] = numArray1[index2 - 1, index3, index4] + numArray7[index4]; - numArray2[index2, index3, index4] = numArray2[index2 - 1, index3, index4] + numArray8[index4]; - numArray3[index2, index3, index4] = numArray3[index2 - 1, index3, index4] + numArray9[index4]; - numArray4[index2, index3, index4] = numArray4[index2 - 1, index3, index4] + numArray10[index4]; - numArray5[index2, index3, index4] = numArray5[index2 - 1, index3, index4] + numArray11[index4]; - numArray6[index2, index3, index4] = numArray6[index2 - 1, index3, index4] + numArray12[index4]; - data.Weights[index1, index2, index3, index4] = data.Weights[index1 - 1, index2, index3, index4] + numArray1[index2, index3, index4]; - data.MomentsAlpha[index1, index2, index3, index4] = data.MomentsAlpha[index1 - 1, index2, index3, index4] + numArray2[index2, index3, index4]; - data.MomentsRed[index1, index2, index3, index4] = data.MomentsRed[index1 - 1, index2, index3, index4] + numArray3[index2, index3, index4]; - data.MomentsGreen[index1, index2, index3, index4] = data.MomentsGreen[index1 - 1, index2, index3, index4] + numArray4[index2, index3, index4]; - data.MomentsBlue[index1, index2, index3, index4] = data.MomentsBlue[index1 - 1, index2, index3, index4] + numArray5[index2, index3, index4]; - data.Moments[index1, index2, index3, index4] = data.Moments[index1 - 1, index2, index3, index4] + numArray6[index2, index3, index4]; - } - } - } - } - return data; - } - - private static long Top(Box cube, int direction, int position, long[,,,] moment) - { - switch (direction) - { - case 0: - return moment[(int)cube.AlphaMaximum, (int)cube.RedMaximum, (int)cube.GreenMaximum, position] - moment[(int)cube.AlphaMaximum, (int)cube.RedMaximum, (int)cube.GreenMinimum, position] - moment[(int)cube.AlphaMaximum, (int)cube.RedMinimum, (int)cube.GreenMaximum, position] + moment[(int)cube.AlphaMaximum, (int)cube.RedMinimum, (int)cube.GreenMinimum, position] - (moment[(int)cube.AlphaMinimum, (int)cube.RedMaximum, (int)cube.GreenMaximum, position] - moment[(int)cube.AlphaMinimum, (int)cube.RedMaximum, (int)cube.GreenMinimum, position] - moment[(int)cube.AlphaMinimum, (int)cube.RedMinimum, (int)cube.GreenMaximum, position] + moment[(int)cube.AlphaMinimum, (int)cube.RedMinimum, (int)cube.GreenMinimum, position]); - case 1: - return moment[(int)cube.AlphaMaximum, (int)cube.RedMaximum, position, (int)cube.BlueMaximum] - moment[(int)cube.AlphaMaximum, (int)cube.RedMinimum, position, (int)cube.BlueMaximum] - moment[(int)cube.AlphaMinimum, (int)cube.RedMaximum, position, (int)cube.BlueMaximum] + moment[(int)cube.AlphaMinimum, (int)cube.RedMinimum, position, (int)cube.BlueMaximum] - (moment[(int)cube.AlphaMaximum, (int)cube.RedMaximum, position, (int)cube.BlueMinimum] - moment[(int)cube.AlphaMaximum, (int)cube.RedMinimum, position, (int)cube.BlueMinimum] - moment[(int)cube.AlphaMinimum, (int)cube.RedMaximum, position, (int)cube.BlueMinimum] + moment[(int)cube.AlphaMinimum, (int)cube.RedMinimum, position, (int)cube.BlueMinimum]); - case 2: - return moment[(int)cube.AlphaMaximum, position, (int)cube.GreenMaximum, (int)cube.BlueMaximum] - moment[(int)cube.AlphaMaximum, position, (int)cube.GreenMinimum, (int)cube.BlueMaximum] - moment[(int)cube.AlphaMinimum, position, (int)cube.GreenMaximum, (int)cube.BlueMaximum] + moment[(int)cube.AlphaMinimum, position, (int)cube.GreenMinimum, (int)cube.BlueMaximum] - (moment[(int)cube.AlphaMaximum, position, (int)cube.GreenMaximum, (int)cube.BlueMinimum] - moment[(int)cube.AlphaMaximum, position, (int)cube.GreenMinimum, (int)cube.BlueMinimum] - moment[(int)cube.AlphaMinimum, position, (int)cube.GreenMaximum, (int)cube.BlueMinimum] + moment[(int)cube.AlphaMinimum, position, (int)cube.GreenMinimum, (int)cube.BlueMinimum]); - case 3: - return moment[position, (int)cube.RedMaximum, (int)cube.GreenMaximum, (int)cube.BlueMaximum] - moment[position, (int)cube.RedMaximum, (int)cube.GreenMinimum, (int)cube.BlueMaximum] - moment[position, (int)cube.RedMinimum, (int)cube.GreenMaximum, (int)cube.BlueMaximum] + moment[position, (int)cube.RedMinimum, (int)cube.GreenMinimum, (int)cube.BlueMaximum] - (moment[position, (int)cube.RedMaximum, (int)cube.GreenMaximum, (int)cube.BlueMinimum] - moment[position, (int)cube.RedMaximum, (int)cube.GreenMinimum, (int)cube.BlueMinimum] - moment[position, (int)cube.RedMinimum, (int)cube.GreenMaximum, (int)cube.BlueMinimum] + moment[position, (int)cube.RedMinimum, (int)cube.GreenMinimum, (int)cube.BlueMinimum]); - default: - return 0; - } - } - - private static long Bottom(Box cube, int direction, long[,,,] moment) - { - switch (direction) - { - case 0: - return -moment[(int)cube.AlphaMaximum, (int)cube.RedMaximum, (int)cube.GreenMaximum, (int)cube.BlueMinimum] + moment[(int)cube.AlphaMaximum, (int)cube.RedMaximum, (int)cube.GreenMinimum, (int)cube.BlueMinimum] + moment[(int)cube.AlphaMaximum, (int)cube.RedMinimum, (int)cube.GreenMaximum, (int)cube.BlueMinimum] - moment[(int)cube.AlphaMaximum, (int)cube.RedMinimum, (int)cube.GreenMinimum, (int)cube.BlueMinimum] - (-moment[(int)cube.AlphaMinimum, (int)cube.RedMaximum, (int)cube.GreenMaximum, (int)cube.BlueMinimum] + moment[(int)cube.AlphaMinimum, (int)cube.RedMaximum, (int)cube.GreenMinimum, (int)cube.BlueMinimum] + moment[(int)cube.AlphaMinimum, (int)cube.RedMinimum, (int)cube.GreenMaximum, (int)cube.BlueMinimum] - moment[(int)cube.AlphaMinimum, (int)cube.RedMinimum, (int)cube.GreenMinimum, (int)cube.BlueMinimum]); - case 1: - return -moment[(int)cube.AlphaMaximum, (int)cube.RedMaximum, (int)cube.GreenMinimum, (int)cube.BlueMaximum] + moment[(int)cube.AlphaMaximum, (int)cube.RedMinimum, (int)cube.GreenMinimum, (int)cube.BlueMaximum] + moment[(int)cube.AlphaMinimum, (int)cube.RedMaximum, (int)cube.GreenMinimum, (int)cube.BlueMaximum] - moment[(int)cube.AlphaMinimum, (int)cube.RedMinimum, (int)cube.GreenMinimum, (int)cube.BlueMaximum] - (-moment[(int)cube.AlphaMaximum, (int)cube.RedMaximum, (int)cube.GreenMinimum, (int)cube.BlueMinimum] + moment[(int)cube.AlphaMaximum, (int)cube.RedMinimum, (int)cube.GreenMinimum, (int)cube.BlueMinimum] + moment[(int)cube.AlphaMinimum, (int)cube.RedMaximum, (int)cube.GreenMinimum, (int)cube.BlueMinimum] - moment[(int)cube.AlphaMinimum, (int)cube.RedMinimum, (int)cube.GreenMinimum, (int)cube.BlueMinimum]); - case 2: - return -moment[(int)cube.AlphaMaximum, (int)cube.RedMinimum, (int)cube.GreenMaximum, (int)cube.BlueMaximum] + moment[(int)cube.AlphaMaximum, (int)cube.RedMinimum, (int)cube.GreenMinimum, (int)cube.BlueMaximum] + moment[(int)cube.AlphaMinimum, (int)cube.RedMinimum, (int)cube.GreenMaximum, (int)cube.BlueMaximum] - moment[(int)cube.AlphaMinimum, (int)cube.RedMinimum, (int)cube.GreenMinimum, (int)cube.BlueMaximum] - (-moment[(int)cube.AlphaMaximum, (int)cube.RedMinimum, (int)cube.GreenMaximum, (int)cube.BlueMinimum] + moment[(int)cube.AlphaMaximum, (int)cube.RedMinimum, (int)cube.GreenMinimum, (int)cube.BlueMinimum] + moment[(int)cube.AlphaMinimum, (int)cube.RedMinimum, (int)cube.GreenMaximum, (int)cube.BlueMinimum] - moment[(int)cube.AlphaMinimum, (int)cube.RedMinimum, (int)cube.GreenMinimum, (int)cube.BlueMinimum]); - case 3: - return -moment[(int)cube.AlphaMinimum, (int)cube.RedMaximum, (int)cube.GreenMaximum, (int)cube.BlueMaximum] + moment[(int)cube.AlphaMinimum, (int)cube.RedMaximum, (int)cube.GreenMinimum, (int)cube.BlueMaximum] + moment[(int)cube.AlphaMinimum, (int)cube.RedMinimum, (int)cube.GreenMaximum, (int)cube.BlueMaximum] - moment[(int)cube.AlphaMinimum, (int)cube.RedMinimum, (int)cube.GreenMinimum, (int)cube.BlueMaximum] - (-moment[(int)cube.AlphaMinimum, (int)cube.RedMaximum, (int)cube.GreenMaximum, (int)cube.BlueMinimum] + moment[(int)cube.AlphaMinimum, (int)cube.RedMaximum, (int)cube.GreenMinimum, (int)cube.BlueMinimum] + moment[(int)cube.AlphaMinimum, (int)cube.RedMinimum, (int)cube.GreenMaximum, (int)cube.BlueMinimum] - moment[(int)cube.AlphaMinimum, (int)cube.RedMinimum, (int)cube.GreenMinimum, (int)cube.BlueMinimum]); - default: - return 0; - } - } - - private static CubeCut Maximize( - ColorData data, - Box cube, - int direction, - byte first, - byte last, - long wholeAlpha, - long wholeRed, - long wholeGreen, - long wholeBlue, - long wholeWeight) - { - long num1 = QuantizerBase.Bottom(cube, direction, data.MomentsAlpha); - long num2 = QuantizerBase.Bottom(cube, direction, data.MomentsRed); - long num3 = QuantizerBase.Bottom(cube, direction, data.MomentsGreen); - long num4 = QuantizerBase.Bottom(cube, direction, data.MomentsBlue); - long num5 = QuantizerBase.Bottom(cube, direction, data.Weights); - float result = 0.0f; - byte? cutPoint = new byte?(); - for (byte index = first; (int)index < (int)last; ++index) - { - long num6 = num1 + QuantizerBase.Top(cube, direction, (int)index, data.MomentsAlpha); - long num7 = num2 + QuantizerBase.Top(cube, direction, (int)index, data.MomentsRed); - long num8 = num3 + QuantizerBase.Top(cube, direction, (int)index, data.MomentsGreen); - long num9 = num4 + QuantizerBase.Top(cube, direction, (int)index, data.MomentsBlue); - long num10 = num5 + QuantizerBase.Top(cube, direction, (int)index, data.Weights); - if (num10 != 0L) - { - long num11 = (num6 * num6 + num7 * num7 + num8 * num8 + num9 * num9) / num10; - long num12 = wholeAlpha - num6; - long num13 = wholeRed - num7; - long num14 = wholeGreen - num8; - long num15 = wholeBlue - num9; - long num16 = wholeWeight - num10; - if (num16 != 0L) - { - long num17 = num12 * num12 + num13 * num13 + num14 * num14 + num15 * num15; - long num18 = num11 + num17 / num16; - if ((double)num18 > (double)result) - { - result = (float)num18; - cutPoint = new byte?(index); - } - } - } - } - return new CubeCut(cutPoint, result); - } - - private bool Cut(ColorData data, ref Box first, ref Box second) - { - long wholeAlpha = QuantizerBase.Volume(first, data.MomentsAlpha); - long wholeRed = QuantizerBase.Volume(first, data.MomentsRed); - long wholeGreen = QuantizerBase.Volume(first, data.MomentsGreen); - long wholeBlue = QuantizerBase.Volume(first, data.MomentsBlue); - long wholeWeight = QuantizerBase.Volume(first, data.Weights); - CubeCut cubeCut1 = QuantizerBase.Maximize(data, first, 3, (byte)((uint)first.AlphaMinimum + 1U), first.AlphaMaximum, wholeAlpha, wholeRed, wholeGreen, wholeBlue, wholeWeight); - CubeCut cubeCut2 = QuantizerBase.Maximize(data, first, 2, (byte)((uint)first.RedMinimum + 1U), first.RedMaximum, wholeAlpha, wholeRed, wholeGreen, wholeBlue, wholeWeight); - CubeCut cubeCut3 = QuantizerBase.Maximize(data, first, 1, (byte)((uint)first.GreenMinimum + 1U), first.GreenMaximum, wholeAlpha, wholeRed, wholeGreen, wholeBlue, wholeWeight); - CubeCut cubeCut4 = QuantizerBase.Maximize(data, first, 0, (byte)((uint)first.BlueMinimum + 1U), first.BlueMaximum, wholeAlpha, wholeRed, wholeGreen, wholeBlue, wholeWeight); - int num1; - if ((double)cubeCut1.Value >= (double)cubeCut2.Value && (double)cubeCut1.Value >= (double)cubeCut3.Value && (double)cubeCut1.Value >= (double)cubeCut4.Value) - { - num1 = 3; - byte? position = cubeCut1.Position; - if (!(position.HasValue ? new int?((int)position.GetValueOrDefault()) : new int?()).HasValue) - return false; - } - else - num1 = (double)cubeCut2.Value < (double)cubeCut1.Value || (double)cubeCut2.Value < (double)cubeCut3.Value || (double)cubeCut2.Value < (double)cubeCut4.Value ? ((double)cubeCut3.Value < (double)cubeCut1.Value || (double)cubeCut3.Value < (double)cubeCut2.Value || (double)cubeCut3.Value < (double)cubeCut4.Value ? 0 : 1) : 2; - second.AlphaMaximum = first.AlphaMaximum; - second.RedMaximum = first.RedMaximum; - second.GreenMaximum = first.GreenMaximum; - second.BlueMaximum = first.BlueMaximum; - switch (num1) - { - case 0: - ref Box local1 = ref second; - ref Box local2 = ref first; - byte? position1 = cubeCut4.Position; - int num2; - byte num3 = (byte)(num2 = (int)position1.Value); - local2.BlueMaximum = (byte)num2; - int num4 = (int)num3; - local1.BlueMinimum = (byte)num4; - second.AlphaMinimum = first.AlphaMinimum; - second.RedMinimum = first.RedMinimum; - second.GreenMinimum = first.GreenMinimum; - break; - case 1: - ref Box local3 = ref second; - ref Box local4 = ref first; - byte? position2 = cubeCut3.Position; - int num5; - byte num6 = (byte)(num5 = (int)position2.Value); - local4.GreenMaximum = (byte)num5; - int num7 = (int)num6; - local3.GreenMinimum = (byte)num7; - second.AlphaMinimum = first.AlphaMinimum; - second.RedMinimum = first.RedMinimum; - second.BlueMinimum = first.BlueMinimum; - break; - case 2: - ref Box local5 = ref second; - ref Box local6 = ref first; - byte? position3 = cubeCut2.Position; - int num8; - byte num9 = (byte)(num8 = (int)position3.Value); - local6.RedMaximum = (byte)num8; - int num10 = (int)num9; - local5.RedMinimum = (byte)num10; - second.AlphaMinimum = first.AlphaMinimum; - second.GreenMinimum = first.GreenMinimum; - second.BlueMinimum = first.BlueMinimum; - break; - case 3: - ref Box local7 = ref second; - ref Box local8 = ref first; - byte? position4 = cubeCut1.Position; - int num11; - byte num12 = (byte)(num11 = (int)position4.Value); - local8.AlphaMaximum = (byte)num11; - int num13 = (int)num12; - local7.AlphaMinimum = (byte)num13; - second.RedMinimum = first.RedMinimum; - second.GreenMinimum = first.GreenMinimum; - second.BlueMinimum = first.BlueMinimum; - break; - } - first.Size = ((int)first.AlphaMaximum - (int)first.AlphaMinimum) * ((int)first.RedMaximum - (int)first.RedMinimum) * ((int)first.GreenMaximum - (int)first.GreenMinimum) * ((int)first.BlueMaximum - (int)first.BlueMinimum); - second.Size = ((int)second.AlphaMaximum - (int)second.AlphaMinimum) * ((int)second.RedMaximum - (int)second.RedMinimum) * ((int)second.GreenMaximum - (int)second.GreenMinimum) * ((int)second.BlueMaximum - (int)second.BlueMinimum); - return true; - } - - private static float CalculateVariance(ColorData data, Box cube) - { - float num1 = (float)QuantizerBase.Volume(cube, data.MomentsAlpha); - float num2 = (float)QuantizerBase.Volume(cube, data.MomentsRed); - float num3 = (float)QuantizerBase.Volume(cube, data.MomentsGreen); - float num4 = (float)QuantizerBase.Volume(cube, data.MomentsBlue); - float num5 = QuantizerBase.VolumeFloat(cube, data.Moments); - float num6 = (float)QuantizerBase.Volume(cube, data.Weights); - float num7 = (float)((double)num1 * (double)num1 + (double)num2 * (double)num2 + (double)num3 * (double)num3 + (double)num4 * (double)num4); - float num8 = num5 - num7 / num6; - if (!double.IsNaN((double)num8)) - return num8; - return 0.0f; - } - - private static long Volume(Box cube, long[,,,] moment) - { - return moment[(int)cube.AlphaMaximum, (int)cube.RedMaximum, (int)cube.GreenMaximum, (int)cube.BlueMaximum] - moment[(int)cube.AlphaMaximum, (int)cube.RedMaximum, (int)cube.GreenMinimum, (int)cube.BlueMaximum] - moment[(int)cube.AlphaMaximum, (int)cube.RedMinimum, (int)cube.GreenMaximum, (int)cube.BlueMaximum] + moment[(int)cube.AlphaMaximum, (int)cube.RedMinimum, (int)cube.GreenMinimum, (int)cube.BlueMaximum] - moment[(int)cube.AlphaMinimum, (int)cube.RedMaximum, (int)cube.GreenMaximum, (int)cube.BlueMaximum] + moment[(int)cube.AlphaMinimum, (int)cube.RedMaximum, (int)cube.GreenMinimum, (int)cube.BlueMaximum] + moment[(int)cube.AlphaMinimum, (int)cube.RedMinimum, (int)cube.GreenMaximum, (int)cube.BlueMaximum] - moment[(int)cube.AlphaMinimum, (int)cube.RedMinimum, (int)cube.GreenMinimum, (int)cube.BlueMaximum] - (moment[(int)cube.AlphaMaximum, (int)cube.RedMaximum, (int)cube.GreenMaximum, (int)cube.BlueMinimum] - moment[(int)cube.AlphaMinimum, (int)cube.RedMaximum, (int)cube.GreenMaximum, (int)cube.BlueMinimum] - moment[(int)cube.AlphaMaximum, (int)cube.RedMaximum, (int)cube.GreenMinimum, (int)cube.BlueMinimum] + moment[(int)cube.AlphaMinimum, (int)cube.RedMaximum, (int)cube.GreenMinimum, (int)cube.BlueMinimum] - moment[(int)cube.AlphaMaximum, (int)cube.RedMinimum, (int)cube.GreenMaximum, (int)cube.BlueMinimum] + moment[(int)cube.AlphaMinimum, (int)cube.RedMinimum, (int)cube.GreenMaximum, (int)cube.BlueMinimum] + moment[(int)cube.AlphaMaximum, (int)cube.RedMinimum, (int)cube.GreenMinimum, (int)cube.BlueMinimum] - moment[(int)cube.AlphaMinimum, (int)cube.RedMinimum, (int)cube.GreenMinimum, (int)cube.BlueMinimum]); - } - - private static float VolumeFloat(Box cube, float[,,,] moment) - { - return (float)((double)moment[(int)cube.AlphaMaximum, (int)cube.RedMaximum, (int)cube.GreenMaximum, (int)cube.BlueMaximum] - (double)moment[(int)cube.AlphaMaximum, (int)cube.RedMaximum, (int)cube.GreenMinimum, (int)cube.BlueMaximum] - (double)moment[(int)cube.AlphaMaximum, (int)cube.RedMinimum, (int)cube.GreenMaximum, (int)cube.BlueMaximum] + (double)moment[(int)cube.AlphaMaximum, (int)cube.RedMinimum, (int)cube.GreenMinimum, (int)cube.BlueMaximum] - (double)moment[(int)cube.AlphaMinimum, (int)cube.RedMaximum, (int)cube.GreenMaximum, (int)cube.BlueMaximum] + (double)moment[(int)cube.AlphaMinimum, (int)cube.RedMaximum, (int)cube.GreenMinimum, (int)cube.BlueMaximum] + (double)moment[(int)cube.AlphaMinimum, (int)cube.RedMinimum, (int)cube.GreenMaximum, (int)cube.BlueMaximum] - (double)moment[(int)cube.AlphaMinimum, (int)cube.RedMinimum, (int)cube.GreenMinimum, (int)cube.BlueMaximum] - ((double)moment[(int)cube.AlphaMaximum, (int)cube.RedMaximum, (int)cube.GreenMaximum, (int)cube.BlueMinimum] - (double)moment[(int)cube.AlphaMinimum, (int)cube.RedMaximum, (int)cube.GreenMaximum, (int)cube.BlueMinimum] - (double)moment[(int)cube.AlphaMaximum, (int)cube.RedMaximum, (int)cube.GreenMinimum, (int)cube.BlueMinimum] + (double)moment[(int)cube.AlphaMinimum, (int)cube.RedMaximum, (int)cube.GreenMinimum, (int)cube.BlueMinimum] - (double)moment[(int)cube.AlphaMaximum, (int)cube.RedMinimum, (int)cube.GreenMaximum, (int)cube.BlueMinimum] + (double)moment[(int)cube.AlphaMinimum, (int)cube.RedMinimum, (int)cube.GreenMaximum, (int)cube.BlueMinimum] + (double)moment[(int)cube.AlphaMaximum, (int)cube.RedMinimum, (int)cube.GreenMinimum, (int)cube.BlueMinimum] - (double)moment[(int)cube.AlphaMinimum, (int)cube.RedMinimum, (int)cube.GreenMinimum, (int)cube.BlueMinimum])); - } - - private IEnumerable SplitData(ref int colorCount, ColorData data) - { - --colorCount; - int index1 = 0; - float[] numArray = new float[mMaxColor]; - Box[] boxArray = new Box[mMaxColor]; - boxArray[0].AlphaMaximum = (byte)32; - boxArray[0].RedMaximum = (byte)32; - boxArray[0].GreenMaximum = (byte)32; - boxArray[0].BlueMaximum = (byte)32; - for (int index2 = 1; index2 < colorCount; ++index2) - { - if (this.Cut(data, ref boxArray[index1], ref boxArray[index2])) - { - numArray[index1] = boxArray[index1].Size > 1 ? QuantizerBase.CalculateVariance(data, boxArray[index1]) : 0.0f; - numArray[index2] = boxArray[index2].Size > 1 ? QuantizerBase.CalculateVariance(data, boxArray[index2]) : 0.0f; - } - else - { - numArray[index1] = 0.0f; - --index2; - } - index1 = 0; - float num = numArray[0]; - for (int index3 = 1; index3 <= index2; ++index3) - { - if ((double)numArray[index3] > (double)num) - { - num = numArray[index3]; - index1 = index3; - } - } - if ((double)num <= 0.0) - { - colorCount = index2 + 1; - break; - } - } - return (IEnumerable)((IEnumerable)boxArray).Take(colorCount).ToList(); - } - - protected LookupData BuildLookups(IEnumerable cubes, ColorData data) - { - LookupData lookupData = new LookupData(33); - int count = lookupData.Lookups.Count; - foreach (Box cube in cubes) - { - for (byte index1 = (byte)((uint)cube.AlphaMinimum + 1U); (int)index1 <= (int)cube.AlphaMaximum; ++index1) - { - for (byte index2 = (byte)((uint)cube.RedMinimum + 1U); (int)index2 <= (int)cube.RedMaximum; ++index2) - { - for (byte index3 = (byte)((uint)cube.GreenMinimum + 1U); (int)index3 <= (int)cube.GreenMaximum; ++index3) - { - for (byte index4 = (byte)((uint)cube.BlueMinimum + 1U); (int)index4 <= (int)cube.BlueMaximum; ++index4) - lookupData.Tags[(int)index1, (int)index2, (int)index3, (int)index4] = count; - } - } - } - long num = QuantizerBase.Volume(cube, data.Weights); - if (num > 0L) - { - Lookup lookup = new Lookup() - { - Alpha = (int)(QuantizerBase.Volume(cube, data.MomentsAlpha) / num), - Red = (int)(QuantizerBase.Volume(cube, data.MomentsRed) / num), - Green = (int)(QuantizerBase.Volume(cube, data.MomentsGreen) / num), - Blue = (int)(QuantizerBase.Volume(cube, data.MomentsBlue) / num) - }; - lookupData.Lookups.Add(lookup); - } - } - return lookupData; - } - - protected abstract QuantizedPalette GetQuantizedPalette( - int colorCount, - ColorData data, - IEnumerable cubes, - int alphaThreshold); - } -} diff --git a/SchematicToVoxCore/Utils/ImageUtils.cs b/SchematicToVoxCore/Utils/ImageUtils.cs index 190489b..d162f5c 100644 --- a/SchematicToVoxCore/Utils/ImageUtils.cs +++ b/SchematicToVoxCore/Utils/ImageUtils.cs @@ -1,30 +1,19 @@ -using System; +using FileToVox.Extensions; +using FileToVoxCore.Schematics; +using FileToVoxCore.Utils; +using ImageMagick; +using System; using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Imaging; using System.Linq; -using FileToVox.Converter.Image; -using FileToVox.Extensions; -using FileToVoxCommon.Generator.Heightmap.Data; -using FileToVoxCore.Schematics; using Color = System.Drawing.Color; namespace FileToVox.Utils { public static class ImageUtils { - public static Bitmap ConvertToFormat32(this Bitmap bitmap) - { - Bitmap clone = new Bitmap(bitmap.Width, bitmap.Height, PixelFormat.Format32bppArgb); - using (Graphics gr = Graphics.FromImage(clone)) - { - gr.DrawImage(bitmap, new Rectangle(0, 0, clone.Width, clone.Height)); - } - - return clone; - } + #region PublicMethods - public static Schematic WriteSchematicFromImage(Bitmap bitmap, Bitmap colorBitmap, HeightmapStep heightmapStep) + public static Schematic WriteSchematicFromImage(MagickImage bitmap, MagickImage colorBitmap, LoadImageParam loadImageParam) { if (colorBitmap != null) { @@ -33,34 +22,44 @@ public static Schematic WriteSchematicFromImage(Bitmap bitmap, Bitmap colorBitma throw new ArgumentException("[ERROR] Image color is not the same size of the original image"); } - if (heightmapStep.ColorLimit != 256 || colorBitmap.CountColor() > 256) + if (loadImageParam.ColorLimit != 256 || colorBitmap.UniqueColors().TotalColors > 256) { - Quantizer.Quantizer quantizer = new Quantizer.Quantizer(); - colorBitmap = quantizer.QuantizeImage(colorBitmap, 10, 70, heightmapStep.ColorLimit); + Quantization.Quantize(colorBitmap, new QuantizeSettings() + { + Colors = loadImageParam.ColorLimit, + }); } } - else if (heightmapStep.EnableColor) + else if (loadImageParam.EnableColor) { - if (heightmapStep.ColorLimit != 256 || bitmap.CountColor() > 256) + Quantization.Quantize(bitmap, new QuantizeSettings() { - Quantizer.Quantizer quantizer = new Quantizer.Quantizer(); - bitmap = quantizer.QuantizeImage(bitmap, 10, 70, heightmapStep.ColorLimit); - } + Colors = loadImageParam.ColorLimit, + }); } - Schematic schematic = WriteSchematicIntern(bitmap, colorBitmap, heightmapStep); + Schematic schematic = WriteSchematicIntern(bitmap, colorBitmap, loadImageParam); return schematic; } - public static Schematic WriteSchematicIntern(Bitmap bitmap, Bitmap bitmapColor, HeightmapStep heightmapStep) + #endregion + + #region PrivateMethods + + private static Schematic WriteSchematicIntern(MagickImage bitmap, MagickImage bitmapColor, LoadImageParam loadImageParam) { Schematic schematic = new Schematic(); - Bitmap bitmapBlack = Grayscale.MakeGrayscale3(bitmap); - DirectBitmap directBitmapBlack = new DirectBitmap(bitmapBlack, heightmapStep.Height); - DirectBitmap directBitmap = new DirectBitmap(bitmap, 1); - DirectBitmap directBitmapColor = new DirectBitmap(bitmapColor, 1); + MagickImage grayscale = new MagickImage(loadImageParam.TexturePath); + grayscale.Grayscale(); + + IPixelCollection pixelCollectionBitmap = bitmap.GetPixels(); + IPixelCollection pixelCollectionGrayscale = grayscale.GetPixels(); + IPixelCollection pixelCollectionBitmapColor = bitmapColor != null ? bitmapColor.GetPixels() : null; + //DirectBitmap directBitmapBlack = new DirectBitmap(bitmapBlack, heightmapStep.Height); + //DirectBitmap directBitmap = new DirectBitmap(bitmap, 1); + //DirectBitmap directBitmapColor = new DirectBitmap(bitmapColor, 1); if (bitmap.Width > Schematic.MAX_WORLD_WIDTH || bitmap.Height > Schematic.MAX_WORLD_LENGTH) @@ -68,7 +67,7 @@ public static Schematic WriteSchematicIntern(Bitmap bitmap, Bitmap bitmapColor, throw new ArgumentException($"Image is too big (max size ${Schematic.MAX_WORLD_WIDTH}x${Schematic.MAX_WORLD_LENGTH} px)"); } - using (FileToVoxCore.Utils.ProgressBar progressbar = new FileToVoxCore.Utils.ProgressBar()) + using (ProgressBar progressbar = new ProgressBar()) { Console.WriteLine("[INFO] Started to write schematic from picture..."); Console.WriteLine("[INFO] Picture Width: " + bitmap.Width); @@ -82,25 +81,53 @@ public static Schematic WriteSchematicIntern(Bitmap bitmap, Bitmap bitmapColor, { for (int y = 0; y < h; y++) { - Color color = directBitmap.GetPixel(x, y); - Color finalColor = !string.IsNullOrEmpty(heightmapStep.ColorTexturePath) ? directBitmapColor.GetPixel(x, y) : (heightmapStep.EnableColor) ? color : Color.White; - if (color.A != 0) + IPixel pixel = pixelCollectionBitmap.GetPixel(x, y); + Color color = pixel.GetPixelColor(); + Color finalColor; + + if (pixelCollectionBitmapColor != null) { - if (heightmapStep.Height != 1) + IPixel p = pixelCollectionBitmapColor.GetPixel(x, y); + Color c = p.GetPixelColor(); + finalColor = c; + } + else if (loadImageParam.EnableColor) + { + finalColor = color; + } + else + { + finalColor = Color.White; + } + + if (bitmap.HasAlpha && color.A != 0 || !bitmap.HasAlpha) + { + if (loadImageParam.Height != 1) { - if (heightmapStep.Excavate) + if (loadImageParam.Excavate) { - GenerateFromMinNeighbor(ref schematic, directBitmapBlack, w, h, finalColor, x, y, heightmapStep.Height, heightmapStep.Offset, heightmapStep.RotationMode, heightmapStep.Reverse); + GenerateFromMinNeighborParam param = new() + { + X = x, + Y = y, + PixelCollection = pixelCollectionGrayscale, + GrayscaleImage = grayscale, + Color = finalColor, + Height = loadImageParam.Height + }; + + GenerateFromMinNeighbor(ref schematic, param); } else { - int computeHeight = directBitmapBlack.GetHeight(x, y) + heightmapStep.Offset; - AddMultipleBlocks(ref schematic, heightmapStep.Offset, computeHeight, x, y, finalColor, heightmapStep.RotationMode); + int computeHeight = GetHeight(pixelCollectionGrayscale.GetPixel(x, y), loadImageParam.Height); + AddMultipleVoxels(ref schematic, 0, computeHeight, x, y, finalColor); + } } else { - AddSingleVoxel(ref schematic, x, heightmapStep.Offset, y, finalColor, heightmapStep.RotationMode, heightmapStep.Reverse); + AddSingleVoxel(ref schematic, x, h, y, finalColor); } } progressbar.Report((i++ / (float)size)); @@ -112,108 +139,86 @@ public static Schematic WriteSchematicIntern(Bitmap bitmap, Bitmap bitmapColor, return schematic; } - public static void AddMultipleBlocks(ref Schematic schematic, int min, int max, int x, int y, Color color, RotationMode rotationMode) + private static void AddMultipleVoxels(ref Schematic schematic, int min, int max, int x, int y, Color color) { - switch (rotationMode) + for (int i = min; i < max; i++) { - case RotationMode.X: - for (int i = min; i < max; i++) - { - AddBlock(ref schematic, new Voxel((ushort)i, (ushort)y, (ushort)x, color.ColorToUInt())); - } - break; - case RotationMode.Y: - for (int i = min; i < max; i++) - { - AddBlock(ref schematic, new Voxel((ushort)x, (ushort)i, (ushort)y, color.ColorToUInt())); - } - break; - case RotationMode.Z: - for (int i = min; i < max; i++) - { - AddBlock(ref schematic, new Voxel((ushort)y, (ushort)x, (ushort)i, color.ColorToUInt())); - } - break; - default: - throw new ArgumentOutOfRangeException(nameof(rotationMode), rotationMode, null); + schematic.AddVoxel(new Voxel((ushort)x, (ushort)i, (ushort)y, color.ColorToUInt())); } } - public static void AddSingleVoxel(ref Schematic schematic, int x, int y, int z, Color color, RotationMode rotationMode, bool reverse) + private static void AddSingleVoxel(ref Schematic schematic, int x, int y, int z, Color color) { - Voxel voxel; - ushort finalY; - ushort finalX; - ushort finalZ; - switch (rotationMode) - { - case RotationMode.X: - finalY = (ushort)(!reverse ? y : Schematic.MAX_WORLD_WIDTH - y); - finalX = (ushort)(x); - finalZ = (ushort)(z); - voxel = new Voxel(finalY, finalZ, finalX, color.ColorToUInt()); - break; - case RotationMode.Y: //historic - finalX = (ushort)(x); - finalY = (ushort)(!reverse ? y : Schematic.MAX_WORLD_HEIGHT - y); - finalZ = (ushort)(z); - voxel = new Voxel(finalX, finalY, finalZ, color.ColorToUInt()); - break; - case RotationMode.Z: - finalX = (ushort)(x); - finalY = (ushort)(!reverse ? y : Schematic.MAX_WORLD_LENGTH - y); - finalZ = (ushort)(z); - voxel = new Voxel(finalZ, finalX, finalY, color.ColorToUInt()); - break; - default: - throw new ArgumentOutOfRangeException(nameof(rotationMode), rotationMode, null); - } - AddBlock(ref schematic, voxel); + ushort finalX = (ushort)(x); + ushort finalY = (ushort)(y); + ushort finalZ = (ushort)(z); + Voxel voxel = new(finalX, finalY, finalZ, color.ColorToUInt()); - } - - public static void AddBlock(ref Schematic schematic, Voxel voxel) - { schematic.AddVoxel(voxel); } - public static void GenerateFromMinNeighbor(ref Schematic schematic, DirectBitmap blackBitmap, int w, int h, Color color, int x, int y, int height, int offset, RotationMode rotationMode, bool reverse) + private static void GenerateFromMinNeighbor(ref Schematic schematic, GenerateFromMinNeighborParam param) { - int computeHeight = blackBitmap.GetHeight(x, y) + offset; - try + int computeHeight = GetHeight(param.PixelCollection.GetPixel(param.X, param.Y), param.Height); + if (param.X - 1 >= 0 && param.X + 1 < param.GrayscaleImage.Width && param.Y - 1 >= 0 && param.Y + 1 < param.GrayscaleImage.Height) { - if (x - 1 >= 0 && x + 1 < w && y - 1 >= 0 && y + 1 < h) - { - int heightLeft = blackBitmap.GetHeight(x - 1, y) + offset; - int heightTop = blackBitmap.GetHeight(x, y - 1) + offset; - int heightRight = blackBitmap.GetHeight(x + 1, y) + offset; - int heightBottom = blackBitmap.GetHeight(x, y + 1) + offset; + int heightLeft = GetHeight(param.PixelCollection.GetPixel(param.X - 1, param.Y), param.Height); + int heightTop = GetHeight(param.PixelCollection.GetPixel(param.X, param.Y - 1), param.Height); + int heightRight = GetHeight( param.PixelCollection.GetPixel(param.X + 1, param.Y), param.Height); + int heightBottom = GetHeight( param.PixelCollection.GetPixel(param.X, param.Y + 1), param.Height); - var list = new List - { - heightLeft, heightTop, heightRight, heightBottom - }; + var list = new List + { + heightLeft, heightTop, heightRight, heightBottom + }; - int min = list.Min(); - if (min < computeHeight) - { - AddMultipleBlocks(ref schematic, min, computeHeight, x, y, color, rotationMode); - } - else - { - int finalHeight = (computeHeight - 1 < 0) ? 0 : computeHeight - 1; - AddSingleVoxel(ref schematic, x, finalHeight, y, color, rotationMode, reverse); - } + int min = list.Min(); + if (min < computeHeight) + { + AddMultipleVoxels(ref schematic, min, computeHeight, param.X, param.Y, param.Color); } else { - AddMultipleBlocks(ref schematic, offset, computeHeight, x, y, color, rotationMode); + int finalHeight = (computeHeight - 1 < 0) ? 0 : computeHeight - 1; + AddSingleVoxel(ref schematic, param.X, finalHeight, param.Y, param.Color); } } - catch (IndexOutOfRangeException) + else { - Console.WriteLine($"[ERROR] x: {x}, y: {y}, schematic width: {schematic.Width}, schematic length: {schematic.Length}"); + AddMultipleVoxels(ref schematic, 0, computeHeight, param.X, param.Y, param.Color); } } + + private static int GetHeight(IPixel pixel, int heightFactor) + { + int average = Math.Min(pixel.Channels, 3) * ushort.MaxValue; + int total = pixel.GetChannel(0) + pixel.GetChannel(1) + pixel.GetChannel(2); + float intensity = total / (float)average; + int height = (int)(intensity * heightFactor); + return height; + } + + + #endregion + } + + public class GenerateFromMinNeighborParam + { + public MagickImage GrayscaleImage; + public IPixelCollection PixelCollection; + public Color Color; + public int X; + public int Y; + public int Height; + } + + public class LoadImageParam + { + public int Height { get; set; } + public bool Excavate { get; set; } + public bool EnableColor { get; set; } + public string TexturePath { get; set; } + public string ColorTexturePath { get; set; } + public int ColorLimit { get; set; } } }