Evas: Complete DDS loader with direct S3TC data load
This requires block flip (could be repeat, but flip is just as fast).
This commit is contained in:
parent
79ed3c4516
commit
81929e3404
|
@ -214,7 +214,7 @@ evas_image_load_file_head_dds(void *loader_data,
|
|||
height = _dword_read(&m);
|
||||
width = _dword_read(&m);
|
||||
pitchOrLinearSize = _dword_read(&m);
|
||||
if (!width || !height || (width & 0x3) || (height & 0x3))
|
||||
if (!width || !height)
|
||||
FAIL();
|
||||
|
||||
// Skip depth & mipmap count + reserved[11]
|
||||
|
@ -302,6 +302,10 @@ evas_image_load_file_head_dds(void *loader_data,
|
|||
|
||||
prop->h = height;
|
||||
prop->w = width;
|
||||
prop->borders.l = 4;
|
||||
prop->borders.t = 4;
|
||||
prop->borders.r = 4 - (prop->w & 0x3);
|
||||
prop->borders.b = 4 - (prop->h & 0x3);
|
||||
*error = EVAS_LOAD_ERROR_NONE;
|
||||
|
||||
on_error:
|
||||
|
@ -309,6 +313,134 @@ on_error:
|
|||
return (*error == EVAS_LOAD_ERROR_NONE);
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_dds_data_load(Evas_Loader_Internal *loader, Evas_Image_Property *prop,
|
||||
unsigned char *map, void *pixels, int *error)
|
||||
{
|
||||
const unsigned char *src;
|
||||
int bsize = 16, srcstride, dststride, w, h;
|
||||
unsigned char *dst;
|
||||
|
||||
void (* flip) (unsigned char *, const unsigned char *, int) = NULL;
|
||||
|
||||
*error = EVAS_LOAD_ERROR_GENERIC;
|
||||
|
||||
if (loader->format != prop->cspace)
|
||||
FAIL();
|
||||
|
||||
switch (loader->format)
|
||||
{
|
||||
case EVAS_COLORSPACE_RGB_S3TC_DXT1:
|
||||
case EVAS_COLORSPACE_RGBA_S3TC_DXT1:
|
||||
flip = s3tc_encode_dxt1_flip;
|
||||
bsize = 8;
|
||||
break;
|
||||
case EVAS_COLORSPACE_RGBA_S3TC_DXT2:
|
||||
flip = s3tc_encode_dxt2_rgba_flip;
|
||||
bsize = 16;
|
||||
break;
|
||||
case EVAS_COLORSPACE_RGBA_S3TC_DXT3:
|
||||
flip = s3tc_encode_dxt3_rgba_flip;
|
||||
bsize = 16;
|
||||
break;
|
||||
case EVAS_COLORSPACE_RGBA_S3TC_DXT4:
|
||||
flip = s3tc_encode_dxt4_rgba_flip;
|
||||
bsize = 16;
|
||||
break;
|
||||
case EVAS_COLORSPACE_RGBA_S3TC_DXT5:
|
||||
flip = s3tc_encode_dxt5_rgba_flip;
|
||||
bsize = 16;
|
||||
break;
|
||||
default: FAIL();
|
||||
}
|
||||
|
||||
src = map + DDS_HEADER_SIZE;
|
||||
w = prop->w;
|
||||
h = prop->h;
|
||||
srcstride = ((prop->w + 3) / 4) * bsize;
|
||||
dststride = ((prop->w + prop->borders.l + prop->borders.r) / 4) * bsize;
|
||||
|
||||
// asserts
|
||||
EINA_SAFETY_ON_FALSE_GOTO(prop->borders.l == 4, on_error);
|
||||
EINA_SAFETY_ON_FALSE_GOTO(prop->borders.t == 4, on_error);
|
||||
EINA_SAFETY_ON_FALSE_GOTO(prop->borders.r == (4 - (w & 0x3)), on_error);
|
||||
EINA_SAFETY_ON_FALSE_GOTO(prop->borders.b == (4 - (h & 0x3)), on_error);
|
||||
|
||||
if (eina_file_size_get(loader->f) <
|
||||
(size_t) (DDS_HEADER_SIZE + srcstride * h / 4))
|
||||
{
|
||||
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
// First, copy the real data
|
||||
for (int y = 0; y < h; y += 4)
|
||||
{
|
||||
dst = ((unsigned char *) pixels) + ((y / 4) + 1) * dststride + bsize;
|
||||
memcpy(dst, src, srcstride);
|
||||
src += srcstride;
|
||||
}
|
||||
// Top
|
||||
for (int x = 0; x < w; x += 4)
|
||||
{
|
||||
src = map + DDS_HEADER_SIZE + (x / 4) * bsize;
|
||||
dst = ((unsigned char *) pixels) + ((x / 4) + 1) * bsize;
|
||||
flip(dst, src, EINA_TRUE);
|
||||
}
|
||||
// Left
|
||||
for (int y = 0; y < h; y += 4)
|
||||
{
|
||||
src = map + DDS_HEADER_SIZE + (y / 4) * srcstride;
|
||||
dst = ((unsigned char *) pixels) + ((y / 4) + 1) * dststride;
|
||||
flip(dst, src, EINA_FALSE);
|
||||
}
|
||||
// Top-left
|
||||
dst = pixels;
|
||||
src = dst + bsize;
|
||||
flip(dst, src, EINA_FALSE);
|
||||
// Right
|
||||
if ((prop->w & 0x3) == 0)
|
||||
{
|
||||
for (int y = 0; y < h; y += 4)
|
||||
{
|
||||
src = map + DDS_HEADER_SIZE + ((y / 4) + 1) * srcstride - bsize;
|
||||
dst = ((unsigned char *) pixels) + ((y / 4) + 2) * dststride - bsize;
|
||||
flip(dst, src, EINA_FALSE);
|
||||
}
|
||||
// Top-right
|
||||
dst = ((unsigned char *) pixels) + dststride - bsize;
|
||||
src = dst - bsize;
|
||||
flip(dst, src, EINA_FALSE);
|
||||
}
|
||||
// Bottom
|
||||
if ((prop->h & 0x3) == 0)
|
||||
{
|
||||
for (int x = 0; x < w; x += 4)
|
||||
{
|
||||
src = map + DDS_HEADER_SIZE + ((h / 4) - 1) * srcstride + (x / 4) * bsize;
|
||||
dst = ((unsigned char *) pixels) + ((h / 4) + 1) * dststride + ((x / 4) + 1) * bsize;
|
||||
flip(dst, src, EINA_TRUE);
|
||||
}
|
||||
// Bottom-left
|
||||
dst = ((unsigned char *) pixels) + ((h / 4) + 1) * dststride;
|
||||
src = dst + bsize;
|
||||
flip(dst, src, EINA_FALSE);
|
||||
if ((prop->w & 0x3) == 0)
|
||||
{
|
||||
// Bottom-right
|
||||
dst = ((unsigned char *) pixels) + ((h / 4) + 2) * dststride - bsize;
|
||||
src = dst - bsize;
|
||||
flip(dst, src, EINA_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
*error = EVAS_LOAD_ERROR_NONE;
|
||||
|
||||
on_error:
|
||||
eina_file_map_free(loader->f, (void *) map);
|
||||
return (*error == EVAS_LOAD_ERROR_NONE);
|
||||
}
|
||||
|
||||
Eina_Bool
|
||||
evas_image_load_file_data_dds(void *loader_data,
|
||||
Evas_Image_Property *prop,
|
||||
|
@ -332,14 +464,7 @@ evas_image_load_file_data_dds(void *loader_data,
|
|||
FAIL();
|
||||
|
||||
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;
|
||||
}
|
||||
return _dds_data_load(loader, prop, map, pixels, error);
|
||||
|
||||
// Decode to BGRA
|
||||
switch (loader->format)
|
||||
|
@ -399,7 +524,7 @@ evas_image_load_file_data_dds(void *loader_data,
|
|||
*error = EVAS_LOAD_ERROR_NONE;
|
||||
|
||||
on_error:
|
||||
eina_file_map_free(loader->f, (void *) src);
|
||||
eina_file_map_free(loader->f, (void *) map);
|
||||
return (*error == EVAS_LOAD_ERROR_NONE);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,4 +8,10 @@ void s3tc_decode_dxt3_rgba(unsigned int *bgra, const unsigned char *s3tc);
|
|||
void s3tc_decode_dxt4_rgba(unsigned int *bgra, const unsigned char *s3tc);
|
||||
void s3tc_decode_dxt5_rgba(unsigned int *bgra, const unsigned char *s3tc);
|
||||
|
||||
void s3tc_encode_dxt1_flip(unsigned char *dest, const unsigned char *orig, int vflip);
|
||||
void s3tc_encode_dxt2_rgba_flip(unsigned char *dest, const unsigned char *orig, int vflip);
|
||||
void s3tc_encode_dxt3_rgba_flip(unsigned char *dest, const unsigned char *orig, int vflip);
|
||||
void s3tc_encode_dxt4_rgba_flip(unsigned char *dest, const unsigned char *orig, int vflip);
|
||||
void s3tc_encode_dxt5_rgba_flip(unsigned char *dest, const unsigned char *orig, int vflip);
|
||||
|
||||
#endif // EFL_S3TC_H
|
||||
|
|
|
@ -95,36 +95,125 @@ _decode_dxt_alpha(unsigned int *bgra, const unsigned char *s3tc)
|
|||
}
|
||||
}
|
||||
|
||||
void s3tc_decode_dxt1_rgb(unsigned int *bgra, const unsigned char *s3tc)
|
||||
void
|
||||
s3tc_decode_dxt1_rgb(unsigned int *bgra, const unsigned char *s3tc)
|
||||
{
|
||||
_decode_dxt1_rgb(bgra, s3tc, 0xFF000000, EINA_TRUE, EINA_FALSE);
|
||||
}
|
||||
|
||||
void s3tc_decode_dxt1_rgba(unsigned int *bgra, const unsigned char *s3tc)
|
||||
void
|
||||
s3tc_decode_dxt1_rgba(unsigned int *bgra, const unsigned char *s3tc)
|
||||
{
|
||||
_decode_dxt1_rgb(bgra, s3tc, 0xFF000000, EINA_TRUE, EINA_TRUE);
|
||||
}
|
||||
|
||||
void s3tc_decode_dxt2_rgba(unsigned int *bgra, const unsigned char *s3tc)
|
||||
void
|
||||
s3tc_decode_dxt2_rgba(unsigned int *bgra, const unsigned char *s3tc)
|
||||
{
|
||||
_decode_dxt1_rgb(bgra, s3tc + 8, 0x0, EINA_FALSE, EINA_FALSE);
|
||||
_decode_alpha4(bgra, s3tc);
|
||||
}
|
||||
|
||||
void s3tc_decode_dxt3_rgba(unsigned int *bgra, const unsigned char *s3tc)
|
||||
void
|
||||
s3tc_decode_dxt3_rgba(unsigned int *bgra, const unsigned char *s3tc)
|
||||
{
|
||||
_decode_dxt1_rgb(bgra, s3tc + 8, 0x0, EINA_FALSE, EINA_FALSE);
|
||||
_decode_alpha4(bgra, s3tc);
|
||||
}
|
||||
|
||||
void s3tc_decode_dxt4_rgba(unsigned int *bgra, const unsigned char *s3tc)
|
||||
void
|
||||
s3tc_decode_dxt4_rgba(unsigned int *bgra, const unsigned char *s3tc)
|
||||
{
|
||||
_decode_dxt1_rgb(bgra, s3tc + 8, 0x0, EINA_FALSE, EINA_FALSE);
|
||||
_decode_dxt_alpha(bgra, s3tc);
|
||||
}
|
||||
|
||||
void s3tc_decode_dxt5_rgba(unsigned int *bgra, const unsigned char *s3tc)
|
||||
void
|
||||
s3tc_decode_dxt5_rgba(unsigned int *bgra, const unsigned char *s3tc)
|
||||
{
|
||||
_decode_dxt1_rgb(bgra, s3tc + 8, 0x0, EINA_FALSE, EINA_FALSE);
|
||||
_decode_dxt_alpha(bgra, s3tc);
|
||||
}
|
||||
|
||||
/* Fast re-encode functions to flip S3TC blocks */
|
||||
|
||||
static inline unsigned char
|
||||
_byte_2222_flip(unsigned char src)
|
||||
{
|
||||
return ((src & (0x3 << 6)) >> 6) |
|
||||
((src & (0x3 << 4)) >> 2) |
|
||||
((src & (0x3 << 2)) << 2) |
|
||||
((src & 0x3) << 6);
|
||||
}
|
||||
|
||||
static inline unsigned char
|
||||
_byte_44_flip(unsigned char src)
|
||||
{
|
||||
return ((src & 0xF0) >> 4) | ((src & 0x0F) << 4);
|
||||
}
|
||||
|
||||
void
|
||||
s3tc_encode_dxt1_flip(unsigned char *dest, const unsigned char *orig, int vflip)
|
||||
{
|
||||
dest[0] = orig[0];
|
||||
dest[1] = orig[1];
|
||||
dest[2] = orig[2];
|
||||
dest[3] = orig[3];
|
||||
|
||||
if (vflip)
|
||||
{
|
||||
dest[4] = orig[7];
|
||||
dest[5] = orig[6];
|
||||
dest[6] = orig[5];
|
||||
dest[7] = orig[4];
|
||||
}
|
||||
else
|
||||
{
|
||||
dest[4] = _byte_2222_flip(orig[4]);
|
||||
dest[5] = _byte_2222_flip(orig[5]);
|
||||
dest[6] = _byte_2222_flip(orig[6]);
|
||||
dest[7] = _byte_2222_flip(orig[7]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
s3tc_encode_dxt2_rgba_flip(unsigned char *dest, const unsigned char *orig, int vflip)
|
||||
{
|
||||
if (vflip)
|
||||
{
|
||||
dest[0] = orig[6];
|
||||
dest[1] = orig[7];
|
||||
dest[2] = orig[4];
|
||||
dest[3] = orig[5];
|
||||
dest[4] = orig[2];
|
||||
dest[5] = orig[3];
|
||||
dest[6] = orig[0];
|
||||
dest[7] = orig[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int k = 0; k < 8; k += 2)
|
||||
{
|
||||
dest[0+k] = _byte_44_flip(orig[1+k]);
|
||||
dest[1+k] = _byte_44_flip(orig[0+k]);
|
||||
}
|
||||
}
|
||||
s3tc_encode_dxt1_flip(dest + 8, orig + 8, vflip);
|
||||
}
|
||||
|
||||
void
|
||||
s3tc_encode_dxt3_rgba_flip(unsigned char *dest, const unsigned char *orig, int vflip)
|
||||
{
|
||||
s3tc_encode_dxt2_rgba_flip(dest, orig, vflip);
|
||||
}
|
||||
|
||||
void s3tc_encode_dxt4_rgba_flip(unsigned char *dest, const unsigned char *orig, int vflip)
|
||||
{
|
||||
s3tc_encode_dxt1_flip(dest, orig, vflip);
|
||||
s3tc_encode_dxt1_flip(dest + 8, orig + 8, vflip);
|
||||
}
|
||||
|
||||
void s3tc_encode_dxt5_rgba_flip(unsigned char *dest, const unsigned char *orig, int vflip)
|
||||
{
|
||||
s3tc_encode_dxt4_rgba_flip(dest, orig, vflip);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue