Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
ArrayTexLib.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.Runtime.InteropServices;
5 using System.Collections.Generic;
6 
7 using SiliconStudio.Core;
8 using SiliconStudio.Core.Diagnostics;
9 using SiliconStudio.TextureConverter.Requests;
10 
11 namespace SiliconStudio.TextureConverter.TexLibraries
12 {
13  /// <summary>
14  /// Allows the creation and manipulation of texture arrays.
15  /// </summary>
16  class ArrayTexLib : ITexLibrary
17  {
18  private static Logger Log = GlobalLogger.GetLogger("ArrayTexLib");
19 
20  /// <summary>
21  /// Initializes a new instance of the <see cref="ArrayTexLib"/> class.
22  /// </summary>
23  public ArrayTexLib() { }
24 
25  public bool CanHandleRequest(TexImage image, IRequest request)
26  {
27  switch (request.Type)
28  {
29  case RequestType.ArrayCreation:
30  case RequestType.ArrayExtraction:
31  case RequestType.ArrayUpdate:
32  case RequestType.ArrayInsertion:
33  case RequestType.ArrayElementRemoval:
34  case RequestType.CubeCreation:
35  return true;
36 
37  default:
38  return false;
39  }
40  }
41 
42  public void Execute(TexImage image, IRequest request)
43  {
44  switch (request.Type)
45  {
46  case RequestType.ArrayCreation:
47  CreateArray(image, (ArrayCreationRequest)request);
48  break;
49  case RequestType.ArrayExtraction:
50  Extract(image, (ArrayExtractionRequest)request);
51  break;
52  case RequestType.ArrayUpdate:
53  Update(image, (ArrayUpdateRequest)request);
54  break;
55  case RequestType.ArrayInsertion:
56  Insert(image, (ArrayInsertionRequest)request);
57  break;
58  case RequestType.ArrayElementRemoval:
59  Remove(image, (ArrayElementRemovalRequest)request);
60  break;
61  case RequestType.CubeCreation:
62  CreateCube(image, (CubeCreationRequest)request);
63  break;
64 
65  default:
66  Log.Error("ArrayTexLib can't handle this request: " + request.Type);
67  throw new TextureToolsException("ArrayTexLib can't handle this request: " + request.Type);
68  }
69  }
70 
71 
72  public void Dispose(TexImage image)
73  {
74  Marshal.FreeHGlobal(image.Data);
75  }
76 
77 
78  public void Dispose() { }
79 
80  public void StartLibrary(TexImage image) { }
81  public void EndLibrary(TexImage image) { }
82 
83  public bool SupportBGRAOrder()
84  {
85  return true;
86  }
87 
88  /// <summary>
89  /// Creates a texture array.
90  /// </summary>
91  /// <param name="array">The array.</param>
92  /// <param name="request">The request.</param>
93  private void Create(TexImage array, ArrayCreationRequest request)
94  {
95  array.Width = request.TextureList[0].Width;
96  array.Height = request.TextureList[0].Height;
97  array.Depth = request.TextureList[0].Depth;
98  array.RowPitch = request.TextureList[0].RowPitch;
99  array.SlicePitch = request.TextureList[0].SlicePitch;
100  array.Format = request.TextureList[0].Format;
101  array.FaceCount = request.TextureList[0].FaceCount;
102  array.MipmapCount = request.TextureList[0].MipmapCount;
103  array.DisposingLibrary = this;
104 
105  array.Name = request.TextureList[0].Name + "_array";
106  array.ArraySize = request.TextureList.Count;
107 
108  array.SubImageArray = new TexImage.SubImage[request.TextureList.Count * request.TextureList[0].SubImageArray.Length];
109 
110  array.DataSize = 0;
111  array.DataSize = request.TextureList[0].DataSize * array.ArraySize;
112 
113  array.Data = Marshal.AllocHGlobal(array.DataSize);
114 
115  int offset1, offset2;
116  long arrayData = array.Data.ToInt64();
117  long currentData;
118  IntPtr buffer;
119  TexImage current;
120 
121  offset1 = 0;
122  for (int i = 0; i < request.TextureList.Count; ++i)
123  {
124  current = request.TextureList[i];
125  buffer = new IntPtr(arrayData + offset1);
126  offset1 += current.DataSize;
127  Utilities.CopyMemory(buffer, current.Data, current.DataSize);
128 
129  offset2 = 0;
130  currentData = buffer.ToInt64();
131  for (int j = 0; j < current.SubImageArray.Length; ++j)
132  {
133  array.SubImageArray[i * current.SubImageArray.Length + j] = current.SubImageArray[j];
134  array.SubImageArray[i * current.SubImageArray.Length + j].Data = new IntPtr(currentData + offset2);
135  offset2 += current.SubImageArray[j].DataSize;
136  }
137  }
138  }
139 
140 
141  /// <summary>
142  /// Creates a texture array.
143  /// </summary>
144  /// <param name="array">The array.</param>
145  /// <param name="request">The request.</param>
146  private void CreateArray(TexImage array, ArrayCreationRequest request)
147  {
148  Log.Info("Creating texture array ...");
149 
150  Create(array, request);
151  }
152 
153 
154  /// <summary>
155  /// Creates a texture cube.
156  /// </summary>
157  /// <param name="image">The future cube texture.</param>
158  /// <param name="request">The request.</param>
159  private void CreateCube(TexImage image, CubeCreationRequest request)
160  {
161  Log.Info("Creating texture cube ...");
162 
163  Create(image, new ArrayCreationRequest(request.TextureList));
164 
165  image.Dimension = TexImage.TextureDimension.TextureCube;
166  }
167 
168 
169  /// <summary>
170  /// Extracts one or every texture from a texture array.
171  /// </summary>
172  /// <param name="image">The image.</param>
173  /// <param name="request">The request.</param>
174  private void Extract(TexImage image, ArrayExtractionRequest request)
175  {
176  int subImageCount = image.SubImageArray.Length / image.ArraySize;
177 
178  // Retrieving the mipmap count and the subimage count corresponding to the minimum mipmap size requested
179  int subImageCountWanted = 0;
180  int newMipMapCount = 0;
181  int curDepth = image.Depth == 1 ? 1 : image.Depth << 1;
182  for (int i = 0; i < image.MipmapCount; ++i)
183  {
184  curDepth = curDepth > 1 ? curDepth >>= 1 : curDepth;
185 
186  if (image.SubImageArray[subImageCountWanted].Width <= request.MinimumMipMapSize || image.SubImageArray[subImageCountWanted].Height <= request.MinimumMipMapSize)
187  {
188  subImageCountWanted += curDepth;
189  ++newMipMapCount;
190  break;
191  }
192  ++newMipMapCount;
193  subImageCountWanted += curDepth;
194  }
195 
196  if (request.Indice != -1)
197  {
198  Log.Info("Extracting texture " + request.Indice + " from the texture array ...");
199 
200  request.Texture = (TexImage)image.Clone(false);
201  request.Texture.ArraySize = 1;
202  request.Texture.MipmapCount = newMipMapCount;
203 
204  request.Texture.SubImageArray = new TexImage.SubImage[subImageCountWanted];
205 
206  int dataSize = 0;
207  for (int i = 0; i < subImageCountWanted; ++i)
208  {
209  request.Texture.SubImageArray[i] = image.SubImageArray[request.Indice * subImageCount + i];
210  dataSize += request.Texture.SubImageArray[i].SlicePitch;
211  }
212 
213  request.Texture.Data = request.Texture.SubImageArray[0].Data;
214  request.Texture.DataSize = dataSize;
215  }
216  else
217  {
218  Log.Info("Extracting each texture from the texture array ...");
219 
220  TexImage texture;
221  for (int i = 0; i < image.ArraySize; ++i)
222  {
223  texture = (TexImage)image.Clone(false);
224  texture.ArraySize = 1;
225  texture.SubImageArray = new TexImage.SubImage[subImageCountWanted];
226  texture.MipmapCount = newMipMapCount;
227 
228  int dataSize = 0;
229  for (int j = 0; j < subImageCountWanted; ++j)
230  {
231  texture.SubImageArray[j] = image.SubImageArray[i * subImageCount + j];
232  dataSize += texture.SubImageArray[j].SlicePitch;
233  }
234 
235  texture.Data = texture.SubImageArray[0].Data;
236  texture.DataSize = dataSize;
237 
238  request.Textures.Add(texture);
239  }
240  }
241  }
242 
243 
244  /// <summary>
245  /// Updates the specified array alement with a given texture.
246  /// </summary>
247  /// <param name="array">The array.</param>
248  /// <param name="request">The request.</param>
249  /// <exception cref="TexLibraryException">The given texture must match the dimension of the texture array.</exception>
250  private void Update(TexImage array, ArrayUpdateRequest request)
251  {
252  Log.Info("Updating texture "+request.Indice+" in the texture array ...");
253 
254  CheckConformity(array, request.Texture);
255 
256  int subImageCount = array.SubImageArray.Length / array.ArraySize;
257  int indice = request.Indice * subImageCount;
258 
259  for (int i = 0; i < subImageCount; ++i)
260  {
261  Utilities.CopyMemory(array.SubImageArray[indice].Data, request.Texture.SubImageArray[i].Data, request.Texture.SubImageArray[i].DataSize);
262  ++indice;
263  }
264  }
265 
266 
267  /// <summary>
268  /// Inserts the specified texture into the array at a given position.
269  /// </summary>
270  /// <param name="array">The array.</param>
271  /// <param name="request">The request.</param>
272  /// <exception cref="TexLibraryException">You can't add a texture to a texture cube.</exception>
273  private void Insert(TexImage array, ArrayInsertionRequest request)
274  {
275  Log.Info("Inserting texture at rank " + request.Indice + " in the texture array ...");
276 
277  if (array.Dimension == TexImage.TextureDimension.TextureCube)
278  {
279  Log.Error("You can't add a texture to a texture cube.");
280  throw new TextureToolsException("You can't add a texture to a texture cube.");
281  }
282 
283  CheckConformity(array, request.Texture);
284 
285  int subImageCount = array.SubImageArray.Length / array.ArraySize;
286  int indice = request.Indice * subImageCount;
287 
288  // Allocating memory
289  int newSize = array.DataSize + request.Texture.DataSize;
290  IntPtr buffer = Marshal.AllocHGlobal(newSize);
291 
292  long bufferData = buffer.ToInt64();
293  TexImage.SubImage[] subImages = new TexImage.SubImage[array.SubImageArray.Length + subImageCount];
294  int offset = 0;
295 
296  // Copying memory of the textures positionned before the new texture
297  for (int i = 0; i < indice; ++i)
298  {
299  subImages[i] = array.SubImageArray[i];
300  subImages[i].Data = new IntPtr(bufferData + offset);
301  Utilities.CopyMemory(subImages[i].Data, array.SubImageArray[i].Data, array.SubImageArray[i].DataSize);
302  offset += array.SubImageArray[i].DataSize;
303  }
304 
305  // copying new texture data
306  int ct = indice;
307  for (int i = 0; i < subImageCount; ++i)
308  {
309  subImages[ct] = request.Texture.SubImageArray[i];
310  Utilities.CopyMemory(subImages[ct].Data, request.Texture.SubImageArray[i].Data, request.Texture.SubImageArray[i].DataSize);
311  offset += request.Texture.SubImageArray[i].DataSize;
312  ++ct;
313  }
314 
315  // Copying memory of the textures positionned after the new texture
316  for (int i = indice; i < array.SubImageArray.Length; ++i)
317  {
318  subImages[ct] = array.SubImageArray[i];
319  subImages[ct].Data = new IntPtr(bufferData + offset);
320  Utilities.CopyMemory(subImages[ct].Data, array.SubImageArray[i].Data, array.SubImageArray[i].DataSize);
321  offset += array.SubImageArray[i].DataSize;
322  ++ct;
323  }
324 
325  // Freeing memory
326  if (array.DisposingLibrary != null) array.DisposingLibrary.Dispose(array);
327 
328  // Updating the array
329  array.Data = buffer;
330  array.DataSize = newSize;
331  ++array.ArraySize;
332  array.SubImageArray = subImages;
333  array.DisposingLibrary = this;
334  }
335 
336 
337  /// <summary>
338  /// Removes the specified texture from the array.
339  /// </summary>
340  /// <param name="array">The array.</param>
341  /// <param name="request">The request.</param>
342  /// <exception cref="TexLibraryException">You can't remove a texture from a texture cube.</exception>
343  private void Remove(TexImage array, ArrayElementRemovalRequest request)
344  {
345  Log.Info("Removing texture at rank " + request.Indice + " from the texture array ...");
346 
347  if (array.Dimension == TexImage.TextureDimension.TextureCube)
348  {
349  Log.Error("You can't remove a texture from a texture cube.");
350  throw new TextureToolsException("You can't remove a texture from a texture cube.");
351  }
352 
353  int subImageCount = array.SubImageArray.Length / array.ArraySize;
354  int indice = request.Indice * subImageCount;
355 
356  // Allocating memory
357  int elementSize = 0;
358  for (int i = 0; i < subImageCount; ++i) elementSize += array.SubImageArray[i].DataSize;
359  int newSize = array.DataSize - elementSize;
360  IntPtr buffer = Marshal.AllocHGlobal(newSize);
361 
362  long bufferData = buffer.ToInt64();
363  TexImage.SubImage[] subImages = new TexImage.SubImage[array.SubImageArray.Length - subImageCount];
364  int offset = 0;
365 
366  for (int i = 0; i < indice; ++i)
367  {
368  subImages[i] = array.SubImageArray[i];
369  subImages[i].Data = new IntPtr(bufferData + offset);
370  Utilities.CopyMemory(subImages[i].Data, array.SubImageArray[i].Data, array.SubImageArray[i].DataSize);
371  offset += array.SubImageArray[i].DataSize;
372  }
373 
374  int ct = indice;
375  for (int i = indice + subImageCount; i < array.SubImageArray.Length; ++i)
376  {
377  subImages[indice] = array.SubImageArray[i];
378  subImages[indice].Data = new IntPtr(bufferData + offset);
379  Utilities.CopyMemory(subImages[indice].Data, array.SubImageArray[i].Data, array.SubImageArray[i].DataSize);
380  offset += array.SubImageArray[i].DataSize;
381  ++indice;
382  }
383 
384  // Freeing memory
385  if (array.DisposingLibrary != null) array.DisposingLibrary.Dispose(array);
386 
387  // Updating the array
388  array.Data = buffer;
389  array.DataSize = newSize;
390  --array.ArraySize;
391  array.SubImageArray = subImages;
392  array.DisposingLibrary = this;
393  }
394 
395 
396  /// <summary>
397  /// Checks the conformity of a texture with a texture array. The texture dimensions must match the the texture array's ones.
398  /// </summary>
399  /// <param name="array">The array.</param>
400  /// <param name="candidate">The candidate.</param>
401  /// <exception cref="TexLibraryException">The given texture must match the dimensions of the texture array.</exception>
402  private void CheckConformity(TexImage array, TexImage candidate)
403  {
404  int subImageCount = array.SubImageArray.Length / array.ArraySize;
405  if (candidate.Width != array.Width || candidate.Height != array.Height || candidate.Depth != array.Depth || candidate.SubImageArray.Length != subImageCount)
406  {
407  Log.Error("The given texture must match the dimensions of the texture array.");
408  throw new TextureToolsException("The given texture must match the dimensions of the texture array.");
409  }
410  }
411  }
412 }
List< TexImage > TextureList
The texture list that will populate the cube.
ArrayTexLib()
Initializes a new instance of the ArrayTexLib class.
Definition: ArrayTexLib.cs:23
bool CanHandleRequest(TexImage image, IRequest request)
Definition: ArrayTexLib.cs:25
Allows the creation and manipulation of texture arrays.
Definition: ArrayTexLib.cs:16
int MinimumMipMapSize
The minimum size of the smallest mipmap.
void Execute(TexImage image, IRequest request)
Definition: ArrayTexLib.cs:42
Base implementation for ILogger.
Definition: Logger.cs:10
Request to insert a specific texture in a texture array.
Request to create a texture array from a texture list.
Request to extract one or every textures from a texture array
Request to remove the texture at a specified position from a texture array.
Request to update a specific texture in a texture array.
Request to create a texture cube from a texture list.
Creates a new file, always. If a file exists, the function overwrites the file, clears the existing a...
A structure describing an image of one mip map level (of one member in an array texture).
Definition: TexImage.cs:57
The remove mixin to remove a mixin from current mixins.
Temporary format containing texture data and information. Used as buffer between texture libraries...
Definition: TexImage.cs:13
int Indice
The indice of the texture to be extracted from the array.
Output message to log right away.