diff options
Diffstat (limited to 'wii')
-rw-r--r-- | wii/filesystem.cpp | 9 | ||||
-rw-r--r-- | wii/filesystem.h | 1 | ||||
-rw-r--r-- | wii/gx.h | 35 | ||||
-rw-r--r-- | wii/texpalette.cpp | 284 | ||||
-rw-r--r-- | wii/texpalette.h | 37 |
5 files changed, 366 insertions, 0 deletions
diff --git a/wii/filesystem.cpp b/wii/filesystem.cpp index 014b693..ef2612d 100644 --- a/wii/filesystem.cpp +++ b/wii/filesystem.cpp @@ -139,3 +139,12 @@ bool WiiDirectory::addChild(WiiFSObject *obj) { return true; } +bool WiiDirectory::removeChild(WiiFSObject *obj) { + if (obj->parent != this) + return false; + + obj->unlinkFromParent(); + delete obj; + + return true; +} diff --git a/wii/filesystem.h b/wii/filesystem.h index 7527a7d..f9e2b54 100644 --- a/wii/filesystem.h +++ b/wii/filesystem.h @@ -67,6 +67,7 @@ public: WiiFSObject *findByName(QString name, bool recursive) const; WiiFSObject *resolvePath(QString path); bool addChild(WiiFSObject *obj); + bool removeChild(WiiFSObject *obj); }; diff --git a/wii/gx.h b/wii/gx.h new file mode 100644 index 0000000..85232f3 --- /dev/null +++ b/wii/gx.h @@ -0,0 +1,35 @@ +#ifndef WII_GX_H +#define WII_GX_H + +namespace GX { + enum TextureFormat { + I4 = 0, + I8 = 1, + IA4 = 2, + IA8 = 3, + RGB565 = 4, + RGB5A3 = 5, + RGBA8 = 6, + CI4 = 8, + CI8 = 9, + CI14X2 = 10, + CMPR = 14 + }; + + enum WrapType { + Clamp = 0, + Repeat = 1, + Mirror = 2 + }; + + enum TextureFilter { + Near = 0, + Linear = 1, + NearMipNear = 2, + LinMipNear = 3, + NearMipLin = 4, + LinMipLin = 5 + }; +}; + +#endif // WII_GX_H diff --git a/wii/texpalette.cpp b/wii/texpalette.cpp new file mode 100644 index 0000000..125454f --- /dev/null +++ b/wii/texpalette.cpp @@ -0,0 +1,284 @@ +#include "texpalette.h" + +WiiTexPalette::WiiTexPalette() { } + +WiiTexPalette::WiiTexPalette(QDataStream &stream) { + quint32 magic; + stream >> (quint32&)magic; + + if (magic != 0x20AF30) + qWarning() << "WiiTexPalette: tried to load a TPL without the proper magic"; + + quint32 textureCount, headerSize; + stream >> textureCount; + stream >> headerSize; + + qDebug() << textureCount << "textures"; + textures.resize(textureCount); + + for (int i = 0; i < textureCount; i++) { + quint32 textureOffs, paletteOffs; + stream >> textureOffs; + stream >> paletteOffs; + + int savePos = stream.device()->pos(); + + readTexture(stream, textureOffs, paletteOffs, textures[i]); + + stream.device()->seek(savePos); + } +} + +static const int TexelWidths[] = { + 8, 8, 8, 4, 4, 4, 4, -1, 8, 8, 4 +}; + +static const int TexelHeights[] = { + 8, 4, 4, 4, 4, 4, 4, -1, 8, 4, 4 +}; + +static const int BitsPerPixel[] = { + 4, 8, 8, 16, 16, 16, 32, -1, 8, 16 +}; + +// This bit shamelessly stolen from Dolphin, but it didn't QUITE work right... +/*inline uchar _3to8(uchar v) { return (v << 5) | (v << 2) | (v >> 1); } +inline uchar _4to8(uchar v) { return (v << 4) | v; } +inline uchar _5to8(uchar v) { return (v << 3) | (v << 2); } +inline uchar _6to8(uchar v) { return (v << 2) | (v >> 4); }*/ +inline uchar _3to8(uchar v) { return (v << 5); } +inline uchar _4to8(uchar v) { return (v << 4); } +inline uchar _5to8(uchar v) { return (v << 3); } +inline uchar _6to8(uchar v) { return (v << 2); } + +void WiiTexPalette::readTexture(QDataStream &in, int textureOffs, int paletteOffs, WiiTPLTexture &tex) { + in.device()->seek(textureOffs); + + quint16 width, height; + quint32 rawFormat, dataOffs, rawWrapS, rawWrapT, rawMinFilter, rawMagFilter; + quint8 rawEdgeLODEnable; + + in >> height; + in >> width; + in >> rawFormat; + in >> dataOffs; + in >> rawWrapS; + in >> rawWrapT; + in >> rawMinFilter; + in >> rawMagFilter; + in >> tex.lodBias; + in >> rawEdgeLODEnable; + in >> tex.minLOD; + in >> tex.maxLOD; + + tex.format = (GX::TextureFormat)rawFormat; + tex.wrapS = (GX::WrapType)rawWrapS; + tex.wrapT = (GX::WrapType)rawWrapT; + tex.minFilter = (GX::TextureFilter)rawMinFilter; + tex.magFilter = (GX::TextureFilter)rawMagFilter; + tex.edgeLODEnable = (rawEdgeLODEnable > 0); + + bool formatValid = ( + (rawFormat <= 6) || + (rawFormat >= 8 && rawFormat <= 10) || + rawFormat == 14); + + if (!formatValid) { + qWarning("unknown texture format (%d)", rawFormat); + return; + } + + tex.image = QImage(width, height, QImage::Format_ARGB32); + + int texelWidth = TexelWidths[rawFormat]; + int texelHeight = TexelHeights[rawFormat]; + int bpp = BitsPerPixel[rawFormat]; + + // how much needs to be added on to get this texture aligned? + int padWidth = width % texelWidth; + int padHeight = height % texelHeight; + + // get the fully padded width + int paddedWidth = width + ((padWidth > 0) ? (texelWidth - padWidth) : 0); + int paddedHeight = height + ((padHeight > 0) ? (texelHeight - padHeight) : 0); + + int texDataSize = (paddedWidth * paddedHeight * bpp) / 8; + + // decode the thing + in.device()->seek(dataOffs); + + QImage &image = tex.image; + + switch (tex.format) { + case GX::I4: + { + for (int texelY = 0; texelY < paddedHeight; texelY += 8) { + for (int texelX = 0; texelX < paddedWidth; texelX += 8) { + for (int y = texelY; y < (texelY + 8); y++) { + QRgb *scanline = (QRgb*)image.scanLine(y); + + for (int x = texelX; x < (texelX + 8); x += 2) { + quint8 v; + in >> v; + + if (x < width && y < height) { + int _v = _4to8(v >> 4); + scanline[x] = qRgb(_v, _v, _v); + } + if ((x+1) < width && y < height) { + int _v = _4to8(v & 0xF); + scanline[x+1] = qRgb(_v, _v, _v); + } + } + } + } + } + } + break; + case GX::I8: + { + for (int texelY = 0; texelY < paddedHeight; texelY += 4) { + for (int texelX = 0; texelX < paddedWidth; texelX += 8) { + for (int y = texelY; y < (texelY + 4); y++) { + QRgb *scanline = (QRgb*)image.scanLine(y); + + for (int x = texelX; x < (texelX + 8); x++) { + quint8 v; + in >> v; + + if (x < width && y < height) + scanline[x] = qRgb(v, v, v); + } + } + } + } + } + break; + case GX::IA4: + { + for (int texelY = 0; texelY < paddedHeight; texelY += 4) { + for (int texelX = 0; texelX < paddedWidth; texelX += 8) { + for (int y = texelY; y < (texelY + 4); y++) { + QRgb *scanline = (QRgb*)image.scanLine(y); + + for (int x = texelX; x < (texelX + 8); x++) { + quint8 v; + in >> v; + + if (x < width && y < height) { + int _i = _4to8(v & 0xF); + int _a = _4to8(v >> 4); + scanline[x] = qRgba(_i, _i, _i, _a); + } + } + } + } + } + } + break; + case GX::IA8: + { + for (int texelY = 0; texelY < paddedHeight; texelY += 4) { + for (int texelX = 0; texelX < paddedWidth; texelX += 4) { + for (int y = texelY; y < (texelY + 4); y++) { + QRgb *scanline = (QRgb*)image.scanLine(y); + + for (int x = texelX; x < (texelX + 4); x++) { + quint16 v; + in >> v; + + if (x < width && y < height) + scanline[x] = qRgba((v&0xFF00)>>8, (v&0xFF00)>>8, (v&0xFF00)>>8, v&0xFF); + } + } + } + } + } + break; + case GX::RGB565: + { + for (int texelY = 0; texelY < paddedHeight; texelY += 4) { + for (int texelX = 0; texelX < paddedWidth; texelX += 4) { + for (int y = texelY; y < (texelY + 4); y++) { + QRgb *scanline = (QRgb*)image.scanLine(y); + + for (int x = texelX; x < (texelX + 4); x++) { + quint16 v; + in >> v; + + if (x < width && y < height) { + scanline[x] = qRgb( + _5to8((v >> 11) & 0x1F), + _6to8((v >> 5) & 0x3F), + _5to8(v & 0x1F)); + } + } + } + } + } + } + break; + case GX::RGB5A3: + { + for (int texelY = 0; texelY < paddedHeight; texelY += 4) { + for (int texelX = 0; texelX < paddedWidth; texelX += 4) { + for (int y = texelY; y < (texelY + 4); y++) { + QRgb *scanline = (QRgb*)image.scanLine(y); + + for (int x = texelX; x < (texelX + 4); x++) { + quint16 v; + in >> v; + + if (x < width && y < height) { + if (v & 0x8000) { + scanline[x] = qRgb( + _5to8((v >> 10) & 0x1F), + _5to8((v >> 5) & 0x1F), + _5to8(v & 0x1F)); + } else { + scanline[x] = qRgba( + _4to8((v >> 8) & 0xF), + _4to8((v >> 4) & 0xF), + _4to8(v & 0xF), + _3to8((v >> 12) & 0x7)); + } + } + } + } + } + } + } + break; + case GX::RGBA8: + { + QByteArray texel1(32, 0), texel2(32, 0); + + for (int texelY = 0; texelY < paddedHeight; texelY += 4) { + for (int texelX = 0; texelX < paddedWidth; texelX += 4) { + in.readRawData(texel1.data(), 32); + in.readRawData(texel2.data(), 32); + + int offs = 0; + + for (int y = texelY; y < (texelY + 4); y++) { + QRgb *scanline = (QRgb*)image.scanLine(y); + + for (int x = texelX; x < (texelX + 4); x++) { + if (x < width && y < height) { + scanline[x] = qRgba(texel1.at(offs+1), texel2.at(offs), texel2.at(offs+1), texel1.at(offs)); + } + offs += 2; + } + } + } + } + } + break; + default: + qWarning("unhandled texture format (%d)", rawFormat); + } +} + + +void WiiTexPalette::writeToDataStream(QDataStream &out) const { +} diff --git a/wii/texpalette.h b/wii/texpalette.h new file mode 100644 index 0000000..ff6a4bd --- /dev/null +++ b/wii/texpalette.h @@ -0,0 +1,37 @@ +#ifndef WIITEXPALETTE_H +#define WIITEXPALETTE_H + +#include "common.h" +#include "gx.h" +#include <QImage> + +class WiiTPLTexture { +public: + // TODO: palette stuff + + QImage image; + GX::TextureFormat format; + + GX::WrapType wrapS, wrapT; + + GX::TextureFilter minFilter, magFilter; + + float lodBias; + bool edgeLODEnable; + quint8 minLOD, maxLOD; +}; + +class WiiTexPalette { +public: + WiiTexPalette(); + WiiTexPalette(QDataStream &stream); + + void writeToDataStream(QDataStream &out) const; + + QVector<WiiTPLTexture> textures; + +private: + void readTexture(QDataStream &in, int textureOffs, int paletteOffs, WiiTPLTexture &tex); +}; + +#endif // WIITEXPALETTE_H |