Example #1
0
        protected override void Compile(AssetCompilerContext context, string urlInStorage, UFile assetAbsolutePath, TextureAsset asset, AssetCompilerResult result)
        {
            if (!EnsureSourceExists(result, asset, assetAbsolutePath))
            {
                return;
            }

            // Get absolute path of asset source on disk
            var assetSource = GetAbsolutePath(assetAbsolutePath, asset.Source);

            var parameter = new TextureConvertParameters(assetSource, asset, context.Platform, context.GetGraphicsPlatform(), context.GetGraphicsProfile(), context.GetTextureQuality());

            result.BuildSteps = new AssetBuildStep(AssetItem)
            {
                new TextureConvertCommand(urlInStorage, parameter)
            };
        }
Example #2
0
            public ImportParameters(TextureConvertParameters textureParameters)
            {
                var asset = textureParameters.Texture;

                IsSRgb             = asset.SRgb;
                DesiredSize        = new Size2((int)asset.Width, (int)asset.Height);
                IsSizeInPercentage = asset.IsSizeInPercentage;
                DesiredFormat      = asset.Format;
                DesiredAlpha       = asset.Alpha;
                TextureHint        = asset.Hint;
                GenerateMipmaps    = asset.GenerateMipmaps;
                PremultiplyAlpha   = asset.PremultiplyAlpha;
                ColorKeyColor      = asset.ColorKeyColor;
                ColorKeyEnabled    = asset.ColorKeyEnabled;
                TextureQuality     = textureParameters.TextureQuality;
                GraphicsPlatform   = textureParameters.GraphicsPlatform;
                GraphicsProfile    = textureParameters.GraphicsProfile;
                Platform           = textureParameters.Platform;
            }
Example #3
0
            public ImportParameters(TextureConvertParameters textureParameters)
            {
                var asset = textureParameters.Texture;

                // Compute SRgb usage
                // If Texture is in auto mode, use the global settings, else use the settings overridden by the texture asset.
                IsSRgb = textureParameters.Texture.ColorSpace.ToColorSpace(textureParameters.ColorSpace, asset.Hint) == ColorSpace.Linear;

                DesiredSize        = new Size2((int)asset.Width, (int)asset.Height);
                IsSizeInPercentage = asset.IsSizeInPercentage;
                DesiredFormat      = asset.Format;
                DesiredAlpha       = asset.Alpha;
                TextureHint        = asset.Hint;
                GenerateMipmaps    = asset.GenerateMipmaps;
                PremultiplyAlpha   = asset.PremultiplyAlpha;
                ColorKeyColor      = asset.ColorKeyColor;
                ColorKeyEnabled    = asset.ColorKeyEnabled;
                TextureQuality     = textureParameters.TextureQuality;
                GraphicsPlatform   = textureParameters.GraphicsPlatform;
                GraphicsProfile    = textureParameters.GraphicsProfile;
                Platform           = textureParameters.Platform;
            }
Example #4
0
        public static ResultStatus ImportAndSaveTextureImage(UFile sourcePath, string outputUrl, TextureAsset textureAsset, TextureConvertParameters parameters, bool separateAlpha, CancellationToken cancellationToken, Logger logger)
        {
            var assetManager = new AssetManager();

            using (var texTool = new TextureTool())
                using (var texImage = texTool.Load(sourcePath))
                {
                    // Apply transformations
                    texTool.Decompress(texImage);

                    if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded
                    {
                        return(ResultStatus.Cancelled);
                    }

                    // Resize the image
                    if (textureAsset.IsSizeInPercentage)
                    {
                        texTool.Rescale(texImage, textureAsset.Width / 100.0f, textureAsset.Height / 100.0f, Filter.Rescaling.Lanczos3);
                    }
                    else
                    {
                        texTool.Resize(texImage, (int)textureAsset.Width, (int)textureAsset.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);

                    // Check that the resulting texture size is supported by the targeted graphics profile
                    if (!TextureSizeSupported(textureAsset.Format, parameters.GraphicsPlatform, parameters.GraphicsProfile, textureSize, textureAsset.GenerateMipmaps, logger))
                    {
                        return(ResultStatus.Failed);
                    }


                    // Apply the color key
                    if (textureAsset.ColorKeyEnabled)
                    {
                        texTool.ColorKey(texImage, textureAsset.ColorKeyColor);
                    }

                    if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded
                    {
                        return(ResultStatus.Cancelled);
                    }


                    // Pre-multiply alpha
                    if (textureAsset.PremultiplyAlpha)
                    {
                        texTool.PreMultiplyAlpha(texImage);
                    }

                    if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded
                    {
                        return(ResultStatus.Cancelled);
                    }


                    // Generate mipmaps
                    if (textureAsset.GenerateMipmaps)
                    {
                        texTool.GenerateMipMaps(texImage, Filter.MipMapGeneration.Box);
                    }

                    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(textureAsset.Format, textureAsset.Alpha, parameters.Platform, parameters.GraphicsPlatform, parameters.GraphicsProfile, textureSize, texImage.Format);
                    texTool.Compress(texImage, outputFormat, (TextureConverter.Requests.TextureQuality)parameters.TextureQuality);

                    if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded
                    {
                        return(ResultStatus.Cancelled);
                    }


                    // Save the texture
                    if (separateAlpha)
                    {
                        TextureAlphaComponentSplitter.CreateAndSaveSeparateTextures(texTool, texImage, outputUrl, textureAsset.GenerateMipmaps);
                    }
                    else
                    {
                        using (var outputImage = texTool.ConvertToParadoxImage(texImage))
                        {
                            if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded
                            {
                                return(ResultStatus.Cancelled);
                            }

                            assetManager.Save(outputUrl, outputImage);

                            logger.Info("Compression successful [{3}] to ({0}x{1},{2})", outputImage.Description.Width, outputImage.Description.Height, outputImage.Description.Format, outputUrl);
                        }
                    }
                }

            return(ResultStatus.Successful);
        }
Example #5
0
        public static ResultStatus ImportAndSaveTextureImage(UFile sourcePath, string outputUrl, TextureAsset textureAsset, TextureConvertParameters parameters, CancellationToken cancellationToken, Logger logger)
        {
            var assetManager = new AssetManager();

            using (var texTool = new TextureTool())
                using (var texImage = texTool.Load(sourcePath, textureAsset.SRgb))
                {
                    // Apply transformations
                    texTool.Decompress(texImage, textureAsset.SRgb);

                    if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded
                    {
                        return(ResultStatus.Cancelled);
                    }

                    var fromSize   = new Size2(texImage.Width, texImage.Height);
                    var targetSize = new Size2((int)textureAsset.Width, (int)textureAsset.Height);

                    // Resize the image
                    if (textureAsset.IsSizeInPercentage)
                    {
                        targetSize = new Size2((int)(fromSize.Width * (float)textureAsset.Width / 100.0f), (int)(fromSize.Height * (float)textureAsset.Height / 100.0f));
                    }

                    // Find the target size
                    targetSize = FindBestTextureSize(textureAsset.Format, parameters.GraphicsPlatform, parameters.GraphicsProfile, fromSize, targetSize, textureAsset.GenerateMipmaps, logger);

                    // Resize the image only if needed
                    if (targetSize != fromSize)
                    {
                        texTool.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 (textureAsset.ColorKeyEnabled)
                    {
                        texTool.ColorKey(texImage, textureAsset.ColorKeyColor);
                    }

                    if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded
                    {
                        return(ResultStatus.Cancelled);
                    }


                    // Pre-multiply alpha
                    if (textureAsset.PremultiplyAlpha)
                    {
                        texTool.PreMultiplyAlpha(texImage);
                    }

                    if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded
                    {
                        return(ResultStatus.Cancelled);
                    }


                    // Generate mipmaps
                    if (textureAsset.GenerateMipmaps)
                    {
                        var boxFilteringIsSupported = texImage.Format != PixelFormat.B8G8R8A8_UNorm_SRgb || (IsPowerOfTwo(textureSize.X) && IsPowerOfTwo(textureSize.Y));
                        texTool.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(textureAsset, parameters, textureSize, texImage.Format, parameters.Platform, parameters.GraphicsPlatform, parameters.GraphicsProfile);
                    texTool.Compress(texImage, outputFormat, (TextureConverter.Requests.TextureQuality)parameters.TextureQuality);

                    if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded
                    {
                        return(ResultStatus.Cancelled);
                    }


                    // Save the texture
                    if (parameters.SeparateAlpha)
                    {
                        //TextureAlphaComponentSplitter.CreateAndSaveSeparateTextures(texTool, texImage, outputUrl, textureAsset.GenerateMipmaps);
                    }
                    else
                    {
                        using (var outputImage = texTool.ConvertToParadoxImage(texImage))
                        {
                            if (cancellationToken.IsCancellationRequested) // abort the process if cancellation is demanded
                            {
                                return(ResultStatus.Cancelled);
                            }

                            assetManager.Save(outputUrl, outputImage.ToSerializableVersion());

                            logger.Info("Compression successful [{3}] to ({0}x{1},{2})", outputImage.Description.Width, outputImage.Description.Height, outputImage.Description.Format, outputUrl);
                        }
                    }
                }

            return(ResultStatus.Successful);
        }
Example #6
0
        /// <summary>
        /// Determine the output format of the texture depending on the platform and asset properties.
        /// </summary>
        /// <param name="parameters">The conversion request parameters</param>
        /// <param name="graphicsPlatform">The graphics platform</param>
        /// <param name="graphicsProfile">The graphics profile</param>
        /// <param name="imageSize">The texture output size</param>
        /// <param name="inputImageFormat">The pixel format of the input image</param>
        /// <param name="textureAsset">The texture asset</param>
        /// <returns>The pixel format to use as output</returns>
        public static PixelFormat DetermineOutputFormat(TextureAsset textureAsset, TextureConvertParameters parameters, Int2 imageSize, PixelFormat inputImageFormat, PlatformType platform, GraphicsPlatform graphicsPlatform,
                                                        GraphicsProfile graphicsProfile)
        {
            if (textureAsset.SRgb && ((int)parameters.GraphicsProfile < (int)GraphicsProfile.Level_9_2 && parameters.GraphicsPlatform != GraphicsPlatform.Direct3D11))
            {
                throw new NotSupportedException("sRGB is not supported on OpenGl profile level {0}".ToFormat(parameters.GraphicsProfile));
            }

            var hint = textureAsset.Hint;

            // Default output format
            var outputFormat = PixelFormat.R8G8B8A8_UNorm;

            switch (textureAsset.Format)
            {
            case TextureFormat.Compressed:
                switch (parameters.Platform)
                {
                case PlatformType.Android:
                    if (inputImageFormat.IsHDR())
                    {
                        outputFormat = inputImageFormat;
                    }
                    else if (textureAsset.SRgb)
                    {
                        outputFormat = PixelFormat.R8G8B8A8_UNorm_SRgb;
                    }
                    else
                    {
                        switch (graphicsProfile)
                        {
                        case GraphicsProfile.Level_9_1:
                        case GraphicsProfile.Level_9_2:
                        case GraphicsProfile.Level_9_3:
                            outputFormat = textureAsset.Alpha == AlphaFormat.None ? PixelFormat.ETC1 : PixelFormat.R8G8B8A8_UNorm;
                            break;

                        case GraphicsProfile.Level_10_0:
                        case GraphicsProfile.Level_10_1:
                        case GraphicsProfile.Level_11_0:
                        case GraphicsProfile.Level_11_1:
                        case GraphicsProfile.Level_11_2:
                            // GLES3.0 starting from Level_10_0, this profile enables ETC2 compression on Android
                            outputFormat = textureAsset.Alpha == AlphaFormat.None ? PixelFormat.ETC1 : PixelFormat.ETC2_RGBA;
                            break;

                        default:
                            throw new ArgumentOutOfRangeException("graphicsProfile");
                        }
                    }
                    break;

                case PlatformType.iOS:
                    // PVRTC works only for square POT textures
                    if (textureAsset.SRgb)
                    {
                        outputFormat = PixelFormat.R8G8B8A8_UNorm_SRgb;
                    }
                    else if (SupportPVRTC(imageSize))
                    {
                        switch (textureAsset.Alpha)
                        {
                        case AlphaFormat.None:
                            // DXT1 handles 1-bit alpha channel
                            outputFormat = PixelFormat.PVRTC_4bpp_RGB;
                            break;

                        case AlphaFormat.Mask:
                            // DXT1 handles 1-bit alpha channel
                            // TODO: Not sure about the equivalent here?
                            outputFormat = PixelFormat.PVRTC_4bpp_RGBA;
                            break;

                        case AlphaFormat.Explicit:
                        case AlphaFormat.Interpolated:
                            // DXT3 is good at sharp alpha transitions
                            // TODO: Not sure about the equivalent here?
                            outputFormat = PixelFormat.PVRTC_4bpp_RGBA;
                            break;

                        default:
                            throw new ArgumentOutOfRangeException();
                        }
                    }
                    else
                    {
                        outputFormat = PixelFormat.R8G8B8A8_UNorm;
                    }
                    break;

                case PlatformType.Windows:
                case PlatformType.WindowsPhone:
                case PlatformType.WindowsStore:
                    switch (parameters.GraphicsPlatform)
                    {
                    case GraphicsPlatform.Direct3D11:


                        // https://msdn.microsoft.com/en-us/library/windows/desktop/hh308955%28v=vs.85%29.aspx
                        // http://www.reedbeta.com/blog/2012/02/12/understanding-bcn-texture-compression-formats/
                        // ----------------------------------------------    ----------------------------------------------------                        ---    ---------------------------------
                        // Source data                                       Minimum required data compression resolution                     Recommended format	Minimum supported feature level
                        // ----------------------------------------------    ----------------------------------------------------                        ---    ---------------------------------
                        // Three-channel color with alpha channel            Three color channels (5 bits:6 bits:5 bits), with 0 or 1 bit(s) of alpha    BC1    Direct3D 9.1     (color maps, cutout color maps - 1 bit alpha, normal maps if memory is tight)
                        // Three-channel color with alpha channel            Three color channels (5 bits:6 bits:5 bits), with 4 bits of alpha           BC2    Direct3D 9.1     (idem)
                        // Three-channel color with alpha channel            Three color channels (5 bits:6 bits:5 bits) with 8 bits of alpha            BC3    Direct3D 9.1     (color maps with alpha, packing color and mono maps together)
                        // One-channel color                                 One color channel (8 bits)                                                  BC4    Direct3D 10      (Height maps, gloss maps, font atlases, any gray scales image)
                        // Two-channel color	                             Two color channels (8 bits:8 bits)                                          BC5    Direct3D 10      (Tangent space normal maps)
                        // Three-channel high dynamic range (HDR) color      Three color channels (16 bits:16 bits:16 bits) in "half" floating point*    BC6H   Direct3D 11      (HDR images)
                        // Three-channel color, alpha channel optional       Three color channels (4 to 7 bits per channel) with 0 to 8 bits of alpha    BC7    Direct3D 11      (High quality color maps, Color maps with full alpha)

                        switch (textureAsset.Alpha)
                        {
                        case AlphaFormat.None:
                        case AlphaFormat.Mask:
                            // DXT1 handles 1-bit alpha channel
                            outputFormat = textureAsset.SRgb ? PixelFormat.BC1_UNorm_SRgb : PixelFormat.BC1_UNorm;
                            break;

                        case AlphaFormat.Explicit:
                            // DXT3 is good at sharp alpha transitions
                            outputFormat = textureAsset.SRgb ? PixelFormat.BC2_UNorm_SRgb : PixelFormat.BC2_UNorm;
                            break;

                        case AlphaFormat.Interpolated:
                            // DXT5 is good at alpha gradients
                            outputFormat = textureAsset.SRgb ? PixelFormat.BC3_UNorm_SRgb : PixelFormat.BC3_UNorm;
                            break;

                        default:
                            throw new ArgumentOutOfRangeException();
                        }

                        // Overrides the format when profile is >= 10.0
                        // Support some specific optimized formats based on the hint or input type
                        if (parameters.GraphicsProfile >= GraphicsProfile.Level_10_0)
                        {
                            if (hint == TextureHint.NormalMap)
                            {
                                outputFormat = PixelFormat.BC5_SNorm;
                            }
                            else if (hint == TextureHint.Grayscale)
                            {
                                outputFormat = PixelFormat.BC4_UNorm;
                            }
                            else if (inputImageFormat.IsHDR())
                            {
                                // BC6H is too slow to compile
                                //outputFormat = parameters.GraphicsProfile >= GraphicsProfile.Level_11_0 && textureAsset.Alpha == AlphaFormat.None ? PixelFormat.BC6H_Uf16 : inputImageFormat;
                                outputFormat = inputImageFormat;
                            }
                            // TODO support the BC6/BC7 but they are so slow to compile that we can't use them right now
                        }
                        break;

                    case GraphicsPlatform.OpenGLES:             // OpenGLES on Windows
                        if (inputImageFormat.IsHDR())
                        {
                            outputFormat = inputImageFormat;
                        }
                        else if (textureAsset.SRgb)
                        {
                            outputFormat = PixelFormat.R8G8B8A8_UNorm_SRgb;
                        }
                        else
                        {
                            switch (graphicsProfile)
                            {
                            case GraphicsProfile.Level_9_1:
                            case GraphicsProfile.Level_9_2:
                            case GraphicsProfile.Level_9_3:
                                outputFormat = textureAsset.Alpha == AlphaFormat.None ? PixelFormat.ETC1 : PixelFormat.R8G8B8A8_UNorm;
                                break;

                            case GraphicsProfile.Level_10_0:
                            case GraphicsProfile.Level_10_1:
                            case GraphicsProfile.Level_11_0:
                            case GraphicsProfile.Level_11_1:
                            case GraphicsProfile.Level_11_2:
                                // GLES3.0 starting from Level_10_0, this profile enables ETC2 compression on Android
                                outputFormat = textureAsset.Alpha == AlphaFormat.None ? PixelFormat.ETC1 : PixelFormat.ETC2_RGBA;
                                break;

                            default:
                                throw new ArgumentOutOfRangeException("graphicsProfile");
                            }
                        }
                        break;

                    default:
                        // OpenGL on Windows
                        // TODO: Need to handle OpenGL Desktop compression
                        outputFormat = textureAsset.SRgb ? PixelFormat.R8G8B8A8_UNorm_SRgb : PixelFormat.R8G8B8A8_UNorm;
                        break;
                    }
                    break;

                default:
                    throw new NotSupportedException("Platform " + parameters.Platform + " is not supported by TextureTool");
                }
                break;

            case TextureFormat.Color16Bits:
                if (textureAsset.SRgb)
                {
                    outputFormat = PixelFormat.R8G8B8A8_UNorm_SRgb;
                }
                else
                {
                    if (textureAsset.Alpha == AlphaFormat.None)
                    {
                        outputFormat = PixelFormat.B5G6R5_UNorm;
                    }
                    else if (textureAsset.Alpha == AlphaFormat.Mask)
                    {
                        outputFormat = PixelFormat.B5G5R5A1_UNorm;
                    }
                }
                break;

            case TextureFormat.Color32Bits:
                if (textureAsset.SRgb)
                {
                    outputFormat = PixelFormat.R8G8B8A8_UNorm_SRgb;
                }
                break;

            case TextureFormat.AsIs:
                outputFormat = inputImageFormat;
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }
            return(outputFormat);
        }