summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--LayoutStudio.pro15
-rw-r--r--README.markdown16
-rw-r--r--layoutgl/texturemanager.cpp31
-rw-r--r--layoutgl/texturemanager.h33
-rw-r--r--layoutgl/widget.cpp389
-rw-r--r--layoutgl/widget.h53
-rw-r--r--lsmainwindow.cpp217
-rw-r--r--lsmainwindow.h40
-rw-r--r--lsmainwindow.ui24
-rw-r--r--lspackagemodel.cpp150
-rw-r--r--lspackagemodel.h42
-rw-r--r--lyt/archivepackage.cpp129
-rw-r--r--lyt/archivepackage.h30
-rw-r--r--lyt/bounding.cpp1
-rw-r--r--lyt/directorypackage.cpp99
-rw-r--r--lyt/directorypackage.h33
-rw-r--r--lyt/layout.h2
-rw-r--r--lyt/packagebase.cpp24
-rw-r--r--lyt/packagebase.h62
-rw-r--r--lyt/pane.cpp33
-rw-r--r--lyt/pane.h20
-rw-r--r--lyt/picture.cpp1
-rw-r--r--lyt/textbox.cpp1
-rw-r--r--lyt/window.cpp1
-rw-r--r--main.cpp41
-rw-r--r--wii/filesystem.cpp9
-rw-r--r--wii/filesystem.h1
-rw-r--r--wii/gx.h35
-rw-r--r--wii/texpalette.cpp284
-rw-r--r--wii/texpalette.h37
30 files changed, 1625 insertions, 228 deletions
diff --git a/LayoutStudio.pro b/LayoutStudio.pro
index 49f2d40..815dcdc 100644
--- a/LayoutStudio.pro
+++ b/LayoutStudio.pro
@@ -32,7 +32,11 @@ SOURCES += main.cpp \
wii/archiveu8.cpp \
wii/filesystem.cpp \
lyt/archivepackage.cpp \
- wii/stringtablebuilder.cpp
+ wii/stringtablebuilder.cpp \
+ layoutgl/texturemanager.cpp \
+ layoutgl/widget.cpp \
+ wii/texpalette.cpp \
+ lspackagemodel.cpp
HEADERS += lsmainwindow.h \
lsglobals.h \
lyt/packagebase.h \
@@ -62,8 +66,13 @@ HEADERS += lsmainwindow.h \
wii/filesystem.h \
lyt/archivepackage.h \
wii/stringtablebuilder.h \
- lyt/materials/materialcontainer.h
-FORMS += lsmainwindow.ui
+ lyt/materials/materialcontainer.h \
+ layoutgl/texturemanager.h \
+ layoutgl/widget.h \
+ wii/texpalette.h \
+ wii/gx.h \
+ lspackagemodel.h
+FORMS +=
RESOURCES += resources.qrc
OTHER_FILES += \
diff --git a/README.markdown b/README.markdown
index f41ca8a..d12c1c1 100644
--- a/README.markdown
+++ b/README.markdown
@@ -7,10 +7,18 @@ functional, real-time previews.
The application is written in C++ (with heavy usage of Nokia's Qt toolkit).
-The graphical rendering will eventually use OpenGL, and build on the excellent
-GX GPU emulation in the [Dolphin][dol] GameCube/Wii emulator.
+I originally started this project in 2010, and wrote all the code required to
+read and write layout files, but then lost interest because I didn't know where
+to start with the rendering code.
-[dol]: http://code.google.com/p/dolphin-emu/
+In July 2012, I've taken it back up and changed my focus. Instead of trying to
+render layouts exactly the same way as they appear on the Wii, I'm going to
+forget about all the fancy TEV stuff and just create something that's usable for
+designing and editing layouts. I've been informed that this is actually how
+Nintendo's official tool works.
+
+Of course, I'd still love to add accurate rendering to this some day, but it's
+not going to be my #1 goal any more. Having a working editor is more important.
### Implemented Features ###
@@ -22,7 +30,7 @@ GX GPU emulation in the [Dolphin][dol] GameCube/Wii emulator.
### Planned Features ###
- BRLAN reading/writing
- Graphical interface for editing layouts and animations
-- Rendering of layouts using OpenGL and Dolphin's GX emulation
+- Rendering of layouts using OpenGL
- BRFNT support
diff --git a/layoutgl/texturemanager.cpp b/layoutgl/texturemanager.cpp
new file mode 100644
index 0000000..80a8186
--- /dev/null
+++ b/layoutgl/texturemanager.cpp
@@ -0,0 +1,31 @@
+#include "texturemanager.h"
+
+LGLTextureManager::LGLTextureManager() {
+}
+
+void LGLTextureManager::setup(QGLWidget *gl, const LYTLayout *layout) {
+ // TODO: code to cleanup previous stuff
+
+ //m_gl = gl;
+ m_layout = layout;
+ m_package = &layout->package();
+
+ QStringList textures = layout->generateTextureRefs();
+
+ foreach (const QString &texName, textures) {
+ qDebug() << texName;
+
+ QByteArray tplData = m_package->getTexture(texName);
+
+ QDataStream tplStream(tplData);
+ WiiTexPalette tpl(tplStream);
+
+ const QImage &image = tpl.textures.first().image;
+ image.save(QString("tpl/%2__%1.png").arg(texName).arg((int)tpl.textures.first().format));
+ // dirty, dirty hack, TODO: FIXME
+ GLuint tex = gl->bindTexture(image, GL_TEXTURE_2D);
+
+ m_textures.insert(texName, tex);
+ m_images.insert(texName, image);
+ }
+}
diff --git a/layoutgl/texturemanager.h b/layoutgl/texturemanager.h
new file mode 100644
index 0000000..07b7739
--- /dev/null
+++ b/layoutgl/texturemanager.h
@@ -0,0 +1,33 @@
+#ifndef TEXTUREMANAGER_H
+#define TEXTUREMANAGER_H
+
+#include "wii/texpalette.h"
+#include "lyt/layout.h"
+#include <QGLContext>
+#include <QHash>
+
+class LGLTextureManager {
+public:
+ LGLTextureManager();
+
+ void setup(QGLWidget *gl, const LYTLayout *layout);
+
+private:
+ const QGLContext *m_gl;
+ const LYTLayout *m_layout;
+ const LYTPackageBase *m_package;
+
+ QHash<QString, GLuint> m_textures;
+ QHash<QString, QImage> m_images;
+
+public:
+ GLuint glTextureForName(const QString name) const {
+ return m_textures.value(name);
+ }
+
+ QImage imageForName(const QString name) const {
+ return m_images.value(name);
+ }
+};
+
+#endif // TEXTUREMANAGER_H
diff --git a/layoutgl/widget.cpp b/layoutgl/widget.cpp
new file mode 100644
index 0000000..0758e88
--- /dev/null
+++ b/layoutgl/widget.cpp
@@ -0,0 +1,389 @@
+#include "widget.h"
+
+LGLWidget::LGLWidget(QWidget *parent) :
+ QGLWidget(parent), m_layout(0) {
+}
+
+
+void LGLWidget::setLayout(LYTLayout *layout) {
+ // TODO: cleanup stuff for previous layout
+
+ m_layout = layout;
+ setFixedSize(layout->width, layout->height);
+}
+
+
+void LGLWidget::initializeGL() {
+ qDebug() << "initialising GL";
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glEnable(GL_TEXTURE_2D);
+
+ // this makes texture transparency work
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ // makes glColor value blend with textures
+ glEnable(GL_COLOR_MATERIAL);
+
+ m_texMgr.setup(this, m_layout);
+}
+
+
+void LGLWidget::resizeGL(int w, int h) {
+ glViewport(0, 0, (GLint)w, (GLint)h);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(-304, 304, -228, 228, -100, 100);
+ glMatrixMode(GL_MODELVIEW);
+}
+
+
+void LGLWidget::paintGL() {
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ if (m_layout == 0)
+ return;
+
+ glLoadIdentity();
+
+ renderPane(m_layout->rootPane);
+}
+
+void LGLWidget::renderPane(const LYTPane *pane) {
+ glPushMatrix();
+
+ glScalef(pane->xScale, pane->yScale, 1.0f);
+ glRotatef(pane->xRot, 1.0f, 0.0f, 0.0f);
+ glRotatef(pane->yRot, 0.0f, 1.0f, 0.0f);
+ glRotatef(pane->zRot, 0.0f, 0.0f, 1.0f);
+ glTranslatef(pane->xTrans, pane->yTrans, pane->zTrans);
+ //qDebug() << "Translating by" << pane->xTrans << pane->yTrans << pane->zTrans;
+
+ switch (pane->type()) {
+ case LYTPane::PictureType:
+ drawPicture((LYTPicture*)pane);
+ break;
+ case LYTPane::WindowType:
+ drawWindow((LYTWindow*)pane);
+ break;
+ }
+
+ foreach (const LYTPane *childPane, pane->children)
+ renderPane(childPane);
+
+ //qDebug() << "Popping";
+ glPopMatrix();
+}
+
+void LGLWidget::drawPicture(const LYTPicture *pic) {
+ float dX = pic->drawnVertexX();
+ float dY = pic->drawnVertexY();
+ //qDebug() << "Drawing" << dX << dY << pic->width << pic->height;
+
+ useMaterial(pic->materialName);
+
+ drawQuad(dX, dY, pic->width, pic->height, pic->texCoords, pic->vtxColours, pic->alpha);
+
+ glColor3ub(255, 255, 255);
+ renderText(dX, (dY-pic->height)+10, 0, pic->name);
+}
+
+struct TexFlipBit {
+ quint8 bits[8];
+ quint8 one, two;
+};
+
+static const TexFlipBit TextureFlipInfo[6] = {
+ {{0,0,1,0,0,1,1,1},0,1},
+ {{1,0,0,0,1,1,0,1},0,1},
+ {{0,1,1,1,0,0,1,0},0,1},
+ {{0,1,0,0,1,1,1,0},1,0},
+ {{1,1,0,1,1,0,0,0},0,1},
+ {{1,0,1,1,0,0,0,1},1,0}
+};
+
+void LGLWidget::dealWithWindowFrame(LYTTexCoords &coords, const QString &materialName,
+ int flipType, float pieceWidth, float pieceHeight,
+ int rep1, int rep2, int rep3, int rep4) {
+ // What are you DOING Nintendo.. the code for this is a mess!
+ // I seriously don't get it.
+ // I am also using a terrible hack here.
+ const TexFlipBit &info = TextureFlipInfo[flipType];
+
+ qreal *hack = (qreal*)(&coords.coord[0]);
+
+ float assign1 = info.bits[rep1 + info.one];
+ hack[rep1 + info.one] = assign1;
+ hack[rep3 + info.one] = assign1;
+
+ float assign2 = info.bits[rep1 + info.two];
+ hack[rep1 + info.two] = assign2;
+ hack[rep2 + info.two] = assign2;
+
+ float texSize[2];
+ getTextureSize(materialName, &texSize[0], &texSize[1]);
+
+ float assign3 = info.bits[rep1 + info.one] + (pieceWidth / ((info.bits[rep2 + info.one] - info.bits[rep1 + info.one]) * texSize[info.one]));
+ hack[rep2 + info.one] = assign3;
+ hack[rep4 + info.one] = assign3;
+
+ float assign4 = info.bits[rep1 + info.two] + (pieceHeight / ((info.bits[rep3 + info.two] - info.bits[rep1 + info.two]) * texSize[info.two]));
+ hack[rep3 + info.two] = assign4;
+ hack[rep4 + info.two] = assign4;
+}
+
+void LGLWidget::drawWindow(const LYTWindow *wnd) {
+ float dX = wnd->drawnVertexX();
+ float dY = wnd->drawnVertexY();
+
+ // get the frame size
+ float frameLeft, frameTop, frameRight, frameBottom;
+
+ switch (wnd->frames.count()) {
+ case 1:
+ float oneW, oneH;
+ getTextureSize(wnd->frames.at(0)->materialName, &oneW, &oneH);
+ frameLeft = frameRight = oneW;
+ frameTop = frameBottom = oneH;
+ break;
+ case 4: case 8:
+ getTextureSize(wnd->frames.at(0)->materialName, &frameLeft, &frameTop);
+ getTextureSize(wnd->frames.at(3)->materialName, &frameRight, &frameBottom);
+ break;
+ }
+
+ // draw the content
+ useMaterial(wnd->contentMaterialName);
+ qDebug() << "content material:" << wnd->contentMaterialName;
+ drawQuad(
+ dX + frameLeft - wnd->contentOverflowLeft,
+ dY - frameTop + wnd->contentOverflowTop,
+ ((wnd->contentOverflowLeft + (wnd->width - frameLeft)) - frameRight) + wnd->contentOverflowRight,
+ ((wnd->contentOverflowTop + (wnd->height - frameTop)) - frameBottom) + wnd->contentOverflowBottom,
+ wnd->contentTexCoords, wnd->contentVtxColours, wnd->alpha);
+
+ // deal with the frame
+ LYTTexCoords texCoords;
+
+ switch (wnd->frames.count()) {
+ case 1:
+ {
+ const LYTWindowFrame &frame = *wnd->frames.first();
+ const LYTMaterial &mat = getMaterial(frame.materialName);
+
+ if (!mat.texMaps.empty()) {
+ useMaterial(mat);
+
+ // top left
+ float pieceWidth = wnd->width - frameRight;
+ float pieceHeight = frameTop;
+
+ dealWithWindowFrame(texCoords, frame.materialName, 0, pieceWidth, pieceHeight, 0, 2, 4, 6);
+ drawQuad(dX, dY, pieceWidth, pieceHeight, 1, &texCoords, 0, wnd->alpha);
+
+ // top right
+ pieceWidth = frameRight;
+ pieceHeight = wnd->height - frameBottom;
+
+ dealWithWindowFrame(texCoords, frame.materialName, 1, pieceWidth, pieceHeight, 2, 0, 6, 4);
+
+ drawQuad(dX + wnd->width - frameRight, dY, pieceWidth, pieceHeight,
+ 1, &texCoords, 0, wnd->alpha);
+
+ // bottom left
+ pieceWidth = frameLeft;
+ pieceHeight = wnd->height - frameTop;
+
+ dealWithWindowFrame(texCoords, frame.materialName, 2, pieceWidth, pieceHeight, 4, 6, 0, 2);
+
+ drawQuad(dX, dY - frameTop, pieceWidth, pieceHeight,
+ 1, &texCoords, 0, wnd->alpha);
+
+ // bottom right
+ pieceWidth = wnd->width - frameLeft;
+ pieceHeight = frameBottom;
+
+ dealWithWindowFrame(texCoords, frame.materialName, 4, pieceWidth, pieceHeight, 6, 4, 2, 0);
+
+ drawQuad(dX + frameLeft, dY - wnd->height + frameBottom, pieceWidth, pieceHeight,
+ 1, &texCoords, 0, wnd->alpha);
+ }
+ }
+ break;
+ case 4:
+ {
+ // top left
+ const LYTWindowFrame &fTL = *wnd->frames.at(0);
+ const LYTMaterial &mTL = getMaterial(fTL.materialName);
+
+ if (!mTL.texMaps.empty()) {
+ useMaterial(mTL);
+
+ float pieceWidth = wnd->width - frameRight;
+ float pieceHeight = frameTop;
+
+ dealWithWindowFrame(texCoords, fTL.materialName, fTL.type, pieceWidth, pieceHeight, 0, 2, 4, 6);
+ drawQuad(dX, dY, pieceWidth, pieceHeight, 1, &texCoords, 0, wnd->alpha);
+ }
+
+ // top right
+ const LYTWindowFrame &fTR = *wnd->frames.at(1);
+ const LYTMaterial &mTR = getMaterial(fTR.materialName);
+
+ if (!mTR.texMaps.empty()) {
+ useMaterial(mTR);
+
+ float pieceWidth = frameRight;
+ float pieceHeight = wnd->height - frameBottom;
+
+ dealWithWindowFrame(texCoords, fTR.materialName, fTR.type, pieceWidth, pieceHeight, 2, 0, 6, 4);
+
+ drawQuad(dX + wnd->width - frameRight, dY, pieceWidth, pieceHeight,
+ 1, &texCoords, 0, wnd->alpha);
+ }
+
+ // bottom left
+ const LYTWindowFrame &fBL = *wnd->frames.at(2);
+ const LYTMaterial &mBL = getMaterial(fBL.materialName);
+
+ if (!mBL.texMaps.empty()) {
+ useMaterial(mBL);
+
+ float pieceWidth = frameLeft;
+ float pieceHeight = wnd->height - frameTop;
+
+ dealWithWindowFrame(texCoords, fBL.materialName, fBL.type, pieceWidth, pieceHeight, 4, 6, 0, 2);
+
+ drawQuad(dX, dY - frameTop, pieceWidth, pieceHeight,
+ 1, &texCoords, 0, wnd->alpha);
+ }
+
+ const LYTWindowFrame &fBR = *wnd->frames.at(3);
+ const LYTMaterial &mBR = getMaterial(fBR.materialName);
+
+ // bottom right
+ if (!mBR.texMaps.empty()) {
+ useMaterial(mBR);
+
+ float pieceWidth = frameRight;
+ float pieceHeight = wnd->height - frameBottom;
+
+ dealWithWindowFrame(texCoords, fBR.materialName, fBR.type, pieceWidth, pieceHeight, 6, 4, 0, 2);
+
+ drawQuad(dX + frameLeft, dY - wnd->height + frameBottom, pieceWidth, pieceHeight,
+ 1, &texCoords, 0, wnd->alpha);
+ }
+ }
+ break;
+ default:
+ qDebug() << "unhandled window frame count" << wnd->frames.count();
+ }
+}
+
+static GLint GLWrapModes[] = {
+ GL_CLAMP_TO_EDGE, // Clamp
+ GL_REPEAT, // Repeat
+ GL_MIRRORED_REPEAT, // Mirror
+};
+
+void LGLWidget::useMaterial(const QString &materialName) {
+ const LYTMaterial *mat = m_layout->materials.getMaterialByName(materialName);
+
+ useMaterial(*mat);
+}
+
+void LGLWidget::useMaterial(const LYTMaterial &mat) {
+ int cutAt = mat.texMaps.count();
+
+ for (int i = 0; i < cutAt; i++) {
+ const LYTTexMap &texMap = mat.texMaps.at(i);
+
+ const QString &texName = texMap.textureName;
+ GLuint texID = m_texMgr.glTextureForName(texName);
+
+ glActiveTexture(GL_TEXTURE0 + i);
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, texID);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GLWrapModes[texMap.wrap_s]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GLWrapModes[texMap.wrap_t]);
+
+ // is there a matching TexSRT?
+ // TODO: fix this
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+
+ if (mat.texSRTs.count() > i) {
+ const LYTTexSRT &srt = mat.texSRTs.at(i);
+
+ glScalef(srt.xScale, srt.yScale, 1.0f);
+ // rotate?
+ glTranslatef(srt.xTrans, -srt.yTrans, 0.0f);
+ }
+
+ glMatrixMode(GL_MODELVIEW);
+ }
+
+ for (int i = cutAt; i < 8; i++) {
+ glActiveTexture(GL_TEXTURE0 + i);
+ glDisable(GL_TEXTURE_2D);
+ }
+
+ glActiveTexture(GL_TEXTURE0);
+}
+
+void LGLWidget::drawQuad(float x, float y, float w, float h, const QVector<LYTTexCoords> &texCoords, const QColor *colours, uchar alpha) {
+ drawQuad(x, y, w, h, texCoords.count(), texCoords.constData(), colours, alpha);
+}
+
+void LGLWidget::drawQuad(float x, float y, float w, float h, int texCoordCount, const LYTTexCoords *texCoords, const QColor *colours, uchar alpha) {
+ if (!colours)
+ glColor4ub(255, 255, 255, 255);
+
+ glBegin(GL_QUADS);
+
+ for (int i = 0; i < texCoordCount; i++)
+ glMultiTexCoord2f(GL_TEXTURE0_ARB+i, texCoords[i].coord[0].x(), 1.0f-texCoords[i].coord[0].y());
+
+ if (colours)
+ qglColor(colours[0]);
+ glVertex2f(x, y);
+
+ for (int i = 0; i < texCoordCount; i++)
+ glMultiTexCoord2f(GL_TEXTURE0_ARB+i, texCoords[i].coord[1].x(), 1.0f-texCoords[i].coord[1].y());
+
+ if (colours)
+ qglColor(colours[1]);
+ glVertex2f(x + w, y);
+
+ for (int i = 0; i < texCoordCount; i++)
+ glMultiTexCoord2f(GL_TEXTURE0_ARB+i, texCoords[i].coord[3].x(), 1.0f-texCoords[i].coord[3].y());
+
+ if (colours)
+ qglColor(colours[2]);
+ glVertex2f(x + w, y - h);
+
+ for (int i = 0; i < texCoordCount; i++)
+ glMultiTexCoord2f(GL_TEXTURE0_ARB+i, texCoords[i].coord[2].x(), 1.0f-texCoords[i].coord[2].y());
+
+ if (colours)
+ qglColor(colours[3]);
+ glVertex2f(x, y - h);
+
+ glEnd();
+}
+
+
+void LGLWidget::getTextureSize(const QString &materialName, float *w, float *h) {
+ const LYTMaterial *mat = m_layout->materials.getMaterialByName(materialName);
+
+ if (mat->texMaps.count() == 0) {
+ *w = 0.0f;
+ *h = 0.0f;
+ } else {
+ const LYTTexMap &tm = mat->texMaps.first();
+
+ QImage img = m_texMgr.imageForName(tm.textureName);
+ *w = img.width();
+ *h = img.height();
+ }
+}
+
diff --git a/layoutgl/widget.h b/layoutgl/widget.h
new file mode 100644
index 0000000..e6abdfc
--- /dev/null
+++ b/layoutgl/widget.h
@@ -0,0 +1,53 @@
+#ifndef WIDGET_H
+#define WIDGET_H
+
+#include <QGLWidget>
+
+#include "lyt/layout.h"
+#include "layoutgl/texturemanager.h"
+
+class LGLWidget : public QGLWidget
+{
+ Q_OBJECT
+public:
+ explicit LGLWidget(QWidget *parent = 0);
+
+ void setLayout(LYTLayout *layout);
+
+protected:
+ void initializeGL();
+ void resizeGL(int w, int h);
+ void paintGL();
+
+ LYTLayout *m_layout;
+
+ void renderPane(const LYTPane *pane);
+
+ void drawPicture(const LYTPicture *pic);
+ void drawWindow(const LYTWindow *wnd);
+
+ const LYTMaterial &getMaterial(const QString &materialName) {
+ return *m_layout->materials.getMaterialByName(materialName);
+ }
+
+ void useMaterial(const QString &materialName);
+ void useMaterial(const LYTMaterial &material);
+
+ void drawQuad(float x, float y, float w, float h, const QVector<LYTTexCoords> &texCoords, const QColor *colours, uchar alpha);
+ void drawQuad(float x, float y, float w, float h, int texCoordCount, const LYTTexCoords *texCoords, const QColor *colours, uchar alpha);
+
+ void getTextureSize(const QString &materialName, float *w, float *h);
+
+ void dealWithWindowFrame(LYTTexCoords &coords, const QString &materialName, int flipType,
+ float pieceWidth, float pieceHeight,
+ int rep1, int rep2, int rep3, int rep4);
+
+ LGLTextureManager m_texMgr;
+
+signals:
+
+public slots:
+
+};
+
+#endif // WIDGET_H
diff --git a/lsmainwindow.cpp b/lsmainwindow.cpp
index 82c82dc..735d7a3 100644
--- a/lsmainwindow.cpp
+++ b/lsmainwindow.cpp
@@ -16,18 +16,217 @@
*******************************************************************************/
#include "lsmainwindow.h"
+#include <QAction>
+#include <QMenuBar>
+#include <QFileDialog>
+#include <QInputDialog>
+#include "lyt/archivepackage.h"
LSMainWindow::LSMainWindow(QWidget *parent) : QMainWindow(parent) {
- ui.setupUi(this);
+ m_package = 0;
+ m_dirty = false;
+ m_isSaved = false;
+
+ createActions();
+
+ m_view = new QTreeView(this);
+ setCentralWidget(m_view);
+
+ newArchive();
+}
+
+LSMainWindow::~LSMainWindow() {
+ if (m_package)
+ delete m_package;
+}
+
+
+void LSMainWindow::createActions() {
+ m_newArchiveAction = new QAction("&New Archive", this);
+ m_openArchiveAction = new QAction("&Open Archive...", this);
+ m_saveAction = new QAction("&Save", this);
+ m_saveArchiveAsAction = new QAction("Save Archive &As...", this);
+
+ connect(m_newArchiveAction, SIGNAL(triggered()), SLOT(newArchive()));
+ connect(m_openArchiveAction, SIGNAL(triggered()), SLOT(openArchive()));
+ connect(m_saveAction, SIGNAL(triggered()), SLOT(save()));
+ connect(m_saveArchiveAsAction, SIGNAL(triggered()), SLOT(saveArchiveAs()));
+
+ m_addLayoutAction = new QAction("New &Layout...", this);
+ m_addAnimationAction = new QAction("New &Animation...", this);
+ m_addTextureAction = new QAction("New &Texture...", this);
+ m_importNewAction = new QAction("&New Item...", this);
+ m_importAction = new QAction("&Replace This Item...", this);
+ m_exportAction = new QAction("&Export to File...", this);
+ m_renameAction = new QAction("Re&name Item...", this);
+ m_removeAction = new QAction("&Remove Item...", this);
+
+ m_addActionMapper = new QSignalMapper(this);
+ m_addActionMapper->setMapping(m_addLayoutAction, (int)LYTPackageBase::Layout);
+ m_addActionMapper->setMapping(m_addAnimationAction, (int)LYTPackageBase::Animation);
+ m_addActionMapper->setMapping(m_addTextureAction, (int)LYTPackageBase::Texture);
+
+ connect(m_addLayoutAction, SIGNAL(triggered()), m_addActionMapper, SLOT(map()));
+ connect(m_addAnimationAction, SIGNAL(triggered()), m_addActionMapper, SLOT(map()));
+ connect(m_addTextureAction, SIGNAL(triggered()), m_addActionMapper, SLOT(map()));
+ connect(m_addActionMapper, SIGNAL(mapped(int)), SLOT(handleAddSomething(int)));
+
+ QMenuBar *bar = menuBar();
+ QMenu *m;
+
+ m = bar->addMenu("&File");
+ m->addAction(m_newArchiveAction);
+ m->addAction(m_openArchiveAction);
+ m->addAction(m_saveAction);
+ m->addAction(m_saveArchiveAsAction);
+
+ m = bar->addMenu("&Edit");
+ m->addAction(m_addLayoutAction);
+ m->addAction(m_addAnimationAction);
+ m->addAction(m_addTextureAction);
+ m->addSeparator();
+ QMenu *importMenu = m->addMenu("&Import from File");
+ importMenu->addAction(m_importNewAction);
+ importMenu->addAction(m_importAction);
+ m->addAction(m_exportAction);
+ m->addSeparator();
+ m->addAction(m_renameAction);
+ m->addAction(m_removeAction);
+}
+
+
+void LSMainWindow::handleAddSomething(int whatToAdd) {
+ LYTPackageBase::ItemType what = (LYTPackageBase::ItemType)whatToAdd;
+
+ const char *typeName;
+ QString extension;
+ switch (what) {
+ case LYTPackageBase::Layout:
+ typeName = "layout";
+ extension = ".brlyt";
+ break;
+ case LYTPackageBase::Animation:
+ typeName = "animation";
+ extension = ".brlan";
+ break;
+ case LYTPackageBase::Texture:
+ typeName = "texture";
+ extension = ".tpl";
+ break;
+ default: return;
+ }
+
+ QString name = QInputDialog::getText(this,
+ "Add Item",
+ QString("Name this %1:").arg(typeName));
+
+ if (!name.isEmpty()) {
+ QByteArray data = LYTPackageBase::createSkeletonItem(what);
+ if (!name.endsWith(extension))
+ name.append(extension);
+
+ m_package->write(what, name, data);
+ }
+}
+
+
+
+bool LSMainWindow::ensureSaved() {
+ // TODO
+ return false;
}
-void LSMainWindow::changeEvent(QEvent *e) {
- QMainWindow::changeEvent(e);
- switch (e->type()) {
- case QEvent::LanguageChange:
- ui.retranslateUi(this);
- break;
- default:
- break;
+void LSMainWindow::updateTitleBar() {
+ QString title;
+ if (m_isSaved)
+ title = m_package->description();
+ else
+ title = "[Unsaved]";
+
+ if (m_dirty)
+ title.append('*');
+ title.append(" - LayoutStudio");
+
+ setWindowTitle(title);
+ setWindowModified(m_dirty);
+}
+
+void LSMainWindow::newArchive() {
+ if (ensureSaved())
+ return;
+
+ LYTArchivePackage *pkg = new LYTArchivePackage;
+ setCurrentPackage(pkg);
+
+ m_dirty = false;
+ m_isSaved = false;
+ updateTitleBar();
+}
+
+void LSMainWindow::openArchive() {
+ if (ensureSaved())
+ return;
+
+ QString path = QFileDialog::getOpenFileName(this,
+ "Open a Layout Archive",
+ QString(),
+ "Wii Archives (*.arc)"
+ );
+
+ if (path.isEmpty())
+ return;
+
+ LYTArchivePackage *pkg = new LYTArchivePackage(path);
+ setCurrentPackage(pkg);
+
+ m_dirty = false;
+ m_isSaved = false;
+ updateTitleBar();
+}
+
+void LSMainWindow::save() {
+ // TODO: check that m_package is an arc
+ if (m_isSaved) {
+ m_dirty = false;
+ m_package->savePackage();
+ updateTitleBar();
+ } else {
+ saveArchiveAs();
}
}
+
+void LSMainWindow::saveArchiveAs() {
+ // TODO: check that m_package is an arc
+ QString newPath = QFileDialog::getSaveFileName(this,
+ "Save Layout Archive",
+ QString(),
+ "Wii Archives (*.arc)"
+ );
+
+ if (newPath.isEmpty())
+ return;
+
+ LYTArchivePackage *pkg = (LYTArchivePackage*)m_package;
+ pkg->setFilename(newPath);
+ pkg->savePackage();
+
+ m_dirty = false;
+ m_isSaved = true;
+ updateTitleBar();
+}
+
+
+void LSMainWindow::setCurrentPackage(LYTPackageBase *pkg) {
+ m_package = pkg;
+
+ QItemSelectionModel *oldSel = m_view->selectionModel();
+ QAbstractItemModel *model = m_view->model();
+
+ m_model = new LSPackageModel(pkg, this);
+ m_view->setModel(m_model);
+
+ if (model)
+ delete model;
+ if (oldSel)
+ delete oldSel;
+}
diff --git a/lsmainwindow.h b/lsmainwindow.h
index 18d694d..f989e7a 100644
--- a/lsmainwindow.h
+++ b/lsmainwindow.h
@@ -18,18 +18,52 @@
#ifndef LSMAINWINDOW_H
#define LSMAINWINDOW_H
-#include "ui_lsmainwindow.h"
+#include "lyt/packagebase.h"
+#include "lspackagemodel.h"
+#include <QMainWindow>
+#include <QTreeView>
+#include <QSignalMapper>
class LSMainWindow : public QMainWindow {
Q_OBJECT
public:
LSMainWindow(QWidget *parent = 0);
+ ~LSMainWindow();
protected:
- void changeEvent(QEvent *e);
+ bool ensureSaved();
+
+public:
+ void updateTitleBar();
+
+public slots:
+ void newArchive();
+ void openArchive();
+ void save();
+ void saveArchiveAs();
+
+private slots:
+ void handleAddSomething(int whatToAdd);
private:
- Ui::LSMainWindow ui;
+ LYTPackageBase *m_package;
+ void setCurrentPackage(LYTPackageBase *pkg);
+
+ void createActions();
+ QAction *m_newArchiveAction, *m_openArchiveAction, *m_saveArchiveAsAction;
+ QAction *m_saveAction;
+
+ QAction *m_addLayoutAction, *m_addAnimationAction;
+ QAction *m_addTextureAction;
+ QSignalMapper *m_addActionMapper;
+ QAction *m_importNewAction, *m_importAction;
+ QAction *m_renameAction, *m_removeAction, *m_exportAction;
+
+ LSPackageModel *m_model;
+ QTreeView *m_view;
+
+ bool m_dirty;
+ bool m_isSaved;
};
#endif // LSMAINWINDOW_H
diff --git a/lsmainwindow.ui b/lsmainwindow.ui
deleted file mode 100644
index a7432f2..0000000
--- a/lsmainwindow.ui
+++ /dev/null
@@ -1,24 +0,0 @@
-<ui version="4.0">
- <class>LSMainWindow</class>
- <widget class="QMainWindow" name="LSMainWindow" >
- <property name="geometry" >
- <rect>
- <x>0</x>
- <y>0</y>
- <width>600</width>
- <height>400</height>
- </rect>
- </property>
- <property name="windowTitle" >
- <string>LSMainWindow</string>
- </property>
- <widget class="QMenuBar" name="menuBar" />
- <widget class="QToolBar" name="mainToolBar" />
- <widget class="QWidget" name="centralWidget" />
- <widget class="QStatusBar" name="statusBar" />
- </widget>
- <layoutDefault spacing="6" margin="11" />
- <pixmapfunction></pixmapfunction>
- <resources/>
- <connections/>
-</ui>
diff --git a/lspackagemodel.cpp b/lspackagemodel.cpp
new file mode 100644
index 0000000..d39bb89
--- /dev/null
+++ b/lspackagemodel.cpp
@@ -0,0 +1,150 @@
+#include "lspackagemodel.h"
+
+struct ContentKind {
+ LYTPackageBase::ItemType type;
+ QString name;
+};
+
+static const ContentKind ContentKinds[4] = {
+ {LYTPackageBase::Layout, "Layouts"},
+ {LYTPackageBase::Animation, "Animations"},
+ {LYTPackageBase::Texture, "Textures"},
+ {LYTPackageBase::Font, "Fonts"},
+};
+const int ContentKindCount = 4;
+
+static int ContentKindForType(LYTPackageBase::ItemType type) {
+ switch (type) {
+ case LYTPackageBase::Layout: return 0;
+ case LYTPackageBase::Animation: return 1;
+ case LYTPackageBase::Texture: return 2;
+ case LYTPackageBase::Font: return 3;
+ }
+ return -1;
+}
+
+LSPackageModel::LSPackageModel(LYTPackageBase *pkg, QObject *parent) :
+ QAbstractItemModel(parent)
+{
+ m_package = pkg;
+
+ m_caches = new QStringList[ContentKindCount];
+ for (int i = 0; i < ContentKindCount; i++) {
+ m_caches[i] = pkg->list(ContentKinds[i].type);
+ m_caches[i].sort();
+ }
+
+ connect(pkg, SIGNAL(fileWasAdded(LYTPackageBase::ItemType,QString)), SLOT(handleFileWasAdded(LYTPackageBase::ItemType,QString)));
+ //connect(pkg, SIGNAL(fileWasModified(LYTPackageBase::ItemType,QString)), SLOT(handleFileWasModified(LYTPackageBase::ItemType,QString)));
+ connect(pkg, SIGNAL(fileWasRemoved(LYTPackageBase::ItemType,QString)), SLOT(handleFileWasRemoved(LYTPackageBase::ItemType,QString)));
+ connect(pkg, SIGNAL(fileWasRenamed(LYTPackageBase::ItemType,QString,QString)), SLOT(handleFileWasRenamed(LYTPackageBase::ItemType,QString,QString)));
+}
+
+LSPackageModel::~LSPackageModel() {
+ delete[] m_caches;
+}
+
+
+QModelIndex LSPackageModel::index(int row, int column, const QModelIndex &parent) const {
+ if (!hasIndex(row, column, parent))
+ return QModelIndex();
+
+ if (!parent.isValid())
+ return createIndex(row, column, 0);
+
+ return createIndex(row, column, parent.row() + 1);
+}
+
+QModelIndex LSPackageModel::parent(const QModelIndex &child) const {
+ if (!child.isValid())
+ return QModelIndex();
+
+ if (child.internalId() > 0)
+ return createIndex(child.internalId() - 1, 0, 0);
+ else
+ return QModelIndex();
+}
+
+int LSPackageModel::rowCount(const QModelIndex &parent) const {
+ if (!parent.isValid())
+ return ContentKindCount;
+ else if (parent.internalId() > 0)
+ return 0; // an actual item
+ else
+ return m_caches[parent.row()].count();
+}
+
+int LSPackageModel::columnCount(const QModelIndex &parent) const {
+ return 1;
+}
+
+QVariant LSPackageModel::data(const QModelIndex &index, int role) const {
+ if (!index.isValid())
+ return QVariant();
+ if (role != Qt::DisplayRole)
+ return QVariant();
+
+ int whatIs = index.internalId();
+ if (whatIs == 0)
+ return ContentKinds[index.row()].name;
+ else
+ return m_caches[whatIs - 1].at(index.row());
+}
+
+
+void LSPackageModel::handleFileWasAdded(LYTPackageBase::ItemType type, QString name) {
+ int kind = ContentKindForType(type);
+
+ QStringList newCache = m_caches[kind];
+ newCache.append(name);
+ newCache.sort();
+
+ // where was this added?
+ int idx = newCache.indexOf(name);
+ beginInsertRows(createIndex(kind, 0, 0), idx, idx);
+ m_caches[kind] = newCache;
+ endInsertRows();
+}
+
+void LSPackageModel::handleFileWasRemoved(LYTPackageBase::ItemType type, QString name) {
+ int kind = ContentKindForType(type);
+
+ int idx = m_caches[kind].indexOf(name);
+ beginRemoveRows(createIndex(kind, 0, 0), idx, idx);
+ m_caches[kind].removeAt(idx);
+ endRemoveRows();
+}
+
+void LSPackageModel::handleFileWasRenamed(LYTPackageBase::ItemType type, QString from, QString to) {
+ int kind = ContentKindForType(type);
+
+ QStringList newCache = m_caches[kind];
+ int fromIdx = newCache.indexOf(from);
+
+ // this is really a mess, but I cannot think of a better way to do it
+ // first, make a new cache, but don't store it to m_caches yet...
+ newCache[fromIdx] = to;
+ newCache.sort();
+
+ // and now, get the to Index...
+ int toIdx = newCache.indexOf(to);
+ // if the new index is less than the old one, then leave it that way
+ // if the new index is the same as the old one, that's fine, do nothing
+ // if the new index is more than the old one... add 1 to it to take into
+ // account that the old one is no longer around when it was computed BUT Qt
+ // expects it to be
+ // did that make sense? probably not, oh well
+ if (toIdx > fromIdx)
+ toIdx++;
+
+ QModelIndex whatChanged = createIndex(fromIdx, 0, kind + 1);
+ emit dataChanged(whatChanged, whatChanged);
+
+ QModelIndex parent = createIndex(kind, 0, 0);
+
+ if (toIdx != fromIdx)
+ beginMoveRows(parent, fromIdx, fromIdx, parent, toIdx);
+ m_caches[kind] = newCache;
+ if (toIdx != fromIdx)
+ endMoveRows();
+}
diff --git a/lspackagemodel.h b/lspackagemodel.h
new file mode 100644
index 0000000..18911de
--- /dev/null
+++ b/lspackagemodel.h
@@ -0,0 +1,42 @@
+#ifndef LSPACKAGEMODEL_H
+#define LSPACKAGEMODEL_H
+
+#include <QAbstractItemModel>
+#include "lyt/packagebase.h"
+
+class LSPackageModel : public QAbstractItemModel {
+ Q_OBJECT
+public:
+ explicit LSPackageModel(LYTPackageBase *pkg, QObject *parent = 0);
+ ~LSPackageModel();
+
+ LYTPackageBase *package() const { return m_package; }
+
+ QModelIndex index(int row, int column, const QModelIndex &parent) const;
+ QModelIndex parent(const QModelIndex &child) const;
+ int rowCount(const QModelIndex &parent) const;
+ int columnCount(const QModelIndex &parent) const;
+ QVariant data(const QModelIndex &index, int role) const;
+
+signals:
+
+private slots:
+ //void handleAboutToAddFile(LYTPackageBase::ItemType type, QString name);
+ //void handleAboutToRemoveFile(LYTPackageBase::ItemType type, QString name);
+ //void handleAboutToRenameFile(LYTPackageBase::ItemType type, QString from, QString to);
+ //void handleAboutToModifyFile(LYTPackageBase::ItemType type, QString name);
+
+ void handleFileWasAdded(LYTPackageBase::ItemType type, QString name);
+ void handleFileWasRemoved(LYTPackageBase::ItemType type, QString name);
+ void handleFileWasRenamed(LYTPackageBase::ItemType type, QString from, QString to);
+ //void handleFileWasModified(LYTPackageBase::ItemType type, QString name);
+
+public slots:
+
+protected:
+ LYTPackageBase *m_package;
+
+ QStringList *m_caches;
+};
+
+#endif // LSPACKAGEMODEL_H
diff --git a/lyt/archivepackage.cpp b/lyt/archivepackage.cpp
index eaabbf2..acb92d2 100644
--- a/lyt/archivepackage.cpp
+++ b/lyt/archivepackage.cpp
@@ -19,11 +19,11 @@
#include <QtCore/QFile>
-LYTArchivePackage::LYTArchivePackage() : LYTPackageBase() {
+LYTArchivePackage::LYTArchivePackage(QObject *parent) : LYTPackageBase(parent) {
m_archive = new WiiArchiveU8;
}
-LYTArchivePackage::LYTArchivePackage(QString filename) : LYTPackageBase() {
+LYTArchivePackage::LYTArchivePackage(QString filename, QObject *parent) : LYTPackageBase(parent) {
m_filename = filename;
QFile file(filename);
@@ -47,11 +47,14 @@ WiiArchiveU8 *LYTArchivePackage::archive() const {
QString LYTArchivePackage::filename() const {
return m_filename;
}
+void LYTArchivePackage::setFilename(QString path) {
+ m_filename = path;
+}
-QStringList LYTArchivePackage::listSubDirIfExists(QString dirName) const {
- WiiFSObject *obj = this->m_archive->root.resolvePath(dirName);
+QStringList LYTArchivePackage::list(ItemType type) const {
+ WiiFSObject *obj = this->m_archive->root.resolvePath(defaultPathForItemType(type, true));
if (obj && obj->isDirectory()) {
QStringList output;
@@ -66,9 +69,9 @@ QStringList LYTArchivePackage::listSubDirIfExists(QString dirName) const {
return QStringList();
}
-
-QByteArray LYTArchivePackage::getFileFromSubDirIfExists(QString dirName, QString fileName) const {
- WiiFSObject *obj = this->m_archive->root.resolvePath(QString("%1/%2").arg(dirName, fileName));
+QByteArray LYTArchivePackage::get(ItemType type, const QString &name) const {
+ QString dirName = defaultPathForItemType(type, true);
+ WiiFSObject *obj = this->m_archive->root.resolvePath(QString("%1/%2").arg(dirName, name));
if (obj && obj->isFile()) {
return ((WiiFile*)obj)->data;
@@ -77,71 +80,97 @@ QByteArray LYTArchivePackage::getFileFromSubDirIfExists(QString dirName, QString
return QByteArray();
}
+bool LYTArchivePackage::write(ItemType type, const QString &name, const QByteArray &data) {
+ if (name.isEmpty())
+ return false;
-bool LYTArchivePackage::writeFileToSubDir(QString dirName, QString fileName, QByteArray data) {
- WiiFSObject *obj = this->m_archive->root.resolvePath(QString("%1/%2").arg(dirName, fileName));
+ WiiFSObject *rootDir = this->m_archive->root.findByName("arc", false);
+ if (!rootDir) {
+ rootDir = new WiiDirectory;
+ rootDir->name = "arc";
+ m_archive->root.addChild(rootDir);
+ }
+ if (!rootDir->isDirectory())
+ return false;
- if (obj && obj->isFile()) {
- ((WiiFile*)obj)->data = data;
- return true;
- }
+ QString dirName = defaultPathForItemType(type, false);
+ WiiFSObject *dir = ((WiiDirectory*)rootDir)->findByName(dirName, false);
- return false;
-}
+ if (!dir) {
+ dir = new WiiDirectory;
+ dir->name = dirName;
+ ((WiiDirectory*)rootDir)->addChild(dir);
+ }
+ if (!dir->isDirectory())
+ return false;
+ WiiFSObject *obj = ((WiiDirectory*)dir)->findByName(name, false);
+ if (obj && obj->isFile()) {
+ emit aboutToModifyFile(type, name);
+ ((WiiFile*)obj)->data = data;
-QStringList LYTArchivePackage::listAnims() const {
- return this->listSubDirIfExists("arc/anim");
-}
+ emit fileWasModified(type, name);
-QStringList LYTArchivePackage::listLayouts() const {
- return this->listSubDirIfExists("arc/blyt");
-}
+ return true;
-QStringList LYTArchivePackage::listTextures() const {
- return this->listSubDirIfExists("arc/timg");
-}
+ } else if (!obj) {
+ emit aboutToAddFile(type, name);
-QStringList LYTArchivePackage::listFonts() const {
- return this->listSubDirIfExists("arc/font");
-}
+ WiiFile *newFile = new WiiFile;
+ newFile->name = name;
+ newFile->data = data;
+ ((WiiDirectory*)dir)->addChild(newFile);
+ emit fileWasAdded(type, name);
+ return true;
+ }
-QByteArray LYTArchivePackage::getAnim(QString name) const {
- return this->getFileFromSubDirIfExists("arc/anim", name);
+ return false;
}
-QByteArray LYTArchivePackage::getLayout(QString name) const {
- return this->getFileFromSubDirIfExists("arc/blyt", name);
-}
+bool LYTArchivePackage::remove(ItemType type, const QString &name) {
+ WiiFSObject *obj = this->m_archive->root.resolvePath(defaultPathForItemType(type, true));
-QByteArray LYTArchivePackage::getTexture(QString name) const {
- return this->getFileFromSubDirIfExists("arc/timg", name);
-}
+ if (obj && obj->isDirectory()) {
+ WiiDirectory *dir = (WiiDirectory*)obj;
+
+ WiiFSObject *what = dir->findByName(name, false);
+ if (what && what->isFile()) {
+ emit aboutToRemoveFile(type, name);
+ dir->removeChild(what);
+ emit fileWasRemoved(type, name);
+ return true;
+ }
+ }
-QByteArray LYTArchivePackage::getFont(QString name) const {
- return this->getFileFromSubDirIfExists("arc/font", name);
+ return false;
}
+bool LYTArchivePackage::rename(ItemType type, const QString &from, const QString &to) {
+ if (to.isEmpty())
+ return false;
+ WiiFSObject *obj = this->m_archive->root.resolvePath(defaultPathForItemType(type, true));
-bool LYTArchivePackage::writeAnim(QString name, QByteArray data) {
- return this->writeFileToSubDir("arc/anim", name, data);
-}
-
-bool LYTArchivePackage::writeLayout(QString name, QByteArray data) {
- return this->writeFileToSubDir("arc/blyt", name, data);
-}
-
-bool LYTArchivePackage::writeTexture(QString name, QByteArray data) {
- return this->writeFileToSubDir("arc/timg", name, data);
-}
+ if (obj && obj->isDirectory()) {
+ WiiDirectory *dir = (WiiDirectory*)obj;
+
+ WiiFSObject *what = dir->findByName(from, false);
+ if (what && what->isFile()) {
+ WiiFSObject *conflict = dir->findByName(to, false);
+ if (!conflict) {
+ emit aboutToRenameFile(type, from, to);
+ what->name = to;
+ emit fileWasRenamed(type, from, to);
+ return true;
+ }
+ }
+ }
-bool LYTArchivePackage::writeFont(QString name, QByteArray data) {
- return this->writeFileToSubDir("arc/font", name, data);
+ return false;
}
diff --git a/lyt/archivepackage.h b/lyt/archivepackage.h
index e2d5f25..786d962 100644
--- a/lyt/archivepackage.h
+++ b/lyt/archivepackage.h
@@ -22,39 +22,29 @@
#include "wii/archiveu8.h"
class LYTArchivePackage : public LYTPackageBase {
+ Q_OBJECT
public:
- LYTArchivePackage();
- LYTArchivePackage(QString filename);
+ LYTArchivePackage(QObject *parent = 0);
+ LYTArchivePackage(QString filename, QObject *parent = 0);
~LYTArchivePackage();
- QStringList listAnims() const;
- QStringList listLayouts() const;
- QStringList listTextures() const;
- QStringList listFonts() const;
-
- QByteArray getAnim(QString name) const;
- QByteArray getLayout(QString name) const;
- QByteArray getTexture(QString name) const;
- QByteArray getFont(QString name) const;
-
- bool writeAnim(QString name, QByteArray data);
- bool writeLayout(QString name, QByteArray data);
- bool writeTexture(QString name, QByteArray data);
- bool writeFont(QString name, QByteArray data);
+ QStringList list(ItemType type) const;
+ QByteArray get(ItemType type, const QString &name) const;
+ bool write(ItemType type, const QString &name, const QByteArray &data);
+ bool rename(ItemType type, const QString &from, const QString &to);
+ bool remove(ItemType type, const QString &name);
+ bool needsExplicitSave() const { return true; }
bool savePackage();
QString description() const;
WiiArchiveU8 *archive() const;
QString filename() const;
+ void setFilename(QString path);
protected:
- QStringList listSubDirIfExists(QString dirName) const;
- QByteArray getFileFromSubDirIfExists(QString dirName, QString fileName) const;
- bool writeFileToSubDir(QString dirName, QString fileName, QByteArray data);
-
WiiArchiveU8 *m_archive;
QString m_filename;
};
diff --git a/lyt/bounding.cpp b/lyt/bounding.cpp
index ce506b3..de61840 100644
--- a/lyt/bounding.cpp
+++ b/lyt/bounding.cpp
@@ -21,6 +21,7 @@
LYTBounding::LYTBounding(LYTLayout &layout) : LYTPane(layout) {
+ m_type = BoundingType;
}
diff --git a/lyt/directorypackage.cpp b/lyt/directorypackage.cpp
index dd8c39d..803cb80 100644
--- a/lyt/directorypackage.cpp
+++ b/lyt/directorypackage.cpp
@@ -19,29 +19,30 @@
#include <QtCore/QDir>
-LYTDirectoryPackage::LYTDirectoryPackage(QString path) : LYTPackageBase() {
+LYTDirectoryPackage::LYTDirectoryPackage(QString path, QObject *parent) : LYTPackageBase(parent) {
+ qWarning("LYTDirectoryPackage is currently unmaintained, you probably shouldn't use it");
+
QDir fix_path(path);
this->m_path = fix_path.absolutePath();
}
-QStringList LYTDirectoryPackage::listSubDirIfExists(QString dirName) const {
+QStringList LYTDirectoryPackage::list(ItemType type) const {
QDir search(m_path);
- if (search.cd(dirName)) {
+ if (search.cd(defaultPathForItemType(type))) {
return search.entryList();
}
return QStringList();
}
-
-QByteArray LYTDirectoryPackage::getFileFromSubDirIfExists(QString dirName, QString fileName) const {
+QByteArray LYTDirectoryPackage::get(ItemType type, const QString &name) const {
QDir search(m_path);
- if (search.cd(dirName)) {
- QFile file(search.absoluteFilePath(fileName));
+ if (search.cd(defaultPathForItemType(type))) {
+ QFile file(search.absoluteFilePath(name));
if (file.open(QFile::ReadOnly)) {
return file.readAll();
@@ -51,76 +52,40 @@ QByteArray LYTDirectoryPackage::getFileFromSubDirIfExists(QString dirName, QStri
return QByteArray();
}
-
-bool LYTDirectoryPackage::writeFileToSubDir(QString dirName, QString fileName, QByteArray data) {
+bool LYTDirectoryPackage::write(ItemType type, const QString &name, const QByteArray &data) {
QDir search(m_path);
+ QString dirName = defaultPathForItemType(type);
- if (search.cd(dirName)) {
- QFile file(search.absoluteFilePath(fileName));
-
- if (file.open(QFile::WriteOnly)) {
- if (file.write(data) != -1) {
- return true;
- }
- }
- }
-
- return false;
-}
+ if (!search.cd(dirName)) {
+ if (!search.mkdir(dirName))
+ return false;
+ if (!search.cd(dirName))
+ return false;
+ }
+ QFile file(search.absoluteFilePath(name));
+ if (file.open(QFile::WriteOnly)) {
+ if (file.write(data) != -1) {
+ return true;
+ }
+ }
-
-QStringList LYTDirectoryPackage::listAnims() const {
- return this->listSubDirIfExists("anim");
-}
-
-QStringList LYTDirectoryPackage::listLayouts() const {
- return this->listSubDirIfExists("blyt");
-}
-
-QStringList LYTDirectoryPackage::listTextures() const {
- return this->listSubDirIfExists("timg");
+ return false;
}
-QStringList LYTDirectoryPackage::listFonts() const {
- return this->listSubDirIfExists("font");
-}
-
-
-
-QByteArray LYTDirectoryPackage::getAnim(QString name) const {
- return this->getFileFromSubDirIfExists("anim", name);
-}
-
-QByteArray LYTDirectoryPackage::getLayout(QString name) const {
- return this->getFileFromSubDirIfExists("blyt", name);
-}
-
-QByteArray LYTDirectoryPackage::getTexture(QString name) const {
- return this->getFileFromSubDirIfExists("timg", name);
-}
-
-QByteArray LYTDirectoryPackage::getFont(QString name) const {
- return this->getFileFromSubDirIfExists("font", name);
-}
-
-
+bool LYTDirectoryPackage::remove(ItemType type, const QString &name) {
+ QDir search(m_path);
-bool LYTDirectoryPackage::writeAnim(QString name, QByteArray data) {
- return this->writeFileToSubDir("anim", name, data);
-}
+ if (search.cd(defaultPathForItemType(type))) {
+ QFile file(search.absoluteFilePath(name));
-bool LYTDirectoryPackage::writeLayout(QString name, QByteArray data) {
- return this->writeFileToSubDir("blyt", name, data);
-}
-
-bool LYTDirectoryPackage::writeTexture(QString name, QByteArray data) {
- return this->writeFileToSubDir("timg", name, data);
-}
+ if (file.open(QFile::WriteOnly)) {
+ return file.remove();
+ }
+ }
-bool LYTDirectoryPackage::writeFont(QString name, QByteArray data) {
- return this->writeFileToSubDir("font", name, data);
+ return false;
}
diff --git a/lyt/directorypackage.h b/lyt/directorypackage.h
index df8a50e..0d6ea19 100644
--- a/lyt/directorypackage.h
+++ b/lyt/directorypackage.h
@@ -15,40 +15,33 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*******************************************************************************/
+// Currently unmaintained.
+// What this needs to be fixed up:
+// -- Implement rename()
+// -- Make it emit signals
+// -- Add support to the LayoutStudio UI
+
#ifndef LYTDIRECTORYPACKAGE_H
#define LYTDIRECTORYPACKAGE_H
#include "packagebase.h"
class LYTDirectoryPackage : public LYTPackageBase {
+ Q_OBJECT
public:
- LYTDirectoryPackage(QString path);
-
- QStringList listAnims() const;
- QStringList listLayouts() const;
- QStringList listTextures() const;
- QStringList listFonts() const;
-
- QByteArray getAnim(QString name) const;
- QByteArray getLayout(QString name) const;
- QByteArray getTexture(QString name) const;
- QByteArray getFont(QString name) const;
+ LYTDirectoryPackage(QString path, QObject *parent = 0);
- bool writeAnim(QString name, QByteArray data);
- bool writeLayout(QString name, QByteArray data);
- bool writeTexture(QString name, QByteArray data);
- bool writeFont(QString name, QByteArray data);
+ QStringList list(ItemType type) const;
+ QByteArray get(ItemType type, const QString &name) const;
+ bool write(ItemType type, const QString &name, const QByteArray &data);
+ bool remove(ItemType type, const QString &name);
+ bool needsExplicitSave() const { return false; }
bool savePackage();
QString description() const;
QString path() const;
protected:
- QStringList listSubDirIfExists(QString dirName) const;
- QByteArray getFileFromSubDirIfExists(QString dirName, QString fileName) const;
- bool writeFileToSubDir(QString dirName, QString fileName, QByteArray data);
-
-
QString m_path;
};
diff --git a/lyt/layout.h b/lyt/layout.h
index 092be44..c051842 100644
--- a/lyt/layout.h
+++ b/lyt/layout.h
@@ -57,6 +57,7 @@ public:
LYTPane *rootPane;
QList<LYTGroup *> groups;
+ QStringList generateTextureRefs() const;
protected:
@@ -77,7 +78,6 @@ protected:
LYTPane *createPaneObj(LYTBinaryFileSection &section);
- QStringList generateTextureRefs() const;
QStringList generateFontRefs() const;
void writeMat1(LYTBinaryFileSection &section) const;
diff --git a/lyt/packagebase.cpp b/lyt/packagebase.cpp
index e186435..5855688 100644
--- a/lyt/packagebase.cpp
+++ b/lyt/packagebase.cpp
@@ -17,9 +17,31 @@
#include "packagebase.h"
-LYTPackageBase::LYTPackageBase() {
+LYTPackageBase::LYTPackageBase(QObject *parent) : QObject(parent) {
// do nothing
}
LYTPackageBase::~LYTPackageBase() {
}
+
+
+
+QString LYTPackageBase::defaultPathForItemType(ItemType type, bool withArc) {
+ switch (type) {
+ case Layout:
+ return withArc ? "arc/blyt" : "blyt";
+ case Animation:
+ return withArc ? "arc/anim" : "anim";
+ case Texture:
+ return withArc ? "arc/timg" : "timg";
+ case Font:
+ return withArc ? "arc/font" : "font";
+ default:
+ return QString();
+ }
+}
+
+
+QByteArray LYTPackageBase::createSkeletonItem(ItemType type) {
+ return QByteArray();
+}
diff --git a/lyt/packagebase.h b/lyt/packagebase.h
index 6129e0b..ac11b92 100644
--- a/lyt/packagebase.h
+++ b/lyt/packagebase.h
@@ -20,30 +20,64 @@
#include <QStringList>
#include <QByteArray>
+#include <QObject>
-class LYTPackageBase {
+class LYTPackageBase : public QObject {
+ Q_OBJECT
public:
- LYTPackageBase();
+ LYTPackageBase(QObject *parent = 0);
virtual ~LYTPackageBase();
- virtual QStringList listAnims() const = 0;
- virtual QStringList listLayouts() const = 0;
- virtual QStringList listTextures() const = 0;
- virtual QStringList listFonts() const = 0;
+ enum ItemType {
+ Layout = 1,
+ Animation,
+ Texture,
+ Font
+ };
- virtual QByteArray getAnim(QString name) const = 0;
- virtual QByteArray getLayout(QString name) const = 0;
- virtual QByteArray getTexture(QString name) const = 0;
- virtual QByteArray getFont(QString name) const = 0;
+ static QString defaultPathForItemType(ItemType type, bool withArc=false);
+ static QByteArray createSkeletonItem(ItemType type);
- virtual bool writeAnim(QString name, QByteArray data) = 0;
- virtual bool writeLayout(QString name, QByteArray data) = 0;
- virtual bool writeTexture(QString name, QByteArray data) = 0;
- virtual bool writeFont(QString name, QByteArray data) = 0;
+ virtual QStringList list(ItemType type) const = 0;
+ virtual QByteArray get(ItemType type, const QString &name) const = 0;
+ virtual bool write(ItemType type, const QString &name, const QByteArray &data) = 0;
+ virtual bool rename(ItemType type, const QString &from, const QString &to) = 0;
+ virtual bool remove(ItemType type, const QString &name) = 0;
+ // Shortcuts
+#define MakeThing(THING, ENUMVAL) \
+ QStringList list##THING##s () const { return list(ENUMVAL); } \
+ QByteArray get##THING (const QString &name) const \
+ { return get(ENUMVAL, name); } \
+ \
+ bool write##THING (const QString &name, const QByteArray &data) \
+ { return write(ENUMVAL, name, data); } \
+ \
+ bool remove##THING(const QString &name) { return remove(ENUMVAL, name); }
+
+ // Use it
+ MakeThing(Layout, Layout)
+ MakeThing(Anim, Animation)
+ MakeThing(Texture, Texture)
+ MakeThing(Font, Font)
+
+#undef MakeThing
+
+ virtual bool needsExplicitSave() const = 0;
virtual bool savePackage() = 0;
virtual QString description() const = 0;
+
+signals:
+ void aboutToAddFile(LYTPackageBase::ItemType type, QString name);
+ void aboutToRemoveFile(LYTPackageBase::ItemType type, QString name);
+ void aboutToRenameFile(LYTPackageBase::ItemType type, QString from, QString to);
+ void aboutToModifyFile(LYTPackageBase::ItemType type, QString name);
+
+ void fileWasAdded(LYTPackageBase::ItemType type, QString name);
+ void fileWasRemoved(LYTPackageBase::ItemType type, QString name);
+ void fileWasRenamed(LYTPackageBase::ItemType type, QString from, QString to);
+ void fileWasModified(LYTPackageBase::ItemType type, QString name);
};
#endif // LYTPACKAGEBASE_H
diff --git a/lyt/pane.cpp b/lyt/pane.cpp
index 7ae768a..3a4abd0 100644
--- a/lyt/pane.cpp
+++ b/lyt/pane.cpp
@@ -20,6 +20,7 @@
LYTPane::LYTPane(LYTLayout &layout) : m_layout(layout) {
this->parent = 0;
+ m_type = PaneType;
}
LYTPane::~LYTPane() {
@@ -59,7 +60,7 @@ void LYTPane::dumpToDebug(bool showHeading) const {
qDebug() << "- Rotation:" << xRot << "," << yRot << "," << zRot;
qDebug() << "- Scale:" << xScale << "," << yScale;
qDebug() << "- Size:" << width << "x" << height;
- qDebug() << "- Flags:" << flags << "- Origin:" << origin;
+ qDebug() << "- Flags:" << flags << "- Origin:" << horzOrigin << "," << vertOrigin;
qDebug() << "- Alpha:" << alpha << "- Userdata:" << userdata;
}
@@ -67,7 +68,7 @@ void LYTPane::dumpToDebug(bool showHeading) const {
void LYTPane::writeToDataStream(QDataStream &out) const {
out << (quint8)flags;
- out << (quint8)origin;
+ out << (quint8)((int)horzOrigin + ((int)vertOrigin * 3));
out << (quint8)alpha;
WritePadding(1, out);
@@ -88,7 +89,10 @@ void LYTPane::writeToDataStream(QDataStream &out) const {
void LYTPane::readFromDataStream(QDataStream &in) {
in >> (quint8&)flags;
- in >> (quint8&)origin;
+ quint8 rawOrigin;
+ in >> rawOrigin;
+ horzOrigin = (OriginType)(rawOrigin % 3);
+ vertOrigin = (OriginType)(rawOrigin / 3);
in >> (quint8&)alpha;
in.skipRawData(1); // padding
@@ -115,3 +119,26 @@ void LYTPane::addFontRefsToList(QStringList &list) const {
p->addFontRefsToList(list);
}
}
+
+
+float LYTPane::drawnVertexX() const {
+ switch (horzOrigin) {
+ case Center:
+ return -width / 2.0f;
+ case Right:
+ return -width;
+ default:
+ return 0.0f;
+ }
+}
+
+float LYTPane::drawnVertexY() const {
+ switch (vertOrigin) {
+ case Center:
+ return height / 2.0f;
+ case Bottom:
+ return height;
+ default:
+ return 0.0f;
+ }
+}
diff --git a/lyt/pane.h b/lyt/pane.h
index 8b80029..0d9936b 100644
--- a/lyt/pane.h
+++ b/lyt/pane.h
@@ -35,6 +35,10 @@ public:
virtual Magic magic() const;
+ enum PaneTypes {
+ PaneType = 0, PictureType, TextBoxType, WindowType, BoundingType
+ };
+
virtual void writeToDataStream(QDataStream &out) const;
virtual void readFromDataStream(QDataStream &in);
@@ -50,7 +54,18 @@ public:
QList<LYTPane *> children;
quint8 flags;
- quint8 origin;
+
+ enum OriginType {
+ Left = 0, Top = 0,
+ Center = 1,
+ Right = 2, Bottom = 2
+ };
+ OriginType horzOrigin;
+ OriginType vertOrigin;
+
+ float drawnVertexX() const;
+ float drawnVertexY() const;
+
quint8 alpha;
QString name;
@@ -70,8 +85,11 @@ public:
float width;
float height;
+ PaneTypes type() const { return m_type; }
+
protected:
LYTLayout &m_layout;
+ PaneTypes m_type;
};
diff --git a/lyt/picture.cpp b/lyt/picture.cpp
index 8cd5f1f..facd5ca 100644
--- a/lyt/picture.cpp
+++ b/lyt/picture.cpp
@@ -21,6 +21,7 @@
LYTPicture::LYTPicture(LYTLayout &layout) : LYTPane(layout) {
+ m_type = PictureType;
}
diff --git a/lyt/textbox.cpp b/lyt/textbox.cpp
index e1b640e..e943963 100644
--- a/lyt/textbox.cpp
+++ b/lyt/textbox.cpp
@@ -21,6 +21,7 @@
LYTTextBox::LYTTextBox(LYTLayout &layout) : LYTPane(layout) {
+ m_type = TextBoxType;
}
diff --git a/lyt/window.cpp b/lyt/window.cpp
index 52d2db9..096f747 100644
--- a/lyt/window.cpp
+++ b/lyt/window.cpp
@@ -50,6 +50,7 @@ void LYTWindowFrame::dumpToDebug() const {
LYTWindow::LYTWindow(LYTLayout &layout) : LYTPane(layout) {
+ m_type = WindowType;
}
LYTWindow::~LYTWindow() {
diff --git a/main.cpp b/main.cpp
index 795386c..e2fb2f7 100644
--- a/main.cpp
+++ b/main.cpp
@@ -27,24 +27,42 @@
#include "wii/archiveu8.h"
+#include "layoutgl/widget.h"
+
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
LSGlobals::setup();
+ LSMainWindow w;
+ w.show();
+
+ return a.exec();
+
/*QFile file("H:\\ISOs\\NSMBWii\\Extracted\\Layout\\continue\\continue.arc");
file.open(QFile::ReadOnly);
QByteArray arc = file.readAll();
file.close();*/
- LYTArchivePackage package("H:\\ISOs\\NSMBWii\\Extracted\\Layout\\continue\\continue.arc");
- LYTLayout layout(package, "continue_05.brlyt");
- QByteArray brlyt = layout.pack();
- QFile file("H:\\ISOs\\NSMBWii\\Extracted\\Layout\\continue\\continue\\arc\\blyt\\continue_05_repack.brlyt");
- file.open(QFile::WriteOnly);
- file.write(brlyt);
- file.close();
+ //LYTArchivePackage package("H:\\ISOs\\NSMBWii\\Extracted\\Layout\\continue\\continue.arc");
+ QString blah1 = "preGame";
+ //QString blah = "preGame/preGame.arc";
+ QString blah = QString("%1/%1.arc").arg(blah1);
+ QString cpath;
+ if (QFile::exists("/home/me/Games/Newer/ISO/files/Layout/" + blah)) {
+ cpath = "/home/me/Games/Newer/ISO/files/Layout/" + blah;
+ } else {
+ cpath = "Z:\\stuff\\Games\\Newer\\ISO\\files\\Layout\\" + blah;
+ }
+ LYTArchivePackage package(cpath);
+ LYTLayout layout(package, package.listLayouts().first());
+ //LYTLayout layout(package, "continue_05.brlyt");
+ //QByteArray brlyt = layout.pack();
+ //QFile file("H:\\ISOs\\NSMBWii\\Extracted\\Layout\\continue\\continue\\arc\\blyt\\continue_05_repack.brlyt");
+ //file.open(QFile::WriteOnly);
+ //file.write(brlyt);
+ //file.close();
//package.writeLayout("continue_05.brlyt", brlyt);
//package.savePackage();
@@ -52,10 +70,17 @@ int main(int argc, char *argv[]) {
//LYTDirectoryPackage package("H:\\ISOs\\NSMBWii\\Extracted\\Layout\\continue\\continue\\arc");
//LYTLayout layout(package, "continue_05.brlyt");
//LYTDirectoryPackage package("H:\\ISOs\\TP\\banner\\arc_extr");
+ //LYTDirectoryPackage package("/mnt/h/ISOs/TP/banner/arc_extr");
+ //LYTDirectoryPackage package("/mnt/h/ISOs/hbm/InetChannelNew/0001000148414450/00000000_app_OUT/meta/banner_bin_OUT/arc");
+ //LYTDirectoryPackage package("/mnt/h/ISOs/CSWii/BannerTools/0001000157435645/00000000_app_OUT/meta/banner_bin_OUT/arc");
//LYTLayout layout(package, "banner.brlyt");
- LSMainWindow w;
+ //LSMainWindow w;
w.show();
+ LGLWidget w2;
+ w2.setLayout(&layout);
+ w2.show();
+
return a.exec();
}
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