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)