mirror of
https://github.com/nitraiolo/CfgUSBLoader.git
synced 2025-01-09 01:40:43 +01:00
303 lines
7.8 KiB
C
303 lines
7.8 KiB
C
/********************************************************************************************
|
|
|
|
PNGU libwiigui & grrlib additions
|
|
|
|
********************************************************************************************/
|
|
#include <stdio.h>
|
|
#include <malloc.h>
|
|
#include "png.h"
|
|
#include "pngu.h"
|
|
#include "pngu_impl.h"
|
|
|
|
#define _SHIFTL(v, s, w) \
|
|
((PNGU_u32) (((PNGU_u32)(v) & ((0x01 << (w)) - 1)) << (s)))
|
|
#define _SHIFTR(v, s, w) \
|
|
((PNGU_u32)(((PNGU_u32)(v) >> (s)) & ((0x01 << (w)) - 1)))
|
|
|
|
|
|
// Coded by Tantric for WiiMC (http://www.wiimc.org)
|
|
static inline PNGU_u32 coordsRGBA8(PNGU_u32 x, PNGU_u32 y, PNGU_u32 w)
|
|
{
|
|
return ((((y >> 2) * (w >> 2) + (x >> 2)) << 5) + ((y & 3) << 2) + (x & 3)) << 1;
|
|
}
|
|
|
|
// Coded by Tantric for WiiMC (http://www.wiimc.org)
|
|
PNGU_u8 * PNGU_DecodeTo4x4RGBA8_EX (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, int * dstWidth, int * dstHeight, PNGU_u8 *dstPtr)
|
|
{
|
|
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;
|
|
|
|
if (pngu_decode (ctx, width, height, 0) != PNGU_OK)
|
|
return NULL;
|
|
|
|
int newWidth = width;
|
|
int newHeight = height;
|
|
|
|
if(width > 1024 || height > 1024)
|
|
{
|
|
float ratio = (float)width/(float)height;
|
|
|
|
if(ratio > 1)
|
|
{
|
|
newWidth = 1024;
|
|
newHeight = 1024/ratio;
|
|
}
|
|
else
|
|
{
|
|
newWidth = 1024*ratio;
|
|
newHeight = 1024;
|
|
}
|
|
xRatio = (int)((width<<16)/newWidth)+1;
|
|
yRatio = (int)((height<<16)/newHeight)+1;
|
|
}
|
|
|
|
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
|
|
dst = memalign (32, len);
|
|
|
|
if(!dst)
|
|
return NULL;
|
|
|
|
for (y = 0; y < padHeight; y++)
|
|
{
|
|
for (x = 0; x < padWidth; x++)
|
|
{
|
|
offset = coordsRGBA8(x, y, padWidth);
|
|
|
|
if(y >= newHeight || x >= newWidth)
|
|
{
|
|
dst[offset] = 0;
|
|
dst[offset+1] = 255;
|
|
dst[offset+32] = 255;
|
|
dst[offset+33] = 255;
|
|
}
|
|
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 (ctx->img_data);
|
|
free (ctx->row_pointers);
|
|
|
|
*dstWidth = padWidth;
|
|
*dstHeight = padHeight;
|
|
return dst;
|
|
}
|
|
|
|
// Coded by Tantric for libwiigui (http://code.google.com/p/libwiigui)
|
|
int PNGU_EncodeFromRGB (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride)
|
|
{
|
|
png_uint_32 rowbytes;
|
|
PNGU_u32 y;
|
|
|
|
// Erase from the context any readed info
|
|
pngu_free_info (ctx);
|
|
ctx->propRead = 0;
|
|
|
|
// Check if the user has selected a file to write the image
|
|
if (ctx->source == PNGU_SOURCE_BUFFER);
|
|
|
|
else if (ctx->source == PNGU_SOURCE_DEVICE)
|
|
{
|
|
// Open file
|
|
if (!(ctx->fd = fopen (ctx->filename, "wb")))
|
|
return PNGU_CANT_OPEN_FILE;
|
|
}
|
|
|
|
else
|
|
return PNGU_NO_FILE_SELECTED;
|
|
|
|
// Allocation of libpng structs
|
|
ctx->png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
|
if (!(ctx->png_ptr))
|
|
{
|
|
if (ctx->source == PNGU_SOURCE_DEVICE)
|
|
fclose (ctx->fd);
|
|
return PNGU_LIB_ERROR;
|
|
}
|
|
|
|
ctx->info_ptr = png_create_info_struct (ctx->png_ptr);
|
|
if (!(ctx->info_ptr))
|
|
{
|
|
png_destroy_write_struct (&(ctx->png_ptr), (png_infopp)NULL);
|
|
if (ctx->source == PNGU_SOURCE_DEVICE)
|
|
fclose (ctx->fd);
|
|
return PNGU_LIB_ERROR;
|
|
}
|
|
|
|
if (ctx->source == PNGU_SOURCE_BUFFER)
|
|
{
|
|
// Installation of our custom data writer function
|
|
ctx->cursor = 0;
|
|
png_set_write_fn (ctx->png_ptr, ctx, pngu_write_data_to_buffer, pngu_flush_data_to_buffer);
|
|
}
|
|
else if (ctx->source == PNGU_SOURCE_DEVICE)
|
|
{
|
|
// Default data writer uses function fwrite, so it needs to use our FILE*
|
|
png_init_io (ctx->png_ptr, ctx->fd);
|
|
}
|
|
|
|
// Setup output file properties
|
|
png_set_IHDR (ctx->png_ptr, ctx->info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB,
|
|
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
|
|
|
// Allocate memory to store the image in RGB format
|
|
rowbytes = width * 3;
|
|
if (rowbytes % 4)
|
|
rowbytes = ((rowbytes >>2) + 1) <<2; // Add extra padding so each row starts in a 4 byte boundary
|
|
|
|
ctx->img_data = malloc(rowbytes * height);
|
|
memset(ctx->img_data, 0, rowbytes * height);
|
|
|
|
if (!ctx->img_data)
|
|
{
|
|
png_destroy_write_struct (&(ctx->png_ptr), (png_infopp)NULL);
|
|
if (ctx->source == PNGU_SOURCE_DEVICE)
|
|
fclose (ctx->fd);
|
|
return PNGU_LIB_ERROR;
|
|
}
|
|
|
|
ctx->row_pointers = malloc (sizeof (png_bytep) * height);
|
|
memset(ctx->row_pointers, 0, sizeof (png_bytep) * height);
|
|
|
|
if (!ctx->row_pointers)
|
|
{
|
|
png_destroy_write_struct (&(ctx->png_ptr), (png_infopp)NULL);
|
|
if (ctx->source == PNGU_SOURCE_DEVICE)
|
|
fclose (ctx->fd);
|
|
return PNGU_LIB_ERROR;
|
|
}
|
|
|
|
for (y = 0; y < height; ++y)
|
|
{
|
|
ctx->row_pointers[y] = buffer + (y * rowbytes);
|
|
}
|
|
|
|
// Tell libpng where is our image data
|
|
png_set_rows (ctx->png_ptr, ctx->info_ptr, ctx->row_pointers);
|
|
|
|
// Write file header and image data
|
|
png_write_png (ctx->png_ptr, ctx->info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
|
|
|
|
// Tell libpng we have no more data to write
|
|
png_write_end (ctx->png_ptr, (png_infop) NULL);
|
|
|
|
// Free resources
|
|
free (ctx->img_data);
|
|
free (ctx->row_pointers);
|
|
png_destroy_write_struct (&(ctx->png_ptr), &(ctx->info_ptr));
|
|
if (ctx->source == PNGU_SOURCE_DEVICE)
|
|
fclose (ctx->fd);
|
|
|
|
// Success
|
|
return ctx->cursor;
|
|
}
|
|
|
|
// Coded by Tantric for libwiigui (http://code.google.com/p/libwiigui)
|
|
int PNGU_EncodeFromGXTexture (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, void *buffer, PNGU_u32 stride)
|
|
{
|
|
int res;
|
|
PNGU_u32 x,y, tmpy1, tmpy2, tmpyWid, tmpxy;
|
|
|
|
unsigned char * ptr = (unsigned char*)buffer;
|
|
unsigned char * tmpbuffer = (unsigned char *)malloc(width*height*3);
|
|
memset(tmpbuffer, 0, width*height*3);
|
|
png_uint_32 offset;
|
|
|
|
for(y=0; y < height; y++)
|
|
{
|
|
tmpy1 = y * 640*3;
|
|
tmpy2 = y%4 << 2;
|
|
tmpyWid = (((y >> 2)<<4)*width);
|
|
|
|
for(x=0; x < width; x++)
|
|
{
|
|
offset = tmpyWid + ((x >> 2)<<6) + ((tmpy2+ x%4 ) << 1);
|
|
tmpxy = x * 3 + tmpy1;
|
|
|
|
tmpbuffer[tmpxy ] = ptr[offset+1]; // R
|
|
tmpbuffer[tmpxy+1] = ptr[offset+32]; // G
|
|
tmpbuffer[tmpxy+2] = ptr[offset+33]; // B
|
|
}
|
|
}
|
|
|
|
res = PNGU_EncodeFromRGB (ctx, width, height, tmpbuffer, stride);
|
|
free(tmpbuffer);
|
|
return res;
|
|
}
|
|
|
|
// Coded by Crayon for GRRLIB (http://code.google.com/p/grrlib)
|
|
int PNGU_EncodeFromEFB (IMGCTX ctx, PNGU_u32 width, PNGU_u32 height, PNGU_u32 stride)
|
|
{
|
|
int res;
|
|
PNGU_u32 x,y, tmpy, tmpxy, regval, val;
|
|
unsigned char * tmpbuffer = (unsigned char *)malloc(width*height*3);
|
|
memset(tmpbuffer, 0, width*height*3);
|
|
|
|
for(y=0; y < height; y++)
|
|
{
|
|
tmpy = y * 640*3;
|
|
for(x=0; x < width; x++)
|
|
{
|
|
regval = 0xc8000000|(_SHIFTL(x,2,10));
|
|
regval = (regval&~0x3FF000)|(_SHIFTL(y,12,10));
|
|
val = *(PNGU_u32*)regval;
|
|
tmpxy = x * 3 + tmpy;
|
|
tmpbuffer[tmpxy ] = _SHIFTR(val,16,8); // R
|
|
tmpbuffer[tmpxy+1] = _SHIFTR(val,8,8); // G
|
|
tmpbuffer[tmpxy+2] = val&0xff; // B
|
|
}
|
|
}
|
|
|
|
res = PNGU_EncodeFromRGB (ctx, width, height, tmpbuffer, stride);
|
|
free(tmpbuffer);
|
|
return res;
|
|
}
|
|
|
|
|