4 using System.Collections.Generic;
 
    8 using System.Runtime.InteropServices;
 
    9 using SiliconStudio.Core.Diagnostics;
 
   10 using SiliconStudio.TextureConverter.DxtWrapper;
 
   11 using SiliconStudio.TextureConverter.Requests;
 
   13 namespace SiliconStudio.TextureConverter.TexLibraries
 
   19     internal class DxtTextureLibraryData : ITextureLibraryData
 
   24         public ScratchImage 
Image;
 
   29         public TexMetadata Metadata;
 
   34         public Image[] DxtImages;
 
   40     internal class DxtTexLib : ITexLibrary
 
   42         private static Logger Log = GlobalLogger.GetLogger(
"DxtTexLib");
 
   56         public void Dispose(TexImage image)
 
   58             DxtTextureLibraryData libraryData = (DxtTextureLibraryData)image.LibraryData[
this];
 
   60             if (libraryData.Image == null && libraryData.DxtImages != null)
 
   62                 ScratchImage img = 
new ScratchImage();
 
   63                 img.InitializeFromImages(libraryData.DxtImages, libraryData.DxtImages.Length);
 
   68                 libraryData.Image.Dispose();
 
   73         public void StartLibrary(TexImage image)
 
   75             if (image.LibraryData.ContainsKey(
this) && ((DxtTextureLibraryData)image.LibraryData[
this]).DxtImages[0].pixels.Equals(image.Data)) 
return;
 
   77             DxtTextureLibraryData libraryData = 
new DxtTextureLibraryData();
 
   78             image.LibraryData[
this] = libraryData;
 
   80             DXGI_FORMAT 
format = RetrieveNativeFormat(image.Format);
 
   82             libraryData.DxtImages = 
new Image[image.SubImageArray.Length];
 
   84             for (
int i = 0; i < image.SubImageArray.Length; ++i)
 
   86                 libraryData.DxtImages[i] = 
new Image(image.SubImageArray[i].Width, image.SubImageArray[i].Height, format, image.SubImageArray[i].RowPitch, image.SubImageArray[i].SlicePitch, image.SubImageArray[i].Data);
 
   89             switch (image.Dimension)
 
   91                 case TexImage.TextureDimension.Texture1D:
 
   92                     libraryData.Metadata = 
new TexMetadata(image.Width, image.Height, image.Depth, image.ArraySize, image.MipmapCount, 0, 0, format, TEX_DIMENSION.TEX_DIMENSION_TEXTURE1D); 
break;
 
   93                 case TexImage.TextureDimension.Texture2D:
 
   94                     libraryData.Metadata = 
new TexMetadata(image.Width, image.Height, image.Depth, image.ArraySize, image.MipmapCount, 0, 0, format, TEX_DIMENSION.TEX_DIMENSION_TEXTURE2D); 
break;
 
   95                 case TexImage.TextureDimension.Texture3D:
 
   96                     libraryData.Metadata = 
new TexMetadata(image.Width, image.Height, image.Depth, image.ArraySize, image.MipmapCount, 0, 0, format, TEX_DIMENSION.TEX_DIMENSION_TEXTURE3D); 
break;
 
   97                 case TexImage.TextureDimension.TextureCube:
 
   98                     libraryData.Metadata = 
new TexMetadata(image.Width, image.Height, image.Depth, image.ArraySize, image.MipmapCount, TEX_MISC_FLAG.TEX_MISC_TEXTURECUBE, 0, format, TEX_DIMENSION.TEX_DIMENSION_TEXTURE2D); 
break;
 
  101             libraryData.Image = null;
 
  105         public void EndLibrary(TexImage image)
 
  107             if (!image.LibraryData.ContainsKey(
this)) 
return;
 
  108             UpdateImage(image, (DxtTextureLibraryData)image.LibraryData[
this]);
 
  111         public bool CanHandleRequest(TexImage image, IRequest request)
 
  113             switch (request.Type)
 
  115                 case RequestType.Loading:
 
  116                     LoadingRequest loader = (LoadingRequest)request;
 
  117                     return loader.Mode==LoadingRequest.LoadingMode.FilePath && Path.GetExtension(loader.FilePath).Equals(
".dds");
 
  119                 case RequestType.Compressing:
 
  120                     CompressingRequest compress = (CompressingRequest)request;
 
  121                     return SupportFormat(compress.Format) && SupportFormat(image.Format);
 
  123                 case RequestType.Export:
 
  124                     return SupportFormat(image.Format) && Path.GetExtension(((ExportRequest)request).FilePath).Equals(
".dds");
 
  126                 case RequestType.Rescaling:
 
  127                     RescalingRequest rescale = (RescalingRequest)request;
 
  128                     return rescale.Filter == Filter.Rescaling.Box || rescale.Filter == Filter.Rescaling.Bicubic || rescale.Filter == Filter.Rescaling.Bicubic || rescale.Filter == Filter.Rescaling.Nearest;
 
  130                 case RequestType.Decompressing:
 
  131                     return SupportFormat(image.Format);
 
  133                 case RequestType.PreMultiplyAlpha:
 
  134                 case RequestType.MipMapsGeneration:
 
  135                 case RequestType.NormalMapGeneration:
 
  143         public void Execute(TexImage image, IRequest request)
 
  145             DxtTextureLibraryData libraryData = image.LibraryData.ContainsKey(
this) ? (DxtTextureLibraryData)image.LibraryData[this] : null;
 
  149                 case RequestType.Loading:
 
  150                     Load(image, libraryData, (LoadingRequest)request);
 
  152                 case RequestType.Compressing:
 
  153                     Compress(image, libraryData, (CompressingRequest)request);
 
  155                 case RequestType.Export:
 
  156                     Export(image, libraryData, (ExportRequest)request);
 
  158                 case RequestType.Decompressing:
 
  161                 case RequestType.MipMapsGeneration:
 
  162                     GenerateMipMaps(image, libraryData, (MipMapsGenerationRequest)request);
 
  164                 case RequestType.Rescaling:
 
  165                     Rescale(image, libraryData, (RescalingRequest)request);
 
  167                 case RequestType.NormalMapGeneration:
 
  170                 case RequestType.PreMultiplyAlpha:
 
  174                     Log.Error(
"DxtTexLib (DirectXTex) can't handle this request: " + request.Type);
 
  175                     throw new TextureToolsException(
"DxtTexLib (DirectXTex) can't handle this request: " + request.Type);
 
  186         private void Load(TexImage image, DxtTextureLibraryData libraryData, LoadingRequest loader)
 
  188             Log.Info(
"Loading " + loader.FilePath + 
" ...");
 
  190             libraryData = 
new DxtTextureLibraryData();
 
  191             image.LibraryData[
this] = libraryData;
 
  193             libraryData.Image = 
new ScratchImage();
 
  194             libraryData.Metadata = 
new TexMetadata();
 
  195             HRESULT hr = Utilities.LoadDDSFile(loader.FilePath, 
DDS_FLAGS.DDS_FLAGS_NONE, out libraryData.Metadata, libraryData.Image);
 
  197             if (hr != HRESULT.S_OK)
 
  199                 Log.Error(
"Loading dds file " + loader.FilePath + 
" failed: " + hr);
 
  200                 throw new TextureToolsException(
"Loading dds file " + loader.FilePath + 
" failed: " + hr);
 
  203             libraryData.DxtImages = libraryData.Image.GetImages();
 
  205             image.DisposingLibrary = 
this;
 
  207             if (libraryData.Metadata.miscFlags == TEX_MISC_FLAG.TEX_MISC_TEXTURECUBE)
 
  209                 image.Dimension = TexImage.TextureDimension.TextureCube;
 
  213                 switch (libraryData.Metadata.dimension)
 
  215                     case TEX_DIMENSION.TEX_DIMENSION_TEXTURE1D:
 
  216                         image.Dimension = TexImage.TextureDimension.Texture1D; 
break;
 
  217                     case TEX_DIMENSION.TEX_DIMENSION_TEXTURE2D:
 
  218                         image.Dimension = TexImage.TextureDimension.Texture2D; 
break;
 
  219                     case TEX_DIMENSION.TEX_DIMENSION_TEXTURE3D:
 
  220                         image.Dimension = TexImage.TextureDimension.Texture3D; 
break;
 
  224             UpdateImage(image, libraryData);
 
  235         private void Compress(TexImage image, DxtTextureLibraryData libraryData, CompressingRequest request)
 
  237             Log.Info(
"Converting/Compressing with " + request.Format + 
" ...");
 
  239             if(libraryData.DxtImages == null || libraryData.DxtImages.Length == 0)
 
  242             ScratchImage scratchImage = 
new ScratchImage();
 
  245             if (Tools.IsCompressed(request.Format))
 
  247                 var topImage = libraryData.DxtImages[0];
 
  248                 if (topImage.width % 4 != 0 || topImage.height % 4 != 0)
 
  249                     throw new TextureToolsException(
string.Format(
"The provided texture cannot be compressed into format '{0}' " +
 
  250                                                                   "because its top resolution ({1}-{2}) is not a multiple of 4.", request.Format, topImage.width, topImage.height));
 
  252                 hr = Utilities.Compress(libraryData.DxtImages, libraryData.DxtImages.Length, ref libraryData.Metadata, 
 
  257                 hr = Utilities.Convert(libraryData.DxtImages, libraryData.DxtImages.Length, ref libraryData.Metadata, 
 
  262             if (hr != HRESULT.S_OK)
 
  264                 Log.Error(
"Compression failed: " + hr);
 
  265                 throw new TextureToolsException(
"Compression failed: " + hr);
 
  268             if (image.DisposingLibrary != null) image.DisposingLibrary.Dispose(image);
 
  271             libraryData.Image = scratchImage;
 
  272             libraryData.DxtImages = libraryData.Image.GetImages();
 
  274             image.DisposingLibrary = 
this;
 
  276             UpdateImage(image, libraryData);
 
  287         private void Rescale(TexImage image, DxtTextureLibraryData libraryData, RescalingRequest request)
 
  289             int width = request.ComputeWidth(image);
 
  290             int height = request.ComputeHeight(image);
 
  292             Log.Info(
"Rescaling to " + width + 
"x" + height + 
" ...");
 
  294             TEX_FILTER_FLAGS filter;
 
  295             switch(request.Filter)
 
  297                 case Filter.Rescaling.Bilinear:
 
  300                 case Filter.Rescaling.Bicubic:
 
  303                 case Filter.Rescaling.Box:
 
  306                 case Filter.Rescaling.Nearest:
 
  314             ScratchImage scratchImage = 
new ScratchImage();
 
  315             HRESULT hr = Utilities.Resize(libraryData.DxtImages, libraryData.DxtImages.Length, ref libraryData.Metadata, width, height, filter, scratchImage);
 
  317             if (hr != HRESULT.S_OK)
 
  319                 Log.Error(
"Rescaling failed: " + hr);
 
  320                 throw new TextureToolsException(
"Rescaling failed: " + hr);
 
  324             if (image.DisposingLibrary != null) image.DisposingLibrary.Dispose(image);
 
  327             image.Rescale(width, height);
 
  329             libraryData.Image = scratchImage;
 
  330             libraryData.DxtImages = libraryData.Image.GetImages();
 
  332             image.DisposingLibrary = 
this;
 
  334             UpdateImage(image, libraryData);
 
  344         private void Decompress(TexImage image, DxtTextureLibraryData libraryData)
 
  346             Log.Info(
"Decompressing texture ...");
 
  347             ScratchImage scratchImage = 
new ScratchImage();
 
  348             HRESULT hr = Utilities.Decompress(libraryData.DxtImages, libraryData.DxtImages.Length, ref libraryData.Metadata, DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM, scratchImage);
 
  350             if (hr != HRESULT.S_OK)
 
  352                 Log.Error(
"Decompression failed: " + hr);
 
  353                 throw new TextureToolsException(
"Decompression failed: " + hr);
 
  357             if (image.DisposingLibrary != null) image.DisposingLibrary.Dispose(image);
 
  359             libraryData.Image = scratchImage;
 
  360             libraryData.DxtImages = libraryData.Image.GetImages();
 
  362             image.DisposingLibrary = 
this;
 
  364             UpdateImage(image, libraryData);
 
  379         private void GenerateMipMaps(TexImage image, DxtTextureLibraryData libraryData, MipMapsGenerationRequest request)
 
  381             Log.Info(
"Generating Mipmaps ... ");
 
  384             switch (request.Filter)
 
  386                 case Filter.MipMapGeneration.Nearest:
 
  389                 case Filter.MipMapGeneration.Linear:
 
  392                 case Filter.MipMapGeneration.Cubic:
 
  395                 case Filter.MipMapGeneration.Box:
 
  404             var scratchImage = 
new ScratchImage();
 
  405             if (libraryData.Metadata.dimension == TEX_DIMENSION.TEX_DIMENSION_TEXTURE3D)
 
  407                 Log.Info(
"Only the box and nearest(point) filters are supported for generating Mipmaps with 3D texture.");
 
  410                     filter = (TEX_FILTER_FLAGS)((
int)filter & 0xf00000);
 
  413                 hr = Utilities.GenerateMipMaps3D(libraryData.DxtImages, libraryData.DxtImages.Length, ref libraryData.Metadata, filter, 0, scratchImage);
 
  417                 hr = Utilities.GenerateMipMaps(libraryData.DxtImages, libraryData.DxtImages.Length, ref libraryData.Metadata, filter, 0, scratchImage);
 
  420             if (hr != HRESULT.S_OK)
 
  422                 Log.Error(
"Mipmaps generation failed: " + hr);
 
  423                 throw new TextureToolsException(
"Mipmaps generation failed: " + hr);
 
  427             if (image.DisposingLibrary != null) image.DisposingLibrary.Dispose(image);
 
  429             libraryData.Image = scratchImage;
 
  431             libraryData.DxtImages = libraryData.Image.GetImages();
 
  432             image.DisposingLibrary = 
this;
 
  434             UpdateImage(image, libraryData);
 
  447         private void Export(TexImage image, DxtTextureLibraryData libraryData, ExportRequest request)
 
  449             Log.Info(
"Exporting to " + request.FilePath + 
" ...");
 
  451             if (request.MinimumMipMapSize > 1 && request.MinimumMipMapSize <= libraryData.Metadata.width && request.MinimumMipMapSize <= libraryData.Metadata.height) 
 
  453                 TexMetadata 
metadata = libraryData.Metadata;
 
  456                 if (image.Dimension == TexImage.TextureDimension.Texture3D)
 
  459                     int newMipMapCount = 0; 
 
  461                     int curDepth = image.Depth << 1;
 
  462                     for (
int i = 0; i < image.MipmapCount; ++i)
 
  464                         curDepth = curDepth > 1 ? curDepth >>= 1 : curDepth;
 
  466                         if (libraryData.DxtImages[ct].width <= request.MinimumMipMapSize || libraryData.DxtImages[ct].height <= request.MinimumMipMapSize)
 
  476                     int SubImagePerArrayElement = image.SubImageArray.Length / image.ArraySize; 
 
  479                     metadata.mipLevels = newMipMapCount;
 
  480                     dxtImages = 
new Image[metadata.arraySize * ct];
 
  483                     for (
int i = 0; i < image.ArraySize; ++i)
 
  485                         for (
int j = 0; j < ct; ++j)
 
  487                             dxtImages[ct2] = libraryData.DxtImages[j + i * SubImagePerArrayElement];
 
  494                     int newMipMapCount = libraryData.Metadata.mipLevels;
 
  495                     for (
int i = libraryData.Metadata.mipLevels - 1; i > 0; --i) 
 
  497                         if (libraryData.DxtImages[i].width >= request.MinimumMipMapSize || libraryData.DxtImages[i].height >= request.MinimumMipMapSize)
 
  505                     metadata.mipLevels = newMipMapCount;
 
  506                     dxtImages = 
new Image[metadata.arraySize * newMipMapCount];
 
  509                     int gap = libraryData.Metadata.mipLevels - newMipMapCount;
 
  511                     for (
int i = 0; i < dxtImages.Length; ++i)
 
  513                         if (i == newMipMapCount || (i > newMipMapCount && i%newMipMapCount == 0)) j += gap;
 
  514                         dxtImages[i] = libraryData.DxtImages[j];
 
  521                 if (hr != HRESULT.S_OK)
 
  523                     Log.Error(
"Exporting texture failed: " + hr);
 
  524                     throw new TextureToolsException(
"Exporting texture failed: " + hr);
 
  529                 HRESULT hr = Utilities.SaveToDDSFile(libraryData.DxtImages, libraryData.DxtImages.Length, ref libraryData.Metadata, 
DDS_FLAGS.DDS_FLAGS_NONE, request.FilePath);
 
  531                 if (hr != HRESULT.S_OK)
 
  533                     Log.Error(
"Exporting texture failed: " + hr);
 
  534                     throw new TextureToolsException(
"Exporting texture failed: " + hr);
 
  538             image.Save(request.FilePath);
 
  551             Log.Info(
"Generating Normal Map ... ");
 
  553             ScratchImage scratchImage = 
new ScratchImage();
 
  555             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);
 
  557             if (hr != HRESULT.S_OK)
 
  559                 Log.Error(
"Failed to generate the normal map : " + hr);
 
  560                 throw new TextureToolsException(
"Failed to generate the normal map : " + hr);
 
  564             request.NormalMap = 
new TexImage();
 
  565             DxtTextureLibraryData normalMapLibraryData = 
new DxtTextureLibraryData();
 
  566             request.NormalMap.LibraryData[
this] = normalMapLibraryData;
 
  567             normalMapLibraryData.DxtImages = scratchImage.GetImages();
 
  569             normalMapLibraryData.Image = scratchImage;
 
  571             UpdateImage(request.
NormalMap, normalMapLibraryData);
 
  572             request.NormalMap.DisposingLibrary = 
this;
 
  581         public void PreMultiplyAlpha(TexImage image, DxtTextureLibraryData libraryData)
 
  583             Log.Info(
"Premultiplying alpha ... ");
 
  585             ScratchImage scratchImage = 
new ScratchImage();
 
  589             if (hr != HRESULT.S_OK)
 
  591                 Log.Error(
"Failed to premultiply the alpha : " + hr);
 
  592                 throw new TextureToolsException(
"Failed to premultiply the alpha : " + hr);
 
  596             if (image.DisposingLibrary != null) image.DisposingLibrary.Dispose(image);
 
  598             libraryData.Image = scratchImage;
 
  600             libraryData.DxtImages = libraryData.Image.GetImages();
 
  601             image.DisposingLibrary = 
this;
 
  603             UpdateImage(image, libraryData);
 
  612         private DXGI_FORMAT RetrieveNativeFormat(SiliconStudio.Paradox.Graphics.PixelFormat format)
 
  614             return (DXGI_FORMAT)
format;
 
  618         public bool SupportBGRAOrder()
 
  629         private void UpdateImage(TexImage image, DxtTextureLibraryData libraryData)
 
  633             image.SubImageArray = 
new TexImage.SubImage[libraryData.DxtImages.Length];
 
  634             for (
int i = 0; i < libraryData.DxtImages.Length; ++i)
 
  636                 image.SubImageArray[i] = 
new TexImage.SubImage();
 
  637                 image.SubImageArray[i].Data = libraryData.DxtImages[i].pixels;
 
  638                 image.SubImageArray[i].DataSize = libraryData.DxtImages[i].slicePitch;
 
  639                 image.SubImageArray[i].Width = libraryData.DxtImages[i].width;
 
  640                 image.SubImageArray[i].Height = libraryData.DxtImages[i].height;
 
  641                 image.SubImageArray[i].RowPitch = libraryData.DxtImages[i].rowPitch;
 
  642                 image.SubImageArray[i].SlicePitch = libraryData.DxtImages[i].slicePitch;
 
  643                 dataSize += image.SubImageArray[i].SlicePitch;
 
  646             image.Data = libraryData.DxtImages[0].pixels;
 
  647             image.DataSize = dataSize;
 
  648             image.Width = libraryData.Metadata.width;
 
  649             image.Height = libraryData.Metadata.height;
 
  650             image.Depth = libraryData.Metadata.depth;
 
  651             image.RowPitch = libraryData.DxtImages[0].rowPitch;
 
  653             image.MipmapCount = libraryData.Metadata.mipLevels;
 
  654             image.ArraySize = libraryData.Metadata.arraySize;
 
  655             image.SlicePitch = libraryData.DxtImages[0].slicePitch;
 
  666         private bool SupportFormat(SiliconStudio.Paradox.Graphics.PixelFormat format)
 
  668             return ((
int) (format) >= 1 && (
int) (format) <= 115);
 
HRESULT GenerateMipMaps(_In_ const Image &baseImage, _In_ DWORD filter, _In_ size_t levels, _Inout_ ScratchImage &mipChain, _In_ bool allow1D=false)
 
Base implementation for ILogger. 
 
_In_ size_t _In_ const TexMetadata & metadata
 
HRESULT Decompress(_In_ const Image &cImage, _In_ DXGI_FORMAT format, _Out_ ScratchImage &image)
 
_In_ size_t _In_ size_t _In_ DXGI_FORMAT format
 
Output message to log right away. 
 
PixelFormat
Defines various types of pixel formats. 
 
HRESULT Compress(_In_ const Image &srcImage, _In_ DXGI_FORMAT format, _In_ DWORD compress, _In_ float alphaRef, _Out_ ScratchImage &cImage)