diff --git a/.gitattributes b/.gitattributes index 1fce1d5..6ef9ba5 100644 --- a/.gitattributes +++ b/.gitattributes @@ -43,6 +43,8 @@ breft_editor/breft.pro -text breft_editor/main.cpp -text breft_editor/mainwindow.cpp -text breft_editor/mainwindow.h -text +breft_editor/texture.cpp -text +breft_editor/texture.h -text nandBinCheck/main.cpp -text nandBinCheck/nandBinCheck.pro -text nandBinCheck/readmii.txt -text diff --git a/breft_editor/breft.pro b/breft_editor/breft.pro index e7914bb..4293b82 100644 --- a/breft_editor/breft.pro +++ b/breft_editor/breft.pro @@ -10,8 +10,10 @@ SOURCES += main.cpp\ breft.cpp \ ../WiiQt/tools.cpp \ ../WiiQt/aes.c \ - ../WiiQt/sha1.c + ../WiiQt/sha1.c \ + texture.cpp HEADERS += mainwindow.h \ breft.h \ ../WiiQt/tools.h \ + texture.h diff --git a/breft_editor/mainwindow.cpp b/breft_editor/mainwindow.cpp index 20f38fa..32ee692 100644 --- a/breft_editor/mainwindow.cpp +++ b/breft_editor/mainwindow.cpp @@ -2,6 +2,7 @@ #include "../WiiQt/tools.h" #include "breft.h" +#include "texture.h" MainWindow::MainWindow( QWidget *parent ) : QMainWindow( parent) { @@ -32,6 +33,13 @@ void MainWindow::setupForms() plainTextEdit_log = new QPlainTextEdit; mainLayout->addWidget(plainTextEdit_log); + gv = new QGraphicsView( this ); + gv->setMaximumHeight( 300 ); + gv->setScene( &gs ); + gv->setAlignment( Qt::AlignLeft ); + gv->setRenderHint( QPainter::Antialiasing ); + mainLayout->addWidget( gv ); + Layout->addLayout(mainLayout, 0, 0); ShowMessage( tr("Done creating forms") ); @@ -90,6 +98,13 @@ void MainWindow::on_actionLoad_triggered() return; } + //clear the old images from the gui + foreach( QGraphicsItem *i, gs.items() ) + { + gs.removeItem( i ); + delete( i ); + } + QDataStream stream(data); header head; stream >> head; @@ -111,6 +126,11 @@ void MainWindow::on_actionLoad_triggered() section1 sec1; stream >> sec1; + quint16 spacing = 5; + quint32 x = spacing; + quint32 y = spacing; + quint32 rowHeight = 0; + for(quint32 ii=0; ii> len; @@ -129,6 +149,23 @@ void MainWindow::on_actionLoad_triggered() stream.readRawData( pic_data.data() , pic_head.size ); // SHOW TPL ON SCREEN + //if you have a format that uses palette data, you need to add that to the last arg here + QImage img = ConvertTextureToImage( pic_data, pic_head.width, pic_head.height, pic_head.format ); + if( img.isNull() )//error converting + continue; + + QGraphicsPixmapItem *item = new QGraphicsPixmapItem( QPixmap::fromImage( img ) ); + if( x + img.width() + spacing >= (quint32)gv->width() )//this row is filled up, skip down and start a new row + { + x = spacing; + y += spacing + rowHeight; + rowHeight = 0; + } + rowHeight = MAX( rowHeight, ((quint32)img.height()) ); + //qDebug() << "setting image" << ii << "at" << x << y; + item->setPos( x, y ); + gs.addItem( item ); + x += img.width() + spacing; // SAVE TPL TO FILE #if 0 diff --git a/breft_editor/mainwindow.h b/breft_editor/mainwindow.h index 7f5c0c6..5f77f34 100644 --- a/breft_editor/mainwindow.h +++ b/breft_editor/mainwindow.h @@ -23,6 +23,9 @@ private: QMenu* menuFile; QPlainTextEdit* plainTextEdit_log; + QGraphicsView *gv; + QGraphicsScene gs; + public slots: private slots: diff --git a/breft_editor/texture.cpp b/breft_editor/texture.cpp new file mode 100644 index 0000000..6b8203b --- /dev/null +++ b/breft_editor/texture.cpp @@ -0,0 +1,481 @@ +#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" << 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; +} diff --git a/breft_editor/texture.h b/breft_editor/texture.h new file mode 100644 index 0000000..1dd9195 --- /dev/null +++ b/breft_editor/texture.h @@ -0,0 +1,29 @@ +#ifndef TEXTURE_H +#define TEXTURE_H + +#include "../WiiQt/includes.h" + +#define TPL_FORMAT_I4 0 +#define TPL_FORMAT_I8 1 + +#define TPL_FORMAT_IA4 2 +#define TPL_FORMAT_IA8 3 + +#define TPL_FORMAT_RGB565 4 +#define TPL_FORMAT_RGB5A3 5 +#define TPL_FORMAT_RGBA8 6 + +#define TPL_FORMAT_CI4 8 +#define TPL_FORMAT_CI8 9 +#define TPL_FORMAT_CI14X2 10 + +#define TPL_FORMAT_CMP 14 + +#define TPL_MIN_FILTER_NORMAL 0x00010000 +#define TPL_MIN_FILTER_CLAMP 0x00000001 +#define TPL_MAG_FILTER_NORMAL 0x00010000 +#define TPL_MAG_FILTER_CLAMP 0x00000001 + +QImage ConvertTextureToImage( const QByteArray &ba, quint32 w, quint32 h, quint32 format, const QByteArray &palData = QByteArray() ); + +#endif // TEXTURE_H