diff options
Diffstat (limited to 'lyt')
-rw-r--r-- | lyt/binaryfile.cpp | 66 | ||||
-rw-r--r-- | lyt/binaryfile.h | 22 | ||||
-rw-r--r-- | lyt/binaryfilesection.cpp | 28 | ||||
-rw-r--r-- | lyt/binaryfilesection.h | 23 | ||||
-rw-r--r-- | lyt/bounding.cpp | 26 | ||||
-rw-r--r-- | lyt/bounding.h | 22 | ||||
-rw-r--r-- | lyt/common.cpp | 92 | ||||
-rw-r--r-- | lyt/common.h | 104 | ||||
-rw-r--r-- | lyt/directorypackage.cpp | 119 | ||||
-rw-r--r-- | lyt/directorypackage.h | 38 | ||||
-rw-r--r-- | lyt/group.cpp | 38 | ||||
-rw-r--r-- | lyt/group.h | 22 | ||||
-rw-r--r-- | lyt/layout.cpp | 223 | ||||
-rw-r--r-- | lyt/layout.h | 67 | ||||
-rw-r--r-- | lyt/materials/material.cpp | 127 | ||||
-rw-r--r-- | lyt/materials/material.h | 183 | ||||
-rw-r--r-- | lyt/materials/texmap.cpp | 41 | ||||
-rw-r--r-- | lyt/materials/texmap.h | 25 | ||||
-rw-r--r-- | lyt/packagebase.cpp | 5 | ||||
-rw-r--r-- | lyt/packagebase.h | 31 | ||||
-rw-r--r-- | lyt/pane.cpp | 87 | ||||
-rw-r--r-- | lyt/pane.h | 58 | ||||
-rw-r--r-- | lyt/picture.cpp | 73 | ||||
-rw-r--r-- | lyt/picture.h | 27 | ||||
-rw-r--r-- | lyt/textbox.cpp | 115 | ||||
-rw-r--r-- | lyt/textbox.h | 37 | ||||
-rw-r--r-- | lyt/window.cpp | 184 | ||||
-rw-r--r-- | lyt/window.h | 63 |
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 §ion) { + // 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 §ion) { + // list of texture references for this layout + + QDataStream in(section.data); + InitDataStream(in); + m_textureRefs = ReadStringList(in); +} + +void LYTLayout::readFnl1(LYTBinaryFileSection §ion) { + // list of font references for this layout + + QDataStream in(section.data); + InitDataStream(in); + m_fontRefs = ReadStringList(in); +} + +void LYTLayout::readMat1(LYTBinaryFileSection §ion) { + // 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 §ion) { + 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 §ion); + void readTxl1(LYTBinaryFileSection §ion); + void readFnl1(LYTBinaryFileSection §ion); + void readMat1(LYTBinaryFileSection §ion); + + LYTPane *createPaneObj(LYTBinaryFileSection §ion); + + 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 |