mirror of
https://github.com/wiidev/usbloadergx.git
synced 2024-11-09 13:05:24 +01:00
7f2778e17f
*Some source optimizations *Increased warning output with -Wextra and fixed the compile warnings
618 lines
13 KiB
C
618 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;
|
|
int x, y;
|
|
u32 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)
|
|
{
|
|
u32 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;
|
|
}
|