wiiqt6/breft_editor/texture.cpp
2024-07-20 01:13:16 +02:00

482 lines
13 KiB
C++

#include "texture.h"
#define align(x, y) ((x) + ((x) % (y)))
#define round_up(x,n) (-(-(x) & -(n)))
int TPL_ConvertRGB565ToBitMap( quint8* tplbuf, quint8** bitmapdata, quint32 width, quint32 height )
{
quint32 x, y;
quint32 x1, y1;
quint32 iv;
*bitmapdata = (quint8*)calloc(width * height, 4);
if(*bitmapdata == NULL)
return -1;
quint32 outsz = width * height * 4;
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++) {
quint16 oldpixel = *(quint16*)(tplbuf + ((iv++) * 2));
if((x >= width) || (y >= height))
continue;
oldpixel = qFromBigEndian(oldpixel);
//quint8 b = ((oldpixel >> 11) & 0x1F) << 3;
//quint8 g = ((oldpixel >> 5) & 0x3F) << 2;
//quint8 r = ((oldpixel >> 0) & 0x1F) << 3;
quint8 b = ((oldpixel >> 11) & 0x1F) *( 255/0x1f );
quint8 g = ((oldpixel >> 5) & 0x3F) *( 255/0x3f );
quint8 r = ((oldpixel >> 0) & 0x1F) *( 255/0x1f );
quint8 a = 255;
quint32 rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24);
(*(quint32**)bitmapdata)[x + (y * width)] = rgba;
}
}
}
}
return outsz;
}
int TPL_ConvertRGBA8ToBitMap(quint8* tplbuf, quint8** bitmapdata, quint32 width, quint32 height)
{
//qDebug() << "TPL_ConvertRGBA8ToBitMap";
quint32 x, y;
quint32 x1, y1;
*bitmapdata = (quint8*)calloc(width * height, 4);
if(*bitmapdata == NULL)
return -1;
quint32 outsz = width * height * 4;
quint8 r, g, b, a;
int i, iv = 0;
for(y = 0; y < height; y += 4) {
for(x = 0; x < width; x += 4) {
for(i = 0; i < 2; i++) {
for(y1 = y; y1 < (y + 4); y1++) {
for(x1 = x; x1 < (x + 4); x1++) {
quint16 oldpixel = qFromBigEndian( *(quint16*)(tplbuf + ((iv++) * 2)) );
if((x1 >= width) || (y1 >= height))
continue;
if(i == 0) {
a = (oldpixel >> 8) & 0xFF;
r = (oldpixel >> 0) & 0xFF;
(*(quint32**)bitmapdata)[x1 + (y1 * width)] |= (quint32)((r << 16) | (a << 24));
} else {
g = (oldpixel >> 8) & 0xFF;
b = (oldpixel >> 0) & 0xFF;
(*(quint32**)bitmapdata)[x1 + (y1 * width)] |= (quint32)((g << 8) | (b << 0));
}
}
}
}
}
}
return outsz;
}
int TPL_ConvertRGB5A3ToBitMap(quint8* tplbuf, quint8** bitmapdata, quint32 width, quint32 height)
{
quint32 x, y;
quint32 x1, y1;
quint32 iv;
*bitmapdata = (quint8*)calloc(width * height, 4);
if(*bitmapdata == NULL)
return -1;
quint32 outsz = width * height * 4;
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++) {
quint16 oldpixel = *(quint16*)(tplbuf + ((iv++) * 2));
if((x >= width) || (y >= height))
continue;
oldpixel = qFromBigEndian(oldpixel);
if(oldpixel & (1 << 15)) {
// RGB5
quint8 b = (((oldpixel >> 10) & 0x1F) * 255) / 31;
quint8 g = (((oldpixel >> 5) & 0x1F) * 255) / 31;
quint8 r = (((oldpixel >> 0) & 0x1F) * 255) / 31;
quint8 a = 255;
quint32 rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24);
(*(quint32**)bitmapdata)[x + (y * width)] = rgba;
}else{
// RGB4A3
quint8 a = (((oldpixel >> 12) & 0x7) * 255) / 7;
quint8 b = (((oldpixel >> 8) & 0xF) * 255) / 15;
quint8 g = (((oldpixel >> 4) & 0xF) * 255) / 15;
quint8 r = (((oldpixel >> 0) & 0xF) * 255) / 15;
quint32 rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24);
(*(quint32**)bitmapdata)[x + (y * width)] = rgba;
}
}
}
}
}
return outsz;
}
int TPL_ConvertI4ToBitMap(quint8* tplbuf, quint8** bitmapdata, quint32 width, quint32 height)
{
quint32 x, y;
quint32 x1, y1;
quint32 iv;
*bitmapdata = (quint8*)calloc(width * height, 8);
if(*bitmapdata == NULL)
return -1;
quint32 outsz = align(width, 4) * align(height, 4) * 4;
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;
quint8 oldpixel = tplbuf[ iv ];
quint8 b = (oldpixel >> 4) * 255 / 15;
quint8 g = (oldpixel >> 4) * 255 / 15;
quint8 r = (oldpixel >> 4) * 255 / 15;
quint8 a = 255;
quint32 rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24);
(*(quint32**)bitmapdata)[x + (y * width)] = rgba;
b = (oldpixel & 0xF) * 255 / 15;
g = (oldpixel & 0xF) * 255 / 15;
r = (oldpixel & 0xF) * 255 / 15;
a = 255;
rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24);
(*(quint32**)bitmapdata)[x + 1 + (y * width)] = rgba;
}
}
}
}
return outsz;
}
int TPL_ConvertIA4ToBitMap(quint8* tplbuf, quint8** bitmapdata, quint32 width, quint32 height)
{
quint32 x, y;
quint32 x1, y1;
quint32 iv;
*bitmapdata = (quint8*)calloc(width * height, 4);
if(*bitmapdata == NULL)
return -1;
quint32 outsz = width * height * 4;
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++) {
quint8 oldpixel = *(quint8*)(tplbuf + ((iv++)));
if((x >= width) || (y >= height))
continue;
quint8 b = ((oldpixel & 0xF) * 255) / 15;
quint8 g = ((oldpixel & 0xF) * 255) / 15;
quint8 r = ((oldpixel & 0xF) * 255) / 15;
quint8 a = ((oldpixel >> 4) * 255) / 15;
quint32 rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24);
(*(quint32**)bitmapdata)[x + (y * width)] = rgba;
}
}
}
}
return outsz;
}
int TPL_ConvertI8ToBitMap(quint8* tplbuf, quint8** bitmapdata, quint32 width, quint32 height)
{
quint32 x, y;
quint32 x1, y1;
quint32 iv;
*bitmapdata = (quint8*)calloc(width * height, 4);
if(*bitmapdata == NULL)
return -1;
quint32 outsz = width * height * 4;
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++) {
quint8 oldpixel = *(quint8*)(tplbuf + ((iv++) * 1));
if((x >= width) || (y >= height))
continue;
quint8 b = oldpixel;
quint8 g = oldpixel;
quint8 r = oldpixel;
quint8 a = 255;
quint32 rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24);
(*(quint32**)bitmapdata)[x + (y * width)] = rgba;
}
}
}
}
return outsz;
}
int TPL_ConvertCI8ToBitMap(quint8* tplbuf, quint8** bitmapdata, quint32 width, quint32 height, const QByteArray &palData )
{
//qDebug() << "TPL_ConvertCI8ToBitMap";
//hexdump( palData );
//hexdump( (const void*)tplbuf, 0x100 );
quint32* output = (quint32*)calloc( width * height, 4 );
if( *bitmapdata == NULL )
return -1;
if( ( palData.size() / 4 ) > 256 )
qWarning() << "TPL_ConvertCI8ToBitMap -> quint8 is too small to hold enough data for this pallatte";
quint32 outsz = width * height * 4;
quint32* palette = (quint32*)palData.constData();
int i = 0;
for( quint32 y = 0; y < height; y += 4 )
{
for (quint32 x = 0; x < width; x += 8)
{
for (quint32 y1 = y; y1 < y + 4; y1++)
{
for (quint32 x1 = x; x1 < x + 8; x1++)
{
quint8 pixel = tplbuf[ i++ ];
if( y1 >= height || x1 >= width )
continue;
output[ y1 * width + x1 ] = palette[ pixel ];
}
}
}
}
*bitmapdata = (quint8*)output;
return outsz;
}
int TPL_ConvertCI4ToBitMap(quint8* tplbuf, quint8** bitmapdata, quint32 width, quint32 height, const QByteArray &palData )
{
//qDebug() << "TPL_ConvertCI4ToBitMap";
quint32* output = (quint32*)calloc(width * height, 4);
if( output == NULL )
return -1;
if( ( palData.size() / 4 ) > 256 )
qWarning() << "TPL_ConvertCI4ToBitMap -> quint8 is too small to hold enough data for this pallatte";
quint32 max = width * height;
quint32 outsz = width * height;
quint32* palette = (quint32*)palData.constData();
int i = 0;
for( quint32 y = 0; y < height; y += 8 )
{
for( quint32 x = 0; x < width; x += 8)
{
for( quint32 y1 = y; y1 < y + 8; y1++)
{
for( quint32 x1 = x; x1 < x + 8; x1 += 2)
{
quint8 pixel = tplbuf[ i++ ];
if( y1 >= height || x1 >= width )
continue;
output[ y1 * width + x1 ] = palette[ pixel >> 4 ];
if( y1 * width + x1 + 1 < max )
output[ y1 * width + x1 + 1 ] = palette[ pixel & 0x0F ];
}
}
}
}
*bitmapdata = (quint8*)output;
return outsz;
}
int TPL_ConvertCI14x2ToBitMap(quint8* tplbuf, quint8** bitmapdata, quint32 width, quint32 height, const QByteArray &palData )
{
//qDebug() << "TPL_ConvertCI14x2ToBitMap";
//hexdump( palData );
//hexdump( (const void*)tplbuf, 0x100 );
quint32* output = (quint32*)calloc(width * height, 4);
if( output == NULL )
return -1;
quint32 outsz = width * height;
quint32* palette = (quint32*)palData.constData();
quint16* tplStuff = (quint16*)tplbuf;
int i = 0;
for( quint32 y = 0; y < height; y += 4 )
{
for( quint32 x = 0; x < width; x += 4)
{
for( quint32 y1 = y; y1 < y + 4; y1++)
{
for( quint32 x1 = x; x1 < x + 4; x1++)
{
quint16 pixel = qFromBigEndian( tplStuff[ i++ ] );
if( y1 >= height || x1 >= width )
continue;
output[ y1 * width + x1 ] = palette[ pixel & 0x3FFF ];
}
}
}
}
*bitmapdata = (quint8*)output;
return outsz;
}
int TPL_ConvertIA8ToBitMap(quint8* tplbuf, quint8** bitmapdata, quint32 width, quint32 height)
{
quint32 x, y;
quint32 x1, y1;
quint32 iv;
*bitmapdata = ( quint8* )calloc( width * height, 4 );
if(*bitmapdata == NULL)
return -1;
quint32 outsz = width * height * 4;
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++) {
quint16 oldpixel = *(quint16*)(tplbuf + ((iv++) * 2));
if((x >= width) || (y >= height))
continue;
quint8 b = oldpixel >> 8;
quint8 g = oldpixel >> 8;
quint8 r = oldpixel >> 8;
quint8 a = oldpixel & 0xFF;
quint32 rgba = (r << 0) | (g << 8) | (b << 16) | (a << 24);
(*(quint32**)bitmapdata)[x + (y * width)] = rgba;
}
}
}
}
return outsz;
}
static quint16 avg(quint16 w0, quint16 w1, quint16 c0, quint16 c1)
{
quint16 a0, a1;
quint16 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;
}
int TPL_ConvertCMPToBitMap(quint8* tplbuf, quint8** bitmapdata, quint32 width, quint32 height)
{
quint32 x, y;
quint32 iv = 0;
*bitmapdata = ( quint8* )calloc( width * height, 4 );
if(*bitmapdata == NULL)
return -1;
quint32 outsz = width * height * 4;
for (y = 0; y < height; y++)
for (x = 0; x < width; x++) {
quint8 pix[4];
quint16 raw;
quint16 c[4];
int x0, x1, x2, y0, y1, y2, off;
int ww = round_up(width, 8);
int ix;
quint32 px;
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] = qFromBigEndian(*(quint16*)(tplbuf + off));
c[1] = qFromBigEndian(*(quint16*)(tplbuf + 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 = qFromBigEndian(*(quint32*)(tplbuf + off + 4));
ix = x0 + (4 * y0);
raw = c[(px >> (30 - (2 * ix))) & 3];
pix[0] = (raw >> 8) & 0xf8;
pix[1] = (raw >> 3) & 0xf8;
pix[2] = (raw << 3) & 0xf8;
pix[3] = 0xff;
if (((px >> (30 - (2 * ix))) & 0x03) == 3 && c[0] <= c[1])
pix[3] = 0x00;
quint32 rgba = (pix[0] << 16) | (pix[1] << 8) | (pix[2] << 0) | (pix[3] << 24);
(*(quint32**)bitmapdata)[iv++] = rgba;
}
return outsz;
}
QImage ConvertTextureToImage( const QByteArray &ba, quint32 w, quint32 h, quint32 format, const QByteArray &palData )
{
quint8* bitmapdata = NULL;//this will hold the converted image
int ret = 0;
switch( format )
{
case TPL_FORMAT_RGB565:
ret = TPL_ConvertRGB565ToBitMap( (quint8*)ba.constData(), &bitmapdata, w, h );
break;
case TPL_FORMAT_RGB5A3:
ret = TPL_ConvertRGB5A3ToBitMap( (quint8*)ba.constData(), &bitmapdata, w, h );
break;
case TPL_FORMAT_RGBA8:
ret = TPL_ConvertRGBA8ToBitMap( (quint8*)ba.constData(), &bitmapdata, w, h );
break;
case TPL_FORMAT_I4:
ret = TPL_ConvertI4ToBitMap( (quint8*)ba.constData(), &bitmapdata, w, h );
break;
case TPL_FORMAT_I8:
ret = TPL_ConvertI8ToBitMap( (quint8*)ba.constData(), &bitmapdata, w, h );
break;
case TPL_FORMAT_IA4:
ret = TPL_ConvertIA4ToBitMap( (quint8*)ba.constData(), &bitmapdata, w, h );
break;
case TPL_FORMAT_IA8:
ret = TPL_ConvertIA8ToBitMap( (quint8*)ba.constData(), &bitmapdata, w, h );
break;
case TPL_FORMAT_CI8:
ret = TPL_ConvertCI8ToBitMap( (quint8*)ba.constData(), &bitmapdata, w, h, palData );
break;
case TPL_FORMAT_CI4:
ret = TPL_ConvertCI4ToBitMap( (quint8*)ba.constData(), &bitmapdata, w, h, palData );
break;
case TPL_FORMAT_CI14X2:
ret = TPL_ConvertCI14x2ToBitMap( (quint8*)ba.constData(), &bitmapdata, w, h, palData );
break;
case TPL_FORMAT_CMP:
ret = TPL_ConvertCMPToBitMap( (quint8*)ba.constData(), &bitmapdata, w, h );
break;
default:
qWarning() << "ConvertTextureToImage -> Unsupported format" << Qt::hex << format;
return QImage();
break;
}
if( !ret )//should only happen if calloc fails
{
qWarning() << "ConvertTextureToImage-> error converting image";
return QImage();
}
QImage im = QImage( (const uchar*)bitmapdata, w, h, QImage::Format_ARGB32 );
QImage im2 = im.copy( im.rect() );//make a copy of the image so the "free" wont delete any data we still want
free( bitmapdata );
return im2;
}