summaryrefslogtreecommitdiff
path: root/lyt
diff options
context:
space:
mode:
Diffstat (limited to 'lyt')
-rw-r--r--lyt/binaryfile.cpp66
-rw-r--r--lyt/binaryfile.h22
-rw-r--r--lyt/binaryfilesection.cpp28
-rw-r--r--lyt/binaryfilesection.h23
-rw-r--r--lyt/bounding.cpp26
-rw-r--r--lyt/bounding.h22
-rw-r--r--lyt/common.cpp92
-rw-r--r--lyt/common.h104
-rw-r--r--lyt/directorypackage.cpp119
-rw-r--r--lyt/directorypackage.h38
-rw-r--r--lyt/group.cpp38
-rw-r--r--lyt/group.h22
-rw-r--r--lyt/layout.cpp223
-rw-r--r--lyt/layout.h67
-rw-r--r--lyt/materials/material.cpp127
-rw-r--r--lyt/materials/material.h183
-rw-r--r--lyt/materials/texmap.cpp41
-rw-r--r--lyt/materials/texmap.h25
-rw-r--r--lyt/packagebase.cpp5
-rw-r--r--lyt/packagebase.h31
-rw-r--r--lyt/pane.cpp87
-rw-r--r--lyt/pane.h58
-rw-r--r--lyt/picture.cpp73
-rw-r--r--lyt/picture.h27
-rw-r--r--lyt/textbox.cpp115
-rw-r--r--lyt/textbox.h37
-rw-r--r--lyt/window.cpp184
-rw-r--r--lyt/window.h63
28 files changed, 1946 insertions, 0 deletions
diff --git a/lyt/binaryfile.cpp b/lyt/binaryfile.cpp
new file mode 100644
index 0000000..8ac2a01
--- /dev/null
+++ b/lyt/binaryfile.cpp
@@ -0,0 +1,66 @@
+#include "binaryfile.h"
+#include "binaryfilesection.h"
+
+#include <QtCore/QDataStream>
+
+LYTBinaryFile::LYTBinaryFile(Magic magic, Version version) {
+ this->magic.value = magic.value;
+ this->version.value = version.value;
+}
+
+
+LYTBinaryFile::LYTBinaryFile(QByteArray data) {
+ QDataStream reader(data);
+ InitDataStream(reader);
+
+ quint16 endian, firstSectionOffset, sectionCount;
+ quint32 fileSize;
+
+ reader >> this->magic.value;
+ reader >> endian;
+ reader >> this->version.value;
+ reader >> fileSize;
+ reader >> firstSectionOffset;
+ reader >> sectionCount;
+
+ LYTBinaryFileSection section;
+
+ for (int i = 0; i < sectionCount; i++) {
+ section.readFromDataStream(reader);
+ this->sections.append(section);
+ }
+}
+
+
+QByteArray LYTBinaryFile::pack() {
+ // first off, calculate filesize for the header
+ quint32 fileSize = 16;
+
+ foreach (LYTBinaryFileSection section, this->sections) {
+ fileSize += section.writtenSize();
+ }
+
+ // set up other fields
+ quint16 endian, firstSectionOffset;
+ endian = 0xFEFF;
+ firstSectionOffset = 16;
+
+
+ // write it
+ QByteArray output;
+ QDataStream writer(&output, QIODevice::WriteOnly);
+ InitDataStream(writer);
+
+ writer << this->magic.value;
+ writer << endian;
+ writer << this->version.value;
+ writer << fileSize;
+ writer << firstSectionOffset;
+ writer << (quint16)this->sections.count();
+
+ foreach (LYTBinaryFileSection section, this->sections) {
+ section.writeToDataStream(writer);
+ }
+
+ return output;
+}
diff --git a/lyt/binaryfile.h b/lyt/binaryfile.h
new file mode 100644
index 0000000..6cc278c
--- /dev/null
+++ b/lyt/binaryfile.h
@@ -0,0 +1,22 @@
+#ifndef LYTBINARYFILE_H
+#define LYTBINARYFILE_H
+
+#include <QtCore/QList>
+
+#include "common.h"
+#include "binaryfilesection.h"
+
+class LYTBinaryFile {
+public:
+ LYTBinaryFile(Magic magic, Version version);
+ LYTBinaryFile(QByteArray data);
+
+ QByteArray pack();
+
+ Magic magic;
+ Version version;
+
+ QList<LYTBinaryFileSection> sections;
+};
+
+#endif // LYTBINARYFILE_H
diff --git a/lyt/binaryfilesection.cpp b/lyt/binaryfilesection.cpp
new file mode 100644
index 0000000..59dd9a1
--- /dev/null
+++ b/lyt/binaryfilesection.cpp
@@ -0,0 +1,28 @@
+#include "binaryfilesection.h"
+
+LYTBinaryFileSection::LYTBinaryFileSection() {
+}
+
+
+void LYTBinaryFileSection::writeToDataStream(QDataStream &out) {
+ out << (quint32)magic.value;
+ out << (quint32)data.length() + 8;
+ out.writeRawData(data.constData(), data.length());
+}
+
+void LYTBinaryFileSection::readFromDataStream(QDataStream &in) {
+ quint32 length;
+
+ in >> (quint32&)magic.value;
+ in >> (quint32&)length;
+
+ char *raw = new char[length - 8];
+ in.readRawData(raw, length - 8);
+
+ data = QByteArray(raw, length - 8);
+}
+
+
+int LYTBinaryFileSection::writtenSize() {
+ return 8 + this->data.length();
+}
diff --git a/lyt/binaryfilesection.h b/lyt/binaryfilesection.h
new file mode 100644
index 0000000..0d6c4f7
--- /dev/null
+++ b/lyt/binaryfilesection.h
@@ -0,0 +1,23 @@
+#ifndef LYTBINARYFILESECTION_H
+#define LYTBINARYFILESECTION_H
+
+#include <QtCore/QDataStream>
+
+#include "common.h"
+
+class LYTBinaryFileSection {
+public:
+ LYTBinaryFileSection();
+
+ Magic magic;
+ QByteArray data;
+
+ void writeToDataStream(QDataStream &out);
+ void readFromDataStream(QDataStream &in);
+
+ int writtenSize();
+};
+
+
+
+#endif // LYTBINARYFILESECTION_H
diff --git a/lyt/bounding.cpp b/lyt/bounding.cpp
new file mode 100644
index 0000000..0ae793b
--- /dev/null
+++ b/lyt/bounding.cpp
@@ -0,0 +1,26 @@
+#include "bounding.h"
+#include "layout.h"
+#include "common.h"
+
+
+LYTBounding::LYTBounding(LYTLayout &layout) : LYTPane(layout) {
+}
+
+
+void LYTBounding::dumpToDebug(bool showHeading) {
+ if (showHeading)
+ qDebug() << "LYTBounding" << name << "@" << (void*)this;
+
+ LYTPane::dumpToDebug(false);
+}
+
+
+
+void LYTBounding::writeToDataStream(QDataStream &out) {
+ LYTPane::writeToDataStream(out);
+}
+
+
+void LYTBounding::readFromDataStream(QDataStream &in) {
+ LYTPane::readFromDataStream(in);
+}
diff --git a/lyt/bounding.h b/lyt/bounding.h
new file mode 100644
index 0000000..c742ad8
--- /dev/null
+++ b/lyt/bounding.h
@@ -0,0 +1,22 @@
+#ifndef LYTBOUNDING_H
+#define LYTBOUNDING_H
+
+#include "common.h"
+#include "pane.h"
+
+// the most useful object in LYT
+// it's just a regular Pane ... with a different name.
+
+class LYTBounding : public LYTPane {
+public:
+ LYTBounding(LYTLayout &layout);
+
+
+ void writeToDataStream(QDataStream &out);
+ void readFromDataStream(QDataStream &in);
+
+ void dumpToDebug(bool showHeading=true);
+};
+
+
+#endif // LYTPICTURE_H
diff --git a/lyt/common.cpp b/lyt/common.cpp
new file mode 100644
index 0000000..f23e68a
--- /dev/null
+++ b/lyt/common.cpp
@@ -0,0 +1,92 @@
+#include "common.h"
+
+QByteArray PadByteArray(QByteArray original, int newLength, char padWith) {
+ QByteArray newArray = original;
+
+ if (original.length() > newLength) {
+ // the original array is longer than the length desired, so truncate it
+ newArray.truncate(newLength);
+
+ } else if (original.length() < newLength) {
+ // the original array is shorter, so pad it
+ int oldLength = original.length();
+ newArray.resize(newLength);
+
+ for (int i = oldLength; i < newLength; i++) {
+ newArray[i] = '\0';
+ }
+ }
+
+ return newArray;
+}
+
+QStringList ReadStringList(QDataStream &in) {
+ QStringList output;
+
+ quint16 count;
+ in >> (quint16&)count;
+ in.skipRawData(2); // padding
+
+ QVector<quint32> stringOffsets(count);
+
+ // save the initial offset so we can get the strings later
+ // string offsets are based on the first offset entry (after the count)
+ // NOT on the section offset
+ qint64 savedPos = in.device()->pos();
+
+ for (int i = 0; i < count; i++) {
+ quint32 offset;
+ in >> (quint32&)offset;
+ in.skipRawData(4); // unused?
+
+ stringOffsets[i] = offset;
+ }
+
+ // ok, now we can get the strings
+ for (int i = 0; i < count; i++) {
+ in.device()->seek(savedPos + stringOffsets[i]);
+
+ // how fun: no length is stored for each string, they're just zero
+ // terminated. so let's try to figure it out!
+ int stringLength = 0;
+ char check;
+
+ in >> (quint8&)check;
+ while (check != 0) {
+ stringLength += 1;
+ in >> (quint8&)check;
+ }
+
+ // now read the string
+ char *buffer = new char[stringLength];
+
+ in.device()->seek(savedPos + stringOffsets[i]);
+ in.readRawData(buffer, stringLength);
+
+ output.append(QString::fromAscii(buffer, stringLength));
+
+ delete[] buffer;
+
+
+ qDebug() << "Read string:" << output.last();
+ }
+
+ return output;
+}
+
+QString ReadFixedLengthASCII(QDataStream &in, int length) {
+ QByteArray readStr(length, '\0');
+ in.readRawData(readStr.data(), readStr.length());
+
+ QString str = QString::fromAscii(readStr.data(), readStr.length());
+ if (str.contains(QChar('\0')))
+ str.truncate(str.indexOf(QChar('\0')));
+
+ return str;
+}
+
+void WriteFixedLengthASCII(QDataStream &out, QString str, int length) {
+ QByteArray paddedStr = PadByteArray(str.toAscii(), length);
+ out.writeRawData(paddedStr.constData(), paddedStr.length());
+}
+
diff --git a/lyt/common.h b/lyt/common.h
new file mode 100644
index 0000000..72149d4
--- /dev/null
+++ b/lyt/common.h
@@ -0,0 +1,104 @@
+#ifndef LYTCOMMON_H
+#define LYTCOMMON_H
+
+#include <QtGlobal>
+#include <QtCore/QByteArray>
+#include <QtGui/QColor>
+#include <QtCore/QPointF>
+#include <QtCore/QDataStream>
+#include <QtCore/QStringList>
+#include <QtCore/QDebug>
+#include <QtCore/QVector>
+
+union Magic {
+ char str[4];
+ quint32 value;
+};
+
+union Version {
+ char str[2];
+ quint16 value;
+};
+
+
+
+inline quint32 BitExtract(quint32 value, int count, int start) {
+ // this function relies on heavy compiler optimisation to be efficient :p
+ quint32 mask = 0;
+ for (int i = start; i < start+count; i++) {
+ mask |= (0x80000000 >> i);
+ }
+
+ return (value & mask) >> (32 - (start + count));
+}
+
+
+QByteArray PadByteArray(QByteArray original, int newLength, char padWith='\0');
+
+inline quint32 ColorToRGBA(QColor col) {
+ return (col.red() << 24) | (col.green() << 16) | (col.blue() << 8) | (col.alpha());
+}
+
+inline QColor RGBAToColor(quint32 col) {
+ return QColor(col >> 24, (col >> 16) & 0xFF, (col >> 8) & 0xFF, col & 0xFF);
+}
+
+inline void ReadRGBA8Color(QColor &out, QDataStream &in) {
+ quint32 col;
+ in >> (quint32&)col;
+ out = RGBAToColor(col);
+}
+
+inline void WriteRGBA8Color(QColor &in, QDataStream &out) {
+ out << (quint32)ColorToRGBA(in);
+}
+
+inline void ReadS10Color(QColor &out, QDataStream &in) {
+ quint16 r, g, b, a;
+ in >> (quint16&)r;
+ in >> (quint16&)g;
+ in >> (quint16&)b;
+ in >> (quint16&)a;
+ out.setRgb(r, g, b, a);
+}
+
+inline void WriteS10Color(QColor &in, QDataStream &out) {
+ out << (quint16)in.red();
+ out << (quint16)in.green();
+ out << (quint16)in.blue();
+ out << (quint16)in.alpha();
+}
+
+
+
+
+struct LYTTexCoords {
+ QPointF coord[4];
+};
+
+inline void ReadPointF(QDataStream &stream, QPointF &point) {
+ float x, y;
+ stream >> x;
+ stream >> y;
+ point.setX(x);
+ point.setY(y);
+}
+
+inline void WritePointF(QDataStream &stream, const QPointF &point) {
+ stream << (float)point.x();
+ stream << (float)point.y();
+}
+
+inline void InitDataStream(QDataStream &stream) {
+ stream.setByteOrder(QDataStream::BigEndian);
+ stream.setVersion(QDataStream::Qt_4_5);
+}
+
+QStringList ReadStringList(QDataStream &in);
+
+QString ReadFixedLengthASCII(QDataStream &in, int length);
+void WriteFixedLengthASCII(QDataStream &out, QString str, int length);
+
+
+
+#endif // LYTCOMMON_H
diff --git a/lyt/directorypackage.cpp b/lyt/directorypackage.cpp
new file mode 100644
index 0000000..93e3ad8
--- /dev/null
+++ b/lyt/directorypackage.cpp
@@ -0,0 +1,119 @@
+#include "directorypackage.h"
+
+#include <QDir>
+
+LYTDirectoryPackage::LYTDirectoryPackage(QString path) : LYTPackageBase() {
+ QDir fix_path(path);
+ this->m_path = fix_path.absolutePath();
+}
+
+
+
+QStringList LYTDirectoryPackage::listSubDirIfExists(QString dirName) {
+ QDir search(m_path);
+
+ if (search.cd(dirName)) {
+ return search.entryList();
+ }
+
+ return QStringList();
+}
+
+
+QByteArray LYTDirectoryPackage::getFileFromSubDirIfExists(QString dirName, QString fileName) {
+ QDir search(m_path);
+
+ if (search.cd(dirName)) {
+ QFile file(search.absoluteFilePath(fileName));
+
+ if (file.open(QFile::ReadOnly)) {
+ return file.readAll();
+ }
+ }
+
+ return QByteArray();
+}
+
+
+bool LYTDirectoryPackage::writeFileToSubDir(QString dirName, QString fileName, QByteArray data) {
+ QDir search(m_path);
+
+ if (search.cd(dirName)) {
+ QFile file(search.absoluteFilePath(fileName));
+
+ if (file.open(QFile::WriteOnly)) {
+ if (file.write(data) != -1) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+
+
+
+QStringList LYTDirectoryPackage::listAnims() {
+ return this->listSubDirIfExists("anim");
+}
+
+QStringList LYTDirectoryPackage::listLayouts() {
+ return this->listSubDirIfExists("blyt");
+}
+
+QStringList LYTDirectoryPackage::listTextures() {
+ return this->listSubDirIfExists("timg");
+}
+
+QStringList LYTDirectoryPackage::listFonts() {
+ return this->listSubDirIfExists("font");
+}
+
+
+
+QByteArray LYTDirectoryPackage::getAnim(QString name) {
+ return this->getFileFromSubDirIfExists("anim", name);
+}
+
+QByteArray LYTDirectoryPackage::getLayout(QString name) {
+ return this->getFileFromSubDirIfExists("blyt", name);
+}
+
+QByteArray LYTDirectoryPackage::getTexture(QString name) {
+ return this->getFileFromSubDirIfExists("timg", name);
+}
+
+QByteArray LYTDirectoryPackage::getFont(QString name) {
+ return this->getFileFromSubDirIfExists("font", name);
+}
+
+
+
+bool LYTDirectoryPackage::writeAnim(QString name, QByteArray data) {
+ return this->writeFileToSubDir("anim", name, data);
+}
+
+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);
+}
+
+bool LYTDirectoryPackage::writeFont(QString name, QByteArray data) {
+ return this->writeFileToSubDir("font", name, data);
+}
+
+
+
+bool LYTDirectoryPackage::savePackage() {
+ // No-op since this is a directory
+ return true;
+}
+
+
+QString LYTDirectoryPackage::description() {
+ return m_path;
+}
diff --git a/lyt/directorypackage.h b/lyt/directorypackage.h
new file mode 100644
index 0000000..78c6580
--- /dev/null
+++ b/lyt/directorypackage.h
@@ -0,0 +1,38 @@
+#ifndef LYTDIRECTORYPACKAGE_H
+#define LYTDIRECTORYPACKAGE_H
+
+#include "packagebase.h"
+
+class LYTDirectoryPackage : public LYTPackageBase {
+public:
+ LYTDirectoryPackage(QString path);
+
+ QStringList listAnims();
+ QStringList listLayouts();
+ QStringList listTextures();
+ QStringList listFonts();
+
+ QByteArray getAnim(QString name);
+ QByteArray getLayout(QString name);
+ QByteArray getTexture(QString name);
+ QByteArray getFont(QString name);
+
+ bool writeAnim(QString name, QByteArray data);
+ bool writeLayout(QString name, QByteArray data);
+ bool writeTexture(QString name, QByteArray data);
+ bool writeFont(QString name, QByteArray data);
+
+ bool savePackage();
+ QString description();
+ QString path();
+
+protected:
+ QStringList listSubDirIfExists(QString dirName);
+ QByteArray getFileFromSubDirIfExists(QString dirName, QString fileName);
+ bool writeFileToSubDir(QString dirName, QString fileName, QByteArray data);
+
+
+ QString m_path;
+};
+
+#endif // LYTDIRECTORYPACKAGE_H
diff --git a/lyt/group.cpp b/lyt/group.cpp
new file mode 100644
index 0000000..c3a16fb
--- /dev/null
+++ b/lyt/group.cpp
@@ -0,0 +1,38 @@
+#include "group.h"
+
+LYTGroup::LYTGroup() {
+}
+
+
+
+
+void LYTGroup::writeToDataStream(QDataStream &out) {
+ WriteFixedLengthASCII(out, name, 0x10);
+
+ // write the contents
+ out << (quint16)panes.count();
+ out.skipRawData(2); // padding
+
+ foreach (LYTPane *pane, panes) {
+ WriteFixedLengthASCII(out, pane->name, 0x10);
+ }
+}
+
+
+void LYTGroup::readFromDataStream(QDataStream &in, LYTPane &linkedPane) {
+ name = ReadFixedLengthASCII(in, 0x10);
+ qDebug() << "reading group" << name;
+
+ // read the contents
+ quint16 paneCount;
+ in >> (quint16&)paneCount;
+ in.skipRawData(2); // padding
+
+ for (int i = 0; i < paneCount; i++) {
+ QString paneName = ReadFixedLengthASCII(in, 0x10);
+
+ qDebug() << "found" << paneName << "in group" << this->name;
+
+ this->panes.append(linkedPane.findPaneByName(paneName, true));
+ }
+}
diff --git a/lyt/group.h b/lyt/group.h
new file mode 100644
index 0000000..e02b710
--- /dev/null
+++ b/lyt/group.h
@@ -0,0 +1,22 @@
+#ifndef LYTGROUP_H
+#define LYTGROUP_H
+
+#include "common.h"
+#include "pane.h"
+
+#include <QtCore/QList>
+
+class LYTGroup {
+public:
+ LYTGroup();
+
+
+ void writeToDataStream(QDataStream &out);
+ void readFromDataStream(QDataStream &in, LYTPane &linkedPane);
+
+ QString name;
+
+ QList<LYTPane *> panes;
+};
+
+#endif // LYTGROUP_H
diff --git a/lyt/layout.cpp b/lyt/layout.cpp
new file mode 100644
index 0000000..e501a72
--- /dev/null
+++ b/lyt/layout.cpp
@@ -0,0 +1,223 @@
+#include "layout.h"
+#include <QtCore/QStack>
+#include <QtCore/QVector>
+
+
+LYTLayout::LYTLayout(LYTPackageBase &package) : rootPane(0), m_package(package) {
+ this->clear();
+}
+
+LYTLayout::LYTLayout(LYTPackageBase &package, QString name) : rootPane(0), m_package(package) {
+ this->loadLayoutFromPackage(name);
+}
+
+LYTLayout::~LYTLayout() {
+ this->clear();
+}
+
+
+void LYTLayout::clear() {
+ this->width = 608.0;
+ this->height = 456.0;
+
+ this->m_fontRefs.clear();
+ this->m_textureRefs.clear();
+
+ foreach (LYTMaterial *material, materials.values())
+ delete material;
+
+ this->materials.clear();
+
+ if (this->rootPane != 0)
+ delete this->rootPane;
+}
+
+
+LYTPackageBase &LYTLayout::package() const {
+ return m_package;
+}
+
+
+bool LYTLayout::loadLayoutFromPackage(QString name) {
+ qDebug() << "Loading layout: " << name;
+ qDebug() << "From package: " << m_package.description();
+
+ QStack<LYTPane *> paneStack;
+ LYTPane *lastPane, *newPane;
+
+ bool hasGroupContainer = false;
+ int groupStackID = 0;
+
+ QByteArray layoutData = m_package.getLayout(name);
+ LYTBinaryFile file(layoutData);
+
+ this->clear();
+
+ foreach (LYTBinaryFileSection section, file.sections) {
+ // Handle every section in the file
+
+ qDebug("Handling %c%c%c%c", section.magic.str[3], section.magic.str[2], section.magic.str[1], section.magic.str[0]);
+
+ switch (section.magic.value) {
+ case 'lyt1':
+ this->readLyt1(section);
+ break;
+
+ case 'txl1':
+ this->readTxl1(section);
+ break;
+
+ case 'fnl1':
+ this->readFnl1(section);
+ break;
+
+ case 'mat1':
+ this->readMat1(section);
+ break;
+
+ case 'pan1':
+ case 'txt1':
+ case 'pic1':
+ case 'wnd1':
+ case 'bnd1':
+ newPane = this->createPaneObj(section);
+ newPane->dumpToDebug();
+
+ if (rootPane == 0)
+ rootPane = newPane;
+
+ if (!paneStack.empty()) {
+ newPane->parent = paneStack.last();
+ paneStack.last()->children.append(newPane);
+ }
+
+ lastPane = newPane;
+
+ break;
+
+ case 'pas1':
+ paneStack.push(lastPane);
+ break;
+
+ case 'pae1':
+ lastPane = paneStack.pop();
+ break;
+
+ case 'grp1':
+ if (!hasGroupContainer) {
+ // nw4r::lyt::Layout::Build actually creates a GroupContainer
+ // but we just use a QList so we don't need to do that
+ hasGroupContainer = true;
+ } else {
+ if (groupStackID == 1) {
+ // create a group and add it to the list
+ QDataStream in(section.data);
+ InitDataStream(in);
+ groups.append(new LYTGroup());
+ groups.last()->readFromDataStream(in, *this->rootPane);
+ }
+ }
+
+ break;
+
+ case 'grs1':
+ groupStackID++;
+ break;
+
+ case 'gre1':
+ groupStackID--;
+ break;
+ }
+ }
+
+ // todo: usd1
+
+ return true;
+}
+
+void LYTLayout::readLyt1(LYTBinaryFileSection &section) {
+ // initial info block containing width + height
+
+ QDataStream in(section.data);
+ InitDataStream(in);
+
+ in.skipRawData(4); // unused in newer nw4r::lyt versions - TODO: add support
+ in >> (float&)width;
+ in >> (float&)height;
+
+ qDebug() << "Read lyt1 block: layout size:" << width << "x" << height;
+}
+
+void LYTLayout::readTxl1(LYTBinaryFileSection &section) {
+ // list of texture references for this layout
+
+ QDataStream in(section.data);
+ InitDataStream(in);
+ m_textureRefs = ReadStringList(in);
+}
+
+void LYTLayout::readFnl1(LYTBinaryFileSection &section) {
+ // list of font references for this layout
+
+ QDataStream in(section.data);
+ InitDataStream(in);
+ m_fontRefs = ReadStringList(in);
+}
+
+void LYTLayout::readMat1(LYTBinaryFileSection &section) {
+ // the material section for the layout
+ // not fun.
+
+ QDataStream in(section.data);
+ InitDataStream(in);
+
+ quint16 count;
+ in >> (quint16&)count;
+ in.skipRawData(2); // padding
+
+ // create a list of every offset
+ // these offsets are from the start of the section, not from
+ // the first offset entry like StringLists are
+ QVector<quint32> materialOffsets(count);
+
+ for (int i = 0; i < count; i++) {
+ quint32 offset;
+ in >> (quint32&)offset;
+ materialOffsets[i] = offset;
+ }
+
+ // now read each material
+ for (int i = 0; i < count; i++) {
+ // subtract 8 from the offset because section.data doesn't contain
+ // the nw4r::ut::BinaryBlockHeader whereas these offsets do count it
+ in.device()->seek(materialOffsets[i] - 8);
+
+ LYTMaterial *material = new LYTMaterial(*this);
+ material->readFromDataStream(in);
+ material->dumpToDebug();
+
+ materials.insert(material->name, material);
+ }
+}
+
+LYTPane *LYTLayout::createPaneObj(LYTBinaryFileSection &section) {
+ LYTPane *pane;
+
+ if (section.magic.value == 'pan1')
+ pane = new LYTPane(*this);
+ else if (section.magic.value == 'txt1')
+ pane = new LYTTextBox(*this);
+ else if (section.magic.value == 'pic1')
+ pane = new LYTPicture(*this);
+ else if (section.magic.value == 'wnd1')
+ pane = new LYTWindow(*this);
+ else if (section.magic.value == 'bnd1')
+ pane = new LYTBounding(*this);
+
+ QDataStream in(section.data);
+ InitDataStream(in);
+
+ pane->readFromDataStream(in);
+
+ return pane;
+}
diff --git a/lyt/layout.h b/lyt/layout.h
new file mode 100644
index 0000000..2af32a1
--- /dev/null
+++ b/lyt/layout.h
@@ -0,0 +1,67 @@
+#ifndef LYTLAYOUT_H
+#define LYTLAYOUT_H
+
+#include "packagebase.h"
+#include "materials/material.h"
+#include "group.h"
+#include "pane.h"
+#include "textbox.h"
+#include "picture.h"
+#include "window.h"
+#include "bounding.h"
+#include "binaryfile.h"
+#include "binaryfilesection.h"
+
+#include <QtCore/QStringList>
+#include <QtCore/QMap>
+#include <QtCore/QDataStream>
+
+class LYTTexMap; // forward declaration so it can be a friend class
+
+class LYTLayout {
+public:
+ LYTLayout(LYTPackageBase &package);
+ LYTLayout(LYTPackageBase &package, QString name);
+ ~LYTLayout();
+
+ void clear();
+ LYTPackageBase &package() const;
+
+ float width;
+ float height;
+
+ QMap<QString, LYTMaterial *> materials;
+
+ LYTPane *rootPane;
+ QList<LYTGroup *> groups;
+
+
+
+protected:
+ LYTPackageBase &m_package;
+
+ // these are private because they are not intended for public use
+ // they're only here so that LYTPane's subclasses and a few others can read
+ // this info when reading/writing -- hence why they are friend classes
+ QStringList m_fontRefs;
+ QStringList m_textureRefs;
+
+ bool loadLayoutFromPackage(QString name);
+
+ void readLyt1(LYTBinaryFileSection &section);
+ void readTxl1(LYTBinaryFileSection &section);
+ void readFnl1(LYTBinaryFileSection &section);
+ void readMat1(LYTBinaryFileSection &section);
+
+ LYTPane *createPaneObj(LYTBinaryFileSection &section);
+
+ friend class LYTPane;
+ friend class LYTTextBox;
+ friend class LYTPicture;
+ friend class LYTWindow;
+ friend class LYTBounding;
+ friend class LYTTexMap;
+
+};
+
+#endif // LYTLAYOUT_H
diff --git a/lyt/materials/material.cpp b/lyt/materials/material.cpp
new file mode 100644
index 0000000..a23534c
--- /dev/null
+++ b/lyt/materials/material.cpp
@@ -0,0 +1,127 @@
+#include "material.h"
+#include "../layout.h"
+
+LYTMaterial::LYTMaterial(LYTLayout &layout) : m_layout(layout) {
+}
+
+LYTMaterial::~LYTMaterial() {
+}
+
+LYTLayout &LYTMaterial::layout() const {
+ return m_layout;
+}
+
+
+void LYTMaterial::dumpToDebug() {
+ qDebug() << "LYTMaterial" << name << "@" << (void*)this;
+}
+
+
+
+void LYTMaterial::writeToDataStream(QDataStream &out) {
+ WriteFixedLengthASCII(out, name, 0x14);
+}
+
+void LYTMaterial::readFromDataStream(QDataStream &in) {
+ name = ReadFixedLengthASCII(in, 0x14);
+
+ for (int i = 0; i < 3; i++)
+ ReadS10Color(this->colours[i], in);
+
+ for (int i = 0; i < 4; i++)
+ ReadRGBA8Color(this->tevKColour[i], in);
+
+
+ LYTMaterialResourceNum resourceNum;
+ in >> (quint32&)resourceNum.value;
+
+ // this is really complicated -_-
+ // first off: TexMap
+ texMaps.clear();
+
+ for (int i = 0; i < resourceNum.getTexMapNum(); i++) {
+ this->readTexMap(in);
+ }
+
+ // TexSRT
+ /*texSRTs.clear();
+
+ for (int i = 0; i < resourceNum.getTexSRTNum(); i++) {
+ this->readTexSRT(in);
+ }
+
+ // TexCoordGen
+ texCoordGens.clear();
+
+ for (int i = 0; i < resourceNum.getTexCoordGenNum(); i++) {
+ this->readTexCoordGen(in);
+ }
+
+ // ChanCtrl
+ if (resourceNum.hasChanCtrl()) {
+ this->hasChanCtrl = true;
+ this->readChanCtrl(in);
+ } else {
+ this->hasChanCtrl = false;
+ }
+
+ // MatCol
+ if (resourceNum.hasMatCol()) {
+ this->hasMatCol = true;
+ this->readMatCol(in);
+ } else {
+ this->hasMatCol = false;
+ }
+
+ // TevSwapTable
+ if (resourceNum.hasTevSwapTable()) {
+ this->hasTevSwapTable = true;
+ this->readTevSwapTable(in);
+ } else {
+ this->hasTevSwapTable = false;
+ }
+
+ // IndTexSRT
+ indTexSRTs.clear();
+
+ for (int i = 0; i < resourceNum.getIndTexSRTNum(); i++) {
+ this->readIndTexSRT(in);
+ }
+
+ // IndTexStage
+ indTexStages.clear();
+
+ for (int i = 0; i < resourceNum.getIndTexStageNum(); i++) {
+ this->readIndirectStage(in);
+ }
+
+ // TevStage
+ tevStages.clear();
+
+ for (int i = 0; i < resourceNum.getTevStageNum(); i++) {
+ this->readTevStage(in);
+ }
+
+ // AlphaCompare
+ if (resourceNum.hasAlphaCompare()) {
+ this->hasAlphaCompare = true;
+ this->readAlphaCompare(in);
+ } else {
+ this->hasAlphaCompare = false;
+ }
+
+ // BlendMode
+ if (resourceNum.hasBlendMode()) {
+ this->hasBlendMode = true;
+ this->readBlendMode(in);
+ } else {
+ this->hasBlendMode = false;
+ }*/
+}
+
+
+
+void LYTMaterial::readTexMap(QDataStream &in) {
+ this->texMaps.append(LYTTexMap());
+ this->texMaps.last().readFromDataStream(in, m_layout);
+}
diff --git a/lyt/materials/material.h b/lyt/materials/material.h
new file mode 100644
index 0000000..73a0e57
--- /dev/null
+++ b/lyt/materials/material.h
@@ -0,0 +1,183 @@
+#ifndef LYTMATERIAL_H
+#define LYTMATERIAL_H
+
+#include <QtCore/QList>
+#include <QtCore/QString>
+#include <QtCore/QDataStream>
+#include <QtCore/QDebug>
+
+#include "../common.h"
+#include "texmap.h"
+
+class LYTLayout;
+
+
+class LYTMaterialResourceNum {
+public:
+ quint32 value;
+
+ inline int getTexMapNum() { return BitExtract(value, 4, 28); }
+ inline int getTexSRTNum() { return BitExtract(value, 4, 24); }
+ inline int getTexCoordGenNum() { return BitExtract(value, 4, 20); }
+ inline bool hasChanCtrl() { return BitExtract(value, 1, 6); }
+ inline bool hasMatCol() { return BitExtract(value, 1, 4); }
+ inline bool hasTevSwapTable() { return BitExtract(value, 1, 19); }
+ inline bool hasAlphaCompare() { return BitExtract(value, 1, 8); }
+ inline bool hasBlendMode() { return BitExtract(value, 1, 7); }
+ inline int getIndTexSRTNum() { return BitExtract(value, 2, 17); }
+ inline int getIndTexStageNum() { return BitExtract(value, 3, 14); }
+ inline int getTevStageNum() { return BitExtract(value, 5, 9); }
+};
+
+
+
+class LYTTexCoordGen {
+public:
+ void writeToDataStream(QDataStream &out);
+ void readFromDataStream(QDataStream &in);
+
+ void dumpToDebug();
+
+ quint8 genType;
+ quint8 src;
+ quint8 mtx;
+};
+
+class LYTChanCtrl {
+public:
+ void writeToDataStream(QDataStream &out);
+ void readFromDataStream(QDataStream &in);
+
+ void dumpToDebug();
+
+ quint8 colourMatSrc;
+ quint8 alphaMatSrc;
+};
+
+class LYTTevSwapMode {
+public:
+ void writeToDataStream(QDataStream &out);
+ void readFromDataStream(QDataStream &in);
+
+ void dumpToDebug();
+
+ int red;
+ int green;
+ int blue;
+ int alpha;
+};
+
+class LYTTexSRT {
+public:
+ void writeToDataStream(QDataStream &out);
+ void readFromDataStream(QDataStream &in);
+
+ void dumpToDebug();
+
+ float xTrans;
+ float yTrans;
+ float rotate;
+ float xScale;
+ float yScale;
+};
+
+class LYTIndirectStage {
+public:
+ void writeToDataStream(QDataStream &out);
+ void readFromDataStream(QDataStream &in);
+
+ void dumpToDebug();
+
+};
+
+class LYTTevStage {
+public:
+ void writeToDataStream(QDataStream &out);
+ void readFromDataStream(QDataStream &in);
+
+ void dumpToDebug();
+
+};
+
+class LYTAlphaCompare {
+public:
+ void writeToDataStream(QDataStream &out);
+ void readFromDataStream(QDataStream &in);
+
+ void dumpToDebug();
+
+};
+
+class LYTBlendMode {
+public:
+ void writeToDataStream(QDataStream &out);
+ void readFromDataStream(QDataStream &in);
+
+ void dumpToDebug();
+
+};
+
+
+
+
+class LYTMaterial {
+public:
+ LYTMaterial(LYTLayout &layout);
+ ~LYTMaterial();
+
+
+ void writeToDataStream(QDataStream &out);
+ void readFromDataStream(QDataStream &in);
+
+ void dumpToDebug();
+
+ LYTLayout &layout() const;
+
+ QString name;
+
+ QColor colours[3];
+ QColor tevKColour[4];
+
+ QList<LYTTexMap> texMaps;
+ QList<LYTTexSRT> texSRTs;
+ QList<LYTTexCoordGen> texCoordGens;
+
+ bool hasChanCtrl;
+ LYTChanCtrl chanCtrl;
+
+ bool hasMatCol;
+ QColor matCol;
+
+ bool hasTevSwapTable;
+ LYTTevSwapMode tevSwapTable;
+
+ bool hasAlphaCompare;
+ LYTAlphaCompare alphaCompare;
+
+ bool hasBlendMode;
+ LYTBlendMode blendMode;
+
+ QList<LYTIndirectStage> indTexStages;
+ QList<LYTTexSRT> indTexSRTs;
+
+ QList<LYTTevStage> tevStages;
+
+
+
+protected:
+ LYTLayout &m_layout;
+
+ void readTexMap(QDataStream &in);
+ void readTexSRT(QDataStream &in);
+ void readTexCoordGen(QDataStream &in);
+ void readChanCtrl(QDataStream &in);
+ void readMatCol(QDataStream &in);
+ void readTevSwapTable(QDataStream &in);
+ void readAlphaCompare(QDataStream &in);
+ void readBlendMode(QDataStream &in);
+ void readIndirectStage(QDataStream &in);
+ void readIndTexSRT(QDataStream &in);
+ void readTevStage(QDataStream &in);
+};
+
+#endif // LYTMATERIAL_H
diff --git a/lyt/materials/texmap.cpp b/lyt/materials/texmap.cpp
new file mode 100644
index 0000000..1bb416b
--- /dev/null
+++ b/lyt/materials/texmap.cpp
@@ -0,0 +1,41 @@
+#include "texmap.h"
+#include "../layout.h"
+
+LYTTexMap::LYTTexMap() {
+}
+
+void LYTTexMap::dumpToDebug() {
+ qDebug() << "LYTTexMap @" << (void*)this << ":" << textureName;
+ qDebug() << "- wrap_s:" << wrap_s << "- wrap_t:" << wrap_t;
+ qDebug() << "- mag_filter:" << mag_filter << "- min_filter:" << min_filter;
+}
+
+
+void LYTTexMap::writeToDataStream(QDataStream &out, LYTLayout &layout) {
+ quint16 texNum = layout.m_textureRefs.indexOf(textureName);
+ out << (quint16)texNum;
+
+ quint8 var1, var2;
+ var1 = wrap_s | (((min_filter + 7) & 7) << 2);
+ var2 = wrap_t | (((mag_filter + 1) & 1) << 2);
+ out << (quint8)var1;
+ out << (quint8)var2;
+}
+
+
+void LYTTexMap::readFromDataStream(QDataStream &in, LYTLayout &layout) {
+ quint16 texNum;
+ in >> (quint16&)texNum;
+
+ textureName = layout.m_textureRefs[texNum];
+
+ quint8 var1, var2;
+ in >> (quint8&)var1;
+ in >> (quint8&)var2;
+
+ wrap_s = BitExtract(var1, 2, 30);
+ wrap_t = BitExtract(var2, 2, 30);
+
+ min_filter = (BitExtract(var1, 3, 27) + 1) & 7;
+ mag_filter = (BitExtract(var2, 1, 29) + 1) & 1;
+}
diff --git a/lyt/materials/texmap.h b/lyt/materials/texmap.h
new file mode 100644
index 0000000..5f74478
--- /dev/null
+++ b/lyt/materials/texmap.h
@@ -0,0 +1,25 @@
+#ifndef LYTTEXMAP_H
+#define LYTTEXMAP_H
+
+#include "../common.h"
+#include <QtCore/QDataStream>
+
+class LYTLayout; // forward declaration
+
+class LYTTexMap {
+public:
+ LYTTexMap();
+
+ void writeToDataStream(QDataStream &out, LYTLayout &layout);
+ void readFromDataStream(QDataStream &in, LYTLayout &layout);
+
+ void dumpToDebug();
+
+ QString textureName;
+ int wrap_s;
+ int wrap_t;
+ int mag_filter;
+ int min_filter;
+};
+
+#endif // LYTTEXMAP_H
diff --git a/lyt/packagebase.cpp b/lyt/packagebase.cpp
new file mode 100644
index 0000000..f1da14b
--- /dev/null
+++ b/lyt/packagebase.cpp
@@ -0,0 +1,5 @@
+#include "packagebase.h"
+
+LYTPackageBase::LYTPackageBase() {
+ // do nothing
+}
diff --git a/lyt/packagebase.h b/lyt/packagebase.h
new file mode 100644
index 0000000..7f04cea
--- /dev/null
+++ b/lyt/packagebase.h
@@ -0,0 +1,31 @@
+#ifndef LYTPACKAGEBASE_H
+#define LYTPACKAGEBASE_H
+
+#include <QStringList>
+#include <QByteArray>
+
+
+class LYTPackageBase {
+public:
+ LYTPackageBase();
+
+ virtual QStringList listAnims() = 0;
+ virtual QStringList listLayouts() = 0;
+ virtual QStringList listTextures() = 0;
+ virtual QStringList listFonts() = 0;
+
+ virtual QByteArray getAnim(QString name) = 0;
+ virtual QByteArray getLayout(QString name) = 0;
+ virtual QByteArray getTexture(QString name) = 0;
+ virtual QByteArray getFont(QString name) = 0;
+
+ 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 bool savePackage() = 0;
+ virtual QString description() = 0;
+};
+
+#endif // LYTPACKAGEBASE_H
diff --git a/lyt/pane.cpp b/lyt/pane.cpp
new file mode 100644
index 0000000..9cf3617
--- /dev/null
+++ b/lyt/pane.cpp
@@ -0,0 +1,87 @@
+#include "pane.h"
+#include "layout.h"
+
+LYTPane::LYTPane(LYTLayout &layout) : m_layout(layout) {
+ this->parent = 0;
+}
+
+LYTPane::~LYTPane() {
+ foreach (LYTPane *ptr, this->children)
+ delete ptr;
+}
+
+LYTPane *LYTPane::findPaneByName(QString name, bool recursive) {
+ foreach (LYTPane *pane, this->children) {
+ if (pane->name == name)
+ return pane;
+
+ if (recursive) {
+ LYTPane *tryThis = pane->findPaneByName(name, recursive);
+ if (tryThis != 0)
+ return tryThis;
+ }
+ }
+
+ return 0;
+}
+
+LYTLayout &LYTPane::layout() const {
+ return m_layout;
+}
+
+
+void LYTPane::dumpToDebug(bool showHeading) {
+ if (showHeading)
+ qDebug() << "LYTPane" << name << "@" << (void*)this;
+
+ qDebug() << "- Translation:" << xTrans << "," << yTrans << "," << zTrans;
+ qDebug() << "- Rotation:" << xRot << "," << yRot << "," << zRot;
+ qDebug() << "- Scale:" << xScale << "," << yScale;
+ qDebug() << "- Size:" << width << "x" << height;
+ qDebug() << "- Flags:" << flags << "- Origin:" << origin;
+ qDebug() << "- Alpha:" << alpha << "- Userdata:" << userdata;
+}
+
+
+
+void LYTPane::writeToDataStream(QDataStream &out) {
+ out << (quint8)flags;
+ out << (quint8)origin;
+ out << (quint8)alpha;
+ out.skipRawData(1); // padding
+
+ WriteFixedLengthASCII(out, name, 0x10);
+ WriteFixedLengthASCII(out, userdata, 8);
+
+ out << (float)xTrans;
+ out << (float)yTrans;
+ out << (float)zTrans;
+ out << (float)xRot;
+ out << (float)yRot;
+ out << (float)zRot;
+ out << (float)xScale;
+ out << (float)yScale;
+ out << (float)width;
+ out << (float)height;
+}
+
+void LYTPane::readFromDataStream(QDataStream &in) {
+ in >> (quint8&)flags;
+ in >> (quint8&)origin;
+ in >> (quint8&)alpha;
+ in.skipRawData(1); // padding
+
+ name = ReadFixedLengthASCII(in, 0x10);
+ userdata = ReadFixedLengthASCII(in, 8);
+
+ in >> (float&)xTrans;
+ in >> (float&)yTrans;
+ in >> (float&)zTrans;
+ in >> (float&)xRot;
+ in >> (float&)yRot;
+ in >> (float&)zRot;
+ in >> (float&)xScale;
+ in >> (float&)yScale;
+ in >> (float&)width;
+ in >> (float&)height;
+}
diff --git a/lyt/pane.h b/lyt/pane.h
new file mode 100644
index 0000000..7b2f37b
--- /dev/null
+++ b/lyt/pane.h
@@ -0,0 +1,58 @@
+#ifndef LYTPANE_H
+#define LYTPANE_H
+
+#include <QtCore/QList>
+#include <QtCore/QString>
+#include <QtCore/QDataStream>
+#include <QtCore/QDebug>
+
+#include "common.h"
+
+class LYTLayout;
+
+class LYTPane {
+public:
+ LYTPane(LYTLayout &layout);
+ virtual ~LYTPane();
+
+
+ virtual void writeToDataStream(QDataStream &out);
+ virtual void readFromDataStream(QDataStream &in);
+
+ virtual void dumpToDebug(bool showHeading=true);
+
+ LYTPane *findPaneByName(QString name, bool recursive);
+
+ LYTLayout &layout() const;
+
+ LYTPane *parent;
+ QList<LYTPane *> children;
+
+ quint8 flags;
+ quint8 origin;
+ quint8 alpha;
+
+ QString name;
+ QString userdata;
+
+ float xTrans;
+ float yTrans;
+ float zTrans;
+
+ float xRot;
+ float yRot;
+ float zRot;
+
+ float xScale;
+ float yScale;
+
+ float width;
+ float height;
+
+protected:
+ LYTLayout &m_layout;
+};
+
+
+
+#endif // LYTPANE_H
diff --git a/lyt/picture.cpp b/lyt/picture.cpp
new file mode 100644
index 0000000..33b2461
--- /dev/null
+++ b/lyt/picture.cpp
@@ -0,0 +1,73 @@
+#include "picture.h"
+#include "layout.h"
+#include "common.h"
+
+
+LYTPicture::LYTPicture(LYTLayout &layout) : LYTPane(layout) {
+}
+
+
+void LYTPicture::dumpToDebug(bool showHeading) {
+ if (showHeading)
+ qDebug() << "LYTPicture" << name << "@" << (void*)this;
+
+ LYTPane::dumpToDebug(false);
+
+ qDebug() << "- Vertex Colours:" << vtxColours[0] << "-" << vtxColours[1];
+ qDebug() << " " << vtxColours[2] << "-" << vtxColours[3];
+ qDebug() << "- Material:" << materialName;
+ qDebug() << "- Tex Coords:" << texCoords.count();
+
+ foreach (LYTTexCoords texCoord, texCoords) {
+ qDebug() << "----" << texCoord.coord[0] << "-" << texCoord.coord[1] << "-" << texCoord.coord[2] << "-" << texCoord.coord[3];
+ }
+}
+
+
+
+
+void LYTPicture::writeToDataStream(QDataStream &out) {
+ LYTPane::writeToDataStream(out);
+
+ for (int i = 0; i < 4; i++)
+ WriteRGBA8Color(vtxColours[i], out);
+
+ // calculate the material number
+ int materialNum = m_layout.materials.keys().indexOf(materialName);
+ out << (quint16)materialNum;
+
+ // write texcoords
+ out << (quint8)texCoords.count();
+ out.skipRawData(1); // padding
+
+ foreach (LYTTexCoords texCoord, texCoords) {
+ for (int i = 0; i < 4; i++)
+ WritePointF(out, texCoord.coord[i]);
+ }
+}
+
+
+void LYTPicture::readFromDataStream(QDataStream &in) {
+ LYTPane::readFromDataStream(in);
+
+ for (int i = 0; i < 4; i++)
+ ReadRGBA8Color(vtxColours[i], in);
+
+ // read the material name
+ quint16 materialNum;
+ in >> (quint16&)materialNum;
+
+ materialName = m_layout.materials.keys().at(materialNum);
+
+ // read texcoords
+ quint8 texCoordNum;
+ in >> (quint8&)texCoordNum;
+ in.skipRawData(1); // padding
+
+ texCoords.resize(texCoordNum);
+
+ foreach (LYTTexCoords texCoord, texCoords) {
+ for (int i = 0; i < 4; i++)
+ ReadPointF(in, texCoord.coord[i]);
+ }
+}
diff --git a/lyt/picture.h b/lyt/picture.h
new file mode 100644
index 0000000..8242c34
--- /dev/null
+++ b/lyt/picture.h
@@ -0,0 +1,27 @@
+#ifndef LYTPICTURE_H
+#define LYTPICTURE_H
+
+#include <QtGui/QColor>
+#include <QtCore/QVector>
+
+#include "common.h"
+#include "pane.h"
+
+class LYTPicture : public LYTPane {
+public:
+ LYTPicture(LYTLayout &layout);
+
+
+ void writeToDataStream(QDataStream &out);
+ void readFromDataStream(QDataStream &in);
+
+ void dumpToDebug(bool showHeading=true);
+
+ QColor vtxColours[4];
+ QString materialName;
+
+ QVector<LYTTexCoords> texCoords;
+};
+
+
+#endif // LYTPICTURE_H
diff --git a/lyt/textbox.cpp b/lyt/textbox.cpp
new file mode 100644
index 0000000..06aed4e
--- /dev/null
+++ b/lyt/textbox.cpp
@@ -0,0 +1,115 @@
+#include "textbox.h"
+#include "layout.h"
+#include "common.h"
+
+
+LYTTextBox::LYTTextBox(LYTLayout &layout) : LYTPane(layout) {
+}
+
+
+void LYTTextBox::dumpToDebug(bool showHeading) {
+ if (showHeading)
+ qDebug() << "LYTTextBox" << name << "@" << (void*)this;
+
+ LYTPane::dumpToDebug(false);
+
+ qDebug() << "- Text:" << text;
+ qDebug() << "- Buffer Length:" << bufferLength;
+ qDebug() << "- Material:" << materialName << "- Font:" << fontName;
+ qDebug() << "- Alignment:" << alignment << "- Alignment Override:" << alignmentOverride;
+ qDebug() << "- Colours:" << colour1 << "--" << colour2;
+ qDebug() << "- Font Size:" << fontSizeX << "x" << fontSizeY;
+ qDebug() << "- Char Space:" << charSpace << "- Line Space:" << lineSpace;
+}
+
+
+
+void LYTTextBox::writeToDataStream(QDataStream &out) {
+ LYTPane::writeToDataStream(out);
+
+ // lengths are stored in bytes (including zero terminator) not characters
+ out << (quint16)((bufferLength + 1) * 2);
+ out << (quint16)((text.length() + 1) * 2);
+
+ // calculate the material and font numbers
+ int materialNum = m_layout.materials.keys().indexOf(materialName);
+ int fontNum = m_layout.m_fontRefs.indexOf(fontName);
+
+ out << (quint16)materialNum;
+ out << (quint16)fontNum;
+
+ out << (quint8)alignment;
+ out << (quint8)alignmentOverride;
+
+ out.skipRawData(2); // padding
+
+ out << (quint32)0x74; // fixed offset to textbox contents
+
+ WriteRGBA8Color(colour1, out);
+ WriteRGBA8Color(colour2, out);
+
+ out << (float)fontSizeX;
+ out << (float)fontSizeY;
+ out << (float)charSpace;
+ out << (float)lineSpace;
+
+ // write the textbox contents
+ const ushort *convertedText = text.utf16();
+ for (int i = 0; i < text.length(); i++)
+ out << (quint16)convertedText[i];
+}
+
+
+void LYTTextBox::readFromDataStream(QDataStream &in) {
+ qint64 saveStartPos = in.device()->pos();
+
+ LYTPane::readFromDataStream(in);
+
+ // the lengths are stored in bytes (not characters) and count the
+ // zero terminator, and strings are UTF-16 (I think) so we need
+ // to take it off here
+ in >> (quint16&)bufferLength;
+ bufferLength >>= 1;
+ bufferLength--;
+
+ quint16 stringLength;
+ in >> (quint16&)stringLength;
+ stringLength >>= 1;
+ stringLength--;
+
+ // read the material and font names
+ quint16 materialNum, fontNum;
+ in >> (quint16&)materialNum;
+ in >> (quint16&)fontNum;
+
+ materialName = m_layout.materials.keys().at(materialNum);
+ fontName = m_layout.m_fontRefs.at(fontNum);
+
+ in >> (quint8&)alignment;
+ in >> (quint8&)alignmentOverride;
+
+ in.skipRawData(2); // padding
+
+ quint32 stringOffset;
+ in >> (quint32&)stringOffset;
+
+ ReadRGBA8Color(colour1, in);
+ ReadRGBA8Color(colour2, in);
+
+ in >> (float&)fontSizeX;
+ in >> (float&)fontSizeY;
+ in >> (float&)charSpace;
+ in >> (float&)lineSpace;
+
+ // read the textbox contents
+ // subtract 8 to account for BinaryBlockHeader or whatever it's called
+ in.device()->seek(saveStartPos + stringOffset - 8);
+
+ ushort *rawText = new ushort[stringLength];
+
+ for (int i = 0; i < stringLength; i++)
+ in >> (quint16&)rawText[i];
+
+ text.setUtf16(rawText, stringLength);
+ delete[] rawText;
+}
diff --git a/lyt/textbox.h b/lyt/textbox.h
new file mode 100644
index 0000000..de1020d
--- /dev/null
+++ b/lyt/textbox.h
@@ -0,0 +1,37 @@
+#ifndef LYTTEXTBOX_H
+#define LYTTEXTBOX_H
+
+#include <QtGui/QColor>
+
+#include "pane.h"
+
+class LYTTextBox : public LYTPane {
+public:
+ LYTTextBox(LYTLayout &layout);
+
+
+ void writeToDataStream(QDataStream &out);
+ void readFromDataStream(QDataStream &in);
+
+ void dumpToDebug(bool showHeading=true);
+
+ quint16 bufferLength;
+ QString text;
+
+ QString materialName;
+ QString fontName;
+
+ quint8 alignment;
+ quint8 alignmentOverride;
+
+ QColor colour1;
+ QColor colour2;
+
+ float fontSizeX;
+ float fontSizeY;
+ float charSpace;
+ float lineSpace;
+};
+
+
+#endif // LYTTEXTBOX_H
diff --git a/lyt/window.cpp b/lyt/window.cpp
new file mode 100644
index 0000000..0430229
--- /dev/null
+++ b/lyt/window.cpp
@@ -0,0 +1,184 @@
+#include "window.h"
+#include "layout.h"
+#include "common.h"
+
+
+LYTWindowFrame::LYTWindowFrame(LYTWindow &window) : m_window(window) {
+}
+
+void LYTWindowFrame::writeToDataStream(QDataStream &out) {
+ // calculate the material number
+ int materialNum = m_window.m_layout.materials.keys().indexOf(materialName);
+ out << (quint16)materialNum;
+
+ out << (quint8)type;
+ out.skipRawData(1); // padding
+}
+
+void LYTWindowFrame::readFromDataStream(QDataStream &in) {
+ // read the material name
+ quint16 materialNum;
+ in >> (quint16&)materialNum;
+
+ materialName = m_window.m_layout.materials.keys().at(materialNum);
+
+ in >> (quint8&)type;
+ in.skipRawData(1); // padding
+}
+
+void LYTWindowFrame::dumpToDebug() {
+ qDebug() << "LYTWindowFrame @" << (void*)this << "- type:" << type << "- material:" << materialName;
+}
+
+
+
+LYTWindow::LYTWindow(LYTLayout &layout) : LYTPane(layout) {
+}
+
+LYTWindow::~LYTWindow() {
+ foreach (LYTWindowFrame *frame, frames)
+ delete frame;
+}
+
+
+
+// all of this needs to be done
+
+void LYTWindow::dumpToDebug(bool showHeading) {
+ if (showHeading)
+ qDebug() << "LYTWindow" << name << "@" << (void*)this;
+
+ LYTPane::dumpToDebug(false);
+
+ qDebug() << "- Content VtxColours:" << contentVtxColours[0] << "-" << contentVtxColours[1];
+ qDebug() << " " << contentVtxColours[2] << "-" << contentVtxColours[3];
+ qDebug() << "- Content Material:" << contentMaterialName;
+ qDebug() << "- Content Tex Coords:" << contentTexCoords.count();
+
+ foreach (LYTTexCoords texCoord, contentTexCoords) {
+ qDebug() << "----" << texCoord.coord[0] << "-" << texCoord.coord[1] << "-" << texCoord.coord[2] << "-" << texCoord.coord[3];
+ }
+
+ qDebug() << "- Content Overflow: Left" << contentOverflowLeft << "- Right" << contentOverflowRight;
+ qDebug() << " Top" << contentOverflowTop << "- Bottom" << contentOverflowBottom;
+
+ qDebug() << "- Frames:" << frames.count();
+
+ foreach (LYTWindowFrame *frame, frames) {
+ frame->dumpToDebug();
+ }
+}
+
+
+
+void LYTWindow::writeToDataStream(QDataStream &out) {
+ LYTPane::writeToDataStream(out);
+
+ out << (float)contentOverflowLeft;
+ out << (float)contentOverflowRight;
+ out << (float)contentOverflowTop;
+ out << (float)contentOverflowBottom;
+
+ out << (quint8)frames.count();
+ out.skipRawData(3); // padding
+
+ out << (quint32)0x68; // offset to content struct
+ out << (quint32)(0x7C + (contentTexCoords.count()*0x20)); // offset to frame offset list
+
+ for (int i = 0; i < 4; i++)
+ WriteRGBA8Color(contentVtxColours[i], out);
+
+ // calculate the material number
+ int materialNum = m_layout.materials.keys().indexOf(contentMaterialName);
+ out << (quint16)materialNum;
+
+ // write texcoords
+ out << (quint8)contentTexCoords.count();
+ out.skipRawData(1); // padding
+
+ foreach (LYTTexCoords texCoord, contentTexCoords) {
+ for (int i = 0; i < 4; i++)
+ WritePointF(out, texCoord.coord[i]);
+ }
+
+ // write frame offsets
+ quint32 frameOffset = 0x7C; // end of fixed-size part of content struct
+ frameOffset += (contentTexCoords.count() * 0x20); // end of content struct
+ frameOffset += (frames.count() * 4); // end of offset list
+
+ for (int i = 0; i < frames.count(); i++) {
+ out << (quint32)frameOffset;
+ frameOffset += 4; // size of frame struct
+ }
+
+ // now write frames
+ foreach (LYTWindowFrame *frame, frames) {
+ frame->writeToDataStream(out);
+ }
+}
+
+
+void LYTWindow::readFromDataStream(QDataStream &in) {
+ qint64 startPos = in.device()->pos();
+
+ LYTPane::readFromDataStream(in);
+
+ in >> (float&)contentOverflowLeft;
+ in >> (float&)contentOverflowRight;
+ in >> (float&)contentOverflowTop;
+ in >> (float&)contentOverflowBottom;
+
+ quint8 frameCount;
+ in >> (quint8&)frameCount;
+ in.skipRawData(3); // padding
+
+ quint32 contentOffset, frameListOffset;
+ in >> (quint32&)contentOffset;
+ in >> (quint32&)frameListOffset;
+
+ // read content struct
+ // subtract 8 from the offset because section.data doesn't contain
+ // the nw4r::ut::BinaryBlockHeader whereas these offsets do count it
+ in.device()->seek(startPos + contentOffset - 8);
+
+ for (int i = 0; i < 4; i++)
+ ReadRGBA8Color(contentVtxColours[i], in);
+
+ // read the material name
+ quint16 materialNum;
+ in >> (quint16&)materialNum;
+
+ contentMaterialName = m_layout.materials.keys().at(materialNum);
+
+ // read texcoords
+ quint8 texCoordNum;
+ in >> (quint8&)texCoordNum;
+ in.skipRawData(1); // padding
+
+ contentTexCoords.resize(texCoordNum);
+
+ foreach (LYTTexCoords texCoord, contentTexCoords) {
+ for (int i = 0; i < 4; i++)
+ ReadPointF(in, texCoord.coord[i]);
+ }
+
+ // read frame offset list
+ // subtract 8 from the offset once again
+ in.device()->seek(startPos + frameListOffset - 8);
+
+ QVector<quint32> frameOffsets(frameCount);
+
+ for (int i = 0; i < frameCount; i++) {
+ quint32 offset;
+ in >> (quint32&)offset;
+ frameOffsets[i] = offset;
+ }
+
+ // now read each frame
+ for (int i = 0; i < frameCount; i++) {
+ in.device()->seek(frameOffsets[i] - 8);
+
+ frames.append(new LYTWindowFrame(*this));
+ frames.last()->readFromDataStream(in);
+ }
+}
diff --git a/lyt/window.h b/lyt/window.h
new file mode 100644
index 0000000..dbd3c1a
--- /dev/null
+++ b/lyt/window.h
@@ -0,0 +1,63 @@
+#ifndef LYTWINDOW_H
+#define LYTWINDOW_H
+
+#include <QtGui/QColor>
+#include <QtCore/QVector>
+
+#include "common.h"
+#include "pane.h"
+
+
+class LYTWindow; // forward declaration
+
+class LYTWindowFrame {
+public:
+ LYTWindowFrame(LYTWindow &window);
+
+
+ void writeToDataStream(QDataStream &out);
+ void readFromDataStream(QDataStream &in);
+
+ void dumpToDebug();
+
+ quint8 type; // 0-5; controls texture flipping; must investigate this more
+ QString materialName;
+
+protected:
+ LYTWindow &m_window;
+};
+
+
+class LYTWindow : public LYTPane {
+public:
+ LYTWindow(LYTLayout &layout);
+ ~LYTWindow();
+
+
+ void writeToDataStream(QDataStream &out);
+ void readFromDataStream(QDataStream &in);
+
+ void dumpToDebug(bool showHeading=true);
+
+
+ float contentOverflowLeft;
+ float contentOverflowRight;
+ float contentOverflowTop;
+ float contentOverflowBottom;
+
+ QColor contentVtxColours[4];
+ QString contentMaterialName;
+ QVector<LYTTexCoords> contentTexCoords;
+
+ QList<LYTWindowFrame *> frames;
+
+
+protected:
+ void writeContentInfo(QDataStream &out);
+ void readContentInfo(QDataStream &in);
+
+ friend class LYTWindowFrame;
+};
+
+
+#endif // LYTWINDOW_H