mirror of
https://github.com/wiidev/usbloadergx.git
synced 2024-11-16 16:29:18 +01:00
8bec876889
*Lot's of changes in image processing *Added use of libgd and ImageData class from WiiXplorer. No more crashes with corrupted images and no more restriction to images sizes that are devidable by 4 :). *Added a recource file manager for better access of all files/images for internal files and theme files. Some themes will have to adjust some filenames because we want to use the same filenames for themes and internal source files.
617 lines
13 KiB
C
617 lines
13 KiB
C
/***************************************************************************
|
|
* Copyright (C) 2010
|
|
* Dimok
|
|
*
|
|
* This software is provided 'as-is', without any express or implied
|
|
* warranty. In no event will the authors be held liable for any
|
|
* damages arising from the use of this software.
|
|
*
|
|
* Permission is granted to anyone to use this software for any
|
|
* purpose, including commercial applications, and to alter it and
|
|
* redistribute it freely, subject to the following restrictions:
|
|
*
|
|
* 1. The origin of this software must not be misrepresented; you
|
|
* must not claim that you wrote the original software. If you use
|
|
* this software in a product, an acknowledgment in the product
|
|
* documentation would be appreciated but is not required.
|
|
*
|
|
* 2. Altered source versions must be plainly marked as such, and
|
|
* must not be misrepresented as being the original software.
|
|
*
|
|
* 3. This notice may not be removed or altered from any source
|
|
* distribution.
|
|
*
|
|
* TextureConverter.cpp
|
|
*
|
|
* for WiiXplorer 2010
|
|
***************************************************************************/
|
|
#include <gccore.h>
|
|
#include <malloc.h>
|
|
#include "TextureConverter.h"
|
|
|
|
#define cut_bounds(x, min, max) ( (x < min) ? min : (x > max) ? max : x )
|
|
#define ALIGN(x) (((x) + 3) & ~3)
|
|
#define ALIGN32(x) (((x) + 31) & ~31)
|
|
#define coordsRGBA8(x, y, w) (((((y >> 2) * (w >> 2) + (x >> 2)) << 5) + ((y & 3) << 2) + (x & 3)) << 1)
|
|
#define datasizeRGBA8(w, h) ALIGN32(((w+3)>>2)*((h+3)>>2)*32*2)
|
|
|
|
#define MAXWIDTH 1024.0f
|
|
#define MAXHEIGHT 768.0f
|
|
|
|
static u16 avg(u16 w0, u16 w1, u16 c0, u16 c1)
|
|
{
|
|
u16 a0, a1;
|
|
u16 a, c;
|
|
|
|
a0 = c0 >> 11;
|
|
a1 = c1 >> 11;
|
|
a = (w0*a0 + w1*a1) / (w0 + w1);
|
|
c = a << 11;
|
|
|
|
a0 = (c0 >> 5) & 63;
|
|
a1 = (c1 >> 5) & 63;
|
|
a = (w0*a0 + w1*a1) / (w0 + w1);
|
|
c |= a << 5;
|
|
|
|
a0 = c0 & 31;
|
|
a1 = c1 & 31;
|
|
a = (w0*a0 + w1*a1) / (w0 + w1);
|
|
c |= a;
|
|
|
|
return c;
|
|
}
|
|
|
|
bool I4ToGD(const u8 * buffer, u32 width, u32 height, gdImagePtr * im)
|
|
{
|
|
u32 x, y;
|
|
u32 x1, y1;
|
|
u32 iv;
|
|
|
|
if(!buffer)
|
|
return false;
|
|
|
|
*im = gdImageCreateTrueColor(width, height);
|
|
if(*im == 0)
|
|
return false;
|
|
|
|
gdImageAlphaBlending(*im, 0);
|
|
gdImageSaveAlpha(*im, 1);
|
|
|
|
for(iv = 0, y1 = 0; y1 < height; y1 += 8)
|
|
{
|
|
for(x1 = 0; x1 < width; x1 += 8)
|
|
{
|
|
for(y = y1; y < (y1 + 8); y++)
|
|
{
|
|
for(x = x1; x < (x1 + 8); x += 2, iv++)
|
|
{
|
|
if((x >= width) || (y >= height))
|
|
continue;
|
|
|
|
u8 oldpixel = buffer[iv];
|
|
u8 b = (oldpixel >> 4) * 255 / 15;
|
|
u8 g = (oldpixel >> 4) * 255 / 15;
|
|
u8 r = (oldpixel >> 4) * 255 / 15;
|
|
u8 a = gdAlphaOpaque;
|
|
|
|
gdImageSetPixel(*im, x, y, gdTrueColorAlpha(r, g, b, a));
|
|
|
|
r = (oldpixel & 0xF) * 255 / 15;
|
|
g = (oldpixel & 0xF) * 255 / 15;
|
|
b = (oldpixel & 0xF) * 255 / 15;
|
|
a = gdAlphaOpaque;
|
|
|
|
gdImageSetPixel(*im, x+1, y, gdTrueColorAlpha(r, g, b, a));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool IA4ToGD(const u8 * buffer, u32 width, u32 height, gdImagePtr * im)
|
|
{
|
|
u32 x, y;
|
|
u32 x1, y1;
|
|
u32 iv;
|
|
|
|
if(!buffer)
|
|
return false;
|
|
|
|
*im = gdImageCreateTrueColor(width, height);
|
|
if(*im == 0)
|
|
return false;
|
|
|
|
gdImageAlphaBlending(*im, 0);
|
|
gdImageSaveAlpha(*im, 1);
|
|
|
|
for(iv = 0, y1 = 0; y1 < height; y1 += 4)
|
|
{
|
|
for(x1 = 0; x1 < width; x1 += 8)
|
|
{
|
|
for(y = y1; y < (y1 + 4); y++)
|
|
{
|
|
for(x = x1; x < (x1 + 8); x++)
|
|
{
|
|
u8 oldpixel = *(u8*)(buffer + (iv++));
|
|
oldpixel = ~oldpixel;
|
|
|
|
if((x >= width) || (y >= height))
|
|
continue;
|
|
|
|
u8 r = ((oldpixel & 0xF) * 255) / 15;
|
|
u8 g = ((oldpixel & 0xF) * 255) / 15;
|
|
u8 b = ((oldpixel & 0xF) * 255) / 15;
|
|
u8 a = ((oldpixel >> 4) * 255) / 15;
|
|
a = 127-127*a/255;
|
|
|
|
gdImageSetPixel(*im, x+1, y, gdTrueColorAlpha(r, g, b, a));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool I8ToGD(const u8 * buffer, u32 width, u32 height, gdImagePtr * im)
|
|
{
|
|
u32 x, y;
|
|
u32 x1, y1;
|
|
u32 iv;
|
|
|
|
if(!buffer)
|
|
return false;
|
|
|
|
*im = gdImageCreateTrueColor(width, height);
|
|
if(*im == 0)
|
|
return false;
|
|
|
|
gdImageAlphaBlending(*im, 0);
|
|
gdImageSaveAlpha(*im, 1);
|
|
|
|
for(iv = 0, y1 = 0; y1 < height; y1 += 4)
|
|
{
|
|
for(x1 = 0; x1 < width; x1 += 8)
|
|
{
|
|
for(y = y1; y < (y1 + 4); y++)
|
|
{
|
|
for(x = x1; x < (x1 + 8); x++)
|
|
{
|
|
u8 pixel = *(u8*)(buffer + ((iv++) * 1));
|
|
if((x >= width) || (y >= height))
|
|
continue;
|
|
|
|
u8 r = pixel;
|
|
u8 g = pixel;
|
|
u8 b = pixel;
|
|
u8 a = gdAlphaOpaque;
|
|
|
|
gdImageSetPixel(*im, x, y, gdTrueColorAlpha(r, g, b, a));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool IA8ToGD(const u8 * buffer, u32 width, u32 height, gdImagePtr * im)
|
|
{
|
|
u32 x, y;
|
|
u32 x1, y1;
|
|
u32 iv;
|
|
|
|
if(!buffer)
|
|
return false;
|
|
|
|
*im = gdImageCreateTrueColor(width, height);
|
|
if(*im == 0)
|
|
return false;
|
|
|
|
gdImageAlphaBlending(*im, 0);
|
|
gdImageSaveAlpha(*im, 1);
|
|
|
|
for(iv = 0, y1 = 0; y1 < height; y1 += 4)
|
|
{
|
|
for(x1 = 0; x1 < width; x1 += 4)
|
|
{
|
|
for(y = y1; y < (y1 + 4); y++)
|
|
{
|
|
for(x = x1; x < (x1 + 4); x++)
|
|
{
|
|
u16 oldpixel = *(u16*)(buffer + ((iv++) * 2));
|
|
|
|
if((x >= width) || (y >= height))
|
|
continue;
|
|
|
|
u8 r = oldpixel >> 8;
|
|
u8 g = oldpixel >> 8;
|
|
u8 b = oldpixel >> 8;
|
|
u8 a = oldpixel & 0xFF;
|
|
a = 127-127*a/255;
|
|
|
|
gdImageSetPixel(*im, x+1, y, gdTrueColorAlpha(r, g, b, a));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CMPToGD(const u8* buffer, u32 width, u32 height, gdImagePtr * im)
|
|
{
|
|
u32 x, y;
|
|
u8 r, g, b, a;
|
|
u16 raw;
|
|
u16 c[4];
|
|
int x0, x1, x2, y0, y1, y2, off;
|
|
int ww = (-(-(width) & -(8)));
|
|
int ix;
|
|
u32 px;
|
|
|
|
if(!buffer)
|
|
return false;
|
|
|
|
*im = gdImageCreateTrueColor(width, height);
|
|
if(*im == 0)
|
|
return false;
|
|
|
|
gdImageAlphaBlending(*im, 0);
|
|
gdImageSaveAlpha(*im, 1);
|
|
|
|
for (y = 0; y < height; y++)
|
|
{
|
|
for (x = 0; x < width; x++)
|
|
{
|
|
x0 = x & 3;
|
|
x1 = (x >> 2) & 1;
|
|
x2 = x >> 3;
|
|
y0 = y & 3;
|
|
y1 = (y >> 2) & 1;
|
|
y2 = y >> 3;
|
|
off = (8 * x1) + (16 * y1) + (32 * x2) + (4 * ww * y2);
|
|
|
|
c[0] = *(u16*)(buffer + off);
|
|
c[1] = *(u16*)(buffer + off + 2);
|
|
if (c[0] > c[1]) {
|
|
c[2] = avg(2, 1, c[0], c[1]);
|
|
c[3] = avg(1, 2, c[0], c[1]);
|
|
} else {
|
|
c[2] = avg(1, 1, c[0], c[1]);
|
|
c[3] = 0;
|
|
}
|
|
|
|
px = *(u32*)(buffer + off + 4);
|
|
ix = x0 + (4 * y0);
|
|
raw = c[(px >> (30 - (2 * ix))) & 3];
|
|
|
|
r = (raw >> 8) & 0xf8;
|
|
g = (raw >> 3) & 0xf8;
|
|
b = (raw << 3) & 0xf8;
|
|
a = gdAlphaOpaque;
|
|
|
|
gdImageSetPixel(*im, x, y, gdTrueColorAlpha(r, g, b, a));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool RGB565ToGD(const u8* buffer, u32 width, u32 height, gdImagePtr * im)
|
|
{
|
|
u32 x, y;
|
|
u32 x1, y1;
|
|
u32 iv;
|
|
|
|
if(!buffer)
|
|
return false;
|
|
|
|
*im = gdImageCreateTrueColor(width, height);
|
|
if(*im == 0)
|
|
return false;
|
|
|
|
gdImageAlphaBlending(*im, 0);
|
|
gdImageSaveAlpha(*im, 1);
|
|
|
|
for(iv = 0, y1 = 0; y1 < height; y1 += 4)
|
|
{
|
|
for(x1 = 0; x1 < width; x1 += 4)
|
|
{
|
|
for(y = y1; y < (y1 + 4); y++)
|
|
{
|
|
for(x = x1; x < (x1 + 4); x++)
|
|
{
|
|
if((x >= width) || (y >= height))
|
|
continue;
|
|
|
|
u16 pixel = *(u16*)(buffer + ((iv++) * 2));
|
|
|
|
u8 r = ((pixel >> 11) & 0x1F) << 3;
|
|
u8 g = ((pixel >> 5) & 0x3F) << 2;
|
|
u8 b = ((pixel >> 0) & 0x1F) << 3;
|
|
u8 a = gdAlphaOpaque;
|
|
|
|
gdImageSetPixel(*im, x, y, gdTrueColorAlpha(r, g, b, a));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool RGB565A3ToGD(const u8* buffer, u32 width, u32 height, gdImagePtr * im)
|
|
{
|
|
u32 x, y;
|
|
u32 x1, y1;
|
|
u32 iv;
|
|
|
|
if(!buffer)
|
|
return false;
|
|
|
|
*im = gdImageCreateTrueColor(width, height);
|
|
if(*im == 0)
|
|
return false;
|
|
|
|
gdImageAlphaBlending(*im, 0);
|
|
gdImageSaveAlpha(*im, 1);
|
|
|
|
for(iv = 0, y1 = 0; y1 < height; y1 += 4)
|
|
{
|
|
for(x1 = 0; x1 < width; x1 += 4)
|
|
{
|
|
for(y = y1; y < (y1 + 4); y++)
|
|
{
|
|
for(x = x1; x < (x1 + 4); x++)
|
|
{
|
|
u16 pixel = *(u16*)(buffer + ((iv++) * 2));
|
|
if((x >= width) || (y >= height))
|
|
continue;
|
|
|
|
if(pixel & (1 << 15))
|
|
{
|
|
// RGB5
|
|
u8 r = (((pixel >> 10) & 0x1F) * 255) / 31;
|
|
u8 g = (((pixel >> 5) & 0x1F) * 255) / 31;
|
|
u8 b = (((pixel >> 0) & 0x1F) * 255) / 31;
|
|
u8 a = gdAlphaOpaque;
|
|
|
|
gdImageSetPixel(*im, x, y, gdTrueColorAlpha(r, g, b, a));
|
|
}
|
|
else
|
|
{
|
|
// RGB4A3
|
|
u8 r = (((pixel >> 12) & 0xF) * 255) / 15;
|
|
u8 g = (((pixel >> 8) & 0xF) * 255) / 15;
|
|
u8 b = (((pixel >> 4) & 0xF) * 255) / 15;
|
|
u8 a = (((pixel >> 0) & 0x7) * 64) / 7;
|
|
a = 127-127*a/255;
|
|
|
|
gdImageSetPixel(*im, x, y, gdTrueColorAlpha(r, g, b, a));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool RGBA8ToGD(const u8* buffer, u32 width, u32 height, gdImagePtr * im)
|
|
{
|
|
u32 x, y, offset;
|
|
u8 r, g, b, a;
|
|
|
|
if(!buffer)
|
|
return false;
|
|
|
|
*im = gdImageCreateTrueColor(width, height);
|
|
if(*im == 0)
|
|
return false;
|
|
|
|
gdImageAlphaBlending(*im, 0);
|
|
gdImageSaveAlpha(*im, 1);
|
|
|
|
for(y = 0; y < height; y++)
|
|
{
|
|
for(x = 0; x < width; x++)
|
|
{
|
|
offset = coordsRGBA8(x, y, width);
|
|
a = *(buffer+offset);
|
|
r = *(buffer+offset+1);
|
|
g = *(buffer+offset+32);
|
|
b = *(buffer+offset+33);
|
|
|
|
a = 127-127*a/255;
|
|
|
|
gdImageSetPixel(*im, x, y, gdTrueColorAlpha(r, g, b, a));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool YCbYCrToGD(const u8* buffer, u32 width, u32 height, gdImagePtr * im)
|
|
{
|
|
u32 x, y, x1, YCbYCr;
|
|
int r, g, b;
|
|
u8 r1, g1, b1;
|
|
|
|
if(!buffer)
|
|
return false;
|
|
|
|
*im = gdImageCreateTrueColor(width, height);
|
|
if(*im == 0)
|
|
return false;
|
|
|
|
gdImageAlphaBlending(*im, 0);
|
|
gdImageSaveAlpha(*im, 1);
|
|
|
|
for(y = 0; y < height; y++)
|
|
{
|
|
for (x = 0, x1 = 0; x < (width / 2); x++, x1++)
|
|
{
|
|
YCbYCr = ((u32 *) buffer)[y*width/2+x];
|
|
|
|
u8 * val = (u8 *) &YCbYCr;
|
|
|
|
r = (int) (1.371f * (val[3] - 128));
|
|
g = (int) (- 0.698f * (val[3] - 128) - 0.336f * (val[1] - 128));
|
|
b = (int) (1.732f * (val[1] - 128));
|
|
|
|
r1 = cut_bounds(val[0] + r, 0, 255);
|
|
g1 = cut_bounds(val[0] + g, 0, 255);
|
|
b1 = cut_bounds(val[0] + b, 0, 255);
|
|
|
|
gdImageSetPixel(*im, x1, y, gdTrueColorAlpha(r1, g1, b1, gdAlphaOpaque));
|
|
x1++;
|
|
|
|
r1 = cut_bounds(val[2] + r, 0, 255);
|
|
g1 = cut_bounds(val[2] + g, 0, 255);
|
|
b1 = cut_bounds(val[2] + b, 0, 255);
|
|
gdImageSetPixel(*im, x1, y, gdTrueColorAlpha(r1, g1, b1, gdAlphaOpaque));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
u8 * GDImageToRGBA8(gdImagePtr * gdImg, int * w, int * h)
|
|
{
|
|
int width = gdImageSX(*gdImg);
|
|
int height = gdImageSY(*gdImg);
|
|
float scale = 1.0f;
|
|
int retries = 100; //shouldn't need that long but to be sure
|
|
|
|
gdImageAlphaBlending(*gdImg, 0);
|
|
gdImageSaveAlpha(*gdImg, 1);
|
|
|
|
while(width*scale > MAXWIDTH || height*scale > MAXHEIGHT)
|
|
{
|
|
if(width*scale > MAXWIDTH)
|
|
scale = MAXWIDTH/width;
|
|
if(height*scale > MAXHEIGHT)
|
|
scale = MAXHEIGHT/height;
|
|
|
|
retries--;
|
|
|
|
if(!retries)
|
|
{
|
|
while(width*scale > MAXWIDTH || height*scale > MAXHEIGHT)
|
|
scale -= 0.02;
|
|
break;
|
|
}
|
|
}
|
|
|
|
width = ALIGN((int) (width * scale));
|
|
height = ALIGN((int) (height * scale));
|
|
|
|
if(width != gdImageSX(*gdImg) || height != gdImageSY(*gdImg))
|
|
{
|
|
gdImagePtr dst = gdImageCreateTrueColor(width, height);
|
|
gdImageAlphaBlending(dst, 0);
|
|
gdImageSaveAlpha(dst, 1);
|
|
gdImageCopyResized(dst, *gdImg, 0, 0, 0, 0, width, height, gdImageSX(*gdImg), gdImageSY(*gdImg));
|
|
|
|
gdImageDestroy(*gdImg);
|
|
*gdImg = dst;
|
|
|
|
width = gdImageSX(*gdImg);
|
|
height = gdImageSY(*gdImg);
|
|
}
|
|
|
|
int len = datasizeRGBA8(width, height);
|
|
|
|
u8 * data = (u8 *) memalign(32, len);
|
|
if(!data)
|
|
return NULL;
|
|
|
|
u8 a;
|
|
u32 x, y, pixel, offset;
|
|
|
|
for(y = 0; y < height; ++y)
|
|
{
|
|
for(x = 0; x < width; ++x)
|
|
{
|
|
pixel = gdImageGetPixel(*gdImg, x, y);
|
|
|
|
a = 254 - 2*((u8)gdImageAlpha(*gdImg, pixel));
|
|
if(a == 254) a++;
|
|
|
|
offset = coordsRGBA8(x, y, width);
|
|
data[offset] = a;
|
|
data[offset+1] = (u8)gdImageRed(*gdImg, pixel);
|
|
data[offset+32] = (u8)gdImageGreen(*gdImg, pixel);
|
|
data[offset+33] = (u8)gdImageBlue(*gdImg, pixel);
|
|
}
|
|
}
|
|
|
|
DCFlushRange(data, len);
|
|
|
|
if(w)
|
|
*w = width;
|
|
if(h)
|
|
*h = height;
|
|
|
|
return data;
|
|
}
|
|
|
|
u8 * FlipRGBAImage(const u8 *src, u32 width, u32 height)
|
|
{
|
|
int x, y;
|
|
|
|
int len = datasizeRGBA8(width, height);
|
|
|
|
u8 * data = memalign(32, len);
|
|
if(!data)
|
|
return NULL;
|
|
|
|
for (y = 0; y < height; y++)
|
|
{
|
|
for (x = 0; x < width; x++)
|
|
{
|
|
u32 offset = coordsRGBA8(x, y, width);
|
|
u8 a = src[offset];
|
|
u8 r = src[offset+1];
|
|
u8 g = src[offset+32];
|
|
u8 b = src[offset+33];
|
|
|
|
u32 offset2 = coordsRGBA8((width-x-1), (height-y-1), width);
|
|
data[offset2] = a;
|
|
data[offset2+1] = r;
|
|
data[offset2+32] = g;
|
|
data[offset2+33] = b;
|
|
}
|
|
}
|
|
|
|
DCFlushRange(data, len);
|
|
|
|
return data;
|
|
}
|
|
|
|
u8 * RGB8ToRGBA8(const u8 *src, u32 width, u32 height)
|
|
{
|
|
u32 x, y, offset;
|
|
|
|
int len = datasizeRGBA8(width, height);
|
|
|
|
u8 * dst = (u8 *) memalign(32, len);
|
|
if(!dst)
|
|
return NULL;
|
|
|
|
for (y = 0; y < height; ++y)
|
|
{
|
|
for (x = 0; x < width; ++x)
|
|
{
|
|
offset = coordsRGBA8(x, y, width);
|
|
dst[offset] = 0xFF;
|
|
dst[offset+1] = src[(y*width+x)*3];
|
|
dst[offset+32] = src[(y*width+x)*3+1];
|
|
dst[offset+33] = src[(y*width+x)*3+2];
|
|
}
|
|
}
|
|
|
|
DCFlushRange(dst, len);
|
|
|
|
return dst;
|
|
}
|