diff options
author | Jean-Philippe Andre <jp.andre@samsung.com> | 2014-06-19 12:34:05 +0900 |
---|---|---|
committer | Jean-Philippe Andre <jp.andre@samsung.com> | 2014-07-03 11:37:48 +0900 |
commit | 8c8a4d37f91db08f96701d5dce78142863fb81c1 (patch) | |
tree | 756795b64afae11c2229c56584cf998c6208d631 | |
parent | c42415386734b71cef0efcbc6575b6e8c7ba8dbf (diff) | |
download | efl-8c8a4d37f91db08f96701d5dce78142863fb81c1.tar.gz |
Evas DDS: Start implementing DDS file loader
This implement the header read.
-rw-r--r-- | src/modules/evas/loaders/dds/evas_image_load_dds.c | 240 | ||||
-rw-r--r-- | src/modules/evas/loaders/dds/s3tc.h | 13 | ||||
-rw-r--r-- | src/modules/evas/loaders/dds/s3tc_decoder.c | 2 |
3 files changed, 247 insertions, 8 deletions
diff --git a/src/modules/evas/loaders/dds/evas_image_load_dds.c b/src/modules/evas/loaders/dds/evas_image_load_dds.c index 356fc68443..836751d651 100644 --- a/src/modules/evas/loaders/dds/evas_image_load_dds.c +++ b/src/modules/evas/loaders/dds/evas_image_load_dds.c @@ -10,23 +10,112 @@ #endif #include "Evas_Loader.h" +#include "s3tc.h" + +#ifdef _WIN32 +# include <ddraw.h> +#endif typedef struct _Evas_Loader_Internal Evas_Loader_Internal; struct _Evas_Loader_Internal { Eina_File *f; + + DxtFormat format; + size_t data_size; + + struct { + uint32_t flags; + uint32_t fourcc; + uint32_t rgb_bitcount; + uint32_t r_mask; + uint32_t g_mask; + uint32_t b_mask; + uint32_t a_mask; + + Eina_Bool has_alpha : 1; + // TODO: check mipmaps to load faster a small image :) + } pf; // pixel format +}; + +#undef FOURCC +#ifndef WORDS_BIGENDIAN +# define FOURCC(a,b,c,d) ((d << 24) | (c << 16) | (b << 8) | a) +#else +# define FOURCC(a,b,c,d) ((a << 24) | (b << 16) | (c << 8) | d) +#endif + +#ifndef DIRECTDRAW_VERSION +// DIRECTDRAW_VERSION is defined in ddraw.h +// These definitions are from the MSDN reference. + +enum DDSFlags { + DDSD_CAPS = 0x1, + DDSD_HEIGHT = 0x2, + DDSD_WIDTH = 0x4, + DDSD_PITCH = 0x8, + DDSD_PIXELFORMAT = 0x1000, + DDSD_MIPMAPCOUNT = 0x20000, + DDSD_LINEARSIZE = 0x80000, + DDSD_DEPTH = 0x800000 +}; + +enum DDSPixelFormatFlags { + DDPF_ALPHAPIXELS = 0x1, + DDPF_ALPHA = 0x2, + DDPF_FOURCC = 0x4, + DDPF_RGB = 0x40, + DDPF_YUV = 0x200, + DDPF_LUMINANCE = 0x20000 +}; + +enum DDSCaps { + DDSCAPS_COMPLEX = 0x8, + DDSCAPS_MIPMAP = 0x400000, + DDSCAPS_TEXTURE = 0x1000 +}; + +#endif + +static const Evas_Colorspace cspaces_s3tc_dxt1_rgb[] = { + //EVAS_COLORSPACE_RGB_S3TC_DXT1, + EVAS_COLORSPACE_ARGB8888 +}; + +static const Evas_Colorspace cspaces_s3tc_dxt1_rgba[] = { + //EVAS_COLORSPACE_RGBA_S3TC_DXT1, + EVAS_COLORSPACE_ARGB8888 +}; + +static const Evas_Colorspace cspaces_s3tc_dxt2[] = { + //EVAS_COLORSPACE_RGBA_S3TC_DXT2, // Not in OpenGL + EVAS_COLORSPACE_ARGB8888 +}; + +static const Evas_Colorspace cspaces_s3tc_dxt3[] = { + //EVAS_COLORSPACE_RGB_S3TC_DXT3, + EVAS_COLORSPACE_ARGB8888 +}; + +static const Evas_Colorspace cspaces_s3tc_dxt4[] = { + //EVAS_COLORSPACE_RGBA_S3TC_DXT4, // Not in OpenGL + EVAS_COLORSPACE_ARGB8888 +}; + +static const Evas_Colorspace cspaces_s3tc_dxt5[] = { + //EVAS_COLORSPACE_RGBA_S3TC_DXT5, + EVAS_COLORSPACE_ARGB8888 }; static void * evas_image_load_file_open_dds(Eina_File *f, Eina_Stringshare *key EINA_UNUSED, - Evas_Image_Load_Opts *opts, + Evas_Image_Load_Opts *opts EINA_UNUSED, Evas_Image_Animated *animated EINA_UNUSED, int *error) { Evas_Loader_Internal *loader; - // TODO: Check file size - if (eina_file_size_get(f) <= 16) + if (eina_file_size_get(f) <= 128) { *error = EVAS_LOAD_ERROR_CORRUPT_FILE; return NULL; @@ -60,12 +149,28 @@ evas_image_load_file_close_dds(void *loader_data) free(loader); } +static inline uint32_t +_dword_read(const char **m) +{ + uint32_t val = *((uint32_t *) *m); + *m += 4; + return val; +} + +#define FAIL() do { fprintf(stderr, "DDS: ERROR at %s:%d", __FUNCTION__, __LINE__); goto on_error; } while (0) + static Eina_Bool evas_image_load_file_head_dds(void *loader_data, Evas_Image_Property *prop, int *error) { + static const uint32_t base_flags = /* 0x1007 */ + DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; + Evas_Loader_Internal *loader = loader_data; + uint32_t flags, height, width, pitchOrLinearSize, block_size = 16, stride, + caps, caps2; + Eina_Bool has_linearsize, has_mipmapcount; const char *m; m = eina_file_map_all(loader->f, EINA_FILE_SEQUENTIAL); @@ -75,15 +180,133 @@ evas_image_load_file_head_dds(void *loader_data, return EINA_FALSE; } + *error = EVAS_LOAD_ERROR_CORRUPT_FILE; if (strncmp(m, "DDS ", 4) != 0) + // TODO: Add support for DX10 + FAIL(); + m += 4; + + // Read DDS_HEADER + if (_dword_read(&m) != 124) + FAIL(); + + flags = _dword_read(&m); + if ((flags & base_flags) != (base_flags)) + FAIL(); + + if ((flags & ~(DDSD_MIPMAPCOUNT | DDSD_LINEARSIZE)) != base_flags) { - *error = EVAS_LOAD_ERROR_CORRUPT_FILE; - return EINA_FALSE; + // TODO: A lot of modes are not supported. + *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + FAIL(); } - // TODO + has_linearsize = !!(flags & DDSD_LINEARSIZE); + if (!has_linearsize) + FAIL(); + + has_mipmapcount = !!(flags & DDSD_MIPMAPCOUNT); + (void) has_mipmapcount; // We don't really care about it. - return EINA_TRUE; + height = _dword_read(&m); + width = _dword_read(&m); + pitchOrLinearSize = _dword_read(&m); + if (!width || !height || (width & 0x3) || (height & 0x3)) + FAIL(); + + // Skip depth & mipmap count + reserved[11] + m += 13 * sizeof(uint32_t); + // Entering DDS_PIXELFORMAT ddspf + if (_dword_read(&m) != 32) + FAIL(); + loader->pf.flags = _dword_read(&m); + if (!(loader->pf.flags & DDPF_FOURCC)) + FAIL(); // Unsupported (uncompressed formats may not have a FOURCC) + loader->pf.fourcc = _dword_read(&m); + loader->pf.has_alpha = EINA_TRUE; + switch (loader->pf.fourcc) + { + case FOURCC('D', 'X', 'T', '1'): + loader->format = DXT1; + if ((loader->pf.flags & DDPF_ALPHAPIXELS) == 0) + { + prop->alpha = EINA_FALSE; + prop->cspaces = cspaces_s3tc_dxt1_rgb; + loader->pf.has_alpha = EINA_FALSE; + } + else + { + prop->alpha = EINA_TRUE; + prop->cspaces = cspaces_s3tc_dxt1_rgba; + } + block_size = 8; + break; +#if 0 + case FOURCC('D', 'X', 'T', '2'): + loader->format = DXT2; + prop->alpha = EINA_TRUE; + prop->cspaces = cspaces_s3tc_dxt2; + break; + case FOURCC('D', 'X', 'T', '3'): + loader->format = DXT3; + prop->alpha = EINA_TRUE; + prop->cspaces = cspaces_s3tc_dxt5; + break; + case FOURCC('D', 'X', 'T', '4'): + loader->format = DXT4; + prop->alpha = EINA_TRUE; + prop->cspaces = cspaces_s3tc_dxt4; + break; + case FOURCC('D', 'X', 'T', '5'): + loader->format = DXT5; + prop->alpha = EINA_TRUE; + prop->cspaces = cspaces_s3tc_dxt5; + break; + case FOURCC('D', 'X', '1', '0'): + loader->format = DX10; + *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + FAIL(); +#endif + default: + // TODO: Implement decoding support for uncompressed formats + FAIL(); + } + loader->pf.rgb_bitcount = _dword_read(&m); + loader->pf.r_mask = _dword_read(&m); + loader->pf.g_mask = _dword_read(&m); + loader->pf.b_mask = _dword_read(&m); + loader->pf.a_mask = _dword_read(&m); + caps = _dword_read(&m); + if ((caps & DDSCAPS_TEXTURE) == 0) + { + *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + FAIL(); + } + caps2 = _dword_read(&m); + if (caps2 != 0) + { + // Cube maps not supported + *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + FAIL(); + } + // Since the rest is unused, just ignore it. + + stride = ((width + 3) >> 2) * block_size; + loader->data_size = stride * ((height + 3) >> 2); + if (loader->data_size != pitchOrLinearSize) + FAIL(); // Invalid size! + + // Check file size + if (eina_file_size_get(loader->f) < (128 + loader->data_size)) + FAIL(); + + prop->h = height; + prop->w = width; + *error = EVAS_LOAD_ERROR_NONE; + +on_error: + eina_file_map_free(loader->f, (void *) m); + return (*error == EVAS_LOAD_ERROR_NONE); } Eina_Bool @@ -104,7 +327,8 @@ evas_image_load_file_data_dds(void *loader_data, // TODO - r = EINA_TRUE; + *error = EVAS_LOAD_ERROR_GENERIC; + r = EINA_FALSE; // FIXME on_error: eina_file_map_free(loader->f, m); diff --git a/src/modules/evas/loaders/dds/s3tc.h b/src/modules/evas/loaders/dds/s3tc.h new file mode 100644 index 0000000000..8380c3a6a8 --- /dev/null +++ b/src/modules/evas/loaders/dds/s3tc.h @@ -0,0 +1,13 @@ +#ifndef EFL_S3TC_H +#define EFL_S3TC_H + +typedef enum { + DXT1, + DXT2, + DXT3, + DXT4, + DXT5, + DX10 +} DxtFormat; + +#endif // EFL_S3TC_H diff --git a/src/modules/evas/loaders/dds/s3tc_decoder.c b/src/modules/evas/loaders/dds/s3tc_decoder.c new file mode 100644 index 0000000000..44492dc517 --- /dev/null +++ b/src/modules/evas/loaders/dds/s3tc_decoder.c @@ -0,0 +1,2 @@ +#include "s3tc.h" + |