Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
ParadoxTexLibrary.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 using System;
4 using System.Collections.Generic;
5 using System.IO;
6 using System.Threading.Tasks;
7 
8 using SiliconStudio.Paradox.Games;
9 using SiliconStudio.Paradox.Graphics;
10 using SiliconStudio.Core;
11 using SiliconStudio.Core.Diagnostics;
12 using SiliconStudio.TextureConverter.Requests;
13 
14 
15 namespace SiliconStudio.TextureConverter.TexLibraries
16 {
17 
18  /// <summary>
19  /// Class containing the needed native Data used by Paradox
20  /// </summary>
21  internal class ParadoxTextureLibraryData : ITextureLibraryData
22  {
23  /// <summary>
24  /// The <see cref="Image"/> image
25  /// </summary>
26  public Image PdxImage;
27  }
28 
29 
30  /// <summary>
31  /// Peforms requests from <see cref="TextureTool" /> using Paradox framework.
32  /// </summary>
33  internal class ParadoxTexLibrary : ITexLibrary
34  {
35  private static Logger Log = GlobalLogger.GetLogger("ParadoxTexLibrary");
36  public static readonly string Extension = ".pdx";
37 
38  /// <summary>
39  /// Initializes a new instance of the <see cref="ParadoxTexLibrary"/> class.
40  /// </summary>
41  public ParadoxTexLibrary(){}
42 
43  /// <summary>
44  /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. Nothing in this case
45  /// </summary>
46  public void Dispose(){}
47 
48 
49  public void Dispose(TexImage image)
50  {
51  ParadoxTextureLibraryData libraryData = (ParadoxTextureLibraryData)image.LibraryData[this];
52  if (libraryData.PdxImage != null) libraryData.PdxImage.Dispose();
53  }
54 
55  public bool SupportBGRAOrder()
56  {
57  return true;
58  }
59 
60  public void StartLibrary(TexImage image)
61  {
62  ParadoxTextureLibraryData libraryData = new ParadoxTextureLibraryData();
63  image.LibraryData[this] = libraryData;
64  }
65 
66  public void EndLibrary(TexImage image)
67  {
68 
69  }
70 
71  public bool CanHandleRequest(TexImage image, IRequest request)
72  {
73  switch (request.Type)
74  {
75  case RequestType.Export:
76  {
77  string extension = Path.GetExtension(((ExportRequest)request).FilePath);
78  return extension.Equals(".dds") || extension.Equals(Extension);
79  }
80 
81  case RequestType.ExportToParadox:
82  return true;
83 
84  case RequestType.Loading: // Paradox can load dds file or his own format or a Paradox <see cref="Image"/> instance.
85  LoadingRequest load = (LoadingRequest)request;
86  if(load.Mode == LoadingRequest.LoadingMode.PdxImage) return true;
87  else if(load.Mode == LoadingRequest.LoadingMode.FilePath)
88  {
89  string extension = Path.GetExtension(load.FilePath);
90  return extension.Equals(".dds") || extension.Equals(Extension);
91  } else return false;
92 
93  }
94  return false;
95  }
96 
97  public void Execute(TexImage image, IRequest request)
98  {
99  ParadoxTextureLibraryData libraryData = image.LibraryData.ContainsKey(this) ? (ParadoxTextureLibraryData)image.LibraryData[this] : null;
100 
101  switch (request.Type)
102  {
103  case RequestType.Export:
104  Export(image, libraryData, (ExportRequest)request);
105  break;
106 
107  case RequestType.ExportToParadox:
108  ExportToParadox(image, libraryData, (ExportToParadoxRequest)request);
109  break;
110 
111  case RequestType.Loading:
112  Load(image, (LoadingRequest)request);
113  break;
114  }
115  }
116 
117 
118  /// <summary>
119  /// Exports the specified image into regular DDS file or a Paradox own file format.
120  /// </summary>
121  /// <param name="image">The image.</param>
122  /// <param name="libraryData">The library data.</param>
123  /// <param name="request">The request.</param>
124  /// <exception cref="System.InvalidOperationException">
125  /// Image size different than expected.
126  /// or
127  /// Image could not be created.
128  /// </exception>
129  /// <exception cref="System.NotImplementedException"></exception>
130  /// <exception cref="TexLibraryException">Unsupported file extension.</exception>
131  private void Export(TexImage image, ParadoxTextureLibraryData libraryDataf, ExportRequest request)
132  {
133  Log.Info("Exporting to " + request.FilePath + " ...");
134 
135  Image pdxImage = null;
136 
137  if (request.MinimumMipMapSize > 1) // Check whether a minimum mipmap size was requested
138  {
139  if (image.Dimension == TexImage.TextureDimension.Texture3D)
140  {
141 
142  int newMipMapCount = 0; // the new mipmap count
143  int ct = 0; // ct will contain the number of SubImages per array element that we need to keep
144  int curDepth = image.Depth << 1;
145  for (int i = 0; i < image.MipmapCount; ++i)
146  {
147  curDepth = curDepth > 1 ? curDepth >>= 1 : curDepth;
148 
149  if (image.SubImageArray[ct].Width <= request.MinimumMipMapSize || image.SubImageArray[ct].Height <= request.MinimumMipMapSize)
150  {
151  ct += curDepth;
152  ++newMipMapCount;
153  break;
154  }
155  ++newMipMapCount;
156  ct += curDepth;
157  }
158 
159  int SubImagePerArrayElement = image.SubImageArray.Length / image.ArraySize; // number of SubImage in each texture array element.
160 
161  // Initializing library native data according to the new mipmap level
162  pdxImage = Image.New3D(image.Width, image.Height, image.Depth, newMipMapCount, image.Format);
163 
164  try
165  {
166  int ct2 = 0;
167  for (int i = 0; i < image.ArraySize; ++i)
168  {
169  for (int j = 0; j < ct; ++j)
170  {
171  Utilities.CopyMemory(pdxImage.PixelBuffer[ct2].DataPointer, pdxImage.PixelBuffer[j + i * SubImagePerArrayElement].DataPointer, pdxImage.PixelBuffer[j + i * SubImagePerArrayElement].BufferStride);
172  ++ct2;
173  }
174  }
175  }
176  catch (AccessViolationException e)
177  {
178  pdxImage.Dispose();
179  Log.Error("Failed to export texture with the mipmap minimum size request. ", e);
180  throw new TextureToolsException("Failed to export texture with the mipmap minimum size request. ", e);
181  }
182  }
183  else
184  {
185 
186  int newMipMapCount = image.MipmapCount;
187  int dataSize = image.DataSize;
188  for (int i = image.MipmapCount - 1; i > 0; --i)
189  {
190  if (image.SubImageArray[i].Width >= request.MinimumMipMapSize || image.SubImageArray[i].Height >= request.MinimumMipMapSize)
191  {
192  break;
193  }
194  dataSize -= image.SubImageArray[i].DataSize * image.ArraySize;
195  --newMipMapCount;
196  }
197 
198  switch (image.Dimension)
199  {
200  case TexImage.TextureDimension.Texture1D:
201  pdxImage = Image.New1D(image.Width, image.MipmapCount, image.Format, image.ArraySize); break;
202  case TexImage.TextureDimension.Texture2D:
203  pdxImage = Image.New2D(image.Width, image.Height, newMipMapCount, image.Format, image.ArraySize); break;
204  case TexImage.TextureDimension.TextureCube:
205  pdxImage = Image.NewCube(image.Width, newMipMapCount, image.Format); break;
206  }
207  if (pdxImage == null)
208  {
209  Log.Error("Image could not be created.");
210  throw new InvalidOperationException("Image could not be created.");
211  }
212 
213  if (pdxImage.TotalSizeInBytes != dataSize)
214  {
215  Log.Error("Image size different than expected.");
216  throw new InvalidOperationException("Image size different than expected.");
217  }
218 
219  try
220  {
221  int gap = image.MipmapCount - newMipMapCount;
222  int j = 0;
223  for (int i = 0; i < image.ArraySize * newMipMapCount; ++i)
224  {
225  if (i == newMipMapCount || (i > newMipMapCount && (i % newMipMapCount == 0))) j += gap;
226  Utilities.CopyMemory(pdxImage.PixelBuffer[i].DataPointer, image.SubImageArray[j].Data, image.SubImageArray[j].DataSize);
227  ++j;
228  }
229  }
230  catch (AccessViolationException e)
231  {
232  pdxImage.Dispose();
233  Log.Error("Failed to export texture with the mipmap minimum size request. ", e);
234  throw new TextureToolsException("Failed to export texture with the mipmap minimum size request. ", e);
235  }
236  }
237  }
238  else
239  {
240  switch (image.Dimension)
241  {
242  case TexImage.TextureDimension.Texture1D:
243  pdxImage = Image.New1D(image.Width, image.MipmapCount, image.Format, image.ArraySize); break;
244  case TexImage.TextureDimension.Texture2D:
245  pdxImage = Image.New2D(image.Width, image.Height, image.MipmapCount, image.Format, image.ArraySize); break;
246  case TexImage.TextureDimension.Texture3D:
247  pdxImage = Image.New3D(image.Width, image.Height, image.Depth, image.MipmapCount, image.Format); break;
248  case TexImage.TextureDimension.TextureCube:
249  pdxImage = Image.NewCube(image.Width, image.MipmapCount, image.Format); break;
250  }
251  if (pdxImage == null)
252  {
253  Log.Error("Image could not be created.");
254  throw new InvalidOperationException("Image could not be created.");
255  }
256 
257  if (pdxImage.TotalSizeInBytes != image.DataSize)
258  {
259  Log.Error("Image size different than expected.");
260  throw new InvalidOperationException("Image size different than expected.");
261  }
262 
263  Utilities.CopyMemory(pdxImage.DataPointer, image.Data, image.DataSize);
264  }
265 
266  using (var fileStream = new FileStream(request.FilePath, FileMode.Create, FileAccess.Write))
267  {
268  String extension = Path.GetExtension(request.FilePath);
269  if(extension.Equals(Extension))
270  pdxImage.Save(fileStream, ImageFileType.Paradox);
271  else if (extension.Equals(".dds"))
272  pdxImage.Save(fileStream, ImageFileType.Dds);
273  else
274  {
275  Log.Error("Unsupported file extension.");
276  throw new TextureToolsException("Unsupported file extension.");
277  }
278  }
279 
280  pdxImage.Dispose();
281  image.Save(request.FilePath);
282  }
283 
284 
285  /// <summary>
286  /// Exports to Paradox <see cref="Image"/>. An instance will be stored in the <see cref="ExportToParadoxRequest"/> instance.
287  /// </summary>
288  /// <param name="image">The image.</param>
289  /// <param name="libraryData">The library data.</param>
290  /// <param name="request">The request.</param>
291  /// <exception cref="System.InvalidOperationException">
292  /// Image size different than expected.
293  /// or
294  /// Failed to convert texture into Paradox Image.
295  /// </exception>
296  /// <exception cref="System.NotImplementedException"></exception>
297  private void ExportToParadox(TexImage image, ParadoxTextureLibraryData libraryData, ExportToParadoxRequest request)
298  {
299  Log.Info("Exporting to Paradox Image ...");
300 
301  Image pdxImage = null;
302  switch (image.Dimension)
303  {
304  case TexImage.TextureDimension.Texture1D:
305  pdxImage = Image.New1D(image.Width, image.MipmapCount, image.Format, image.ArraySize); break;
306  case TexImage.TextureDimension.Texture2D:
307  pdxImage = Image.New2D(image.Width, image.Height, image.MipmapCount, image.Format, image.ArraySize); break;
308  case TexImage.TextureDimension.Texture3D:
309  pdxImage = Image.New3D(image.Width, image.Height, image.Depth, image.MipmapCount, image.Format); break;
310  case TexImage.TextureDimension.TextureCube:
311  pdxImage = Image.NewCube(image.Width, image.MipmapCount, image.Format); break;
312  }
313  if (pdxImage == null)
314  {
315  Log.Error("Image could not be created.");
316  throw new InvalidOperationException("Image could not be created.");
317  }
318 
319  if (pdxImage.TotalSizeInBytes != image.DataSize)
320  {
321  Log.Error("Image size different than expected.");
322  throw new InvalidOperationException("Image size different than expected.");
323  }
324 
325  Utilities.CopyMemory(pdxImage.DataPointer, image.Data, image.DataSize);
326 
327  request.PdxImage = pdxImage;
328  }
329 
330 
331  /// <summary>
332  /// Loads the specified image.
333  /// </summary>
334  /// <param name="image">The image.</param>
335  /// <param name="request">The request.</param>
336  private void Load(TexImage image, LoadingRequest request)
337  {
338  Log.Info("Loading Paradox Image ...");
339 
340  ParadoxTextureLibraryData libraryData = new ParadoxTextureLibraryData();
341  image.LibraryData[this] = libraryData;
342 
343  Image inputImage;
344  if (request.Mode == LoadingRequest.LoadingMode.PdxImage)
345  {
346  inputImage = request.PdxImage;
347  }
348  else if (request.Mode == LoadingRequest.LoadingMode.FilePath)
349  {
350  using (var fileStream = new FileStream(request.FilePath, FileMode.Open, FileAccess.Read))
351  inputImage = Image.Load(fileStream);
352 
353  libraryData.PdxImage = inputImage; // the image need to be disposed by the paradox text library
354  }
355  else
356  {
357  throw new NotImplementedException();
358  }
359 
360  image.Data = inputImage.DataPointer;
361  image.DataSize = 0;
362  image.Width = inputImage.Description.Width;
363  image.Height = inputImage.Description.Height;
364  image.Depth = inputImage.Description.Depth;
365  image.Format = inputImage.Description.Format;
366  image.MipmapCount = request.KeepMipMap ? inputImage.Description.MipLevels : 1;
367  image.ArraySize = inputImage.Description.ArraySize;
368 
369  int rowPitch, slicePitch;
370  Tools.ComputePitch(image.Format, image.Width, image.Height, out rowPitch, out slicePitch);
371  image.RowPitch = rowPitch;
372  image.SlicePitch = slicePitch;
373 
374  var bufferStepFactor = request.KeepMipMap ? 1 : inputImage.Description.MipLevels;
375  int imageCount = inputImage.PixelBuffer.Count / bufferStepFactor;
376  image.SubImageArray = new TexImage.SubImage[imageCount];
377 
378  for (int i = 0; i < imageCount; ++i)
379  {
380  image.SubImageArray[i] = new TexImage.SubImage();
381  image.SubImageArray[i].Data = inputImage.PixelBuffer[i * bufferStepFactor].DataPointer;
382  image.SubImageArray[i].DataSize = inputImage.PixelBuffer[i * bufferStepFactor].BufferStride;
383  image.SubImageArray[i].Width = inputImage.PixelBuffer[i * bufferStepFactor].Width;
384  image.SubImageArray[i].Height = inputImage.PixelBuffer[i * bufferStepFactor].Height;
385  image.SubImageArray[i].RowPitch = inputImage.PixelBuffer[i * bufferStepFactor].RowStride;
386  image.SubImageArray[i].SlicePitch = inputImage.PixelBuffer[i * bufferStepFactor].BufferStride;
387  image.DataSize += image.SubImageArray[i].DataSize;
388  }
389 
390  switch (inputImage.Description.Dimension)
391  {
392  case TextureDimension.Texture1D:
393  image.Dimension = TexImage.TextureDimension.Texture1D; break;
394  case TextureDimension.Texture2D:
395  image.Dimension = TexImage.TextureDimension.Texture2D; break;
396  case TextureDimension.Texture3D:
397  image.Dimension = TexImage.TextureDimension.Texture3D; break;
398  case TextureDimension.TextureCube:
399  image.Dimension = TexImage.TextureDimension.TextureCube; break;
400  }
401 
402  image.DisposingLibrary = this;
403  }
404 
405  }
406 }
ImageFileType
Image file format used by Image.Save(string,SiliconStudio.Paradox.Graphics.ImageFileType) ...
static Image Load(DataPointer dataBuffer, bool makeACopy=false)
Loads an image from an unmanaged memory pointer.
Definition: Image.cs:477
Provides method to instantiate an image 1D/2D/3D supporting TextureArray and mipmaps on the CPU or to...
Definition: Image.cs:88
System.IO.FileMode FileMode
Definition: ScriptSync.cs:33
ImageDescription Description
Description of this image.
Definition: Image.cs:137
Base implementation for ILogger.
Definition: Logger.cs:10
switch(inFormat)
Output message to log right away.
TextureDimension Dimension
The dimension of a texture.