public void ConvertToXenkoImageTest(string file) { TexImage image = texTool.Load(Module.PathToInputImages + file); var xk = texTool.ConvertToXenkoImage(image); Assert.IsTrue(xk.TotalSizeInBytes == image.DataSize); Assert.IsTrue(xk.Description.MipLevels == image.MipmapCount); image.Dispose(); xk.Dispose(); }
protected override Task <ResultStatus> DoCommandOverride(ICommandContext commandContext) { using (var texTool = new TextureTool()) using (var texImage = texTool.Load(Parameters.FontDataFile, Parameters.IsSrgb)) { //make sure we are RGBA and not BGRA texTool.Convert(texImage, Parameters.IsSrgb ? PixelFormat.R8G8B8A8_UNorm_SRgb : PixelFormat.R8G8B8A8_UNorm); var image = texTool.ConvertToXenkoImage(texImage); Graphics.SpriteFont staticFont = FontDataFactory.NewStatic( Parameters.Size, Parameters.Glyphs, new[] { image }, Parameters.BaseOffset, Parameters.DefaultLineSpacing, Parameters.Kernings, Parameters.ExtraSpacing, Parameters.ExtraLineSpacing, Parameters.DefaultCharacter); // save the data into the database var assetManager = new ContentManager(); assetManager.Save(Url, staticFont); image.Dispose(); } return(Task.FromResult(ResultStatus.Successful)); }
protected override Task <ResultStatus> DoCommandOverride(ICommandContext commandContext) { // load the sound thumbnail image from the resources using (var imageStream = new MemoryStream(staticImageData)) using (var image = Image.Load(imageStream)) using (var texTool = new TextureTool()) using (var texImage = texTool.Load(image, Parameters.SRgb)) { // Rescale image so that it fits the thumbnail asked resolution texTool.Decompress(texImage, texImage.Format.IsSRgb()); texTool.Resize(texImage, thumbnailSize.X, thumbnailSize.Y, Filter.Rescaling.Lanczos3); // Save using (var outputImageStream = MicrothreadLocalDatabases.DatabaseFileProvider.OpenStream(Url, VirtualFileMode.Create, VirtualFileAccess.Write)) using (var outputImage = texTool.ConvertToXenkoImage(texImage)) { ThumbnailBuildHelper.ApplyThumbnailStatus(outputImage, DependencyBuildStatus); outputImage.Save(outputImageStream, ImageFileType.Png); commandContext.Logger.Verbose($"Thumbnail creation successful [{Url}] to ({outputImage.Description.Width}x{outputImage.Description.Height},{outputImage.Description.Format})"); } } return(Task.FromResult(ResultStatus.Successful)); }
public static ResultStatus ImportTextureImage(ContentManager assetManager, TextureTool textureTool, TexImage texImage, ImportParameters parameters, CancellationToken cancellationToken, Logger logger) { // Convert image to the final format var result = ImportTextureImageRaw(textureTool, texImage, parameters, cancellationToken, logger); if (result != ResultStatus.Successful) { return(result); } // Save the texture using (var outputImage = textureTool.ConvertToXenkoImage(texImage)) { if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } assetManager.Save(parameters.OutputUrl, outputImage.ToSerializableVersion(), typeof(Texture)); logger.Verbose($"Compression successful [{parameters.OutputUrl}] to ({outputImage.Description.Width}x{outputImage.Description.Height},{outputImage.Description.Format})"); } return(ResultStatus.Successful); }
/// <summary> /// Loads image from a path with texTool /// </summary> /// <param name="texTool">A tool for loading an image</param> /// <param name="sourcePath">Source path of an image</param> /// <param name="isSRgb">Indicate if the texture to load is sRGB</param> /// <returns></returns> private static Image LoadImage(TextureTool texTool, UFile sourcePath, bool isSRgb) { using (var texImage = texTool.Load(sourcePath, isSRgb)) { texTool.Decompress(texImage, isSRgb); if (texImage.Format == PixelFormat.B8G8R8A8_UNorm || texImage.Format == PixelFormat.B8G8R8A8_UNorm_SRgb) { texTool.SwitchChannel(texImage); } return(texTool.ConvertToXenkoImage(texImage)); } }
private Image LoadImage(TextureTool texTool, UFile sourcePath) { using (var texImage = texTool.Load(sourcePath, false)) { // Decompresses the specified texImage texTool.Decompress(texImage, false); if (texImage.Format == PixelFormat.B8G8R8A8_UNorm) { texTool.SwitchChannel(texImage); } return(texTool.ConvertToXenkoImage(texImage)); } }
protected override Task <ResultStatus> DoCommandOverride(ICommandContext commandContext) { var assetManager = new AssetManager(); // Load image var image = assetManager.Load <Image>(InputUrl); // Initialize TextureTool library using (var texTool = new TextureTool()) using (var texImage = texTool.Load(image)) { var outputFormat = Format.HasValue ? Format.Value : image.Description.Format; // Apply transformations texTool.Decompress(texImage); if (IsAbsolute) { texTool.Resize(texImage, (int)Width, (int)Height, Filter.Rescaling.Lanczos3); } else { texTool.Rescale(texImage, Width / 100.0f, Height / 100.0f, Filter.Rescaling.Lanczos3); } // Generate mipmaps if (GenerateMipmaps) { texTool.GenerateMipMaps(texImage, Filter.MipMapGeneration.Box); } // Convert/Compress to output format texTool.Compress(texImage, outputFormat); // Save using (var outputImage = texTool.ConvertToXenkoImage(texImage)) { assetManager.Save(OutputUrl, outputImage); commandContext.Logger.Verbose("Compression successful [{3}] to ({0}x{1},{2})", outputImage.Description.Width, outputImage.Description.Height, outputImage.Description.Format, OutputUrl); } } return(Task.FromResult(ResultStatus.Successful)); }
public static ResultStatus ImportTextureImage(TextureTool textureTool, TexImage texImage, ImportParameters parameters, CancellationToken cancellationToken, Logger logger) { var assetManager = new ContentManager(); // Apply transformations textureTool.Decompress(texImage, parameters.IsSRgb); // Special case when the input texture is monochromatic but it is supposed to be a color and we are working in SRGB // In that case, we need to transform it to a supported SRGB format (R8G8B8A8_UNorm_SRgb) // TODO: As part of a conversion phase, this code may be moved to a dedicated method in this class at some point if (parameters.TextureHint == TextureHint.Color && parameters.IsSRgb && (texImage.Format == PixelFormat.R8_UNorm || texImage.Format == PixelFormat.A8_UNorm)) { textureTool.Convert(texImage, PixelFormat.R8G8B8A8_UNorm_SRgb); } if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } var fromSize = new Size2(texImage.Width, texImage.Height); var targetSize = parameters.DesiredSize; // Resize the image if (parameters.IsSizeInPercentage) { targetSize = new Size2((int)(fromSize.Width * targetSize.Width / 100.0f), (int)(fromSize.Height * targetSize.Height / 100.0f)); } // Find the target size targetSize = FindBestTextureSize(parameters, targetSize, logger); // Resize the image only if needed if (targetSize != fromSize) { textureTool.Resize(texImage, targetSize.Width, targetSize.Height, Filter.Rescaling.Lanczos3); } if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } // texture size is now determined, we can cache it var textureSize = new Int2(texImage.Width, texImage.Height); // determine the alpha format of the texture when set to Auto // Note: this has to be done before the ColorKey transformation in order to be able to take advantage of image file AlphaDepth information if (parameters.DesiredAlpha == AlphaFormat.Auto) { var colorKey = parameters.ColorKeyEnabled? (Color?)parameters.ColorKeyColor : null; var alphaLevel = textureTool.GetAlphaLevels(texImage, new Rectangle(0, 0, textureSize.X, textureSize.Y), colorKey, logger); parameters.DesiredAlpha = alphaLevel.ToAlphaFormat(); } // Apply the color key if (parameters.ColorKeyEnabled) { textureTool.ColorKey(texImage, parameters.ColorKeyColor); } if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } // Pre-multiply alpha only for relevant formats if (parameters.PremultiplyAlpha && texImage.Format.HasAlpha32Bits()) { textureTool.PreMultiplyAlpha(texImage); } if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } // Generate mipmaps if (parameters.GenerateMipmaps) { var boxFilteringIsSupported = !texImage.Format.IsSRgb() || (MathUtil.IsPow2(textureSize.X) && MathUtil.IsPow2(textureSize.Y)); textureTool.GenerateMipMaps(texImage, boxFilteringIsSupported? Filter.MipMapGeneration.Box: Filter.MipMapGeneration.Linear); } if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } // Convert/Compress to output format // TODO: Change alphaFormat depending on actual image content (auto-detection)? var outputFormat = DetermineOutputFormat(parameters, textureSize, texImage.Format); textureTool.Compress(texImage, outputFormat, (TextureConverter.Requests.TextureQuality)parameters.TextureQuality); if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } // Save the texture using (var outputImage = textureTool.ConvertToXenkoImage(texImage)) { if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded { return(ResultStatus.Cancelled); } assetManager.Save(parameters.OutputUrl, outputImage.ToSerializableVersion()); logger.Verbose("Compression successful [{3}] to ({0}x{1},{2})", outputImage.Description.Width, outputImage.Description.Height, outputImage.Description.Format, parameters.OutputUrl); } return(ResultStatus.Successful); }
protected override Task <ResultStatus> DoCommandOverride(ICommandContext commandContext) { var assetManager = new ContentManager(MicrothreadLocalDatabases.ProviderService); var items = new Heightmap[] { new Heightmap(), }; foreach (var heightmap in items) { var source = Parameters.Source; if (!string.IsNullOrEmpty(source)) { using (var textureTool = new TextureTool()) using (var texImage = textureTool.Load(source, Parameters.IsSRgb)) { // Resize the image if need var size = Parameters.Resizing.Enabled ? Parameters.Resizing.Size : new Int2(texImage.Width, texImage.Height); if (!HeightfieldColliderShapeDesc.IsValidHeightStickSize(size)) { continue; } if (texImage.Width != size.X || texImage.Height != size.Y) { textureTool.Resize(texImage, size.X, size.Y, Filter.Rescaling.Nearest); } // Convert pixel format of the image var heightfieldType = Parameters.HeightParameters.HeightType; switch (heightfieldType) { case HeightfieldTypes.Float: switch (texImage.Format) { case PixelFormat.R32_Float: break; case PixelFormat.R32G32B32A32_Float: case PixelFormat.R16_Float: textureTool.Convert(texImage, PixelFormat.R32_Float); break; case PixelFormat.R16G16B16A16_UNorm: case PixelFormat.R16_UNorm: textureTool.Convert(texImage, PixelFormat.R16_SNorm); textureTool.Convert(texImage, PixelFormat.R32_Float); break; case PixelFormat.B8G8R8A8_UNorm: case PixelFormat.R8G8B8A8_UNorm: case PixelFormat.R8_UNorm: textureTool.Convert(texImage, PixelFormat.R8_SNorm); textureTool.Convert(texImage, PixelFormat.R32_Float); break; case PixelFormat.B8G8R8A8_UNorm_SRgb: case PixelFormat.B8G8R8X8_UNorm_SRgb: case PixelFormat.R8G8B8A8_UNorm_SRgb: textureTool.Convert(texImage, PixelFormat.R8_SNorm); textureTool.Convert(texImage, PixelFormat.R32_Float); break; default: continue; } break; case HeightfieldTypes.Short: switch (texImage.Format) { case PixelFormat.R16_SNorm: break; case PixelFormat.R16G16B16A16_SNorm: case PixelFormat.R16G16B16A16_UNorm: case PixelFormat.R16_UNorm: textureTool.Convert(texImage, PixelFormat.R16_SNorm); break; case PixelFormat.R8G8B8A8_SNorm: case PixelFormat.B8G8R8A8_UNorm: case PixelFormat.R8G8B8A8_UNorm: case PixelFormat.R8_UNorm: textureTool.Convert(texImage, PixelFormat.R8_SNorm); textureTool.Convert(texImage, PixelFormat.R16_SNorm); break; case PixelFormat.B8G8R8A8_UNorm_SRgb: case PixelFormat.B8G8R8X8_UNorm_SRgb: case PixelFormat.R8G8B8A8_UNorm_SRgb: textureTool.Convert(texImage, PixelFormat.R8_SNorm); textureTool.Convert(texImage, PixelFormat.R16_SNorm); break; default: continue; } break; case HeightfieldTypes.Byte: switch (texImage.Format) { case PixelFormat.R8_UNorm: break; case PixelFormat.R8G8B8A8_SNorm: case PixelFormat.B8G8R8A8_UNorm: case PixelFormat.R8G8B8A8_UNorm: textureTool.Convert(texImage, PixelFormat.R8_UNorm); break; case PixelFormat.B8G8R8A8_UNorm_SRgb: case PixelFormat.B8G8R8X8_UNorm_SRgb: case PixelFormat.R8G8B8A8_UNorm_SRgb: textureTool.Convert(texImage, PixelFormat.R8_UNorm); break; default: continue; } break; default: continue; } // Range var heightRange = Parameters.HeightParameters.HeightRange; if (heightRange.Y < heightRange.X) { continue; } // Read, scale and set heights var heightScale = Parameters.HeightParameters.HeightScale; if (Math.Abs(heightScale) < float.Epsilon) { continue; } using (var image = textureTool.ConvertToXenkoImage(texImage)) { var pixelBuffer = image.PixelBuffer[0]; switch (heightfieldType) { case HeightfieldTypes.Float: { heightmap.Floats = pixelBuffer.GetPixels <float>(); var floatConversionParameters = Parameters.HeightParameters as FloatHeightmapHeightConversionParamters; if (floatConversionParameters == null) { continue; } float scale = 1f; if (floatConversionParameters.ScaleToFit) { var max = heightmap.Floats.Max(h => Math.Abs(h)); if ((max - 1f) < float.Epsilon) { max = 1f; } scale = Math.Max(Math.Abs(heightRange.X), Math.Abs(heightRange.Y)) / max; } for (int i = 0; i < heightmap.Floats.Length; ++i) { heightmap.Floats[i] = MathUtil.Clamp(heightmap.Floats[i] * scale, heightRange.X, heightRange.Y); } } break; case HeightfieldTypes.Short: { heightmap.Shorts = pixelBuffer.GetPixels <short>(); } break; case HeightfieldTypes.Byte: { heightmap.Bytes = pixelBuffer.GetPixels <byte>(); } break; default: continue; } // Set rest of properties heightmap.HeightType = heightfieldType; heightmap.Size = size; heightmap.HeightRange = heightRange; heightmap.HeightScale = heightScale; } } } } assetManager.Save(Url, items[0]); return(Task.FromResult(ResultStatus.Successful)); }
public BitmapImage RetrieveImage(UFile filePath) { if (filePath == null) { return(null); } if (!File.Exists(filePath)) { return(null); } var lastWrite = File.GetLastWriteTime(filePath); var entry = cache.FirstOrDefault(x => x.Item1 == filePath); if (entry != null) { if (lastWrite == entry.Item2) { return(entry.Item4); } // Clear from cache cache.Remove(entry); } try { using (var stream = new MemoryStream()) { TexImage texImage; using (var texTool = new TextureTool()) { texImage = texTool.Load(filePath, false); texTool.Decompress(texImage, texImage.Format.IsSRgb()); if (texImage.Format == PixelFormat.R16G16B16A16_UNorm) { texTool.Convert(texImage, PixelFormat.R8G8B8A8_UNorm); } var image = texTool.ConvertToXenkoImage(texImage); image.Save(stream, ImageFileType.Png); } stream.Position = 0; var bitmap = new BitmapImage(); bitmap.BeginInit(); bitmap.StreamSource = stream; //bitmap.UriSource = new Uri(filePath); bitmap.CacheOption = BitmapCacheOption.OnLoad; // This flag is only used when loaded via UriSource, and make it crash when loaded via StreamSource //bitmap.CreateOptions = BitmapCreateOptions.IgnoreImageCache; bitmap.EndInit(); bitmap.Freeze(); // Update the cache cache.Add(Tuple.Create(filePath, lastWrite, texImage, bitmap)); if (cache.Count == CacheSize) { cache.RemoveAt(0); } return(bitmap); } } catch (InvalidOperationException) { return(null); } catch (TextureToolsException) { return(null); } }
public static ResultStatus ImportStreamableTextureImage(ContentManager assetManager, TextureTool textureTool, TexImage texImage, TextureHelper.ImportParameters convertParameters, CancellationToken cancellationToken, ICommandContext commandContext) { // Perform normal texture importing (but don't save it to file now) var importResult = TextureHelper.ImportTextureImageRaw(textureTool, texImage, convertParameters, cancellationToken, commandContext.Logger); if (importResult != ResultStatus.Successful) { return(importResult); } // Make sure we don't compress mips data var dataUrl = convertParameters.OutputUrl + "_Data"; commandContext.AddTag(new ObjectUrl(UrlType.Content, dataUrl), Builder.DoNotCompressTag); using (var outputImage = textureTool.ConvertToXenkoImage(texImage)) { if (cancellationToken.IsCancellationRequested) { return(ResultStatus.Cancelled); } // Create texture mips data containers (storage all array slices for every mip in separate chunks) var desc = outputImage.Description; List <byte[]> mipsData = new List <byte[]>(desc.MipLevels); for (int mipIndex = 0; mipIndex < desc.MipLevels; mipIndex++) { int totalSize = 0; for (int arrayIndex = 0; arrayIndex < desc.ArraySize; arrayIndex++) { var pixelBuffer = outputImage.GetPixelBuffer(arrayIndex, 0, mipIndex); totalSize += pixelBuffer.BufferStride; } var buf = new byte[totalSize]; int startIndex = 0; for (int arrayIndex = 0; arrayIndex < desc.ArraySize; arrayIndex++) { var pixelBuffer = outputImage.GetPixelBuffer(arrayIndex, 0, mipIndex); int size = pixelBuffer.BufferStride; Marshal.Copy(pixelBuffer.DataPointer, buf, startIndex, size); startIndex += size; } mipsData.Add(buf); } // Pack mip maps to the storage container ContentStorageHeader storageHeader; ContentStorage.Create(assetManager, dataUrl, mipsData, out storageHeader); if (cancellationToken.IsCancellationRequested) { return(ResultStatus.Cancelled); } // Serialize texture to file var outputTexture = new TextureSerializationData(outputImage, true, storageHeader); assetManager.Save(convertParameters.OutputUrl, outputTexture.ToSerializableVersion(), typeof(Texture)); commandContext.Logger.Verbose($"Compression successful [{dataUrl}] to ({outputImage.Description.Width}x{outputImage.Description.Height},{outputImage.Description.Format})"); } return(ResultStatus.Successful); }
protected override Task <ResultStatus> DoCommandOverride(ICommandContext commandContext) { var assetManager = new ContentManager(MicrothreadLocalDatabases.ProviderService); var items = new Heightmap[] { new Heightmap(), }; foreach (var heightmap in items) { var source = Parameters.Source; if (!string.IsNullOrEmpty(source)) { using (var textureTool = new TextureTool()) using (var texImage = textureTool.Load(source, Parameters.IsSRgb)) { // Resize the image if need var size = Parameters.Size.Enabled && Parameters.Size.Size.X > 1 && Parameters.Size.Size.Y > 1 ? Parameters.Size.Size : new Int2(texImage.Width, texImage.Height); if (texImage.Width != size.X || texImage.Height != size.Y) { textureTool.Resize(texImage, size.X, size.Y, Filter.Rescaling.Nearest); } // Convert pixel format of the image var heightfieldType = Parameters.Type; switch (heightfieldType) { case HeightfieldTypes.Float: switch (texImage.Format) { case PixelFormat.R32_Float: break; case PixelFormat.R32G32B32A32_Float: case PixelFormat.R16_Float: textureTool.Convert(texImage, PixelFormat.R32_Float); break; case PixelFormat.R16G16B16A16_UNorm: case PixelFormat.R16_UNorm: textureTool.Convert(texImage, PixelFormat.R16_SNorm); textureTool.Convert(texImage, PixelFormat.R32_Float); break; case PixelFormat.B8G8R8A8_UNorm: case PixelFormat.R8G8B8A8_UNorm: case PixelFormat.R8_UNorm: textureTool.Convert(texImage, PixelFormat.R8_SNorm); textureTool.Convert(texImage, PixelFormat.R32_Float); break; case PixelFormat.B8G8R8A8_UNorm_SRgb: case PixelFormat.B8G8R8X8_UNorm_SRgb: case PixelFormat.R8G8B8A8_UNorm_SRgb: textureTool.Convert(texImage, PixelFormat.R8_SNorm); textureTool.Convert(texImage, PixelFormat.R32_Float); break; default: continue; } break; case HeightfieldTypes.Short: switch (texImage.Format) { case PixelFormat.R16_SNorm: break; case PixelFormat.R16G16B16A16_SNorm: case PixelFormat.R16G16B16A16_UNorm: case PixelFormat.R16_UNorm: textureTool.Convert(texImage, PixelFormat.R16_SNorm); break; case PixelFormat.R8G8B8A8_SNorm: case PixelFormat.B8G8R8A8_UNorm: case PixelFormat.R8G8B8A8_UNorm: case PixelFormat.R8_UNorm: textureTool.Convert(texImage, PixelFormat.R8_SNorm); textureTool.Convert(texImage, PixelFormat.R16_SNorm); break; case PixelFormat.B8G8R8A8_UNorm_SRgb: case PixelFormat.B8G8R8X8_UNorm_SRgb: case PixelFormat.R8G8B8A8_UNorm_SRgb: textureTool.Convert(texImage, PixelFormat.R8_SNorm); textureTool.Convert(texImage, PixelFormat.R16_SNorm); break; default: continue; } break; case HeightfieldTypes.Byte: switch (texImage.Format) { case PixelFormat.R8_UNorm: break; case PixelFormat.R8G8B8A8_SNorm: case PixelFormat.B8G8R8A8_UNorm: case PixelFormat.R8G8B8A8_UNorm: textureTool.Convert(texImage, PixelFormat.R8_UNorm); break; case PixelFormat.B8G8R8A8_UNorm_SRgb: case PixelFormat.B8G8R8X8_UNorm_SRgb: case PixelFormat.R8G8B8A8_UNorm_SRgb: textureTool.Convert(texImage, PixelFormat.R8_UNorm); break; default: continue; } break; default: continue; } // Read, scale and set heights using (var image = textureTool.ConvertToXenkoImage(texImage)) { var pixelBuffer = image.PixelBuffer[0]; var scale = Parameters.HeightScale; switch (heightfieldType) { case HeightfieldTypes.Float: heightmap.Floats = pixelBuffer.GetPixels <float>(); for (int i = 0; i < heightmap.Floats.Length; ++i) { heightmap.Floats[i] *= scale; } break; case HeightfieldTypes.Short: heightmap.Shorts = pixelBuffer.GetPixels <short>(); for (int i = 0; i < heightmap.Shorts.Length; ++i) { heightmap.Shorts[i] = (short)MathUtil.Clamp(heightmap.Shorts[i] * scale, short.MinValue, short.MaxValue); } break; case HeightfieldTypes.Byte: heightmap.Bytes = pixelBuffer.GetPixels <byte>(); for (int i = 0; i < heightmap.Bytes.Length; ++i) { heightmap.Bytes[i] = (byte)MathUtil.Clamp(heightmap.Bytes[i] * scale, byte.MinValue, byte.MaxValue); } break; default: continue; } // Set rest of properties heightmap.HeightfieldType = heightfieldType; heightmap.Width = size.X; heightmap.Length = size.Y; } } } } assetManager.Save(Url, items[0]); return(Task.FromResult(ResultStatus.Successful)); }
protected override Task <ResultStatus> DoCommandOverride(ICommandContext commandContext) { var assetManager = new ContentManager(MicrothreadLocalDatabases.ProviderService); Heightmap heightmap = null; var heightType = Parameters.HeightConversionParameters.HeightType; var heightScale = Parameters.HeightConversionParameters.HeightScale; var heightRange = Parameters.HeightConversionParameters.HeightRange; // Heights var source = Parameters.Source; using (var textureTool = new TextureTool()) using (var texImage = textureTool.Load(source, Parameters.IsSRgb)) { // Resize if needed. var size = Parameters.Resizing.Enabled ? Parameters.Resizing.Size : new Int2(texImage.Width, texImage.Height); HeightmapUtils.CheckHeightParameters(size, heightType, heightRange, heightScale, true); // Convert the pixel format to single component one. var isConvertedR16 = false; switch (texImage.Format) { case PixelFormat.R32_Float: case PixelFormat.R16_SNorm: case PixelFormat.R8_UNorm: break; case PixelFormat.R32G32B32A32_Float: case PixelFormat.R16G16B16A16_Float: case PixelFormat.R16_Float: textureTool.Convert(texImage, PixelFormat.R32_Float); break; case PixelFormat.R16_UNorm: case PixelFormat.R16G16B16A16_UNorm: case PixelFormat.R16G16_UNorm: textureTool.Convert(texImage, PixelFormat.R16_SNorm); isConvertedR16 = true; break; case PixelFormat.R16G16B16A16_SNorm: case PixelFormat.R16G16_SNorm: textureTool.Convert(texImage, PixelFormat.R16_SNorm); break; case PixelFormat.R8_SNorm: case PixelFormat.B8G8R8A8_UNorm: case PixelFormat.B8G8R8X8_UNorm: case PixelFormat.R8G8B8A8_UNorm: case PixelFormat.R8G8_UNorm: textureTool.Convert(texImage, PixelFormat.R8_UNorm); break; case PixelFormat.R8G8B8A8_SNorm: case PixelFormat.R8G8_SNorm: textureTool.Convert(texImage, PixelFormat.R8_UNorm); break; case PixelFormat.B8G8R8A8_UNorm_SRgb: case PixelFormat.B8G8R8X8_UNorm_SRgb: case PixelFormat.R8G8B8A8_UNorm_SRgb: textureTool.Convert(texImage, PixelFormat.R8_UNorm); break; default: throw new Exception($"{ texImage.Format } format is not supported."); } // Convert pixels to heights using (var image = textureTool.ConvertToXenkoImage(texImage)) { var pixelBuffer = image.PixelBuffer[0]; var pixelBufferSize = new Int2(pixelBuffer.Width, pixelBuffer.Height); var minFloat = Parameters.FloatingPointComponentRange.X; var maxFloat = Parameters.FloatingPointComponentRange.Y; var isSNorm = (Math.Abs(-1 - minFloat) < float.Epsilon) && (Math.Abs(1 - maxFloat) < float.Epsilon); if (maxFloat < minFloat) { throw new Exception($"{ nameof(Parameters.FloatingPointComponentRange) }.{ nameof(Parameters.FloatingPointComponentRange.Y) } should be greater than { nameof(Parameters.FloatingPointComponentRange.X) }."); } var useScaleToRange = Parameters.ScaleToHeightRange; switch (heightType) { case HeightfieldTypes.Float: { float[] floats = null; switch (image.Description.Format) { case PixelFormat.R32_Float: floats = HeightmapUtils.Resize(pixelBuffer.GetPixels <float>(), pixelBufferSize, size); floats = isSNorm ? floats : HeightmapUtils.ConvertToFloatHeights(floats, minFloat, maxFloat); break; case PixelFormat.R16_SNorm: var shorts = HeightmapUtils.Resize(pixelBuffer.GetPixels <short>(), pixelBufferSize, size); floats = !isConvertedR16 && Parameters.IsSymmetricShortComponent ? HeightmapUtils.ConvertToFloatHeights(shorts, -short.MaxValue, short.MaxValue) : HeightmapUtils.ConvertToFloatHeights(shorts); break; case PixelFormat.R8_UNorm: var bytes = HeightmapUtils.Resize(pixelBuffer.GetPixels <byte>(), pixelBufferSize, size); floats = HeightmapUtils.ConvertToFloatHeights(bytes); break; } if (useScaleToRange) { ScaleToHeightRange(floats, -1, 1, heightRange, heightScale, commandContext); } heightmap = Heightmap.Create(size, heightType, heightRange, heightScale, floats); } break; case HeightfieldTypes.Short: { short[] shorts = null; switch (image.Description.Format) { case PixelFormat.R32_Float: var floats = HeightmapUtils.Resize(pixelBuffer.GetPixels <float>(), pixelBufferSize, size); shorts = HeightmapUtils.ConvertToShortHeights(floats, minFloat, maxFloat); break; case PixelFormat.R16_SNorm: shorts = HeightmapUtils.Resize(pixelBuffer.GetPixels <short>(), pixelBufferSize, size); shorts = !isConvertedR16 && Parameters.IsSymmetricShortComponent ? shorts : HeightmapUtils.ConvertToShortHeights(shorts); break; case PixelFormat.R8_UNorm: var bytes = HeightmapUtils.Resize(pixelBuffer.GetPixels <byte>(), pixelBufferSize, size); shorts = HeightmapUtils.ConvertToShortHeights(bytes); break; } if (useScaleToRange) { ScaleToHeightRange(shorts, short.MinValue, short.MaxValue, heightRange, heightScale, commandContext); } heightmap = Heightmap.Create(size, heightType, heightRange, heightScale, shorts); } break; case HeightfieldTypes.Byte: { byte[] bytes = null; switch (image.Description.Format) { case PixelFormat.R32_Float: var floats = HeightmapUtils.Resize(pixelBuffer.GetPixels <float>(), pixelBufferSize, size); bytes = HeightmapUtils.ConvertToByteHeights(floats, minFloat, maxFloat); break; case PixelFormat.R16_SNorm: var shorts = HeightmapUtils.Resize(pixelBuffer.GetPixels <short>(), pixelBufferSize, size); bytes = !isConvertedR16 && Parameters.IsSymmetricShortComponent ? HeightmapUtils.ConvertToByteHeights(shorts, -short.MaxValue, short.MaxValue) : HeightmapUtils.ConvertToByteHeights(shorts); break; case PixelFormat.R8_UNorm: bytes = HeightmapUtils.Resize(pixelBuffer.GetPixels <byte>(), pixelBufferSize, size); break; } if (useScaleToRange) { ScaleToHeightRange(bytes, byte.MinValue, byte.MaxValue, heightRange, heightScale, commandContext); } heightmap = Heightmap.Create(size, heightType, heightRange, heightScale, bytes); } break; default: throw new Exception($"{ heightType } height type is not supported."); } commandContext.Logger.Info($"[{Url}] Convert Image(Format={ texImage.Format }, Width={ texImage.Width }, Height={ texImage.Height }) " + $"to Heightmap(HeightType={ heightType }, MinHeight={ heightRange.X }, MaxHeight={ heightRange.Y }, HeightScale={ heightScale }, Size={ size })."); } } if (heightmap == null) { throw new Exception($"Failed to compile { Url }."); } assetManager.Save(Url, heightmap); return(Task.FromResult(ResultStatus.Successful)); }