# include <ddraw.h>
#endif
+#define DDS_HEADER_SIZE 128
+
typedef struct _Evas_Loader_Internal Evas_Loader_Internal;
struct _Evas_Loader_Internal
{
Eina_File *f;
- DxtFormat format;
- size_t data_size;
+ Evas_Colorspace format;
+ unsigned int stride, block_size, 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;
+ unsigned int flags;
+ unsigned int fourcc;
+ unsigned int rgb_bitcount;
+ unsigned int r_mask;
+ unsigned int g_mask;
+ unsigned int b_mask;
+ unsigned int a_mask;
Eina_Bool has_alpha : 1;
// TODO: check mipmaps to load faster a small image :)
};
static const Evas_Colorspace cspaces_s3tc_dxt2[] = {
- //EVAS_COLORSPACE_RGBA_S3TC_DXT2, // Not in OpenGL
+ //EVAS_COLORSPACE_RGBA_S3TC_DXT2,
EVAS_COLORSPACE_ARGB8888
};
static const Evas_Colorspace cspaces_s3tc_dxt3[] = {
- //EVAS_COLORSPACE_RGB_S3TC_DXT3,
+ //EVAS_COLORSPACE_RGBA_S3TC_DXT3,
EVAS_COLORSPACE_ARGB8888
};
static const Evas_Colorspace cspaces_s3tc_dxt4[] = {
- //EVAS_COLORSPACE_RGBA_S3TC_DXT4, // Not in OpenGL
+ //EVAS_COLORSPACE_RGBA_S3TC_DXT4,
EVAS_COLORSPACE_ARGB8888
};
{
Evas_Loader_Internal *loader;
- if (eina_file_size_get(f) <= 128)
+ if (eina_file_size_get(f) <= DDS_HEADER_SIZE)
{
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
return NULL;
free(loader);
}
-static inline uint32_t
+static inline unsigned int
_dword_read(const char **m)
{
- uint32_t val = *((uint32_t *) *m);
+ unsigned int val = *((unsigned int *) *m);
*m += 4;
return val;
}
-#define FAIL() do { fprintf(stderr, "DDS: ERROR at %s:%d", __FUNCTION__, __LINE__); goto on_error; } while (0)
+#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 */
+ static const unsigned int 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;
+ unsigned int flags, height, width, pitchOrLinearSize, caps, caps2;
Eina_Bool has_linearsize, has_mipmapcount;
const char *m;
+ char *map;
- m = eina_file_map_all(loader->f, EINA_FILE_SEQUENTIAL);
- if (!m)
+ map = eina_file_map_all(loader->f, EINA_FILE_SEQUENTIAL);
+ if (!map)
{
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
return EINA_FALSE;
}
+ m = map;
+
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
if (strncmp(m, "DDS ", 4) != 0)
// TODO: Add support for DX10
FAIL();
// Skip depth & mipmap count + reserved[11]
- m += 13 * sizeof(uint32_t);
+ m += 13 * sizeof(unsigned int);
// Entering DDS_PIXELFORMAT ddspf
if (_dword_read(&m) != 32)
FAIL();
FAIL(); // Unsupported (uncompressed formats may not have a FOURCC)
loader->pf.fourcc = _dword_read(&m);
loader->pf.has_alpha = EINA_TRUE;
+ loader->block_size = 16;
switch (loader->pf.fourcc)
{
case FOURCC('D', 'X', 'T', '1'):
- loader->format = DXT1;
+ loader->block_size = 8;
if ((loader->pf.flags & DDPF_ALPHAPIXELS) == 0)
{
prop->alpha = EINA_FALSE;
prop->cspaces = cspaces_s3tc_dxt1_rgb;
loader->pf.has_alpha = EINA_FALSE;
+ loader->format = EVAS_COLORSPACE_RGB_S3TC_DXT1;
}
else
{
prop->alpha = EINA_TRUE;
prop->cspaces = cspaces_s3tc_dxt1_rgba;
+ loader->format = EVAS_COLORSPACE_RGBA_S3TC_DXT1;
}
- block_size = 8;
break;
#if 0
case FOURCC('D', 'X', 'T', '2'):
- loader->format = DXT2;
+ loader->format = EVAS_COLORSPACE_RGBA_S3TC_DXT2;
prop->alpha = EINA_TRUE;
prop->cspaces = cspaces_s3tc_dxt2;
break;
case FOURCC('D', 'X', 'T', '3'):
- loader->format = DXT3;
+ loader->format = EVAS_COLORSPACE_RGBA_S3TC_DXT3;
prop->alpha = EINA_TRUE;
prop->cspaces = cspaces_s3tc_dxt5;
break;
case FOURCC('D', 'X', 'T', '4'):
- loader->format = DXT4;
+ loader->format = EVAS_COLORSPACE_RGBA_S3TC_DXT4;
prop->alpha = EINA_TRUE;
prop->cspaces = cspaces_s3tc_dxt4;
break;
case FOURCC('D', 'X', 'T', '5'):
- loader->format = DXT5;
+ loader->format = EVAS_COLORSPACE_RGBA_S3TC_DXT5;
prop->alpha = EINA_TRUE;
prop->cspaces = cspaces_s3tc_dxt5;
break;
}
// Since the rest is unused, just ignore it.
- stride = ((width + 3) >> 2) * block_size;
- loader->data_size = stride * ((height + 3) >> 2);
+ loader->stride = ((width + 3) >> 2) * loader->block_size;
+ loader->data_size = loader->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))
+ if (eina_file_size_get(loader->f) < (DDS_HEADER_SIZE + loader->data_size))
FAIL();
prop->h = height;
*error = EVAS_LOAD_ERROR_NONE;
on_error:
- eina_file_map_free(loader->f, (void *) m);
+ eina_file_map_free(loader->f, map);
return (*error == EVAS_LOAD_ERROR_NONE);
}
void *pixels,
int *error)
{
+ void (*func) (unsigned int *bgra, const unsigned char *s3tc) = NULL;
Evas_Loader_Internal *loader = loader_data;
- const char *m;
-
- Eina_Bool r = EINA_FALSE;
+ unsigned int *pix = pixels;
+ unsigned char *map = NULL;
+ const unsigned char *src;
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
- m = eina_file_map_all(loader->f, EINA_FILE_WILLNEED);
- if (!m) return EINA_FALSE;
+ map = eina_file_map_all(loader->f, EINA_FILE_WILLNEED);
+ if (!map)
+ return EINA_FALSE;
- // TODO
+ src = map + DDS_HEADER_SIZE;
+ if (eina_file_size_get(loader->f) < (DDS_HEADER_SIZE + loader->data_size))
+ FAIL();
- *error = EVAS_LOAD_ERROR_GENERIC;
- r = EINA_FALSE; // FIXME
+ if (prop->cspace != EVAS_COLORSPACE_ARGB8888)
+ {
+ if (loader->format != prop->cspace)
+ FAIL();
+ memcpy(pixels, src, loader->data_size);
+ *error = EVAS_LOAD_ERROR_NONE;
+ eina_file_map_free(loader->f, (void *) src);
+ return EINA_TRUE;
+ }
+
+ // Decode to BGRA
+ switch (loader->format)
+ {
+ case EVAS_COLORSPACE_RGB_S3TC_DXT1:
+ func = s3tc_decode_dxt1_rgb;
+ break;
+ case EVAS_COLORSPACE_RGBA_S3TC_DXT1:
+ func = s3tc_decode_dxt1_rgba;
+ break;
+ default:
+ FAIL();
+ }
+ if (!func) FAIL();
+
+ for (unsigned int y = 0; y < prop->h; y += 4)
+ {
+ int blockh = prop->h - y;
+ if (blockh > 4) blockh = 4;
+
+ for (unsigned int x = 0; x < prop->w; x += 4)
+ {
+ unsigned int bgra[16];
+ int k, j;
+
+ func(bgra, src);
+ src += loader->block_size;
+
+ j = prop->w - x;
+ if (j > 4) j = 4;
+ for (k = 0; k < blockh; k++)
+ {
+ memcpy(pix + (((y + k) * prop->w) + x), bgra + (k * 4),
+ j * sizeof (unsigned int));
+ };
+ }
+ }
+
+ *error = EVAS_LOAD_ERROR_NONE;
on_error:
- eina_file_map_free(loader->f, m);
- return r;
+ eina_file_map_free(loader->f, (void *) src);
+ return (*error == EVAS_LOAD_ERROR_NONE);
}
Evas_Image_Load_Func evas_image_load_dds_func =
#include "s3tc.h"
+// For INTERP_256 and INTERP_RGB_256
+#include "evas_common_private.h"
+#include "evas_blend_ops.h"
+
+// From evas_convert_colorspace.c
+#define CONVERT_RGB_565_TO_RGB_888(s) \
+ (((((s) << 3) & 0xf8) | (((s) >> 2) & 0x7)) | \
+ ((((s) << 5) & 0xfc00) | (((s) >> 1) & 0x300)) | \
+ ((((s) << 8) & 0xf80000) | (((s) << 3) & 0x70000)))
+
+static inline unsigned int
+_rgb565_to_rgba8888(unsigned short s)
+{
+ return 0xFF000000 | CONVERT_RGB_565_TO_RGB_888(s);
+}
+
+static void
+_decode_dxt1_rgb(unsigned int *bgra, const unsigned char *s3tc,
+ Eina_Bool alpha)
+{
+ unsigned short color0, color1;
+ unsigned int colors[4];
+ unsigned int bits;
+
+ color0 = s3tc[0] | (s3tc[1] << 8);
+ color1 = s3tc[2] | (s3tc[3] << 8);
+
+ colors[0] = _rgb565_to_rgba8888(color0);
+ colors[1] = _rgb565_to_rgba8888(color1);
+ if (color0 > color1)
+ {
+ // This is what's not supported by S2TC.
+ colors[2] = 0xFF000000 | INTERP_RGB_256((2*256)/3, colors[0], colors[1]);
+ colors[3] = 0xFF000000 | INTERP_RGB_256((1*256)/3, colors[0], colors[1]);
+ }
+ else
+ {
+ colors[2] = 0xFF000000 | INTERP_RGB_256(128, colors[0], colors[1]);
+ colors[3] = (alpha ? 0x00000000 : 0xFF000000);
+ }
+
+ bits = s3tc[4] + ((s3tc[5] + ((s3tc[6] + (s3tc[7] << 8)) << 8)) << 8);
+ for (int j = 0; j < 4; j++)
+ for (int i = 0; i < 4; i++)
+ {
+ int idx = bits & 0x3;
+ bits >>= 2;
+
+ bgra[(j * 4) + i] = colors[idx];
+ }
+}
+
+void s3tc_decode_dxt1_rgb(unsigned int *bgra, const unsigned char *s3tc)
+{
+ _decode_dxt1_rgb(bgra, s3tc, EINA_FALSE);
+}
+
+void s3tc_decode_dxt1_rgba(unsigned int *bgra, const unsigned char *s3tc)
+{
+ _decode_dxt1_rgb(bgra, s3tc, EINA_TRUE);
+}