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.ConvertToStrideImage(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(MicrothreadLocalDatabases.ProviderService); assetManager.Save(Url, staticFont); image.Dispose(); } 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); }
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.ConvertToStrideImage(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); } }
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)); }
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.ConvertToStrideImage(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)); }
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)); }