Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
Image.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 //
4 // Copyright (c) 2010-2012 SharpDX - Alexandre Mutel
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to deal
8 // in the Software without restriction, including without limitation the rights
9 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 // copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 // THE SOFTWARE.
23 // -----------------------------------------------------------------------------
24 // Part of te following code is a port of http://directxtex.codeplex.com
25 // -----------------------------------------------------------------------------
26 // Microsoft Public License (Ms-PL)
27 //
28 // This license governs use of the accompanying software. If you use the
29 // software, you accept this license. If you do not accept the license, do not
30 // use the software.
31 //
32 // 1. Definitions
33 // The terms "reproduce," "reproduction," "derivative works," and
34 // "distribution" have the same meaning here as under U.S. copyright law.
35 // A "contribution" is the original software, or any additions or changes to
36 // the software.
37 // A "contributor" is any person that distributes its contribution under this
38 // license.
39 // "Licensed patents" are a contributor's patent claims that read directly on
40 // its contribution.
41 //
42 // 2. Grant of Rights
43 // (A) Copyright Grant- Subject to the terms of this license, including the
44 // license conditions and limitations in section 3, each contributor grants
45 // you a non-exclusive, worldwide, royalty-free copyright license to reproduce
46 // its contribution, prepare derivative works of its contribution, and
47 // distribute its contribution or any derivative works that you create.
48 // (B) Patent Grant- Subject to the terms of this license, including the license
49 // conditions and limitations in section 3, each contributor grants you a
50 // non-exclusive, worldwide, royalty-free license under its licensed patents to
51 // make, have made, use, sell, offer for sale, import, and/or otherwise dispose
52 // of its contribution in the software or derivative works of the contribution
53 // in the software.
54 //
55 // 3. Conditions and Limitations
56 // (A) No Trademark License- This license does not grant you rights to use any
57 // contributors' name, logo, or trademarks.
58 // (B) If you bring a patent claim against any contributor over patents that
59 // you claim are infringed by the software, your patent license from such
60 // contributor to the software ends automatically.
61 // (C) If you distribute any portion of the software, you must retain all
62 // copyright, patent, trademark, and attribution notices that are present in the
63 // software.
64 // (D) If you distribute any portion of the software in source code form, you
65 // may do so only under this license by including a complete copy of this
66 // license with your distribution. If you distribute any portion of the software
67 // in compiled or object code form, you may only do so under a license that
68 // complies with this license.
69 // (E) The software is licensed "as-is." You bear the risk of using it. The
70 // contributors give no express warranties, guarantees or conditions. You may
71 // have additional consumer rights under your local laws which this license
72 // cannot change. To the extent permitted under your local laws, the
73 // contributors exclude the implied warranties of merchantability, fitness for a
74 // particular purpose and non-infringement.
75 using System;
76 using System.Collections.Generic;
77 using System.IO;
78 using System.Runtime.InteropServices;
79 using SiliconStudio.Core;
80 using SiliconStudio.Core.Serialization.Contents;
81 
82 namespace SiliconStudio.Paradox.Graphics
83 {
84  /// <summary>
85  /// Provides method to instantiate an image 1D/2D/3D supporting TextureArray and mipmaps on the CPU or to load/save an image from the disk.
86  /// </summary>
87  [ContentSerializer(typeof(ImageSerializer))]
88  public sealed class Image : IDisposable
89  {
90  public delegate Image ImageLoadDelegate(IntPtr dataPointer, int dataSize, bool makeACopy, GCHandle? handle);
91  public delegate void ImageSaveDelegate(PixelBuffer[] pixelBuffers, int count, ImageDescription description, Stream imageStream);
92 
93  private const string MagicCodeTKTX = "TKTX";
94 
95  /// <summary>
96  /// Pixel buffers.
97  /// </summary>
98  internal PixelBuffer[] pixelBuffers;
99  private DataBox[] dataBoxArray;
100  private List<int> mipMapToZIndex;
101  private int zBufferCountPerArraySlice;
102  private MipMapDescription[] mipmapDescriptions;
103  private static List<LoadSaveDelegate> loadSaveDelegates = new List<LoadSaveDelegate>();
104 
105  /// <summary>
106  /// Provides access to all pixel buffers.
107  /// </summary>
108  /// <remarks>
109  /// For Texture3D, each z slice of the Texture3D has a pixelBufferArray * by the number of mipmaps.
110  /// For other textures, there is Description.MipLevels * Description.ArraySize pixel buffers.
111  /// </remarks>
112  private PixelBufferArray pixelBufferArray;
113 
114  /// <summary>
115  /// Gets the total number of bytes occupied by this image in memory.
116  /// </summary>
117  private int totalSizeInBytes;
118 
119  /// <summary>
120  /// Pointer to the buffer.
121  /// </summary>
122  private IntPtr buffer;
123 
124  /// <summary>
125  /// True if the buffer must be disposed.
126  /// </summary>
127  private bool bufferIsDisposable;
128 
129  /// <summary>
130  /// Handke != null if the buffer is a pinned managed object on the LOH (Large Object Heap).
131  /// </summary>
132  private GCHandle? handle;
133 
134  /// <summary>
135  /// Description of this image.
136  /// </summary>
138 
139  private Image()
140  {
141  }
142 
143  /// <summary>
144  /// Initializes a new instance of the <see cref="Image" /> class.
145  /// </summary>
146  /// <param name="description">The image description.</param>
147  /// <param name="dataPointer">The pointer to the data buffer.</param>
148  /// <param name="offset">The offset from the beginning of the data buffer.</param>
149  /// <param name="handle">The handle (optionnal).</param>
150  /// <param name="bufferIsDisposable">if set to <c>true</c> [buffer is disposable].</param>
151  /// <exception cref="System.InvalidOperationException">If the format is invalid, or width/height/depth/arraysize is invalid with respect to the dimension.</exception>
152  internal unsafe Image(ImageDescription description, IntPtr dataPointer, int offset, GCHandle? handle, bool bufferIsDisposable, PitchFlags pitchFlags = PitchFlags.None, int rowStride = 0)
153  {
154  Initialize(description, dataPointer, offset, handle, bufferIsDisposable, pitchFlags, rowStride);
155  }
156 
157  public void Dispose()
158  {
159  if (handle.HasValue)
160  {
161  handle.Value.Free();
162  }
163 
164  if (bufferIsDisposable)
165  {
166  Utilities.FreeMemory(buffer);
167  }
168  }
169 
170  /// <summary>
171  /// Gets the mipmap description of this instance for the specified mipmap level.
172  /// </summary>
173  /// <param name="mipmap">The mipmap.</param>
174  /// <returns>A description of a particular mipmap for this texture.</returns>
176  {
177  return mipmapDescriptions[mipmap];
178  }
179 
180  /// <summary>
181  /// Gets the pixel buffer for the specified array/z slice and mipmap level.
182  /// </summary>
183  /// <param name="arrayOrZSliceIndex">For 3D image, the parameter is the Z slice, otherwise it is an index into the texture array.</param>
184  /// <param name="mipmap">The mipmap.</param>
185  /// <returns>A <see cref="pixelBufferArray"/>.</returns>
186  /// <exception cref="System.ArgumentException">If arrayOrZSliceIndex or mipmap are out of range.</exception>
187  public PixelBuffer GetPixelBuffer(int arrayOrZSliceIndex, int mipmap)
188  {
189  // Check for parameters, as it is easy to mess up things...
190  if (mipmap > Description.MipLevels)
191  throw new ArgumentException("Invalid mipmap level", "mipmap");
192 
193  if (Description.Dimension == TextureDimension.Texture3D)
194  {
195  if (arrayOrZSliceIndex > Description.Depth)
196  throw new ArgumentException("Invalid z slice index", "arrayOrZSliceIndex");
197 
198  // For 3D textures
199  return GetPixelBufferUnsafe(0, arrayOrZSliceIndex, mipmap);
200  }
201 
202  if (arrayOrZSliceIndex > Description.ArraySize)
203  {
204  throw new ArgumentException("Invalid array slice index", "arrayOrZSliceIndex");
205  }
206 
207  // For 1D, 2D textures
208  return GetPixelBufferUnsafe(arrayOrZSliceIndex, 0, mipmap);
209  }
210 
211  /// <summary>
212  /// Gets the pixel buffer for the specified array/z slice and mipmap level.
213  /// </summary>
214  /// <param name="arrayIndex">Index into the texture array. Must be set to 0 for 3D images.</param>
215  /// <param name="zIndex">Z index for 3D image. Must be set to 0 for all 1D/2D images.</param>
216  /// <param name="mipmap">The mipmap.</param>
217  /// <returns>A <see cref="pixelBufferArray"/>.</returns>
218  /// <exception cref="System.ArgumentException">If arrayIndex, zIndex or mipmap are out of range.</exception>
219  public PixelBuffer GetPixelBuffer(int arrayIndex, int zIndex, int mipmap)
220  {
221  // Check for parameters, as it is easy to mess up things...
222  if (mipmap > Description.MipLevels)
223  throw new ArgumentException("Invalid mipmap level", "mipmap");
224 
225  if (arrayIndex > Description.ArraySize)
226  throw new ArgumentException("Invalid array slice index", "arrayIndex");
227 
228  if (zIndex > Description.Depth)
229  throw new ArgumentException("Invalid z slice index", "zIndex");
230 
231  return this.GetPixelBufferUnsafe(arrayIndex, zIndex, mipmap);
232  }
233 
234 
235  /// <summary>
236  /// Registers a loader/saver for a specified image file type.
237  /// </summary>
238  /// <param name="type">The file type (use integer and explicit casting to <see cref="ImageFileType"/> to register other fileformat.</param>
239  /// <param name="loader">The loader delegate (can be null).</param>
240  /// <param name="saver">The saver delegate (can be null).</param>
241  /// <exception cref="System.ArgumentException"></exception>
242  public static void Register(ImageFileType type, ImageLoadDelegate loader, ImageSaveDelegate saver)
243  {
244  // If reference equals, then it is null
245  if (ReferenceEquals(loader, saver))
246  throw new ArgumentNullException("Can set both loader and saver to null", "loader/saver");
247 
248  var newDelegate = new LoadSaveDelegate(type, loader, saver);
249  for (int i = 0; i < loadSaveDelegates.Count; i++)
250  {
251  var loadSaveDelegate = loadSaveDelegates[i];
252  if (loadSaveDelegate.FileType == type)
253  {
254  loadSaveDelegates[i] = newDelegate;
255  return;
256  }
257  }
258  loadSaveDelegates.Add(newDelegate);
259  }
260 
261 
262  /// <summary>
263  /// Gets a pointer to the image buffer in memory.
264  /// </summary>
265  /// <value>A pointer to the image buffer in memory.</value>
266  public IntPtr DataPointer
267  {
268  get { return this.buffer; }
269  }
270 
271  /// <summary>
272  /// Provides access to all pixel buffers.
273  /// </summary>
274  /// <remarks>
275  /// For Texture3D, each z slice of the Texture3D has a pixelBufferArray * by the number of mipmaps.
276  /// For other textures, there is Description.MipLevels * Description.ArraySize pixel buffers.
277  /// </remarks>
279  {
280  get { return pixelBufferArray; }
281  }
282 
283  /// <summary>
284  /// Gets the total number of bytes occupied by this image in memory.
285  /// </summary>
286  public int TotalSizeInBytes
287  {
288  get { return totalSizeInBytes; }
289  }
290 
291  /// <summary>
292  /// Gets the databox from this image.
293  /// </summary>
294  /// <returns>The databox of this image.</returns>
295  public DataBox[] ToDataBox()
296  {
297  return (DataBox[])dataBoxArray.Clone();
298  }
299 
300  /// <summary>
301  /// Gets the databox from this image.
302  /// </summary>
303  /// <returns>The databox of this image.</returns>
304  private DataBox[] ComputeDataBox()
305  {
306  dataBoxArray = new DataBox[Description.ArraySize * Description.MipLevels];
307  int i = 0;
308  for (int arrayIndex = 0; arrayIndex < Description.ArraySize; arrayIndex++)
309  {
310  for (int mipIndex = 0; mipIndex < Description.MipLevels; mipIndex++)
311  {
312  // Get the first z-slize (A DataBox for a Texture3D is pointing to the whole texture).
313  var pixelBuffer = this.GetPixelBufferUnsafe(arrayIndex, 0, mipIndex);
314 
315  dataBoxArray[i].DataPointer = pixelBuffer.DataPointer;
316  dataBoxArray[i].RowPitch = pixelBuffer.RowStride;
317  dataBoxArray[i].SlicePitch = pixelBuffer.BufferStride;
318  i++;
319  }
320  }
321  return dataBoxArray;
322  }
323 
324  /// <summary>
325  /// Creates a new instance of <see cref="Image"/> from an image description.
326  /// </summary>
327  /// <param name="description">The image description.</param>
328  /// <returns>A new image.</returns>
329  public static Image New(ImageDescription description)
330  {
331  return New(description, IntPtr.Zero);
332  }
333 
334  /// <summary>
335  /// Creates a new instance of a 1D <see cref="Image"/>.
336  /// </summary>
337  /// <param name="width">The width.</param>
338  /// <param name="mipMapCount">The mip map count.</param>
339  /// <param name="format">The format.</param>
340  /// <param name="arraySize">Size of the array.</param>
341  /// <returns>A new image.</returns>
342  public static Image New1D(int width, MipMapCount mipMapCount, PixelFormat format, int arraySize = 1)
343  {
344  return New1D(width, mipMapCount, format, arraySize, IntPtr.Zero);
345  }
346 
347  /// <summary>
348  /// Creates a new instance of a 2D <see cref="Image"/>.
349  /// </summary>
350  /// <param name="width">The width.</param>
351  /// <param name="height">The height.</param>
352  /// <param name="mipMapCount">The mip map count.</param>
353  /// <param name="format">The format.</param>
354  /// <param name="arraySize">Size of the array.</param>
355  /// <returns>A new image.</returns>
356  public static Image New2D(int width, int height, MipMapCount mipMapCount, PixelFormat format, int arraySize = 1, int rowStride = 0)
357  {
358  return New2D(width, height, mipMapCount, format, arraySize, IntPtr.Zero, rowStride);
359  }
360 
361  /// <summary>
362  /// Creates a new instance of a Cube <see cref="Image"/>.
363  /// </summary>
364  /// <param name="width">The width.</param>
365  /// <param name="mipMapCount">The mip map count.</param>
366  /// <param name="format">The format.</param>
367  /// <returns>A new image.</returns>
368  public static Image NewCube(int width, MipMapCount mipMapCount, PixelFormat format)
369  {
370  return NewCube(width, mipMapCount, format, IntPtr.Zero);
371  }
372 
373  /// <summary>
374  /// Creates a new instance of a 3D <see cref="Image"/>.
375  /// </summary>
376  /// <param name="width">The width.</param>
377  /// <param name="height">The height.</param>
378  /// <param name="depth">The depth.</param>
379  /// <param name="mipMapCount">The mip map count.</param>
380  /// <param name="format">The format.</param>
381  /// <returns>A new image.</returns>
382  public static Image New3D(int width, int height, int depth, MipMapCount mipMapCount, PixelFormat format)
383  {
384  return New3D(width, height, depth, mipMapCount, format, IntPtr.Zero);
385  }
386 
387  /// <summary>
388  /// Creates a new instance of <see cref="Image"/> from an image description.
389  /// </summary>
390  /// <param name="description">The image description.</param>
391  /// <param name="dataPointer">Pointer to an existing buffer.</param>
392  /// <returns>A new image.</returns>
393  public static Image New(ImageDescription description, IntPtr dataPointer)
394  {
395  return new Image(description, dataPointer, 0, null, false);
396  }
397 
398  /// <summary>
399  /// Initializes a new instance of the <see cref="Image" /> class.
400  /// </summary>
401  /// <param name="description">The image description.</param>
402  /// <param name="dataPointer">The pointer to the data buffer.</param>
403  /// <param name="offset">The offset from the beginning of the data buffer.</param>
404  /// <param name="handle">The handle (optionnal).</param>
405  /// <param name="bufferIsDisposable">if set to <c>true</c> [buffer is disposable].</param>
406  /// <exception cref="System.InvalidOperationException">If the format is invalid, or width/height/depth/arraysize is invalid with respect to the dimension.</exception>
407  public static Image New(ImageDescription description, IntPtr dataPointer, int offset, GCHandle? handle, bool bufferIsDisposable)
408  {
409  return new Image(description, dataPointer, offset, handle, bufferIsDisposable);
410  }
411 
412  /// <summary>
413  /// Creates a new instance of a 1D <see cref="Image"/>.
414  /// </summary>
415  /// <param name="width">The width.</param>
416  /// <param name="mipMapCount">The mip map count.</param>
417  /// <param name="format">The format.</param>
418  /// <param name="arraySize">Size of the array.</param>
419  /// <param name="dataPointer">Pointer to an existing buffer.</param>
420  /// <returns>A new image.</returns>
421  public static Image New1D(int width, MipMapCount mipMapCount, PixelFormat format, int arraySize, IntPtr dataPointer)
422  {
423  return new Image(CreateDescription(TextureDimension.Texture1D, width, 1, 1, mipMapCount, format, arraySize), dataPointer, 0, null, false);
424  }
425 
426  /// <summary>
427  /// Creates a new instance of a 2D <see cref="Image"/>.
428  /// </summary>
429  /// <param name="width">The width.</param>
430  /// <param name="height">The height.</param>
431  /// <param name="mipMapCount">The mip map count.</param>
432  /// <param name="format">The format.</param>
433  /// <param name="arraySize">Size of the array.</param>
434  /// <param name="dataPointer">Pointer to an existing buffer.</param>
435  /// <param name="rowStride">Specify a specific rowStride, only valid when mipMapCount == 1 and pixel format is not compressed.</param>
436  /// <returns>A new image.</returns>
437  public static Image New2D(int width, int height, MipMapCount mipMapCount, PixelFormat format, int arraySize, IntPtr dataPointer, int rowStride = 0)
438  {
439  return new Image(CreateDescription(TextureDimension.Texture2D, width, height, 1, mipMapCount, format, arraySize), dataPointer, 0, null, false, PitchFlags.None, rowStride);
440  }
441 
442  /// <summary>
443  /// Creates a new instance of a Cube <see cref="Image"/>.
444  /// </summary>
445  /// <param name="width">The width.</param>
446  /// <param name="mipMapCount">The mip map count.</param>
447  /// <param name="format">The format.</param>
448  /// <param name="dataPointer">Pointer to an existing buffer.</param>
449  /// <returns>A new image.</returns>
450  public static Image NewCube(int width, MipMapCount mipMapCount, PixelFormat format, IntPtr dataPointer)
451  {
452  return new Image(CreateDescription(TextureDimension.TextureCube, width, width, 1, mipMapCount, format, 6), dataPointer, 0, null, false);
453  }
454 
455  /// <summary>
456  /// Creates a new instance of a 3D <see cref="Image"/>.
457  /// </summary>
458  /// <param name="width">The width.</param>
459  /// <param name="height">The height.</param>
460  /// <param name="depth">The depth.</param>
461  /// <param name="mipMapCount">The mip map count.</param>
462  /// <param name="format">The format.</param>
463  /// <param name="dataPointer">Pointer to an existing buffer.</param>
464  /// <returns>A new image.</returns>
465  public static Image New3D(int width, int height, int depth, MipMapCount mipMapCount, PixelFormat format, IntPtr dataPointer)
466  {
467  return new Image(CreateDescription(TextureDimension.Texture3D, width, width, depth, mipMapCount, format, 1), dataPointer, 0, null, false);
468  }
469 
470  /// <summary>
471  /// Loads an image from an unmanaged memory pointer.
472  /// </summary>
473  /// <param name="dataBuffer">Pointer to an unmanaged memory. If <see cref="makeACopy"/> is false, this buffer must be allocated with <see cref="Utilities.AllocateMemory"/>.</param>
474  /// <param name="makeACopy">True to copy the content of the buffer to a new allocated buffer, false otherwhise.</param>
475  /// <returns>An new image.</returns>
476  /// <remarks>If <see cref="makeACopy"/> is set to false, the returned image is now the holder of the unmanaged pointer and will release it on Dispose. </remarks>
477  public static Image Load(DataPointer dataBuffer, bool makeACopy = false)
478  {
479  return Load(dataBuffer.Pointer, dataBuffer.Size, makeACopy);
480  }
481 
482  /// <summary>
483  /// Loads an image from an unmanaged memory pointer.
484  /// </summary>
485  /// <param name="dataPointer">Pointer to an unmanaged memory. If <see cref="makeACopy"/> is false, this buffer must be allocated with <see cref="Utilities.AllocateMemory"/>.</param>
486  /// <param name="dataSize">Size of the unmanaged buffer.</param>
487  /// <param name="makeACopy">True to copy the content of the buffer to a new allocated buffer, false otherwise.</param>
488  /// <returns>An new image.</returns>
489  /// <remarks>If <see cref="makeACopy"/> is set to false, the returned image is now the holder of the unmanaged pointer and will release it on Dispose. </remarks>
490  public static Image Load(IntPtr dataPointer, int dataSize, bool makeACopy = false)
491  {
492  return Load(dataPointer, dataSize, makeACopy, null);
493  }
494 
495  /// <summary>
496  /// Loads an image from a managed buffer.
497  /// </summary>
498  /// <param name="buffer">Reference to a managed buffer.</param>
499  /// <returns>An new image.</returns>
500  /// <remarks>This method support the following format: <c>dds, bmp, jpg, png, gif, tiff, wmp, tga</c>.</remarks>
501  public unsafe static Image Load(byte[] buffer)
502  {
503  if (buffer == null)
504  throw new ArgumentNullException("buffer");
505 
506  int size = buffer.Length;
507 
508  // If buffer is allocated on Larget Object Heap, then we are going to pin it instead of making a copy.
509  if (size > (85 * 1024))
510  {
511  var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
512  return Load(handle.AddrOfPinnedObject(), size, false, handle);
513  }
514 
515  fixed (void* pbuffer = buffer)
516  {
517  return Load((IntPtr) pbuffer, size, true);
518  }
519  }
520 
521  /// <summary>
522  /// Loads the specified image from a stream.
523  /// </summary>
524  /// <param name="imageStream">The image stream.</param>
525  /// <returns>An new image.</returns>
526  /// <remarks>This method support the following format: <c>dds, bmp, jpg, png, gif, tiff, wmp, tga</c>.</remarks>
527  public static Image Load(Stream imageStream)
528  {
529  if (imageStream == null) throw new ArgumentNullException("imageStream");
530  // Read the whole stream into memory.
531  return Load(Utilities.ReadStream(imageStream));
532  }
533 
534  /// <summary>
535  /// Saves this instance to a stream.
536  /// </summary>
537  /// <param name="imageStream">The destination stream.</param>
538  /// <param name="fileType">Specify the output format.</param>
539  /// <remarks>This method support the following format: <c>dds, bmp, jpg, png, gif, tiff, wmp, tga</c>.</remarks>
540  public void Save(Stream imageStream, ImageFileType fileType)
541  {
542  if (imageStream == null) throw new ArgumentNullException("imageStream");
543  Save(pixelBuffers, this.pixelBuffers.Length, Description, imageStream, fileType);
544  }
545 
546  /// <summary>
547  /// Calculates the number of miplevels for a Texture 1D.
548  /// </summary>
549  /// <param name="width">The width of the texture.</param>
550  /// <param name="mipLevels">A <see cref="MipMapCount"/>, set to true to calculates all mipmaps, to false to calculate only 1 miplevel, or > 1 to calculate a specific amount of levels.</param>
551  /// <returns>The number of miplevels.</returns>
552  public static int CalculateMipLevels(int width, MipMapCount mipLevels)
553  {
554  if (mipLevels > 1)
555  {
556  int maxMips = CountMips(width);
557  if (mipLevels > maxMips)
558  throw new InvalidOperationException(String.Format("MipLevels must be <= {0}", maxMips));
559  }
560  else if (mipLevels == 0)
561  {
562  mipLevels = CountMips(width);
563  }
564  else
565  {
566  mipLevels = 1;
567  }
568  return mipLevels;
569  }
570 
571  /// <summary>
572  /// Calculates the number of miplevels for a Texture 2D.
573  /// </summary>
574  /// <param name="width">The width of the texture.</param>
575  /// <param name="height">The height of the texture.</param>
576  /// <param name="mipLevels">A <see cref="MipMapCount"/>, set to true to calculates all mipmaps, to false to calculate only 1 miplevel, or > 1 to calculate a specific amount of levels.</param>
577  /// <returns>The number of miplevels.</returns>
578  public static int CalculateMipLevels(int width, int height, MipMapCount mipLevels)
579  {
580  if (mipLevels > 1)
581  {
582  int maxMips = CountMips(width, height);
583  if (mipLevels > maxMips)
584  throw new InvalidOperationException(String.Format("MipLevels must be <= {0}", maxMips));
585  }
586  else if (mipLevels == 0)
587  {
588  mipLevels = CountMips(width, height);
589  }
590  else
591  {
592  mipLevels = 1;
593  }
594  return mipLevels;
595  }
596 
597  /// <summary>
598  /// Calculates the number of miplevels for a Texture 2D.
599  /// </summary>
600  /// <param name="width">The width of the texture.</param>
601  /// <param name="height">The height of the texture.</param>
602  /// <param name="depth">The depth of the texture.</param>
603  /// <param name="mipLevels">A <see cref="MipMapCount"/>, set to true to calculates all mipmaps, to false to calculate only 1 miplevel, or > 1 to calculate a specific amount of levels.</param>
604  /// <returns>The number of miplevels.</returns>
605  public static int CalculateMipLevels(int width, int height, int depth, MipMapCount mipLevels)
606  {
607  if (mipLevels > 1)
608  {
609  if (!IsPow2(width) || !IsPow2(height) || !IsPow2(depth))
610  throw new InvalidOperationException("Width/Height/Depth must be power of 2");
611 
612  int maxMips = CountMips(width, height, depth);
613  if (mipLevels > maxMips)
614  throw new InvalidOperationException(String.Format("MipLevels must be <= {0}", maxMips));
615  }
616  else if (mipLevels == 0)
617  {
618  if (!IsPow2(width) || !IsPow2(height) || !IsPow2(depth))
619  throw new InvalidOperationException("Width/Height/Depth must be power of 2");
620 
621  mipLevels = CountMips(width, height, depth);
622  }
623  else
624  {
625  mipLevels = 1;
626  }
627  return mipLevels;
628  }
629 
630  public static int CalculateMipSize(int width, int mipLevel)
631  {
632  mipLevel = Math.Min(mipLevel, CountMips(width));
633  width = width >> mipLevel;
634  return width > 0 ? width : 1;
635  }
636 
637  /// <summary>
638  /// Loads an image from the specified pointer.
639  /// </summary>
640  /// <param name="dataPointer">The data pointer.</param>
641  /// <param name="dataSize">Size of the data.</param>
642  /// <param name="makeACopy">if set to <c>true</c> [make A copy].</param>
643  /// <param name="handle">The handle.</param>
644  /// <returns></returns>
645  /// <exception cref="System.NotSupportedException"></exception>
646  private static Image Load(IntPtr dataPointer, int dataSize, bool makeACopy, GCHandle? handle)
647  {
648  foreach (var loadSaveDelegate in loadSaveDelegates)
649  {
650  if (loadSaveDelegate.Load != null)
651  {
652  var image = loadSaveDelegate.Load(dataPointer, dataSize, makeACopy, handle);
653  if (image != null)
654  {
655  return image;
656  }
657  }
658  }
659  throw new NotSupportedException("Image format not supported");
660  }
661 
662  /// <summary>
663  /// Saves this instance to a stream.
664  /// </summary>
665  /// <param name="pixelBuffers">The buffers to save.</param>
666  /// <param name="count">The number of buffers to save.</param>
667  /// <param name="description">Global description of the buffer.</param>
668  /// <param name="imageStream">The destination stream.</param>
669  /// <param name="fileType">Specify the output format.</param>
670  /// <remarks>This method support the following format: <c>dds, bmp, jpg, png, gif, tiff, wmp, tga</c>.</remarks>
671  internal static void Save(PixelBuffer[] pixelBuffers, int count, ImageDescription description, Stream imageStream, ImageFileType fileType)
672  {
673  foreach (var loadSaveDelegate in loadSaveDelegates)
674  {
675  if (loadSaveDelegate.FileType == fileType)
676  {
677  loadSaveDelegate.Save(pixelBuffers, count, description, imageStream);
678  return;
679  }
680 
681  }
682  throw new NotSupportedException("This file format is not yet implemented.");
683  }
684 
685  static Image()
686  {
687  Register(ImageFileType.Paradox, ImageHelper.LoadFromMemory, ImageHelper.SaveFromMemory);
688  Register(ImageFileType.Dds, DDSHelper.LoadFromDDSMemory, DDSHelper.SaveToDDSStream);
689  Register(ImageFileType.Gif, StandardImageHelper.LoadFromMemory, StandardImageHelper.SaveGifFromMemory);
690  Register(ImageFileType.Tiff,StandardImageHelper.LoadFromMemory, StandardImageHelper.SaveTiffFromMemory);
691  Register(ImageFileType.Bmp, StandardImageHelper.LoadFromMemory, StandardImageHelper.SaveBmpFromMemory);
692  Register(ImageFileType.Jpg, StandardImageHelper.LoadFromMemory, StandardImageHelper.SaveJpgFromMemory);
693  Register(ImageFileType.Png, StandardImageHelper.LoadFromMemory, StandardImageHelper.SavePngFromMemory);
694  Register(ImageFileType.Wmp, StandardImageHelper.LoadFromMemory, StandardImageHelper.SaveWmpFromMemory);
695  }
696 
697 
698  internal unsafe void Initialize(ImageDescription description, IntPtr dataPointer, int offset, GCHandle? handle, bool bufferIsDisposable, PitchFlags pitchFlags = PitchFlags.None, int rowStride = 0)
699  {
700  if (!description.Format.IsValid() || description.Format.IsVideo())
701  throw new InvalidOperationException("Unsupported DXGI Format");
702 
703  if (rowStride > 0 && description.MipLevels != 1)
704  throw new InvalidOperationException("Cannot specify custom stride with mipmaps");
705 
706 
707  this.handle = handle;
708 
709  switch (description.Dimension)
710  {
711  case TextureDimension.Texture1D:
712  if (description.Width <= 0 || description.Height != 1 || description.Depth != 1 || description.ArraySize == 0)
713  throw new InvalidOperationException("Invalid Width/Height/Depth/ArraySize for Image 1D");
714 
715  // Check that miplevels are fine
716  description.MipLevels = CalculateMipLevels(description.Width, 1, description.MipLevels);
717  break;
718 
719  case TextureDimension.Texture2D:
720  case TextureDimension.TextureCube:
721  if (description.Width <= 0 || description.Height <= 0 || description.Depth != 1 || description.ArraySize == 0)
722  throw new InvalidOperationException("Invalid Width/Height/Depth/ArraySize for Image 2D");
723 
724  if (description.Dimension == TextureDimension.TextureCube)
725  {
726  if ((description.ArraySize % 6) != 0)
727  throw new InvalidOperationException("TextureCube must have an arraysize = 6");
728  }
729 
730  // Check that miplevels are fine
731  description.MipLevels = CalculateMipLevels(description.Width, description.Height, description.MipLevels);
732  break;
733 
734  case TextureDimension.Texture3D:
735  if (description.Width <= 0 || description.Height <= 0 || description.Depth <= 0 || description.ArraySize != 1)
736  throw new InvalidOperationException("Invalid Width/Height/Depth/ArraySize for Image 3D");
737 
738  // Check that miplevels are fine
739  description.MipLevels = CalculateMipLevels(description.Width, description.Height, description.Depth, description.MipLevels);
740  break;
741  }
742 
743  // Calculate mipmaps
744  int pixelBufferCount;
745  this.mipMapToZIndex = CalculateImageArray(description, pitchFlags, rowStride, out pixelBufferCount, out totalSizeInBytes);
746  this.mipmapDescriptions = CalculateMipMapDescription(description, pitchFlags);
747  zBufferCountPerArraySlice = this.mipMapToZIndex[this.mipMapToZIndex.Count - 1];
748 
749  // Allocate all pixel buffers
750  pixelBuffers = new PixelBuffer[pixelBufferCount];
751  pixelBufferArray = new PixelBufferArray(this);
752 
753  // Setup all pointers
754  // only release buffer that is not pinned and is asked to be disposed.
755  this.bufferIsDisposable = !handle.HasValue && bufferIsDisposable;
756  this.buffer = dataPointer;
757 
758  if (dataPointer == IntPtr.Zero)
759  {
760  buffer = Utilities.AllocateMemory(totalSizeInBytes);
761  offset = 0;
762  this.bufferIsDisposable = true;
763  }
764 
765  SetupImageArray((IntPtr)((byte*)buffer + offset), totalSizeInBytes, rowStride, description, pitchFlags, pixelBuffers);
766 
767  Description = description;
768 
769  // PreCompute databoxes
770  dataBoxArray = ComputeDataBox();
771  }
772 
773  private PixelBuffer GetPixelBufferUnsafe(int arrayIndex, int zIndex, int mipmap)
774  {
775  var depthIndex = this.mipMapToZIndex[mipmap];
776  var pixelBufferIndex = arrayIndex * this.zBufferCountPerArraySlice + depthIndex + zIndex;
777  return pixelBuffers[pixelBufferIndex];
778  }
779 
780  private static ImageDescription CreateDescription(TextureDimension dimension, int width, int height, int depth, MipMapCount mipMapCount, PixelFormat format, int arraySize)
781  {
782  return new ImageDescription()
783  {
784  Width = width,
785  Height = height,
786  Depth = depth,
787  ArraySize = arraySize,
788  Dimension = dimension,
789  Format = format,
790  MipLevels = mipMapCount,
791  };
792  }
793 
794  [Flags]
795  internal enum PitchFlags
796  {
797  None = 0x0, // Normal operation
798  LegacyDword = 0x1, // Assume pitch is DWORD aligned instead of BYTE aligned
799  Bpp24 = 0x10000, // Override with a legacy 24 bits-per-pixel format size
800  Bpp16 = 0x20000, // Override with a legacy 16 bits-per-pixel format size
801  Bpp8 = 0x40000, // Override with a legacy 8 bits-per-pixel format size
802  };
803 
804  internal static void ComputePitch(PixelFormat fmt, int width, int height, out int rowPitch, out int slicePitch, out int widthCount, out int heightCount, PitchFlags flags = PitchFlags.None)
805  {
806  widthCount = width;
807  heightCount = height;
808 
809  if (fmt.IsCompressed())
810  {
811  int minWidth = 1;
812  int minHeight = 1;
813  int bpb = 8;
814 
815  switch (fmt)
816  {
817  case PixelFormat.BC1_Typeless:
818  case PixelFormat.BC1_UNorm:
819  case PixelFormat.BC1_UNorm_SRgb:
820  case PixelFormat.BC4_Typeless:
821  case PixelFormat.BC4_UNorm:
822  case PixelFormat.BC4_SNorm:
823  case PixelFormat.ETC1:
824  bpb = 8;
825  break;
826  case PixelFormat.PVRTC_4bpp_RGB:
827  case PixelFormat.PVRTC_4bpp_RGBA:
828  case PixelFormat.PVRTC_II_4bpp:
829  minWidth = 8;
830  minHeight = 8;
831  break;
832  case PixelFormat.PVRTC_2bpp_RGBA:
833  case PixelFormat.PVRTC_II_2bpp:
834  minWidth = 16;
835  minHeight = 8;
836  bpb = 4;
837  break;
838  default:
839  bpb = 16;
840  break;
841  }
842 
843  widthCount = Math.Max(1, (Math.Max(minWidth, width) + 3)) / 4;
844  heightCount = Math.Max(1, (Math.Max(minHeight, height) + 3)) / 4;
845  rowPitch = widthCount*bpb;
846 
847  slicePitch = rowPitch*heightCount;
848  }
849  else if (fmt.IsPacked())
850  {
851  rowPitch = ((width + 1) >> 1) * 4;
852 
853  slicePitch = rowPitch * height;
854  }
855  else
856  {
857  int bpp;
858 
859  if ((flags & PitchFlags.Bpp24) != 0)
860  bpp = 24;
861  else if ((flags & PitchFlags.Bpp16) != 0)
862  bpp = 16;
863  else if ((flags & PitchFlags.Bpp8) != 0)
864  bpp = 8;
865  else
866  bpp = fmt.SizeInBits();
867 
868  if ((flags & PitchFlags.LegacyDword) != 0)
869  {
870  // Special computation for some incorrectly created DDS files based on
871  // legacy DirectDraw assumptions about pitch alignment
872  rowPitch = ((width * bpp + 31) / 32) * sizeof(int);
873  slicePitch = rowPitch * height;
874  }
875  else
876  {
877  rowPitch = (width * bpp + 7) / 8;
878  slicePitch = rowPitch * height;
879  }
880  }
881  }
882 
883  internal static MipMapDescription[] CalculateMipMapDescription(ImageDescription metadata, PitchFlags cpFlags = PitchFlags.None)
884  {
885  int nImages;
886  int pixelSize;
887  return CalculateMipMapDescription(metadata, cpFlags, out nImages, out pixelSize);
888  }
889 
890  internal static MipMapDescription[] CalculateMipMapDescription(ImageDescription metadata, PitchFlags cpFlags, out int nImages, out int pixelSize)
891  {
892  pixelSize = 0;
893  nImages = 0;
894 
895  int w = metadata.Width;
896  int h = metadata.Height;
897  int d = metadata.Depth;
898 
899  var mipmaps = new MipMapDescription[metadata.MipLevels];
900 
901  for (int level = 0; level < metadata.MipLevels; ++level)
902  {
903  int rowPitch, slicePitch;
904  int widthPacked;
905  int heightPacked;
906  ComputePitch(metadata.Format, w, h, out rowPitch, out slicePitch, out widthPacked, out heightPacked, PitchFlags.None);
907 
908  mipmaps[level] = new MipMapDescription(
909  w,
910  h,
911  d,
912  rowPitch,
913  slicePitch,
914  widthPacked,
915  heightPacked
916  );
917 
918  pixelSize += d * slicePitch;
919  nImages += d;
920 
921  if (h > 1)
922  h >>= 1;
923 
924  if (w > 1)
925  w >>= 1;
926 
927  if (d > 1)
928  d >>= 1;
929  }
930  return mipmaps;
931  }
932 
933  /// <summary>
934  /// Determines number of image array entries and pixel size.
935  /// </summary>
936  /// <param name="imageDesc">Description of the image to create.</param>
937  /// <param name="pitchFlags">Pitch flags.</param>
938  /// <param name="bufferCount">Output number of mipmap.</param>
939  /// <param name="pixelSizeInBytes">Output total size to allocate pixel buffers for all images.</param>
940  private static List<int> CalculateImageArray( ImageDescription imageDesc, PitchFlags pitchFlags, int rowStride, out int bufferCount, out int pixelSizeInBytes)
941  {
942  pixelSizeInBytes = 0;
943  bufferCount = 0;
944 
945  var mipmapToZIndex = new List<int>();
946 
947  for (int j = 0; j < imageDesc.ArraySize; j++)
948  {
949  int w = imageDesc.Width;
950  int h = imageDesc.Height;
951  int d = imageDesc.Depth;
952 
953  for (int i = 0; i < imageDesc.MipLevels; i++)
954  {
955  int rowPitch, slicePitch;
956  int widthPacked;
957  int heightPacked;
958  ComputePitch(imageDesc.Format, w, h, out rowPitch, out slicePitch, out widthPacked, out heightPacked, pitchFlags);
959 
960  if (rowStride > 0)
961  {
962  // Check that stride is ok
963  if (rowStride < rowPitch)
964  throw new InvalidOperationException(string.Format("Invalid stride [{0}]. Value can't be lower than actual stride [{1}]", rowStride, rowPitch));
965 
966  if (widthPacked != w || heightPacked != h)
967  throw new InvalidOperationException("Custom strides is not supported with packed PixelFormats");
968 
969  // Override row pitch
970  rowPitch = rowStride;
971 
972  // Recalculate slice pitch
973  slicePitch = rowStride * h;
974  }
975 
976  // Store the number of z-slicec per miplevels
977  if ( j == 0)
978  mipmapToZIndex.Add(bufferCount);
979 
980  // Keep a trace of indices for the 1st array size, for each mip levels
981  pixelSizeInBytes += d * slicePitch;
982  bufferCount += d;
983 
984  if (h > 1)
985  h >>= 1;
986 
987  if (w > 1)
988  w >>= 1;
989 
990  if (d > 1)
991  d >>= 1;
992  }
993 
994  // For the last mipmaps, store just the number of zbuffers in total
995  if (j == 0)
996  mipmapToZIndex.Add(bufferCount);
997  }
998  return mipmapToZIndex;
999  }
1000 
1001  /// <summary>
1002  /// Allocates PixelBuffers
1003  /// </summary>
1004  /// <param name="buffer"></param>
1005  /// <param name="pixelSize"></param>
1006  /// <param name="imageDesc"></param>
1007  /// <param name="pitchFlags"></param>
1008  /// <param name="output"></param>
1009  private static unsafe void SetupImageArray(IntPtr buffer, int pixelSize, int rowStride, ImageDescription imageDesc, PitchFlags pitchFlags, PixelBuffer[] output)
1010  {
1011  int index = 0;
1012  var pixels = (byte*)buffer;
1013  for (uint item = 0; item < imageDesc.ArraySize; ++item)
1014  {
1015  int w = imageDesc.Width;
1016  int h = imageDesc.Height;
1017  int d = imageDesc.Depth;
1018 
1019  for (uint level = 0; level < imageDesc.MipLevels; ++level)
1020  {
1021  int rowPitch, slicePitch;
1022  int widthPacked;
1023  int heightPacked;
1024  ComputePitch(imageDesc.Format, w, h, out rowPitch, out slicePitch, out widthPacked, out heightPacked, pitchFlags);
1025 
1026  if (rowStride > 0)
1027  {
1028  // Check that stride is ok
1029  if (rowStride < rowPitch)
1030  throw new InvalidOperationException(string.Format("Invalid stride [{0}]. Value can't be lower than actual stride [{1}]", rowStride, rowPitch));
1031 
1032  if (widthPacked != w || heightPacked != h)
1033  throw new InvalidOperationException("Custom strides is not supported with packed PixelFormats");
1034 
1035  // Override row pitch
1036  rowPitch = rowStride;
1037 
1038  // Recalculate slice pitch
1039  slicePitch = rowStride * h;
1040  }
1041 
1042  for (uint zSlice = 0; zSlice < d; ++zSlice)
1043  {
1044  // We use the same memory organization that Direct3D 11 needs for D3D11_SUBRESOURCE_DATA
1045  // with all slices of a given miplevel being continuous in memory
1046  output[index] = new PixelBuffer(w, h, imageDesc.Format, rowPitch, slicePitch, (IntPtr)pixels);
1047  ++index;
1048 
1049  pixels += slicePitch;
1050  }
1051 
1052  if (h > 1)
1053  h >>= 1;
1054 
1055  if (w > 1)
1056  w >>= 1;
1057 
1058  if (d > 1)
1059  d >>= 1;
1060  }
1061  }
1062  }
1063 
1064  private static bool IsPow2(int x)
1065  {
1066  return ((x != 0) && (x & (x - 1)) == 0);
1067  }
1068 
1069  public static int CountMips(int width)
1070  {
1071  int mipLevels = 1;
1072 
1073  while (width > 1)
1074  {
1075  ++mipLevels;
1076 
1077  if (width > 1)
1078  width >>= 1;
1079  }
1080 
1081  return mipLevels;
1082  }
1083 
1084  public static int CountMips(int width, int height)
1085  {
1086  int mipLevels = 1;
1087 
1088  while (height > 1 || width > 1)
1089  {
1090  ++mipLevels;
1091 
1092  if (height > 1)
1093  height >>= 1;
1094 
1095  if (width > 1)
1096  width >>= 1;
1097  }
1098 
1099  return mipLevels;
1100  }
1101 
1102  public static int CountMips(int width, int height, int depth)
1103  {
1104  int mipLevels = 1;
1105 
1106  while (height > 1 || width > 1 || depth > 1)
1107  {
1108  ++mipLevels;
1109 
1110  if (height > 1)
1111  height >>= 1;
1112 
1113  if (width > 1)
1114  width >>= 1;
1115 
1116  if (depth > 1)
1117  depth >>= 1;
1118  }
1119 
1120  return mipLevels;
1121  }
1122 
1123  private class LoadSaveDelegate
1124  {
1125  public LoadSaveDelegate(ImageFileType fileType, ImageLoadDelegate load, ImageSaveDelegate save)
1126  {
1127  FileType = fileType;
1128  Load = load;
1129  Save = save;
1130  }
1131 
1132  public ImageFileType FileType;
1133 
1134  public ImageLoadDelegate Load;
1135 
1136  public ImageSaveDelegate Save;
1137  }
1138  }
1139 }
static Image New3D(int width, int height, int depth, MipMapCount mipMapCount, PixelFormat format, IntPtr dataPointer)
Creates a new instance of a 3D Image.
Definition: Image.cs:465
static Image New2D(int width, int height, MipMapCount mipMapCount, PixelFormat format, int arraySize, IntPtr dataPointer, int rowStride=0)
Creates a new instance of a 2D Image.
Definition: Image.cs:437
_In_ size_t _In_ const TexMetadata _In_ DWORD cpFlags
Definition: DirectXTexP.h:116
void Save(Stream imageStream, ImageFileType fileType)
Saves this instance to a stream.
Definition: Image.cs:540
static int CalculateMipSize(int width, int mipLevel)
Definition: Image.cs:630
ImageFileType
Image file format used by Image.Save(string,SiliconStudio.Paradox.Graphics.ImageFileType) ...
A simple wrapper to specify number of mipmaps. Set to true to specify all mipmaps or sets an integer ...
Definition: MipMapCount.cs:43
static Image Load(DataPointer dataBuffer, bool makeACopy=false)
Loads an image from an unmanaged memory pointer.
Definition: Image.cs:477
_In_ size_t _In_ const TexMetadata _In_ DWORD _In_ size_t nImages
Definition: DirectXTexP.h:118
PixelBuffer GetPixelBuffer(int arrayOrZSliceIndex, int mipmap)
Gets the pixel buffer for the specified array/z slice and mipmap level.
Definition: Image.cs:187
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ DXGI_FORMAT _In_ DWORD flags
Definition: DirectXTexP.h:170
static int CountMips(int width)
Definition: Image.cs:1069
static int CalculateMipLevels(int width, int height, MipMapCount mipLevels)
Calculates the number of miplevels for a Texture 2D.
Definition: Image.cs:578
Provides method to instantiate an image 1D/2D/3D supporting TextureArray and mipmaps on the CPU or to...
Definition: Image.cs:88
static Image Load(Stream imageStream)
Loads the specified image from a stream.
Definition: Image.cs:527
static Image New1D(int width, MipMapCount mipMapCount, PixelFormat format, int arraySize=1)
Creates a new instance of a 1D Image.
Definition: Image.cs:342
_In_ size_t pixelSize
Definition: DirectXTexP.h:116
ImageDescription Description
Description of this image.
Definition: Image.cs:137
static Image New3D(int width, int height, int depth, MipMapCount mipMapCount, PixelFormat format)
Creates a new instance of a 3D Image.
Definition: Image.cs:382
TextureDimension
Defines the dimension of a texture.
Flags
Enumeration of the new Assimp's flags.
_In_ size_t _In_ const TexMetadata & metadata
Definition: DirectXTexP.h:116
_In_ size_t count
Definition: DirectXTexP.h:174
void ComputePitch(_In_ DXGI_FORMAT fmt, _In_ size_t width, _In_ size_t height, _Out_ size_t &rowPitch, _Out_ size_t &slicePitch, _In_ DWORD flags=CP_FLAGS_NONE)
static byte[] ReadStream(Stream stream)
Read stream to a byte[] buffer
Definition: Utilities.cs:485
static int CalculateMipLevels(int width, MipMapCount mipLevels)
Calculates the number of miplevels for a Texture 1D.
Definition: Image.cs:552
static Image Load(IntPtr dataPointer, int dataSize, bool makeACopy=false)
Loads an image from an unmanaged memory pointer.
Definition: Image.cs:490
static int CountMips(int width, int height)
Definition: Image.cs:1084
static int CountMips(int width, int height, int depth)
Definition: Image.cs:1102
Used by Image to provide a selector to a PixelBuffer.
An unmanaged buffer of pixels.
Definition: PixelBuffer.cs:32
static Image New1D(int width, MipMapCount mipMapCount, PixelFormat format, int arraySize, IntPtr dataPointer)
Creates a new instance of a 1D Image.
Definition: Image.cs:421
DataBox[] ToDataBox()
Gets the databox from this image.
Definition: Image.cs:295
static Image New(ImageDescription description, IntPtr dataPointer)
Creates a new instance of Image from an image description.
Definition: Image.cs:393
static unsafe Image Load(byte[] buffer)
Loads an image from a managed buffer.
Definition: Image.cs:501
static int CalculateMipLevels(int width, int height, int depth, MipMapCount mipLevels)
Calculates the number of miplevels for a Texture 2D.
Definition: Image.cs:605
PixelBuffer GetPixelBuffer(int arrayIndex, int zIndex, int mipmap)
Gets the pixel buffer for the specified array/z slice and mipmap level.
Definition: Image.cs:219
MipMapDescription GetMipMapDescription(int mipmap)
Gets the mipmap description of this instance for the specified mipmap level.
Definition: Image.cs:175
Provides access to data organized in 3D.
Definition: DataBox.cs:12
static void Register(ImageFileType type, ImageLoadDelegate loader, ImageSaveDelegate saver)
Registers a loader/saver for a specified image file type.
Definition: Image.cs:242
_In_ size_t _In_ size_t _In_ DXGI_FORMAT format
Definition: DirectXTexP.h:175
static Image New2D(int width, int height, MipMapCount mipMapCount, PixelFormat format, int arraySize=1, int rowStride=0)
Creates a new instance of a 2D Image.
Definition: Image.cs:356
_In_ size_t _In_ size_t size
Definition: DirectXTexP.h:175
PixelFormat
Defines various types of pixel formats.
Definition: PixelFormat.cs:32
static Image New(ImageDescription description)
Creates a new instance of Image from an image description.
Definition: Image.cs:329
static Image New(ImageDescription description, IntPtr dataPointer, int offset, GCHandle?handle, bool bufferIsDisposable)
Initializes a new instance of the Image class.
Definition: Image.cs:407
static Image NewCube(int width, MipMapCount mipMapCount, PixelFormat format, IntPtr dataPointer)
Creates a new instance of a Cube Image.
Definition: Image.cs:450
static Image NewCube(int width, MipMapCount mipMapCount, PixelFormat format)
Creates a new instance of a Cube Image.
Definition: Image.cs:368