[CHG] Updated PNGU with code from Tantric for the PNGU_DecodeTo4x4RGBA8 function

This commit is contained in:
Crayon2000 2010-06-09 01:06:15 +00:00
parent 7771f167c9
commit 54be46f4e4
5 changed files with 120 additions and 131 deletions

View file

@ -158,11 +158,12 @@ void GRRLIB_BMFX_Blur (const GRRLIB_texImg *texsrc,
for (k = x - factor; k <= x + factor; k++) { for (k = x - factor; k <= x + factor; k++) {
for (l = y - factor; l <= y + factor; l++) { for (l = y - factor; l <= y + factor; l++) {
if (k < 0) { colours[tmp] = thiscol; } if (k < 0 || k >= texsrc->w || l < 0 || l >= texsrc->h) {
else if (k >= texsrc->w) { colours[tmp] = thiscol; } colours[tmp] = thiscol;
else if (l < 0) { colours[tmp] = thiscol; } }
else if (l >= texsrc->h) { colours[tmp] = thiscol; } else {
else { colours[tmp] = GRRLIB_GetPixelFromtexImg(k, l, texsrc); } colours[tmp] = GRRLIB_GetPixelFromtexImg(k, l, texsrc);
}
tmp++; tmp++;
} }
} }

View file

@ -26,10 +26,15 @@ THE SOFTWARE.
/** /**
* Load a file to memory. * Load a file to memory.
* @param filename Name of the file to be loaded. * @param filename Name of the file to be loaded.
* @param data Pointer-to-your-pointer. Ie. { u8 *data; load("file", &data); }. * @param data Pointer-to-your-pointer.
* Ie. { u8 *data; GRRLIB_LoadFile("file", &data); }.
* It is your responsibility to free the memory allocated by this function. * It is your responsibility to free the memory allocated by this function.
* @return int 0:EmptyFile, -1:FileNotFound, -2:OutOfMemory, -3:FileReadError, * @return A integer representating a code:
* >0 -> FileLength. * - 0 : EmptyFile.
* - -1 : FileNotFound.
* - -2 : OutOfMemory.
* - -3 : FileReadError.
* - >0 : FileLength.
*/ */
int GRRLIB_LoadFile(const char* filename, unsigned char* *data) { int GRRLIB_LoadFile(const char* filename, unsigned char* *data) {
int len; int len;

View file

@ -127,8 +127,10 @@ GRRLIB_texImg* GRRLIB_LoadTexture (const u8 *my_img) {
* Load a texture from a buffer. * Load a texture from a buffer.
* @param my_png the PNG buffer to load. * @param my_png the PNG buffer to load.
* @return A GRRLIB_texImg structure filled with image information. * @return A GRRLIB_texImg structure filled with image information.
* If image size is not correct, the texture will be completely transparent.
*/ */
GRRLIB_texImg* GRRLIB_LoadTexturePNG (const u8 *my_png) { GRRLIB_texImg* GRRLIB_LoadTexturePNG (const u8 *my_png) {
int width = 0, height = 0;
PNGUPROP imgProp; PNGUPROP imgProp;
IMGCTX ctx; IMGCTX ctx;
GRRLIB_texImg *my_texture = calloc(1, sizeof(GRRLIB_texImg)); GRRLIB_texImg *my_texture = calloc(1, sizeof(GRRLIB_texImg));
@ -136,19 +138,16 @@ GRRLIB_texImg* GRRLIB_LoadTexturePNG (const u8 *my_png) {
if(my_texture != NULL) { if(my_texture != NULL) {
ctx = PNGU_SelectImageFromBuffer(my_png); ctx = PNGU_SelectImageFromBuffer(my_png);
PNGU_GetImageProperties(ctx, &imgProp); PNGU_GetImageProperties(ctx, &imgProp);
my_texture->data = memalign(32, imgProp.imgWidth * imgProp.imgHeight * 4); my_texture->data = PNGU_DecodeTo4x4RGBA8(ctx, imgProp.imgWidth, imgProp.imgHeight, &width, &height, NULL);
if(my_texture->data != NULL) { if(my_texture->data != NULL) {
if(PNGU_DecodeTo4x4RGBA8(ctx, imgProp.imgWidth, imgProp.imgHeight, my_texture->data, 255) == PNGU_OK) { my_texture->w = width;
my_texture->w = imgProp.imgWidth; my_texture->h = height;
my_texture->h = imgProp.imgHeight; GRRLIB_SetHandle( my_texture, 0, 0 );
GRRLIB_SetHandle( my_texture, 0, 0 ); if(imgProp.imgWidth != width || imgProp.imgHeight != height) {
GRRLIB_FlushTex( my_texture ); // PGNU has resized the texture
} memset(my_texture->data, 0, (my_texture->h * my_texture->w) << 2);
else
{
free(my_texture->data);
my_texture->data = NULL;
} }
GRRLIB_FlushTex( my_texture );
} }
PNGU_ReleaseImageContext(ctx); PNGU_ReleaseImageContext(ctx);
} }

View file

@ -556,134 +556,118 @@ int PNGU_DecodeTo4x4RGB5A3 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *b
return PNGU_OK; return PNGU_OK;
} }
// Coded by Tantric for WiiMC (http://www.wiimc.org)
int PNGU_DecodeTo4x4RGBA8 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u8 default_alpha) static inline PNGU_u32 coordsRGBA8(PNGU_u32 x, PNGU_u32 y, PNGU_u32 w)
{ {
int result; return ((((y >> 2) * (w >> 2) + (x >> 2)) << 5) + ((y & 3) << 2) + (x & 3)) << 1;
PNGU_u32 x, y, qwidth, qheight; }
PNGU_u64 alphaMask;
// width and height need to be divisible by four // Coded by Tantric for WiiMC (http://www.wiimc.org)
if ((width % 4) || (height % 4)) PNGU_u8 * PNGU_DecodeTo4x4RGBA8 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, int * dstWidth, int * dstHeight, PNGU_u8 *dstPtr)
return PNGU_INVALID_WIDTH_OR_HEIGHT; {
PNGU_u8 default_alpha = 255; // default alpha value, which is used if the source image doesn't have an alpha channel.
PNGU_u8 *dst;
int x, y, x2=0, y2=0, offset;
int xRatio = 0, yRatio = 0;
png_byte *pixel;
result = pngu_decode (ctx, width, height, 0); if (pngu_decode (ctx, width, height, 0) != PNGU_OK)
if (result != PNGU_OK) return NULL;
return result;
// Init some variables int newWidth = width;
qwidth = width / 4; int newHeight = height;
qheight = height / 4;
// Check is source image has an alpha channel if(width > 1024 || height > 1024)
if ( (ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY_ALPHA) || (ctx->prop.imgColorType == PNGU_COLOR_TYPE_RGB_ALPHA) )
{ {
// Alpha channel present, copy image to the output buffer float ratio = (float)width/(float)height;
for (y = 0; y < qheight; y++)
for (x = 0; x < qwidth; x++)
{
int blockbase = (y * qwidth + x) * 8;
PNGU_u64 fieldA = *((PNGU_u64 *)(ctx->row_pointers[y*4]+x*16)); if(ratio > 1)
PNGU_u64 fieldB = *((PNGU_u64 *)(ctx->row_pointers[y*4]+x*16+8)); {
((PNGU_u64 *) buffer)[blockbase] = newWidth = 1024;
((fieldA & 0xFF00000000ULL) << 24) | ((fieldA & 0xFF00000000000000ULL) >> 8) | newHeight = 1024/ratio;
((fieldA & 0xFFULL) << 40) | ((fieldA & 0xFF000000ULL) << 8) | }
((fieldB & 0xFF00000000ULL) >> 8) | ((fieldB & 0xFF00000000000000ULL) >> 40) | else
((fieldB & 0xFFULL) << 8) | ((fieldB & 0xFF000000ULL) >> 24); {
((PNGU_u64 *) buffer)[blockbase+4] = newWidth = 1024*ratio;
((fieldA & 0xFFFF0000000000ULL) << 8) | ((fieldA & 0xFFFF00ULL) << 24) | newHeight = 1024;
((fieldB & 0xFFFF0000000000ULL) >> 24) | ((fieldB & 0xFFFF00ULL) >> 8); }
xRatio = (int)((width<<16)/newWidth)+1;
fieldA = *((PNGU_u64 *)(ctx->row_pointers[y*4+1]+x*16)); yRatio = (int)((height<<16)/newHeight)+1;
fieldB = *((PNGU_u64 *)(ctx->row_pointers[y*4+1]+x*16+8));
((PNGU_u64 *) buffer)[blockbase+1] =
((fieldA & 0xFF00000000ULL) << 24) | ((fieldA & 0xFF00000000000000ULL) >> 8) |
((fieldA & 0xFFULL) << 40) | ((fieldA & 0xFF000000ULL) << 8) |
((fieldB & 0xFF00000000ULL) >> 8) | ((fieldB & 0xFF00000000000000ULL) >> 40) |
((fieldB & 0xFFULL) << 8) | ((fieldB & 0xFF000000ULL) >> 24);
((PNGU_u64 *) buffer)[blockbase+5] =
((fieldA & 0xFFFF0000000000ULL) << 8) | ((fieldA & 0xFFFF00ULL) << 24) |
((fieldB & 0xFFFF0000000000ULL) >> 24) | ((fieldB & 0xFFFF00ULL) >> 8);
fieldA = *((PNGU_u64 *)(ctx->row_pointers[y*4+2]+x*16));
fieldB = *((PNGU_u64 *)(ctx->row_pointers[y*4+2]+x*16+8));
((PNGU_u64 *) buffer)[blockbase+2] =
((fieldA & 0xFF00000000ULL) << 24) | ((fieldA & 0xFF00000000000000ULL) >> 8) |
((fieldA & 0xFFULL) << 40) | ((fieldA & 0xFF000000ULL) << 8) |
((fieldB & 0xFF00000000ULL) >> 8) | ((fieldB & 0xFF00000000000000ULL) >> 40) |
((fieldB & 0xFFULL) << 8) | ((fieldB & 0xFF000000ULL) >> 24);
((PNGU_u64 *) buffer)[blockbase+6] =
((fieldA & 0xFFFF0000000000ULL) << 8) | ((fieldA & 0xFFFF00ULL) << 24) |
((fieldB & 0xFFFF0000000000ULL) >> 24) | ((fieldB & 0xFFFF00ULL) >> 8);
fieldA = *((PNGU_u64 *)(ctx->row_pointers[y*4+3]+x*16));
fieldB = *((PNGU_u64 *)(ctx->row_pointers[y*4+3]+x*16+8));
((PNGU_u64 *) buffer)[blockbase+3] =
((fieldA & 0xFF00000000ULL) << 24) | ((fieldA & 0xFF00000000000000ULL) >> 8) |
((fieldA & 0xFFULL) << 40) | ((fieldA & 0xFF000000ULL) << 8) |
((fieldB & 0xFF00000000ULL) >> 8) | ((fieldB & 0xFF00000000000000ULL) >> 40) |
((fieldB & 0xFFULL) << 8) | ((fieldB & 0xFF000000ULL) >> 24);
((PNGU_u64 *) buffer)[blockbase+7] =
((fieldA & 0xFFFF0000000000ULL) << 8) | ((fieldA & 0xFFFF00ULL) << 24) |
((fieldB & 0xFFFF0000000000ULL) >> 24) | ((fieldB & 0xFFFF00ULL) >> 8);
}
} }
int padWidth = newWidth;
int padHeight = newHeight;
if(padWidth%4) padWidth += (4-padWidth%4);
if(padHeight%4) padHeight += (4-padHeight%4);
int len = (padWidth * padHeight) << 2;
if(len%32) len += (32-len%32);
if(dstPtr)
dst = dstPtr; // use existing allocation
else else
dst = memalign (32, len);
if(!dst)
return NULL;
for (y = 0; y < padHeight; y++)
{ {
// No alpha channel present, copy image to the output buffer for (x = 0; x < padWidth; x++)
alphaMask = (((PNGU_u64)default_alpha) << 56) | (((PNGU_u64)default_alpha) << 40) | {
(((PNGU_u64)default_alpha) << 24) | (((PNGU_u64)default_alpha) << 8); offset = coordsRGBA8(x, y, padWidth);
for (y = 0; y < qheight; y++) if(y >= newHeight || x >= newWidth)
for (x = 0; x < qwidth; x++)
{ {
int blockbase = (y * qwidth + x) * 8; dst[offset] = 0;
dst[offset+1] = 255;
PNGU_u64 field64 = *((PNGU_u64 *)(ctx->row_pointers[y*4]+x*12)); dst[offset+32] = 255;
PNGU_u64 field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y*4]+x*12+8)); dst[offset+33] = 255;
((PNGU_u64 *) buffer)[blockbase] =
(((field64 & 0xFF00000000000000ULL) >> 8) | (field64 & 0xFF00000000ULL) |
((field64 & 0xFF00ULL) << 8) | ((field32 & 0xFF0000ULL) >> 16) | alphaMask);
((PNGU_u64 *) buffer)[blockbase+4] =
(((field64 & 0xFFFF0000000000ULL) << 8) | ((field64 & 0xFFFF0000ULL) << 16) |
((field64 & 0xFFULL) << 24) | ((field32 & 0xFF000000ULL) >> 8) | (field32 & 0xFFFFULL));
field64 = *((PNGU_u64 *)(ctx->row_pointers[y*4+1]+x*12));
field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y*4+1]+x*12+8));
((PNGU_u64 *) buffer)[blockbase+1] =
(((field64 & 0xFF00000000000000ULL) >> 8) | (field64 & 0xFF00000000ULL) |
((field64 & 0xFF00ULL) << 8) | ((field32 & 0xFF0000ULL) >> 16) | alphaMask);
((PNGU_u64 *) buffer)[blockbase+5] =
(((field64 & 0xFFFF0000000000ULL) << 8) | ((field64 & 0xFFFF0000ULL) << 16) |
((field64 & 0xFFULL) << 24) | ((field32 & 0xFF000000ULL) >> 8) | (field32 & 0xFFFFULL));
field64 = *((PNGU_u64 *)(ctx->row_pointers[y*4+2]+x*12));
field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y*4+2]+x*12+8));
((PNGU_u64 *) buffer)[blockbase+2] =
(((field64 & 0xFF00000000000000ULL) >> 8) | (field64 & 0xFF00000000ULL) |
((field64 & 0xFF00ULL) << 8) | ((field32 & 0xFF0000ULL) >> 16) | alphaMask);
((PNGU_u64 *) buffer)[blockbase+6] =
(((field64 & 0xFFFF0000000000ULL) << 8) | ((field64 & 0xFFFF0000ULL) << 16) |
((field64 & 0xFFULL) << 24) | ((field32 & 0xFF000000ULL) >> 8) | (field32 & 0xFFFFULL));
field64 = *((PNGU_u64 *)(ctx->row_pointers[y*4+3]+x*12));
field32 = (PNGU_u64) *((PNGU_u32 *)(ctx->row_pointers[y*4+3]+x*12+8));
((PNGU_u64 *) buffer)[blockbase+3] =
(((field64 & 0xFF00000000000000ULL) >> 8) | (field64 & 0xFF00000000ULL) |
((field64 & 0xFF00ULL) << 8) | ((field32 & 0xFF0000ULL) >> 16) | alphaMask);
((PNGU_u64 *) buffer)[blockbase+7] =
(((field64 & 0xFFFF0000000000ULL) << 8) | ((field64 & 0xFFFF0000ULL) << 16) |
((field64 & 0xFFULL) << 24) | ((field32 & 0xFF000000ULL) >> 8) | (field32 & 0xFFFFULL));
} }
else
{
if(xRatio > 0)
{
x2 = ((x*xRatio)>>16);
y2 = ((y*yRatio)>>16);
}
if (ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY_ALPHA ||
ctx->prop.imgColorType == PNGU_COLOR_TYPE_RGB_ALPHA)
{
if(xRatio > 0)
pixel = &(ctx->row_pointers[y2][x2*4]);
else
pixel = &(ctx->row_pointers[y][x*4]);
dst[offset] = pixel[3]; // Alpha
dst[offset+1] = pixel[0]; // Red
dst[offset+32] = pixel[1]; // Green
dst[offset+33] = pixel[2]; // Blue
}
else
{
if(xRatio > 0)
pixel = &(ctx->row_pointers[y2][x2*3]);
else
pixel = &(ctx->row_pointers[y][x*3]);
dst[offset] = default_alpha; // Alpha
dst[offset+1] = pixel[0]; // Red
dst[offset+32] = pixel[1]; // Green
dst[offset+33] = pixel[2]; // Blue
}
}
}
} }
// Free resources // Free resources
free (ctx->img_data); free (ctx->img_data);
free (ctx->row_pointers); free (ctx->row_pointers);
// Success *dstWidth = padWidth;
return PNGU_OK; *dstHeight = padHeight;
return dst;
} }
// Coded by Tantric for libwiigui (http://code.google.com/p/libwiigui) // Coded by Tantric for libwiigui (http://code.google.com/p/libwiigui)

View file

@ -150,8 +150,8 @@ int PNGU_DecodeTo4x4RGB565 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *b
int PNGU_DecodeTo4x4RGB5A3 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u8 default_alpha); int PNGU_DecodeTo4x4RGB5A3 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u8 default_alpha);
// Expands selected image into a 4x4 tiled RGBA8 buffer. You need to specify context, image dimensions, // Expands selected image into a 4x4 tiled RGBA8 buffer. You need to specify context, image dimensions,
// destination address and default alpha value, which is used if the source image doesn't have an alpha channel. // destination address.
int PNGU_DecodeTo4x4RGBA8 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u8 default_alpha); PNGU_u8 * PNGU_DecodeTo4x4RGBA8 (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, int * dstWidth, int * dstHeight, PNGU_u8 *dstPtr);
// Encodes an YCbYCr image in PNG format and stores it in the selected device or memory buffer. You need to // Encodes an YCbYCr image in PNG format and stores it in the selected device or memory buffer. You need to
// specify context, image dimensions, destination address and stride in pixels (stride = buffer width - image width). // specify context, image dimensions, destination address and stride in pixels (stride = buffer width - image width).