Beispiel #1
0
        /// <summary>
        /// Generates the normal map.
        /// </summary>
        /// <param name="image">The image.</param>
        /// <param name="libraryData">The library data.</param>
        /// <param name="request">The request.</param>
        /// <exception cref="TexLibraryException">Failed to generate the normal map</exception>
        public void GenerateNormalMap(TexImage image, DxtTextureLibraryData libraryData, NormalMapGenerationRequest request)
        {
            Log.Verbose("Generating Normal Map ... ");

            ScratchImage scratchImage = new ScratchImage();

            HRESULT hr = Utilities.ComputeNormalMap(libraryData.DxtImages, libraryData.DxtImages.Length, ref libraryData.Metadata, CNMAP_FLAGS.CNMAP_CHANNEL_RED, request.Amplitude, DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM, scratchImage);

            if (hr != HRESULT.S_OK)
            {
                Log.Error("Failed to generate the normal map : " + hr);
                throw new TextureToolsException("Failed to generate the normal map : " + hr);
            }

            // Creating new TexImage with the normal map data.
            request.NormalMap = new TexImage();
            DxtTextureLibraryData normalMapLibraryData = new DxtTextureLibraryData();

            request.NormalMap.LibraryData[this] = normalMapLibraryData;
            normalMapLibraryData.DxtImages      = scratchImage.GetImages();
            normalMapLibraryData.Metadata       = scratchImage.metadata;
            normalMapLibraryData.Image          = scratchImage;

            UpdateImage(request.NormalMap, normalMapLibraryData);
            request.NormalMap.DisposingLibrary = this;
        }
Beispiel #2
0
        /// <summary>
        /// Premultiplies the alpha.
        /// </summary>
        /// <param name="image">The image.</param>
        /// <param name="libraryData">The library data.</param>
        public void PreMultiplyAlpha(TexImage image, DxtTextureLibraryData libraryData)
        {
            Log.Verbose("Premultiplying alpha ... ");

            ScratchImage scratchImage = new ScratchImage();

            HRESULT hr = Utilities.PremultiplyAlpha(libraryData.DxtImages, libraryData.DxtImages.Length, ref libraryData.Metadata, TEX_PREMULTIPLY_ALPHA_FLAGS.TEX_PMALPHA_DEFAULT, scratchImage);

            if (hr != HRESULT.S_OK)
            {
                Log.Error("Failed to premultiply the alpha : " + hr);
                throw new TextureToolsException("Failed to premultiply the alpha : " + hr);
            }

            // Freeing Memory
            if (image.DisposingLibrary != null)
            {
                image.DisposingLibrary.Dispose(image);
            }

            libraryData.Image      = scratchImage;
            libraryData.Metadata   = libraryData.Image.metadata;
            libraryData.DxtImages  = libraryData.Image.GetImages();
            image.DisposingLibrary = this;

            UpdateImage(image, libraryData);
        }
Beispiel #3
0
        /// <summary>
        /// Decompresses the specified image.
        /// </summary>
        /// <param name="image">The image.</param>
        /// <param name="libraryData">The library data.</param>
        /// <param name="request">The decompression request</param>
        /// <exception cref="TextureToolsException">Decompression failed</exception>
        private void Decompress(TexImage image, DxtTextureLibraryData libraryData, DecompressingRequest request)
        {
            Log.Verbose("Decompressing texture ...");

            // determine the output format to avoid any sRGB/RGB conversions (only decompression, no conversion)
            var outputFormat = !((PixelFormat)libraryData.Metadata.format).IsSRgb() ? request.DecompressedFormat.ToNonSRgb() : request.DecompressedFormat.ToSRgb();

            var scratchImage = new ScratchImage();
            var hr           = Utilities.Decompress(libraryData.DxtImages, libraryData.DxtImages.Length, ref libraryData.Metadata, (DXGI_FORMAT)outputFormat, scratchImage);

            if (hr != HRESULT.S_OK)
            {
                Log.Error("Decompression failed: " + hr);
                throw new TextureToolsException("Decompression failed: " + hr);
            }

            // Freeing Memory
            if (image.DisposingLibrary != null)
            {
                image.DisposingLibrary.Dispose(image);
            }

            libraryData.Image      = scratchImage;
            libraryData.DxtImages  = libraryData.Image.GetImages();
            libraryData.Metadata   = libraryData.Image.metadata;
            image.DisposingLibrary = this;

            // adapt the image format based on desired output format
            ChangeDxtImageType(libraryData, (DXGI_FORMAT)request.DecompressedFormat);

            UpdateImage(image, libraryData);
        }
Beispiel #4
0
        /// <summary>
        /// Convert the specified image.
        /// </summary>
        /// <param name="image">The image.</param>
        /// <param name="libraryData">The library data.</param>
        /// <param name="request">The decompression request</param>
        /// <exception cref="TextureToolsException">Decompression failed</exception>
        private void Convert(TexImage image, DxtTextureLibraryData libraryData, ConvertingRequest request)
        {
            // TODO: temp if request format is SRGB we force it to non-srgb to perform the conversion. Will not work if texture input is SRGB
            var outputFormat = request.Format.IsSRgb() ? request.Format.ToNonSRgb() : request.Format;

            Log.Verbose($"Converting texture from {(PixelFormat)libraryData.Metadata.format} to {outputFormat}");

            var scratchImage = new ScratchImage();
            var hr           = Utilities.Convert(libraryData.DxtImages, libraryData.DxtImages.Length, ref libraryData.Metadata, (DXGI_FORMAT)outputFormat, TEX_FILTER_FLAGS.TEX_FILTER_BOX, 0.0f, scratchImage);

            if (hr != HRESULT.S_OK)
            {
                Log.Error("Converting failed: " + hr);
                throw new TextureToolsException("Converting failed: " + hr);
            }

            // Freeing Memory
            if (image.DisposingLibrary != null)
            {
                image.DisposingLibrary.Dispose(image);
            }

            libraryData.Image      = scratchImage;
            libraryData.DxtImages  = libraryData.Image.GetImages();
            libraryData.Metadata   = libraryData.Image.metadata;
            image.DisposingLibrary = this;

            // adapt the image format based on desired output format
            ChangeDxtImageType(libraryData, (DXGI_FORMAT)request.Format);

            UpdateImage(image, libraryData);
        }
Beispiel #5
0
        /// <summary>
        /// Rescales the specified image.
        /// </summary>
        /// <param name="image">The image.</param>
        /// <param name="libraryData">The library data.</param>
        /// <param name="request">The request.</param>
        /// <exception cref="TexLibraryException">Rescaling failed</exception>
        private void Rescale(TexImage image, DxtTextureLibraryData libraryData, RescalingRequest request)
        {
            int width  = request.ComputeWidth(image);
            int height = request.ComputeHeight(image);

            Log.Verbose("Rescaling to " + width + "x" + height + " ...");

            TEX_FILTER_FLAGS filter;

            switch (request.Filter)
            {
            case Filter.Rescaling.Bilinear:
                filter = TEX_FILTER_FLAGS.TEX_FILTER_LINEAR;
                break;

            case Filter.Rescaling.Bicubic:
                filter = TEX_FILTER_FLAGS.TEX_FILTER_CUBIC;
                break;

            case Filter.Rescaling.Box:
                filter = TEX_FILTER_FLAGS.TEX_FILTER_FANT;
                break;

            case Filter.Rescaling.Nearest:
                filter = TEX_FILTER_FLAGS.TEX_FILTER_POINT;
                break;

            default:
                filter = TEX_FILTER_FLAGS.TEX_FILTER_FANT;
                break;
            }

            ScratchImage scratchImage = new ScratchImage();
            HRESULT      hr           = Utilities.Resize(libraryData.DxtImages, libraryData.DxtImages.Length, ref libraryData.Metadata, width, height, filter, scratchImage);

            if (hr != HRESULT.S_OK)
            {
                Log.Error("Rescaling failed: " + hr);
                throw new TextureToolsException("Rescaling failed: " + hr);
            }

            // Freeing Memory
            if (image.DisposingLibrary != null)
            {
                image.DisposingLibrary.Dispose(image);
            }

            // Updating image data
            image.Rescale(width, height);

            libraryData.Image      = scratchImage;
            libraryData.DxtImages  = libraryData.Image.GetImages();
            libraryData.Metadata   = libraryData.Image.metadata;
            image.DisposingLibrary = this;

            UpdateImage(image, libraryData);
        }
Beispiel #6
0
        /// <summary>
        /// Compresses the specified image.
        /// </summary>
        /// <param name="image">The image.</param>
        /// <param name="libraryData">The library data.</param>
        /// <param name="request">The request.</param>
        /// <exception cref="TextureToolsException">Compression failed</exception>
        private void Compress(TexImage image, DxtTextureLibraryData libraryData, CompressingRequest request)
        {
            Log.Verbose("Converting/Compressing with " + request.Format + " ...");

            if (libraryData.DxtImages == null || libraryData.DxtImages.Length == 0)
            {
                return;
            }

            ScratchImage scratchImage = new ScratchImage();

            HRESULT hr;

            if (request.Format.IsCompressed())
            {
                var topImage = libraryData.DxtImages[0];
                if (topImage.Width % 4 != 0 || topImage.Height % 4 != 0)
                {
                    throw new TextureToolsException(string.Format("The provided texture cannot be compressed into format '{0}' " +
                                                                  "because its top resolution ({1}-{2}) is not a multiple of 4.", request.Format, topImage.Width, topImage.Height));
                }

                hr = Utilities.Compress(libraryData.DxtImages, libraryData.DxtImages.Length, ref libraryData.Metadata,
                                        RetrieveNativeFormat(request.Format), TEX_COMPRESS_FLAGS.TEX_COMPRESS_DEFAULT, 0.5f, scratchImage);
            }
            else
            {
                hr = Utilities.Convert(libraryData.DxtImages, libraryData.DxtImages.Length, ref libraryData.Metadata,
                                       RetrieveNativeFormat(request.Format), TEX_FILTER_FLAGS.TEX_FILTER_DEFAULT, 0.5f, scratchImage);
            }


            if (hr != HRESULT.S_OK)
            {
                Log.Error("Compression failed: " + hr);
                throw new TextureToolsException("Compression failed: " + hr);
            }

            if (image.DisposingLibrary != null)
            {
                image.DisposingLibrary.Dispose(image);
            }

            // Updating attributes
            libraryData.Image      = scratchImage;
            libraryData.DxtImages  = libraryData.Image.GetImages();
            libraryData.Metadata   = libraryData.Image.metadata;
            image.DisposingLibrary = this;

            UpdateImage(image, libraryData);
        }
Beispiel #7
0
        /// <summary>
        /// Exports the specified image.
        /// </summary>
        /// <param name="image">The image.</param>
        /// <param name="libraryData">The library data.</param>
        /// <param name="request">The request.</param>
        /// <exception cref="TexLibraryException">
        /// Exporting texture failed
        /// </exception>
        private void Export(TexImage image, DxtTextureLibraryData libraryData, ExportRequest request)
        {
            Log.Verbose("Exporting to " + request.FilePath + " ...");

            if (request.MinimumMipMapSize > 1 && request.MinimumMipMapSize <= libraryData.Metadata.Width && request.MinimumMipMapSize <= libraryData.Metadata.Height) // if a mimimun mipmap size was requested
            {
                TexMetadata metadata = libraryData.Metadata;
                DxtImage[]  dxtImages;

                if (image.Dimension == TexImage.TextureDimension.Texture3D)
                {
                    int newMipMapCount = 0; // the new mipmap count
                    int ct             = 0; // ct will contain the number of SubImages per array element that we need to keep
                    int curDepth       = image.Depth << 1;
                    for (int i = 0; i < image.MipmapCount; ++i)
                    {
                        curDepth = curDepth > 1 ? curDepth >>= 1 : curDepth;

                        if (libraryData.DxtImages[ct].Width <= request.MinimumMipMapSize || libraryData.DxtImages[ct].Height <= request.MinimumMipMapSize)
                        {
                            ct += curDepth;
                            ++newMipMapCount;
                            break;
                        }
                        ++newMipMapCount;
                        ct += curDepth;
                    }

                    int SubImagePerArrayElement = image.SubImageArray.Length / image.ArraySize; // number of SubImage in each texture array element.

                    // Initializing library native data according to the new mipmap level
                    metadata.MipLevels = newMipMapCount;
                    dxtImages          = new DxtImage[metadata.ArraySize * ct];

                    int ct2 = 0;
                    for (int i = 0; i < image.ArraySize; ++i)
                    {
                        for (int j = 0; j < ct; ++j)
                        {
                            dxtImages[ct2] = libraryData.DxtImages[j + i * SubImagePerArrayElement];
                            ++ct2;
                        }
                    }
                }
                else
                {
                    int newMipMapCount = libraryData.Metadata.MipLevels;
                    for (int i = libraryData.Metadata.MipLevels - 1; i > 0; --i) // looking for the mipmap level corresponding to the minimum size requeted.
                    {
                        if (libraryData.DxtImages[i].Width >= request.MinimumMipMapSize || libraryData.DxtImages[i].Height >= request.MinimumMipMapSize)
                        {
                            break;
                        }
                        --newMipMapCount;
                    }

                    // Initializing library native data according to the new mipmap level
                    metadata.MipLevels = newMipMapCount;
                    dxtImages          = new DxtImage[metadata.ArraySize * newMipMapCount];

                    // Assigning the right sub images for the texture to be exported (no need for memory to be adjacent)
                    int gap = libraryData.Metadata.MipLevels - newMipMapCount;
                    int j   = 0;
                    for (int i = 0; i < dxtImages.Length; ++i)
                    {
                        if (i == newMipMapCount || (i > newMipMapCount && i % newMipMapCount == 0))
                        {
                            j += gap;
                        }
                        dxtImages[i] = libraryData.DxtImages[j];
                        ++j;
                    }
                }

                HRESULT hr = Utilities.SaveToDDSFile(dxtImages, dxtImages.Length, ref metadata, DDS_FLAGS.DDS_FLAGS_NONE, request.FilePath);

                if (hr != HRESULT.S_OK)
                {
                    Log.Error("Exporting texture failed: " + hr);
                    throw new TextureToolsException("Exporting texture failed: " + hr);
                }
            }
            else
            {
                HRESULT hr = Utilities.SaveToDDSFile(libraryData.DxtImages, libraryData.DxtImages.Length, ref libraryData.Metadata, DDS_FLAGS.DDS_FLAGS_NONE, request.FilePath);

                if (hr != HRESULT.S_OK)
                {
                    Log.Error("Exporting texture failed: " + hr);
                    throw new TextureToolsException("Exporting texture failed: " + hr);
                }
            }

            image.Save(request.FilePath);
        }
Beispiel #8
0
        /// <summary>
        /// Generates the mip maps.
        /// </summary>
        /// <param name="image">The image.</param>
        /// <param name="libraryData">The library data.</param>
        /// <param name="request">The request.</param>
        /// <exception cref="TexLibraryException">
        /// Not implemented !
        /// or
        /// Mipmaps generation failed
        /// </exception>
        private void GenerateMipMaps(TexImage image, DxtTextureLibraryData libraryData, MipMapsGenerationRequest request)
        {
            Log.Verbose("Generating Mipmaps ... ");

            var filter = TEX_FILTER_FLAGS.TEX_FILTER_DEFAULT;

            switch (request.Filter)
            {
            case Filter.MipMapGeneration.Nearest:
                filter |= TEX_FILTER_FLAGS.TEX_FILTER_POINT;
                break;

            case Filter.MipMapGeneration.Linear:
                filter |= TEX_FILTER_FLAGS.TEX_FILTER_LINEAR;
                break;

            case Filter.MipMapGeneration.Cubic:
                filter |= TEX_FILTER_FLAGS.TEX_FILTER_CUBIC;
                break;

            case Filter.MipMapGeneration.Box:
                // Box filter is supported only for power of two textures
                filter |= image.IsPowerOfTwo() ? TEX_FILTER_FLAGS.TEX_FILTER_FANT : TEX_FILTER_FLAGS.TEX_FILTER_LINEAR;
                break;

            default:
                filter |= TEX_FILTER_FLAGS.TEX_FILTER_FANT;
                break;
            }

            // Don't use WIC if we have a Float texture as mipmaps are clamped to [0, 1]
            // TODO: Report bug to DirectXTex
            var isPowerOfTwoAndFloat = image.IsPowerOfTwo() && (image.Format == PixelFormat.R16G16_Float || image.Format == PixelFormat.R16G16B16A16_Float);

            if (isPowerOfTwoAndFloat)
            {
                filter = TEX_FILTER_FLAGS.TEX_FILTER_FORCE_NON_WIC;
            }

            HRESULT hr;
            var     scratchImage = new ScratchImage();

            if (libraryData.Metadata.dimension == TEX_DIMENSION.TEX_DIMENSION_TEXTURE3D)
            {
                Log.Verbose("Only the box and nearest(point) filters are supported for generating Mipmaps with 3D texture.");
                if ((filter & TEX_FILTER_FLAGS.TEX_FILTER_FANT) == 0 && (filter & TEX_FILTER_FLAGS.TEX_FILTER_POINT) == 0)
                {
                    filter  = (TEX_FILTER_FLAGS)((int)filter & 0xf00000);
                    filter |= TEX_FILTER_FLAGS.TEX_FILTER_FANT;
                }
                hr = Utilities.GenerateMipMaps3D(libraryData.DxtImages, libraryData.DxtImages.Length, ref libraryData.Metadata, filter, 0, scratchImage);
            }
            else
            {
                hr = Utilities.GenerateMipMaps(libraryData.DxtImages, libraryData.DxtImages.Length, ref libraryData.Metadata, filter, 0, scratchImage);
            }

            if (hr != HRESULT.S_OK)
            {
                Log.Error("Mipmaps generation failed: " + hr);
                throw new TextureToolsException("Mipmaps generation failed: " + hr);
            }

            // Freeing Memory
            if (image.DisposingLibrary != null)
            {
                image.DisposingLibrary.Dispose(image);
            }

            libraryData.Image      = scratchImage;
            libraryData.Metadata   = libraryData.Image.metadata;
            libraryData.DxtImages  = libraryData.Image.GetImages();
            image.DisposingLibrary = this;

            UpdateImage(image, libraryData);
        }
Beispiel #9
0
        /// <summary>
        /// Loads the specified image.
        /// </summary>
        /// <param name="image">The image.</param>
        /// <param name="loader">The loader.</param>
        /// <exception cref="TextureToolsException">Loading dds file failed</exception>
        private void Load(TexImage image, LoadingRequest loader)
        {
            Log.Verbose("Loading " + loader.FilePath + " ...");

            var libraryData = new DxtTextureLibraryData();

            image.LibraryData[this] = libraryData;
            libraryData.Image       = new ScratchImage();
            libraryData.Metadata    = new TexMetadata();

            var     extension = Path.GetExtension(loader.FilePath);
            HRESULT hr        = 0;

            if (extension.EndsWith(".dds", StringComparison.InvariantCultureIgnoreCase))
            {
                hr = Utilities.LoadDDSFile(loader.FilePath, DDS_FLAGS.DDS_FLAGS_NONE, out libraryData.Metadata, libraryData.Image);
            }
            else if (extension.EndsWith(".tga", StringComparison.InvariantCultureIgnoreCase))
            {
                hr = Utilities.LoadTGAFile(loader.FilePath, out libraryData.Metadata, libraryData.Image);
            }
            else
            {
                hr = Utilities.LoadWICFile(loader.FilePath, WIC_FLAGS.WIC_FLAGS_NONE, out libraryData.Metadata, libraryData.Image);
            }

            if (hr != HRESULT.S_OK)
            {
                Log.Error("Loading dds file " + loader.FilePath + " failed: " + hr);
                throw new TextureToolsException("Loading dds file " + loader.FilePath + " failed: " + hr);
            }

            libraryData.DxtImages = libraryData.Image.GetImages();

            // adapt the image format based on whether input image is sRGB or not
            var format = (PixelFormat)libraryData.Metadata.format;

            ChangeDxtImageType(libraryData, (DXGI_FORMAT)(loader.LoadAsSRgb ? format.ToSRgb() : format.ToNonSRgb()));

            image.DisposingLibrary = this;

            if (libraryData.Metadata.miscFlags == TEX_MISC_FLAG.TEX_MISC_TEXTURECUBE)
            {
                image.Dimension = TexImage.TextureDimension.TextureCube;
            }
            else
            {
                switch (libraryData.Metadata.dimension)
                {
                case TEX_DIMENSION.TEX_DIMENSION_TEXTURE1D:
                    image.Dimension = TexImage.TextureDimension.Texture1D; break;

                case TEX_DIMENSION.TEX_DIMENSION_TEXTURE2D:
                    image.Dimension = TexImage.TextureDimension.Texture2D; break;

                case TEX_DIMENSION.TEX_DIMENSION_TEXTURE3D:
                    image.Dimension = TexImage.TextureDimension.Texture3D; break;
                }
            }

            UpdateImage(image, libraryData);

            var alphaSize = DDSHeader.GetAlphaDepth(loader.FilePath);

            image.OriginalAlphaDepth = alphaSize != -1 ? alphaSize : image.Format.AlphaSizeInBits();
        }