/// <summary> /// Gets the alpha levels of the image in the provided region. /// </summary> /// <param name="texture">The texture</param> /// <param name="region">The region of the texture to analyze</param> /// <param name="tranparencyColor">The color used as transparent color. If null use standard alpha channel.</param> /// <param name="logger">The logger used to log information</param> /// <returns></returns> public unsafe AlphaLevels GetAlphaLevels(TexImage texture, Rectangle region, Color? tranparencyColor, ILogger logger = null) { // quick escape when it is possible to know the absence of alpha from the file itself var alphaDepth = texture.GetAlphaDepth(); if(!tranparencyColor.HasValue && alphaDepth == 0) return AlphaLevels.NoAlpha; // check that we support the format var format = texture.Format; var pixelSize = format.SizeInBytes(); if (texture.Dimension != TexImage.TextureDimension.Texture2D || !(format.IsRGBAOrder() || format.IsBGRAOrder() || pixelSize != 4)) { var guessedAlphaLevel = alphaDepth > 0 ? AlphaLevels.InterpolatedAlpha : AlphaLevels.NoAlpha; logger?.Debug("Impossible to find alpha levels for texture type {0}. Returning default alpha level '{1}'.", format, guessedAlphaLevel); return guessedAlphaLevel; } // truncate the provided region in order to be sure to be in the texture region.Width = Math.Min(region.Width, texture.Width - region.Left); region.Height = Math.Min(region.Height, texture.Height- region.Top); var alphaLevel = AlphaLevels.NoAlpha; var stride = texture.RowPitch; var startPtr = (byte*)texture.Data + stride * region.Y + pixelSize * region.X; var rowPtr = startPtr; if (tranparencyColor.HasValue) // specific case when using a transparency color { var transparencyValue = format.IsRGBAOrder() ? tranparencyColor.Value.ToRgba() : tranparencyColor.Value.ToBgra(); for (int y = 0; y < region.Height; ++y) { var ptr = (int*)rowPtr; for (int x = 0; x < region.Width; x++) { if (*ptr == transparencyValue) return AlphaLevels.MaskAlpha; ptr += 1; } rowPtr += stride; } } else // use default alpha channel { for (int y = 0; y < region.Height; ++y) { var ptr = rowPtr+3; for (int x = 0; x < region.Width; x++) { var value = *ptr; if (value == 0) { if (alphaDepth == 1) return AlphaLevels.MaskAlpha; alphaLevel = AlphaLevels.MaskAlpha; } else if (value != 0xff) { return AlphaLevels.InterpolatedAlpha; } ptr += 4; } rowPtr += stride; } } return alphaLevel; }
public static ResultStatus ImportTextureImage(TextureTool textureTool, TexImage texImage, ImportParameters parameters, CancellationToken cancellationToken, Logger logger) { var assetManager = new AssetManager(); // Apply transformations textureTool.Decompress(texImage, parameters.IsSRgb); 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, fromSize, 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); // 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 if (parameters.PremultiplyAlpha) 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 != PixelFormat.B8G8R8A8_UNorm_SRgb || (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, texImage.GetAlphaDepth()); 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.ConvertToParadoxImage(texImage)) { if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded return ResultStatus.Cancelled; assetManager.Save(parameters.OutputUrl, outputImage.ToSerializableVersion()); logger.Info("Compression successful [{3}] to ({0}x{1},{2})", outputImage.Description.Width, outputImage.Description.Height, outputImage.Description.Format, parameters.OutputUrl); } return ResultStatus.Successful; }