Visualization Library 2.0.0

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

[Download] [Tutorials] [All Classes] [Grouped Classes]
ioDDS.cpp
Go to the documentation of this file.
1 /**************************************************************************************/
2 /* */
3 /* Visualization Library */
4 /* http://visualizationlibrary.org */
5 /* */
6 /* Copyright (c) 2005-2020, Michele Bosi */
7 /* All rights reserved. */
8 /* */
9 /* Redistribution and use in source and binary forms, with or without modification, */
10 /* are permitted provided that the following conditions are met: */
11 /* */
12 /* - Redistributions of source code must retain the above copyright notice, this */
13 /* list of conditions and the following disclaimer. */
14 /* */
15 /* - Redistributions in binary form must reproduce the above copyright notice, this */
16 /* list of conditions and the following disclaimer in the documentation and/or */
17 /* other materials provided with the distribution. */
18 /* */
19 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */
20 /* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
21 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
22 /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */
23 /* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
24 /* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
25 /* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
26 /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
27 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
28 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
29 /* */
30 /**************************************************************************************/
31 
32 #include "ioDDS.hpp"
36 #include <vlCore/FileSystem.hpp>
37 #include <vlCore/VirtualFile.hpp>
38 #include <vlCore/Image.hpp>
39 
40 // mic fixme:
41 // http://msdn.microsoft.com/en-us/library/bb943991(v=vs.85).aspx#dds_variants
42 // - read and write float and half float images.
43 // - support directx 10 dds and formats
44 // - support A8R8G8B8, A1R5G5B5, A4R4G4B4, R8G8B8, R5G6B5
45 
46 using namespace vl;
47 
48 #include <vlCore/ImageTools.hpp>
49 
50 //-----------------------------------------------------------------------------
51 // DDS loader
52 //-----------------------------------------------------------------------------
53 namespace
54 {
55  // DDSURFACEDESC2.dwFlags
56  const unsigned long DDS_CAPS = 0x00000001;
57  const unsigned long DDS_HEIGHT = 0x00000002;
58  const unsigned long DDS_WIDTH = 0x00000004;
59  const unsigned long DDS_PITCH = 0x00000008;
60  const unsigned long DDS_BACKBUFFERCOUNT = 0x00000020;
61  const unsigned long DDS_ZBUFFERBITDEPTH = 0x00000040;
62  const unsigned long DDS_ALPHABITDEPTH = 0x00000080;
63  const unsigned long DDS_LPSURFACE = 0x00000800;
64  const unsigned long DDS_PIXELFORMAT = 0x00001000;
65  const unsigned long DDS_CKDESTOVERLAY = 0x00002000;
66  const unsigned long DDS_CKDESTBLT = 0x00004000;
67  const unsigned long DDS_CKSRCOVERLAY = 0x00008000;
68  const unsigned long DDS_CKSRCBLT = 0x00010000;
69  const unsigned long DDS_MIPMAPCOUNT = 0x00020000;
70  const unsigned long DDS_REFRESHRATE = 0x00040000;
71  const unsigned long DDS_LINEARSIZE = 0x00080000;
72  const unsigned long DDS_TEXTURESTAGE = 0x00100000;
73  const unsigned long DDS_FVF = 0x00200000;
74  const unsigned long DDS_SRCVBHANDLE = 0x00400000;
75  const unsigned long DDS_DEPTH = 0x00800000;
76  const unsigned long DDS_ALL = 0x007FF9EE;
77  const unsigned long DDS_REQUIRED_FLAGS = DDS_CAPS|DDS_PIXELFORMAT|DDS_WIDTH|DDS_HEIGHT;
78 
79  // DDPIXELFORMAT.dwFlags
80  const unsigned long DDPF_ALPHAPIXELS = 0x00000001; // there is an alpha channel
81  const unsigned long DDPF_ALPHA = 0x00000002; // the image is an alpha channel only image
82  const unsigned long DDPF_FOURCC = 0x00000004; // the foucc code defines the pixel format
83  const unsigned long DDPF_INDEXED4 = 0x00000008;
84  const unsigned long DDPF_INDEXEDTO8 = 0x00000010;
85  const unsigned long DDPF_INDEXED8 = 0x00000020;
86  const unsigned long DDPF_RGB = 0x00000040; // RGB, no fourcc
87  const unsigned long DDPF_RGBA = 0x00000041; // DDPF_RGB | DDPF_ALPHAPIXELS
88  const unsigned long DDPF_COMPRESSED = 0x00000080; // It's a compressed format
89  const unsigned long DDPF_RGBTOYUV = 0x00000100;
90  const unsigned long DDPF_YUV = 0x00000200;
91  const unsigned long DDPF_ZBUFFER = 0x00000400;
92  const unsigned long DDPF_PALETTEINDEXED1 = 0x00000800;
93  const unsigned long DDPF_PALETTEINDEXED2 = 0x00001000;
94  const unsigned long DDPF_ZPIXELS = 0x00002000;
95  const unsigned long DDPF_STENCILBUFFER = 0x00004000;
96  const unsigned long DDPF_ALPHAPREMULT = 0x00008000;
97  const unsigned long DDPF_LUMINANCE = 0x00020000; // Is a luminance image
98  const unsigned long DDPF_BUMPLUMINANCE = 0x00040000;
99  const unsigned long DDPF_BUMPDUDV = 0x00080000;
100 
101  // DDSCAPS2.dwCaps1
102  const unsigned long DDSCAPS_COMPLEX = 0x00000008; // Whenever is cubemap or volume
103  const unsigned long DDSCAPS_TEXTURE = 0x00001000; // Always present
104  const unsigned long DDSCAPS_MIPMAP = 0x00400000; // It's a mipmap image
105 
106  // DDSCAPS2.dwCaps2
107  const unsigned long DDSCAPS2_VOLUME = 0x00200000; // It's a 3D texture
108  const unsigned long DDSCAPS2_CUBEMAP = 0x00000200; // It's a cubemap
109  const unsigned long DDSCAPS2_CUBEMAP_POSITIVEX = 0x00000400;
110  const unsigned long DDSCAPS2_CUBEMAP_NEGATIVEX = 0x00000800;
111  const unsigned long DDSCAPS2_CUBEMAP_POSITIVEY = 0x00001000;
112  const unsigned long DDSCAPS2_CUBEMAP_NEGATIVEY = 0x00002000;
113  const unsigned long DDSCAPS2_CUBEMAP_POSITIVEZ = 0x00004000;
114  const unsigned long DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x00008000;
115  const unsigned long DDSCAPS2_CUBEMAP_FACES = DDSCAPS2_CUBEMAP_POSITIVEX | DDSCAPS2_CUBEMAP_NEGATIVEX |
116  DDSCAPS2_CUBEMAP_POSITIVEY | DDSCAPS2_CUBEMAP_NEGATIVEY |
117  DDSCAPS2_CUBEMAP_POSITIVEZ | DDSCAPS2_CUBEMAP_NEGATIVEZ ;
118 
119  inline unsigned int makeFourCC(unsigned int ch0, unsigned int ch1, unsigned int ch2, unsigned int ch3)
120  {
121  return ch0 | (ch1 << 8) | ( ch2 << 16) | ( ch3 << 24 );
122  }
123 
124  inline bool isFourCC(const char* code, unsigned int fcc)
125  {
126  return makeFourCC(code[0], code[1], code[2], code[3]) == fcc;
127  }
128 
129  // quick surface type macros
130 
131  #define IS_BGRA8(pf) \
132  ((pf.dwFlags & DDPF_RGB) && \
133  (pf.dwFlags & DDPF_ALPHAPIXELS) && \
134  (pf.dwRGBBitCount == 32))
135 
136  #define IS_BGRX8(pf) \
137  ((pf.dwFlags & DDPF_RGB) && \
138  !(pf.dwFlags & DDPF_ALPHAPIXELS) && \
139  (pf.dwRGBBitCount == 32))
140 
141  #define IS_BGR8(pf) \
142  ((pf.dwFlags & DDPF_RGB) && \
143  !(pf.dwFlags & DDPF_ALPHAPIXELS) && \
144  (pf.dwRGBBitCount == 24))
145 
146  #define IS_GRAY8(pf) \
147  ((((pf.dwFlags & DDPF_LUMINANCE) || (pf.dwFlags & DDPF_ALPHA) ) && \
148  (pf.dwRGBBitCount == 8) && !(pf.dwFlags & DDPF_ALPHAPIXELS) ) || \
149  isFourCC("G8 ", pf.dwFourCC ) )
150 
151  #define IS_GRAY8_ALPHA8(pf) \
152  (((pf.dwFlags & DDPF_LUMINANCE) && \
153  (pf.dwRGBBitCount == 16) && (pf.dwFlags & DDPF_ALPHAPIXELS)) || \
154  isFourCC("AG8 ", pf.dwFourCC ) )
155 
156  #define IS_PALETTE8(pf) isFourCC("P8 ", pf.dwFourCC)
157 
158  #define IS_DXT1(pf) isFourCC("DXT1", pf.dwFourCC)
159 
160  #define IS_DXT3(pf) isFourCC("DXT3", pf.dwFourCC)
161 
162  #define IS_DXT5(pf) isFourCC("DXT5", pf.dwFourCC)
163 
164  typedef struct
165  {
166  unsigned int dwSize;
167  unsigned int dwFlags;
168  unsigned int dwHeight;
169  unsigned int dwWidth;
170  unsigned int dwPitchOrLinearSize;
171  unsigned int dwDepth;
172  unsigned int dwMipMapCount;
173  unsigned int dwReserved1[ 11 ];
174 
175  // DDPIXELFORMAT
176  struct
177  {
178  unsigned int dwSize;
179  unsigned int dwFlags;
180  unsigned int dwFourCC;
181  unsigned int dwRGBBitCount;
182  unsigned int dwRBitMask;
183  unsigned int dwGBitMask;
184  unsigned int dwBBitMask;
185  unsigned int dwAlphaBitMask;
186  } ddpfPixelFormat;
187 
188  // DDCAPS2
189  struct
190  {
191  unsigned int dwCaps1;
192  unsigned int dwCaps2;
193  unsigned int dwReserved[2];
194  } ddsCaps;
195 
196  unsigned int dwReserved2;
197 
198  } DDSURFACEDESC2;
199 
200  enum
201  {
202  DDS_IMAGE_NULL = 0,
203  DDS_IMAGE_2D = 2,
204  DDS_IMAGE_3D = 3,
205  DDS_IMAGE_CUBEMAP = 4
206  };
207 }
208 //-----------------------------------------------------------------------------
229 {
230  ref<VirtualFile> file = defFileSystem()->locateFile(path);
231  if ( !file )
232  {
233  Log::error( Say("File '%s' not found.\n") << path );
234  return NULL;
235  }
236 
237  return loadDDS(file.get());
238 }
239 
240 VL_COMPILE_TIME_CHECK( sizeof(DDSURFACEDESC2) == 124 );
241 
243 {
244  if ( !file->open(OM_ReadOnly) )
245  {
246  Log::error( Say("DDS: could not open file '%s'.\n") << file->path() );
247  return NULL;
248  }
249 
250  char signature[4];
251  file->read(signature,4);
252  if (strncmp(signature, "DDS ", 4) != 0)
253  {
254  file->close();
255  Log::error( Say("DDS: '%s' is not a DDS file.\n") << file->path() );
256  return NULL;
257  }
258 
259  DDSURFACEDESC2 header;
260  memset(&header, 0, sizeof(header));
261 
262  file->read(&header, sizeof(header));
263 
264  if (header.dwSize != 124 || header.ddpfPixelFormat.dwSize != 32)
265  {
266  Log::error( Say("DDS file '%s': corrupted header.\n") << file->path() );
267  file->close();
268  return NULL;
269  }
270 
271  if ((header.dwFlags & DDS_REQUIRED_FLAGS) != DDS_REQUIRED_FLAGS )
272  Log::warning( Say("DDS file '%s': missing DDS_REQUIRED_FLAGS flags.\n") << file->path() );
273 
274  if ((header.ddsCaps.dwCaps1 & DDSCAPS_TEXTURE) != DDSCAPS_TEXTURE)
275  Log::warning( Say("DDS file '%s': missing DDSCAPS_TEXTURE flag.\n") << file->path() );
276 
277  int image_type = header.dwDepth ? DDS_IMAGE_3D : DDS_IMAGE_2D;
278 
279  if (header.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
280  {
281  bool allfaces = (header.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_FACES) != DDSCAPS2_CUBEMAP_FACES;
282 
283  if (!allfaces)
284  {
285  Log::error( Say("DDS: '%s' contains an invalid cubemap.\n") << file->path() );
286  file->close();
287  return NULL;
288  }
289  else
290  image_type = DDS_IMAGE_CUBEMAP;
291  }
292 
293  bool reverse_rgba_bgra = false;
294  if (header.ddpfPixelFormat.dwRBitMask != 0xFF)
295  reverse_rgba_bgra = true;
296 
297  // loosen alpha mask checks
298 
299  // int width = header.dwWidth;
300  // int height = header.dwHeight;
301  // int depth = (header.dwFlags & DDS_DEPTH) ? header.dwDepth : 0;
302  int mipmaps = (header.dwFlags & DDS_MIPMAPCOUNT) ? header.dwMipMapCount : 1; // implies DDSCAPS_MIPMAP | DDSCAPS_COMPLEX
303  int hasalpha = header.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS;
304 
305  // int pitch = (header.dwFlags & DDS_PITCH) ? header.dwPitchOrLinearSize : 0;
306  // int linearsize = (header.dwFlags & DDS_LINEARSIZE) ? header.dwPitchOrLinearSize : 0;
307  // int luminance = header.ddpfPixelFormat.dwFlags & DDPF_LUMINANCE;
308  // int fourcc = (header.ddpfPixelFormat.dwFlags & DDPF_FOURCC) ? header.ddpfPixelFormat.dwFourCC : 0;
309  // int indexed4 = header.ddpfPixelFormat.dwFlags & DDPF_INDEXED4;
310  // int indexed8 = header.ddpfPixelFormat.dwFlags & DDPF_INDEXED8;
311  // int indexedto8 = header.ddpfPixelFormat.dwFlags & DDPF_INDEXEDTO8;
312  // int fcc = header.ddpfPixelFormat.dwFlags & DDPF_FOURCC;
313  int rgb = header.ddpfPixelFormat.dwFlags & DDPF_RGB;
314  // int alpha = header.ddpfPixelFormat.dwFlags & DDPF_ALPHA;
315  int bitcount = header.ddpfPixelFormat.dwRGBBitCount;
316 
317  if (rgb && bitcount == 8)
318  {
319  Log::warning( Say("%s: corrupted DDS format! will try to recover...\n") << file->path() );
320  header.ddpfPixelFormat.dwFlags &= ~DDPF_RGB;
321  header.ddpfPixelFormat.dwFlags |= DDPF_LUMINANCE;
322  }
323 
324  int max_face = 1;
325  if (image_type == DDS_IMAGE_CUBEMAP)
326  max_face = 6;
327 
328  std::vector< ref<Image> > image;
329  for(int i=0; i<mipmaps; ++i)
330  {
331  image.push_back( new Image );
332  image.back()->setObjectName(file->path().toStdString().c_str());
333  }
334 
335  if (IS_BGRA8(header.ddpfPixelFormat) || IS_BGRX8(header.ddpfPixelFormat))
336  {
337  for(int i=0, w = header.dwWidth, h = header.dwHeight, d = header.dwDepth; i<mipmaps; ++i, w/=2, h/=2, d/=2)
338  {
339  w = w == 0 ? 1 : w;
340  h = h == 0 ? 1 : h;
341  d = d == 0 ? 1 : d;
342 
343  if (image_type == DDS_IMAGE_2D)
344  image[i]->allocate2D(w, h, 1, IF_RGBA, IT_UNSIGNED_BYTE);
345  else
346  if (image_type == DDS_IMAGE_CUBEMAP)
347  image[i]->allocateCubemap(w, h, 1, IF_RGBA, IT_UNSIGNED_BYTE);
348  else
349  if (image_type == DDS_IMAGE_3D)
350  image[i]->allocate3D(w, h, d, 1, IF_RGBA, IT_UNSIGNED_BYTE);
351  }
352 
353  for(int face=0; face<max_face; ++face)
354  {
355  for(int i=0, w = header.dwWidth, h = header.dwHeight, d = header.dwDepth; i<mipmaps; ++i, w/=2, h/=2, d/=2)
356  {
357  w = w == 0 ? 1 : w;
358  h = h == 0 ? 1 : h;
359  d = d == 0 ? 1 : d;
360 
361  int req_mem = Image::requiredMemory( w, h, d, 1, IF_RGBA, IT_UNSIGNED_BYTE, false );
362  int offset = req_mem * face;
363  file->read(image[i]->pixels() + offset, req_mem);
364 
365  if(reverse_rgba_bgra)
366  swapBytes32_BGRA_RGBA(image[i]->pixels() + offset, req_mem);
367 
368  if (IS_BGRX8(header.ddpfPixelFormat))
369  fillRGBA32_Alpha(image[i]->pixels() + offset, req_mem, 0xFF);
370  }
371  }
372  }
373  else
374  if (IS_BGR8(header.ddpfPixelFormat))
375  {
376  for(int i=0, w = header.dwWidth, h = header.dwHeight, d = header.dwDepth; i<mipmaps; ++i, w/=2, h/=2, d/=2)
377  {
378  w = w == 0 ? 1 : w;
379  h = h == 0 ? 1 : h;
380  d = d == 0 ? 1 : d;
381 
382  if (image_type == DDS_IMAGE_2D)
383  image[i]->allocate2D(w, h, 1, IF_RGB, IT_UNSIGNED_BYTE);
384  else
385  if (image_type == DDS_IMAGE_CUBEMAP)
386  image[i]->allocateCubemap(w, h, 1, IF_RGB, IT_UNSIGNED_BYTE);
387  else
388  if (image_type == DDS_IMAGE_3D)
389  image[i]->allocate3D(w, h, d, 1, IF_RGB, IT_UNSIGNED_BYTE);
390  }
391 
392  for(int face=0; face<max_face; ++face)
393  {
394  for(int i=0, w = header.dwWidth, h = header.dwHeight, d = header.dwDepth; i<mipmaps; ++i, w/=2, h/=2, d/=2)
395  {
396  w = w == 0 ? 1 : w;
397  h = h == 0 ? 1 : h;
398  d = d == 0 ? 1 : d;
399 
400  int req_mem = Image::requiredMemory( w, h, d, 1, IF_RGB, IT_UNSIGNED_BYTE, false );
401  int offset = req_mem * face;
402  file->read(image[i]->pixels() + offset, req_mem);
403 
404  if(reverse_rgba_bgra)
405  swapBytes24_BGR_RGB(image[i]->pixels() + offset, req_mem);
406  }
407  }
408  }
409  else
410  if (IS_GRAY8(header.ddpfPixelFormat))
411  {
412  for(int i=0, w = header.dwWidth, h = header.dwHeight, d = header.dwDepth; i<mipmaps; ++i, w/=2, h/=2, d/=2)
413  {
414  w = w == 0 ? 1 : w;
415  h = h == 0 ? 1 : h;
416  d = d == 0 ? 1 : d;
417 
418  if (image_type == DDS_IMAGE_2D)
419  image[i]->allocate2D(w, h, 1, IF_LUMINANCE, IT_UNSIGNED_BYTE);
420  else
421  if (image_type == DDS_IMAGE_CUBEMAP)
422  image[i]->allocateCubemap(w, h, 1, IF_LUMINANCE, IT_UNSIGNED_BYTE);
423  else
424  if (image_type == DDS_IMAGE_3D)
425  image[i]->allocate3D(w, h, d, 1, IF_LUMINANCE, IT_UNSIGNED_BYTE);
426  }
427 
428  for(int face=0; face<max_face; ++face)
429  {
430  for(int i=0, w = header.dwWidth, h = header.dwHeight, d = header.dwDepth; i<mipmaps; ++i, w/=2, h/=2, d/=2)
431  {
432  w = w == 0 ? 1 : w;
433  h = h == 0 ? 1 : h;
434  d = d == 0 ? 1 : d;
435 
436  int req_mem = Image::requiredMemory( w, h, d, 1, IF_LUMINANCE, IT_UNSIGNED_BYTE, false );
437  int offset = req_mem*face;
438  file->read(image[i]->pixels() + offset, req_mem);
439  }
440  }
441  }
442  else
443  if (IS_GRAY8_ALPHA8(header.ddpfPixelFormat))
444  {
445  for(int i=0, w = header.dwWidth, h = header.dwHeight, d = header.dwDepth; i<mipmaps; ++i, w/=2, h/=2, d/=2)
446  {
447  w = w == 0 ? 1 : w;
448  h = h == 0 ? 1 : h;
449  d = d == 0 ? 1 : d;
450 
451  if (image_type == DDS_IMAGE_2D)
452  image[i]->allocate2D(w, h, 1, IF_LUMINANCE_ALPHA, IT_UNSIGNED_BYTE);
453  else
454  if (image_type == DDS_IMAGE_CUBEMAP)
455  image[i]->allocateCubemap(w, h, 1, IF_LUMINANCE_ALPHA, IT_UNSIGNED_BYTE);
456  else
457  if (image_type == DDS_IMAGE_3D)
458  image[i]->allocate3D(w, h, d, 1, IF_LUMINANCE_ALPHA, IT_UNSIGNED_BYTE);
459  }
460 
461  for(int face=0; face<max_face; ++face)
462  {
463  for(int i=0, w = header.dwWidth, h = header.dwHeight, d = header.dwDepth; i<mipmaps; ++i, w/=2, h/=2, d/=2)
464  {
465  w = w == 0 ? 1 : w;
466  h = h == 0 ? 1 : h;
467  d = d == 0 ? 1 : d;
468 
469  int req_mem = Image::requiredMemory( w, h, d, 1, IF_LUMINANCE_ALPHA, IT_UNSIGNED_BYTE, false );
470  int offset = req_mem*face;
471  file->read(image[i]->pixels() + offset, req_mem);
472 
473  if (!hasalpha)
474  fillGray8Alpha8_Alpha(image[i]->pixels() + offset, req_mem, 0xFF);
475  }
476  }
477  }
478  else
479  if (IS_PALETTE8(header.ddpfPixelFormat))
480  {
481  for(int i=0, w = header.dwWidth, h = header.dwHeight, d = header.dwDepth; i<mipmaps; ++i, w/=2, h/=2, d/=2)
482  {
483  w = w == 0 ? 1 : w;
484  h = h == 0 ? 1 : h;
485  d = d == 0 ? 1 : d;
486 
487  if (image_type == DDS_IMAGE_2D)
488  image[i]->allocate2D(w, h, 1, IF_RGBA, IT_UNSIGNED_BYTE);
489  else
490  if (image_type == DDS_IMAGE_CUBEMAP)
491  image[i]->allocateCubemap(w, h, 1, IF_RGBA, IT_UNSIGNED_BYTE);
492  else
493  if (image_type == DDS_IMAGE_3D)
494  image[i]->allocate3D(w, h, d, 1, IF_RGBA, IT_UNSIGNED_BYTE);
495  }
496 
497  for(int face=0; face<max_face; ++face)
498  {
499  TPalette4x256 palette;
500  file->read( palette, sizeof(TPalette4x256) );
501  for(int i=0, w = header.dwWidth, h = header.dwHeight, d = header.dwDepth; i<mipmaps; ++i, w/=2, h/=2, d/=2)
502  {
503  w = w == 0 ? 1 : w;
504  h = h == 0 ? 1 : h;
505  d = d == 0 ? 1 : d;
506 
507  int req_mem1 = w*h*d*1;
508  int req_mem4 = w*h*d*4;
509  int offset = req_mem4*face;
510  // read the palette first
511  file->read( image[i]->pixels() + offset, req_mem1 );
512  convert8ToRGBA( palette, image[i]->pixels() + offset, w, h * d );
513  swapBytes32_BGRA_RGBA(image[i]->pixels() + offset, req_mem4);
514  if (!hasalpha)
515  fillRGBA32_Alpha(image[i]->pixels() + offset, req_mem4, 0xFF);
516  }
517  }
518  }
519  else
520  if ( IS_DXT1(header.ddpfPixelFormat) )
521  {
523 
524  for(int i=0, w = header.dwWidth, h = header.dwHeight, d = header.dwDepth; i<mipmaps; ++i, w/=2, h/=2, d/=2)
525  {
526  w = w == 0 ? 1 : w;
527  h = h == 0 ? 1 : h;
528  d = d == 0 ? 1 : d;
529 
530  if (image_type == DDS_IMAGE_2D)
531  image[i]->allocate2D(w, h, 1, DXT1, IT_IMPLICIT_TYPE);
532  else
533  if (image_type == DDS_IMAGE_CUBEMAP)
534  image[i]->allocateCubemap(w, h, 1, DXT1, IT_IMPLICIT_TYPE);
535  else
536  if (image_type == DDS_IMAGE_3D)
537  image[i]->allocate3D(w, h, d, 1, DXT1, IT_IMPLICIT_TYPE);
538  }
539 
540  for(int face=0; face<max_face; ++face)
541  {
542  for(int i=0, w = header.dwWidth, h = header.dwHeight, d = header.dwDepth; i<mipmaps; ++i, w/=2, h/=2, d/=2)
543  {
544  w = w == 0 ? 1 : w;
545  h = h == 0 ? 1 : h;
546  d = d == 0 ? 1 : d;
547 
548  int req_mem = Image::requiredMemory( w, h, d, 1, DXT1, IT_IMPLICIT_TYPE, false );
549  int offset = req_mem*face;
550  file->read(image[i]->pixels() + offset, req_mem);
551  }
552  }
553  }
554  else
555  if ( IS_DXT3(header.ddpfPixelFormat) )
556  {
557  for(int i=0, w = header.dwWidth, h = header.dwHeight, d = header.dwDepth; i<mipmaps; ++i, w/=2, h/=2, d/=2)
558  {
559  w = w == 0 ? 1 : w;
560  h = h == 0 ? 1 : h;
561  d = d == 0 ? 1 : d;
562 
563  if (image_type == DDS_IMAGE_2D)
564  image[i]->allocate2D(w, h, 1, IF_COMPRESSED_RGBA_S3TC_DXT3, IT_IMPLICIT_TYPE);
565  else
566  if (image_type == DDS_IMAGE_CUBEMAP)
567  image[i]->allocateCubemap(w, h, 1, IF_COMPRESSED_RGBA_S3TC_DXT3, IT_IMPLICIT_TYPE);
568  else
569  if (image_type == DDS_IMAGE_3D)
570  image[i]->allocate3D(w, h, d, 1, IF_COMPRESSED_RGBA_S3TC_DXT3, IT_IMPLICIT_TYPE);
571  }
572 
573  for(int face=0; face<max_face; ++face)
574  {
575  for(int i=0, w = header.dwWidth, h = header.dwHeight, d = header.dwDepth; i<mipmaps; ++i, w/=2, h/=2, d/=2)
576  {
577  w = w == 0 ? 1 : w;
578  h = h == 0 ? 1 : h;
579  d = d == 0 ? 1 : d;
580 
581  int req_mem = Image::requiredMemory( w, h, d, 1, IF_COMPRESSED_RGBA_S3TC_DXT3, IT_IMPLICIT_TYPE, false );
582  int offset = req_mem*face;
583  file->read(image[i]->pixels() + offset, req_mem);
584  }
585  }
586  }
587  else
588  if ( IS_DXT5(header.ddpfPixelFormat) )
589  {
590  for(int i=0, w = header.dwWidth, h = header.dwHeight, d = header.dwDepth; i<mipmaps; ++i, w/=2, h/=2, d/=2)
591  {
592  w = w == 0 ? 1 : w;
593  h = h == 0 ? 1 : h;
594  d = d == 0 ? 1 : d;
595 
596  if (image_type == DDS_IMAGE_2D)
597  image[i]->allocate2D(w, h, 1, IF_COMPRESSED_RGBA_S3TC_DXT5, IT_IMPLICIT_TYPE);
598  else
599  if (image_type == DDS_IMAGE_CUBEMAP)
600  image[i]->allocateCubemap(w, h, 1, IF_COMPRESSED_RGBA_S3TC_DXT5, IT_IMPLICIT_TYPE);
601  else
602  if (image_type == DDS_IMAGE_3D)
603  image[i]->allocate3D(w, h, d, 1, IF_COMPRESSED_RGBA_S3TC_DXT5, IT_IMPLICIT_TYPE);
604  }
605 
606  for(int face=0; face<max_face; ++face)
607  {
608  for(int i=0, w = header.dwWidth, h = header.dwHeight, d = header.dwDepth; i<mipmaps; ++i, w/=2, h/=2, d/=2)
609  {
610  w = w == 0 ? 1 : w;
611  h = h == 0 ? 1 : h;
612  d = d == 0 ? 1 : d;
613 
614  int req_mem = Image::requiredMemory( w, h, d, 1, IF_COMPRESSED_RGBA_S3TC_DXT5, IT_IMPLICIT_TYPE, false );
615  int offset = req_mem*face;
616  file->read(image[i]->pixels() + offset, req_mem);
617  }
618  }
619  }
620  else
621  {
622  Log::error( Say("DDS: not supported format for '%s'.\n") << file->path() );
623  file->close();
624  return NULL;
625  }
626 
627  file->close();
628 
629  // We don't flip at all the DDS to be consistent since flipping
630  // vertically/horizontally compressed images is not possible.
631  // The textures must be already flipped using the OpenGL reference system.
632 
633  #if 0
634  if (image_type == DDS_IMAGE_2D && !s3tc_compressed)
635  {
636  for (int i=0; i<(int)image.size(); ++i)
637  internal_FlipVertically(image[i]);
638  }
639  else
640  if (image_type == DDS_IMAGE_3D)
641  {
642  // should be flipped vertically and then
643  // invert their order along the z-axis
644  // ...
645  }
646  else
647  if (image_type == DDS_IMAGE_CUBEMAP)
648  {
649  // should be flipped in a more sofisticated way, sg like:
650  // X+- flip orizontally
651  // Y+- flip vertically
652  // Z+- exchange one with the other
653  // ...
654  }
655  #endif
656 
657  VL_CHECK(image.size());
658 
659  ref<Image> img = new Image;
660  img->setObjectName(file->path().toStdString().c_str());
661  *img = *image[0];
662  image.erase(image.begin());
663  img->setMipmaps(image);
664 
665  return img;
666 }
667 //-----------------------------------------------------------------------------
669 {
670  if (!file->open(OM_ReadOnly))
671  return false;
672 
673  char signature[4];
674  file->read(signature, 4);
675  if (strncmp(signature, "DDS ", 4) != 0)
676  {
677  file->close();
678  return false;
679  }
680 
681  DDSURFACEDESC2 header;
682  memset(&header, 0, sizeof(header));
683 
684  // fread(&header, 1, sizeof(header), fin);
685 
686  header.dwSize = file->readUInt32();
687  header.dwFlags = file->readUInt32();
688  header.dwHeight = file->readUInt32();
689  header.dwWidth = file->readUInt32();
690  header.dwPitchOrLinearSize = file->readUInt32();
691  header.dwDepth = file->readUInt32();
692  header.dwMipMapCount = file->readUInt32();
693  // fread(header.dwReserved1, 1, 11*sizeof(unsigned long), fin);
694  file->read(header.dwReserved1, 11*sizeof(unsigned long));
695  header.ddpfPixelFormat.dwSize = file->readUInt32();
696  header.ddpfPixelFormat.dwFlags = file->readUInt32();
697  header.ddpfPixelFormat.dwFourCC = file->readUInt32();
698  header.ddpfPixelFormat.dwRGBBitCount = file->readUInt32();
699  header.ddpfPixelFormat.dwRBitMask = file->readUInt32();
700  header.ddpfPixelFormat.dwGBitMask = file->readUInt32();
701  header.ddpfPixelFormat.dwBBitMask = file->readUInt32();
702  header.ddpfPixelFormat.dwAlphaBitMask = file->readUInt32();
703  header.ddsCaps.dwCaps1 = file->readUInt32();
704  header.ddsCaps.dwCaps2 = file->readUInt32();
705  header.ddsCaps.dwReserved[0] = file->readUInt32();
706  header.ddsCaps.dwReserved[1] = file->readUInt32();
707  header.dwReserved2 = file->readUInt32();
708 
709  file->close();
710 
711  if (header.dwSize != 124 || header.ddpfPixelFormat.dwSize != 32)
712  return false;
713 
714  // warn only when actually loading
715 #if 0
716  if ((header.dwFlags & DDS_REQUIRED_FLAGS) != DDS_REQUIRED_FLAGS )
717  Log::warning( Say("DDS file '%s': missing DDS_REQUIRED_FLAGS flags.\n") << file->path() );
718 
719  if ((header.ddsCaps.dwCaps1 & DDSCAPS_TEXTURE) != DDSCAPS_TEXTURE)
720  Log::warning( Say("DDS file '%s': missing DDSCAPS_TEXTURE flag.\n") << file->path() );
721 #endif
722 
723  return true;
724 }
725 //-----------------------------------------------------------------------------
long long read(void *buffer, long long byte_count)
Reads byte_count bytes from a file. Returns the number of bytes actually read.
Definition: VirtualFile.cpp:82
VLCORE_EXPORT FileSystem * defFileSystem()
Returns the default FileSystem used by VisualizationLibrary.
Definition: pimpl.cpp:97
#define IS_DXT3(pf)
Definition: ioDDS.cpp:160
const T * get() const
Definition: Object.hpp:128
An abstract class representing a file.
Definition: VirtualFile.hpp:60
void convert8ToRGBA(const TPalette3x256 &palette, void *buf, int w, int h, unsigned char alpha, int bytealign=1)
Definition: ImageTools.hpp:117
A simple String formatting class.
Definition: Say.hpp:124
void setObjectName(const char *name)
The name of the object, by default set to the object&#39;s class name in debug builds.
Definition: Object.hpp:220
static void warning(const String &message)
Use this function to provide information about situations that might lead to errors or loss of data...
Definition: Log.cpp:155
void swapBytes32_BGRA_RGBA(void *buf, int bytecount)
Definition: ImageTools.hpp:211
The String class implements an advanced UTF16 (Unicode BMP) string manipulation engine.
Definition: String.hpp:62
static void error(const String &message)
Use this function to provide information about run-time errors: file not found, out of memory...
Definition: Log.cpp:165
virtual ref< VirtualFile > locateFile(const String &full_path, const String &alternate_path=String()) const
Looks for a VirtualFile on the disk and in the currently active FileSystem.
Definition: FileSystem.cpp:61
void fillRGBA32_Alpha(void *buf, int bytecount, unsigned char alpha)
Definition: ImageTools.hpp:236
int requiredMemory() const
Returns the number of bytes requested to store the image.
Definition: Image.cpp:532
virtual void close()=0
Closes the file.
const String & path() const
Returns the path of the file.
Definition: VirtualFile.hpp:98
Visualization Library main namespace.
#define IS_BGRA8(pf)
Definition: ioDDS.cpp:131
void fillGray8Alpha8_Alpha(void *buf, int bytecount, unsigned char alpha)
Definition: ImageTools.hpp:245
VLCORE_EXPORT ref< Image > loadDDS(VirtualFile *file)
Definition: ioDDS.cpp:242
The type is implicitly defined by the EImageFormat value, for ex.
VL_COMPILE_TIME_CHECK(sizeof(i8) *8==8)
virtual bool open(EOpenMode mode)=0
Opens the file in the specified mode.
VLCORE_EXPORT bool isDDS(VirtualFile *file)
Definition: ioDDS.cpp:668
#define IS_DXT1(pf)
Definition: ioDDS.cpp:158
#define IS_GRAY8(pf)
Definition: ioDDS.cpp:146
EImageFormat
#define NULL
Definition: OpenGLDefs.hpp:81
#define IS_BGRX8(pf)
Definition: ioDDS.cpp:136
#define IS_DXT5(pf)
Definition: ioDDS.cpp:162
unsigned int readUInt32(bool little_endian_data=true)
Reads single entry.
Implements a generic 1d, 2d, 3d and cubemap image that can have mipmaps.
Definition: Image.hpp:54
The ref<> class is used to reference-count an Object.
Definition: Object.hpp:55
std::string toStdString() const
Returns a UTF8 encoded std::string.
Definition: String.cpp:1156
#define IS_GRAY8_ALPHA8(pf)
Definition: ioDDS.cpp:151
#define IS_BGR8(pf)
Definition: ioDDS.cpp:141
#define VL_CHECK(expr)
Definition: checks.hpp:73
void swapBytes24_BGR_RGB(void *buf, int bytecount)
Definition: ImageTools.hpp:223
unsigned char TPalette4x256[256 *4]
Definition: ImageTools.hpp:41
#define IS_PALETTE8(pf)
Definition: ioDDS.cpp:156